Changes in / [933f32f:6a9d4b4]


Ignore:
Files:
18 added
152 deleted
224 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    r933f32f r6a9d4b4  
    1010config.py
    1111stamp-h1
    12 libtool
    1312/Makefile
    1413**/Makefile
     
    5049libcfa/arm-nolib/
    5150
     51
    5252# generated by bison and lex from parser.yy and lex.ll
    5353src/Parser/parser.output
  • Jenkins/FullBuild

    r933f32f r6a9d4b4  
    1717
    1818                                parallel (
    19                                         gcc_6_x64: { trigger_build( 'gcc-6',   'x64' ) },
    20                                         gcc_6_x86: { trigger_build( 'gcc-6',   'x86' ) },
    21                                         gcc_5_x64: { trigger_build( 'gcc-5',   'x64' ) },
    22                                         gcc_5_x86: { trigger_build( 'gcc-5',   'x86' ) },
    23                                         clang_x64: { trigger_build( 'clang',   'x64' ) },
    24                                         clang_x86: { trigger_build( 'clang',   'x86' ) },
     19                                        gcc_6_x64: { trigger_build( 'gcc-6',   'x64', true ) },
     20                                        gcc_6_x86: { trigger_build( 'gcc-6',   'x86', true ) },
     21                                        gcc_5_x64: { trigger_build( 'gcc-5',   'x64', false ) },
     22                                        gcc_5_x86: { trigger_build( 'gcc-5',   'x86', false ) },
     23                                        clang_x64: { trigger_build( 'clang',   'x64', false ) },
     24                                        clang_x86: { trigger_build( 'clang',   'x86', false ) },
    2525                                )
    2626                        }
     27
     28                        //Push latest changes to do-lang repo
     29                        push_build()
    2730                }
    28 
    29                 promote_email(true)
    3031        }
    3132
     
    4243
    4344                //Send email to notify the failure
    44                 promote_email(false)
     45                promote_failure_email()
    4546        }
    4647
     
    5657//===========================================================================================================
    5758
    58 def trigger_build(String cc, String arch) {
     59def trigger_build(String cc, String arch, Boolean publish) {
    5960        def result = build job: 'Cforall/master',               \
    6061                parameters: [                                           \
     
    7677                        [$class: 'BooleanParameterValue',               \
    7778                          name: 'Publish',                              \
    78                           value: true],                                 \
     79                          value: publish],                              \
    7980                        [$class: 'BooleanParameterValue',               \
    8081                          name: 'Silent',                               \
     
    8889                sh("wget -q -O - http://localhost:8084/jenkins/job/Cforall/job/master/${result.number}/consoleText")
    8990                error(result.result)
     91        }
     92}
     93
     94def push_build() {
     95        //Don't use the build_stage function which outputs the compiler
     96        stage('Push') {
     97
     98                status_prefix = 'Push'
     99
     100                def out_dir = pwd tmp: true
     101                sh "mkdir -p ${out_dir}"
     102
     103                //checkout the code to make sure this is a valid git repo
     104                checkout scm
     105
     106                collect_git_info()
     107
     108                //parse git logs to find what changed
     109                sh "git remote > ${out_dir}/GIT_REMOTE"
     110                git_remote = readFile("${out_dir}/GIT_REMOTE")
     111                remoteDoLangExists = git_remote.contains("DoLang")
     112
     113                if( !remoteDoLangExists ) {
     114                        sh 'git remote add DoLang git@gitlab.do-lang.org:internal/cfa-cc.git'
     115                }
     116
     117                //sh "GIT_SSH_COMMAND=\"ssh -v\" git push DoLang ${gitRefNewValue}:master"
     118                echo('BUILD NOT PUSH SINCE DO-LANG SERVER WAS DOWN')
    90119        }
    91120}
     
    112141
    113142//Email notification on a full build failure
    114 def promote_email(boolean success) {
     143def promote_failure_email() {
    115144        echo('notifying users')
    116 
    117         def result = success ? "PROMOTE - SUCCESS" : "PROMOTE - FAILURE"
    118145
    119146        //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
    120147        //Configurations for email format
    121         def email_subject = "[cforall git][${result}]"
    122         def email_body = """<p>This is an automated email from the Jenkins build machine. It was
    123 generated following the result of the C\u2200 nightly build.</p>
     148        def email_subject = "[cforall git][PROMOTE - FAILURE]"
     149        def email_body = """This is an automated email from the Jenkins build machine. It was
     150generated because of a git hooks/post-receive script following
     151a ref change was pushed to the repository containing
     152the project "UNNAMED PROJECT".
    124153
    125 <p>Check console output at ${env.BUILD_URL} to view the results.</p>
     154Check console output at ${env.BUILD_URL} to view the results.
    126155
    127 <p>- Status --------------------------------------------------------------</p>
     156- Status --------------------------------------------------------------
    128157
    129 <p>${result}</p>
    130 
    131 <p>- Performance ---------------------------------------------------------</p>
    132 
    133 <img src="https://cforall.uwaterloo.ca/jenkins/job/Cforall/job/master/plot/Compilation/getPlot?index=0" >
    134 
    135 <p>- Logs ----------------------------------------------------------------</p>
     158PROMOTE FAILURE
    136159"""
    137160
     
    139162
    140163        //send email notification
    141         emailext body: email_body, subject: email_subject, to: email_to, attachLog: !success
     164        emailext body: email_body, subject: email_subject, to: email_to, attachLog: true
    142165}
  • Jenkinsfile

    r933f32f r6a9d4b4  
    11#!groovy
    2 
    3 import groovy.transform.Field
    42
    53//===========================================================================================================
     
    2422                wrap([$class: 'TimestamperBuildWrapper']) {
    2523
     24                        notify_server(0)
     25
    2626                        Settings = prepare_build()
    2727
     
    3434                                checkout()
    3535
     36                                notify_server(0)
     37
    3638                                build()
    3739
     
    4850                        BuildDir  = pwd tmp: true
    4951                        SrcDir    = pwd tmp: false
     52
     53                        notify_server(45)
    5054                }
    5155        }
     
    6872        finally {
    6973                //Send email with final results if this is not a full build
    70                 email(log_needed)
     74                if( Settings && !Settings.Silent ) {
     75                        email(log_needed, Settings.IsSandbox)
     76                }
    7177
    7278                echo 'Build Completed'
     
    110116                        //Also specify the compiler by hand
    111117                        targets=""
    112                         if( Settings.RunAllTests || Settings.RunBenchmark ) {
     118                        if( Settings.RunAllTests ) {
    113119                                targets="--with-target-hosts='host:debug,host:nodebug'"
    114120                        } else {
     
    147153                dir (BuildDir) {
    148154                        //Append bench results
    149                         sh "make --no-print-directory -C benchmark jenkins"
     155                        sh "${SrcDir}/benchmark/jenkins.sh ${Settings.GitNewRef} ${Settings.Architecture} ${BuildDir}/bench.json"
    150156                }
    151157        }
     
    170176        build_stage('Publish') {
    171177
    172                 if( Settings.Publish && !Settings.RunBenchmark ) { echo 'No results to publish!!!' }
    173 
    174                 def groupCompile = new PlotGroup('Compilation', 'seconds', true)
    175                 def groupConcurrency = new PlotGroup('Concurrency', 'nanoseconds', false)
     178                if( !Settings.Publish ) return
    176179
    177180                //Then publish the results
    178                 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile'  , groupCompile    , 'Compilation')
    179                 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch', groupConcurrency, 'Context Switching')
    180                 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex'    , groupConcurrency, 'Mutual Exclusion')
    181                 do_plot(Settings.RunBenchmark && Settings.Publish, 'signal'   , groupConcurrency, 'Internal and External Scheduling')
     181                sh 'curl --silent --show-error -H \'Content-Type: application/json\' --data @${BuildDir}/bench.json https://cforall.uwaterloo.ca:8082/jenkins/publish > /dev/null || true'
    182182        }
    183183}
     
    196196
    197197        return """
    198 <pre>
    199198The branch ${env.BRANCH_NAME} has been updated.
    200199${gitUpdate}
    201 </pre>
    202 
    203 <p>Check console output at ${env.BUILD_URL} to view the results.</p>
    204 
    205 <p>- Status --------------------------------------------------------------</p>
    206 
    207 <p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p>
    208 
    209 <p>- Log -----------------------------------------------------------------</p>
    210 
    211 <pre>
     200
     201Check console output at ${env.BUILD_URL} to view the results.
     202
     203- Status --------------------------------------------------------------
     204
     205BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}
     206
     207- Log -----------------------------------------------------------------
    212208${gitLog}
    213 </pre>
    214 
    215 <p>-----------------------------------------------------------------------</p>
    216 <pre>
     209-----------------------------------------------------------------------
    217210Summary of changes:
    218211${gitDiff}
    219 </pre>
    220212"""
    221213}
    222214
    223215//Standard build email notification
    224 def email(boolean log) {
     216def email(boolean log, boolean bIsSandbox) {
    225217        //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
    226218        //Configurations for email format
     
    229221        def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()
    230222        def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}"
    231         def email_body = """<p>This is an automated email from the Jenkins build machine. It was
     223        def email_body = """This is an automated email from the Jenkins build machine. It was
    232224generated because of a git hooks/post-receive script following
    233 a ref change which was pushed to the C\u2200 repository.</p>
     225a ref change which was pushed to the Cforall repository.
    234226""" + GitLogMessage()
    235227
    236         def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"
    237 
    238         if( Settings && !Settings.Silent ) {
     228        def email_to = "cforall@lists.uwaterloo.ca"
     229
     230        if( Settings && !Settings.IsSandbox ) {
    239231                //send email notification
    240232                emailext body: email_body, subject: email_subject, to: email_to, attachLog: log
     
    319311                }
    320312
    321                 this.IsSandbox          = (branch == "jenkins-sandbox")
    322313                this.RunAllTests        = param.RunAllTests
    323314                this.RunBenchmark       = param.RunBenchmark
     
    325316                this.Publish            = param.Publish
    326317                this.Silent             = param.Silent
     318                this.IsSandbox          = (branch == "jenkins-sandbox")
    327319
    328320                def full = param.RunAllTests ? " (Full)" : ""
     
    341333                this.GitNewRef = ''
    342334                this.GitOldRef = ''
    343         }
    344 }
    345 
    346 class PlotGroup implements Serializable {
    347         public String name
    348         public String unit
    349         public boolean log
    350 
    351         PlotGroup(String name, String unit, boolean log) {
    352                 this.name = name
    353                 this.unit = unit
    354                 this.log = log
    355335        }
    356336}
     
    418398}
    419399
     400def notify_server(int wait) {
     401        sh """curl --silent --show-error --data "wait=${wait}" -X POST https://cforall.uwaterloo.ca:8082/jenkins/notify > /dev/null || true"""
     402        return
     403}
     404
    420405def make_doc() {
    421406        def err = null
     
    432417        }
    433418}
    434 
    435 def do_plot(boolean new_data, String file, PlotGroup group, String title) {
    436 
    437         if(new_data) {
    438                 echo "Publishing new data"
    439         }
    440 
    441         def series = new_data ? [[
    442                                 file: "${file}.csv",
    443                                 exclusionValues: '',
    444                                 displayTableFlag: false,
    445                                 inclusionFlag: 'OFF',
    446                                 url: ''
    447                         ]] : [];
    448 
    449         echo "file is ${BuildDir}/benchmark/${file}.csv, group ${group}, title ${title}"
    450         dir("${BuildDir}/benchmark/") {
    451                 plot csvFileName: "cforall-${env.BRANCH_NAME}-${file}.csv",
    452                         csvSeries: series,
    453                         group: "${group.name}",
    454                         title: "${title}",
    455                         style: 'lineSimple',
    456                         exclZero: false,
    457                         keepRecords: false,
    458                         logarithmic: group.log,
    459                         numBuilds: '120',
    460                         useDescr: true,
    461                         yaxis: group.unit,
    462                         yaxisMaximum: '',
    463                         yaxisMinimum: ''
    464         }
    465 }
  • Makefile.am

    r933f32f r6a9d4b4  
    1111## Created On       : Sun May 31 22:14:18 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Feb  2 16:54:42 2019
    14 ## Update Count     : 21
     13## Last Modified On : Wed Dec 14 14:20:48 2016
     14## Update Count     : 15
    1515###############################################################################
    1616
     
    1818ACLOCAL_AMFLAGS  = -I automake
    1919
    20 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* # order important
     20MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/*
     21 # order important
    2122
    2223SUBDIRS = driver src . @LIBCFA_TARGET_DIRS@
  • Makefile.in

    r933f32f r6a9d4b4  
    250250distcleancheck_listfiles = find . -type f -print
    251251ACLOCAL = @ACLOCAL@
     252ALLOCA = @ALLOCA@
    252253AMTAR = @AMTAR@
    253254AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    395396AUTOMAKE_OPTIONS = foreign    # do not require all the GNU file names
    396397ACLOCAL_AMFLAGS = -I automake
    397 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* # order important
     398MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/*
    398399SUBDIRS = driver src . @LIBCFA_TARGET_DIRS@
    399400noinst_DATA = @LIBCFA_TARGET_MAKEFILES@
     
    927928.PRECIOUS: Makefile
    928929
     930 # order important
    929931
    930932@LIBCFA_TARGET_MAKEFILES@ : Makefile $(srcdir)/libcfa/configure
  • automake/cfa.m4

    r933f32f r6a9d4b4  
    8080        esac
    8181])
    82 
    83 # http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m4
    84 AC_DEFUN([M4CFA_CHECK_COMPILE_FLAG],
    85 [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
    86 AS_VAR_PUSHDEF([CACHEVAR],[m4cfa_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
    87 AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
    88         m4cfa_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
    89         _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
    90         AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
    91                 [AS_VAR_SET(CACHEVAR,[yes])],
    92                 [AS_VAR_SET(CACHEVAR,[no])])
    93         _AC_LANG_PREFIX[]FLAGS=$m4cfa_check_save_flags])
    94 AS_VAR_IF(CACHEVAR,yes,
    95         [m4_default([$2], :)],
    96         [m4_default([$3], :)])
    97 AS_VAR_POPDEF([CACHEVAR])dnl
    98 ])dnl M4CFA_CHECK_COMPILE_FLAGS
  • benchmark/Makefile.am

    r933f32f r6a9d4b4  
    2121include $(top_srcdir)/src/cfa.make
    2222
    23 AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread
    24 AM_CFAFLAGS = -quiet -nodebug -in-tree
    25 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14
    26 
    27 BENCH_V_CC = $(__bench_v_CC_$(__quiet))
    28 BENCH_V_CFA = $(__bench_v_CFA_$(__quiet))
    29 BENCH_V_CXX = $(__bench_v_CXX_$(__quiet))
    30 BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
    31 BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    32 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
    33 
    34 __quiet = verbose
    35 __bench_v_CC_quiet = @
    36 __bench_v_CFA_quiet = @
    37 __bench_v_CXX_quiet = @
    38 __bench_v_GOC_quiet = @
    39 __bench_v_JAVAC_quiet = @
    40 __bench_v_UPP_quiet = @
    41 __bench_v_CC_verbose = $(AM_V_CC)
    42 __bench_v_CFA_verbose = $(AM_V_CFA)
    43 __bench_v_CXX_verbose = $(AM_V_CXX)
    44 __bench_v_GOC_verbose = $(AM_V_GOC)
    45 __bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    46 __bench_v_UPP_verbose = $(AM_V_UPP)
    47 
    48 
     23
     24
     25AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread
     26AM_CFAFLAGS = -quiet -in-tree -nodebug
     27AM_UPPFLAGS = -quiet -nodebug -multi
    4928
    5029TOOLSDIR = ${abs_top_builddir}/tools/
     
    6746
    6847.NOTPARALLEL:
    69 .PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv
    7048
    7149## =========================================================================================================
     
    8260
    8361%.runquiet :
    84         @+make $(basename $@) CFLAGS="-w" __quiet=quiet
     62        @+make $(basename $@) CFLAGS="-w"
    8563        @taskset -c 1 ./a.out
    8664        @rm -f a.out
     
    9573## =========================================================================================================
    9674
    97 FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
    98 
    9975jenkins$(EXEEXT):
     76        @echo "{"
     77        @echo -e '\t"githash": "'${githash}'",'
     78        @echo -e '\t"arch": "'   ${arch}   '",'
    10079@DOifskipcompile@
    101         @+make compile.csv
     80        @echo -e '\t"compile": {'
     81        @+make compile TIME_FORMAT='%e,' PRINT_FORMAT='\t\t\"%s\" :'
     82        @echo -e '\t\t"dummy" : {}'
     83        @echo -e '\t},'
    10284@DOendif@
    103         @+make ctxswitch.csv
    104         @+make mutex.csv
    105         @+make signal.csv
    106 @DOifskipcompile@
    107         @cat compile.csv
    108 @DOendif@
    109         @cat ctxswitch.csv
    110         @cat mutex.csv
    111         @cat signal.csv
    112 
    113 compile.csv:
    114         @echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@
    115         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@
    116         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-attributes.make >> $@
    117         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-empty.make >> $@
    118         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-expression.make >> $@
    119         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-io.make >> $@
    120         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-monitor.make >> $@
    121         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-operators.make >> $@
    122         @+make TIME_FORMAT='%e' PRINT_FORMAT='' compile-typeof.make >> $@
    123         @$(srcdir)/fixcsv.sh $@
    124 
    125 ctxswitch.csv:
    126         @echo "coroutine,thread" > $@
    127         @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
    128         @+make ctxswitch-cfa_thread.runquiet >> $@
    129         @$(srcdir)/fixcsv.sh $@
    130 
    131 mutex.csv:
    132         @echo "1-monitor,2-monitor" > $@
    133         @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
    134         @+make mutex-cfa2.runquiet >> $@
    135         @$(srcdir)/fixcsv.sh $@
    136 
    137 signal.csv:
    138         @echo "signal-1,signal-2,waitfor-1,waitfor-2" > $@
    139         @+make signal-cfa1.runquiet >> $@ && echo -n ',' >> $@
    140         @+make signal-cfa2.runquiet >> $@ && echo -n ',' >> $@
    141         @+make waitfor-cfa1.runquiet >> $@ && echo -n ',' >> $@
    142         @+make waitfor-cfa2.runquiet >> $@
    143         @$(srcdir)/fixcsv.sh $@
     85        @echo -e '\t"ctxswitch": {'
     86        @echo -en '\t\t"coroutine":'
     87        @+make ctxswitch-cfa_coroutine.runquiet
     88        @echo -en '\t\t,"thread":'
     89        @+make ctxswitch-cfa_thread.runquiet
     90        @echo -e '\t},'
     91        @echo -e '\t"mutex": ['
     92        @echo -en '\t\t'
     93        @+make mutex-cfa1.runquiet
     94        @echo -en '\t\t,'
     95        @+make mutex-cfa2.runquiet
     96        @echo -e '\t],'
     97        @echo -e '\t"scheduling": ['
     98        @echo -en '\t\t'
     99        @+make signal-cfa1.runquiet
     100        @echo -en '\t\t,'
     101        @+make signal-cfa2.runquiet
     102        @echo -en '\t\t,'
     103        @+make waitfor-cfa1.runquiet
     104        @echo -en '\t\t,'
     105        @+make waitfor-cfa2.runquiet
     106        @echo -e '\n\t],'
     107        @echo -e '\t"epoch": ' $(shell date +%s)
     108        @echo "}"
    144109
    145110## =========================================================================================================
    146111loop$(EXEEXT):
    147         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
     112        $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
    148113
    149114function$(EXEEXT):
    150         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
     115        $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
    151116
    152117fetch_add$(EXEEXT):
    153         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    154 
    155 tls-fetch_add$(EXEEXT):
    156         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
     118        $(AM_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    157119
    158120## =========================================================================================================
     
    161123        function.run                    \
    162124        fetch_add.run                   \
    163         tls-fetch_add.run                       \
    164125        ctxswitch-pthread.run           \
    165126        ctxswitch-cfa_coroutine.run     \
     
    178139
    179140ctxswitch-kos_fibre$(EXEEXT):
    180         $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
     141        $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
    181142
    182143ctxswitch-kos_fibre2$(EXEEXT):
    183         $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre
     144        $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre
    184145endif
    185146
     
    187148
    188149ctxswitch-pthread$(EXEEXT):
    189         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
     150        $(AM_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
    190151
    191152ctxswitch-cfa_coroutine$(EXEEXT):
    192         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
     153        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
    193154
    194155ctxswitch-cfa_thread$(EXEEXT):
    195         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
     156        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
    196157
    197158ctxswitch-cfa_thread2$(EXEEXT):
    198         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
     159        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
    199160
    200161ctxswitch-upp_coroutine$(EXEEXT):
    201         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
     162        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
    202163
    203164ctxswitch-upp_thread$(EXEEXT):
    204         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
     165        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
    205166
    206167ctxswitch-goroutine$(EXEEXT):
    207         $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
     168        $(AM_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
    208169
    209170ctxswitch-java_thread$(EXEEXT):
    210         $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
     171        $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
    211172        @echo "#!/bin/sh" > a.out
    212173        @echo "java JavaThread" >> a.out
     
    226187
    227188mutex-pthread_lock$(EXEEXT):
    228         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
     189        $(AM_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
    229190
    230191mutex-upp$(EXEEXT):
    231         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
     192        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
    232193
    233194mutex-cfa1$(EXEEXT):
    234         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
     195        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
    235196
    236197mutex-cfa2$(EXEEXT):
    237         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
     198        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
    238199
    239200mutex-cfa4$(EXEEXT):
    240         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
     201        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
    241202
    242203mutex-java_thread$(EXEEXT):
    243         $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
     204        $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
    244205        @echo "#!/bin/sh" > a.out
    245206        @echo "java JavaThread" >> a.out
     
    256217
    257218signal-pthread_cond$(EXEEXT):
    258         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
     219        $(AM_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
    259220
    260221signal-upp$(EXEEXT):
    261         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
     222        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
    262223
    263224signal-cfa1$(EXEEXT):
    264         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
     225        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
    265226
    266227signal-cfa2$(EXEEXT):
    267         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
     228        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
    268229
    269230signal-cfa4$(EXEEXT):
    270         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
     231        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
    271232
    272233signal-java_thread$(EXEEXT):
    273         $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
     234        $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
    274235        @echo "#!/bin/sh" > a.out
    275236        @echo "java JavaThread" >> a.out
     
    285246
    286247waitfor-upp$(EXEEXT):
    287         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
     248        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
    288249
    289250waitfor-cfa1$(EXEEXT):
    290         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
     251        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
    291252
    292253waitfor-cfa2$(EXEEXT):
    293         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
     254        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
    294255
    295256waitfor-cfa4$(EXEEXT):
    296         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
     257        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
    297258
    298259## =========================================================================================================
     
    308269
    309270creation-cfa_coroutine$(EXEEXT):
    310         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
     271        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
    311272
    312273creation-cfa_coroutine_eager$(EXEEXT):
    313         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
     274        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
    314275
    315276creation-cfa_thread$(EXEEXT):
    316         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
     277        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
    317278
    318279creation-upp_coroutine$(EXEEXT):
    319         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
     280        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
    320281
    321282creation-upp_thread$(EXEEXT):
    322         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
     283        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
    323284
    324285creation-pthread$(EXEEXT):
    325         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
     286        $(AM_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
    326287
    327288creation-goroutine$(EXEEXT):
    328         $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
     289        $(AM_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
    329290
    330291creation-java_thread$(EXEEXT):
    331         $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
     292        $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
    332293        @echo "#!/bin/sh" > a.out
    333294        @echo "java JavaThread" >> a.out
     
    350311
    351312compile-array$(EXEEXT):
    352         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
     313        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
    353314
    354315compile-attributes$(EXEEXT):
    355         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
     316        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
    356317
    357318compile-empty$(EXEEXT):
    358         @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
     319        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
    359320
    360321compile-expression$(EXEEXT):
    361         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
     322        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
    362323
    363324compile-io$(EXEEXT):
    364         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
     325        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
    365326
    366327compile-monitor$(EXEEXT):
    367         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     328        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
    368329
    369330compile-operators$(EXEEXT):
    370         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
     331        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
    371332
    372333compile-thread$(EXEEXT):
    373         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     334        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
    374335
    375336compile-typeof$(EXEEXT):
    376         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
    377 
     337        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
     338
  • benchmark/Makefile.in

    r933f32f r6a9d4b4  
    200200DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    201201ACLOCAL = @ACLOCAL@
     202ALLOCA = @ALLOCA@
    202203AMTAR = @AMTAR@
    203204AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    371372
    372373# applies to both programs
    373 AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread
    374 AM_CFAFLAGS = -quiet -nodebug -in-tree
    375 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14
    376 BENCH_V_CC = $(__bench_v_CC_$(__quiet))
    377 BENCH_V_CFA = $(__bench_v_CFA_$(__quiet))
    378 BENCH_V_CXX = $(__bench_v_CXX_$(__quiet))
    379 BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
    380 BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    381 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
    382 __quiet = verbose
    383 __bench_v_CC_quiet = @
    384 __bench_v_CFA_quiet = @
    385 __bench_v_CXX_quiet = @
    386 __bench_v_GOC_quiet = @
    387 __bench_v_JAVAC_quiet = @
    388 __bench_v_UPP_quiet = @
    389 __bench_v_CC_verbose = $(AM_V_CC)
    390 __bench_v_CFA_verbose = $(AM_V_CFA)
    391 __bench_v_CXX_verbose = $(AM_V_CXX)
    392 __bench_v_GOC_verbose = $(AM_V_GOC)
    393 __bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    394 __bench_v_UPP_verbose = $(AM_V_UPP)
     374AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread
     375AM_CFAFLAGS = -quiet -in-tree -nodebug
     376AM_UPPFLAGS = -quiet -nodebug -multi
    395377TOOLSDIR = ${abs_top_builddir}/tools/
    396378REPEAT = ${abs_top_builddir}/tools/repeat
     
    401383PRINT_FORMAT = %20s: #Comments needed for spacing
    402384dummy_SOURCES = dummyC.c dummyCXX.cpp
    403 FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
    404385CTXSWITCH_DEPEND = loop.run function.run fetch_add.run \
    405         tls-fetch_add.run ctxswitch-pthread.run \
    406         ctxswitch-cfa_coroutine.run ctxswitch-cfa_thread.run \
    407         ctxswitch-cfa_thread2.run ctxswitch-upp_coroutine.run \
    408         ctxswitch-upp_thread.run ctxswitch-goroutine.run \
    409         ctxswitch-java_thread.run $(am__append_1)
     386        ctxswitch-pthread.run ctxswitch-cfa_coroutine.run \
     387        ctxswitch-cfa_thread.run ctxswitch-cfa_thread2.run \
     388        ctxswitch-upp_coroutine.run ctxswitch-upp_thread.run \
     389        ctxswitch-goroutine.run ctxswitch-java_thread.run \
     390        $(am__append_1)
    410391testdir = $(top_srcdir)/tests
    411392all: all-am
     
    732713
    733714.NOTPARALLEL:
    734 .PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv
    735715
    736716all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT)
     
    746726
    747727%.runquiet :
    748         @+make $(basename $@) CFLAGS="-w" __quiet=quiet
     728        @+make $(basename $@) CFLAGS="-w"
    749729        @taskset -c 1 ./a.out
    750730        @rm -f a.out
     
    758738
    759739jenkins$(EXEEXT):
     740        @echo "{"
     741        @echo -e '\t"githash": "'${githash}'",'
     742        @echo -e '\t"arch": "'   ${arch}   '",'
    760743@DOifskipcompile@
    761         @+make compile.csv
     744        @echo -e '\t"compile": {'
     745        @+make compile TIME_FORMAT='%e,' PRINT_FORMAT='\t\t\"%s\" :'
     746        @echo -e '\t\t"dummy" : {}'
     747        @echo -e '\t},'
    762748@DOendif@
    763         @+make ctxswitch.csv
    764         @+make mutex.csv
    765         @+make signal.csv
    766 @DOifskipcompile@
    767         @cat compile.csv
    768 @DOendif@
    769         @cat ctxswitch.csv
    770         @cat mutex.csv
    771         @cat signal.csv
    772 
    773 compile.csv:
    774         @echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@
    775         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@
    776         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-attributes.make >> $@
    777         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-empty.make >> $@
    778         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-expression.make >> $@
    779         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-io.make >> $@
    780         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-monitor.make >> $@
    781         @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-operators.make >> $@
    782         @+make TIME_FORMAT='%e' PRINT_FORMAT='' compile-typeof.make >> $@
    783         @$(srcdir)/fixcsv.sh $@
    784 
    785 ctxswitch.csv:
    786         @echo "coroutine,thread" > $@
    787         @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
    788         @+make ctxswitch-cfa_thread.runquiet >> $@
    789         @$(srcdir)/fixcsv.sh $@
    790 
    791 mutex.csv:
    792         @echo "1-monitor,2-monitor" > $@
    793         @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
    794         @+make mutex-cfa2.runquiet >> $@
    795         @$(srcdir)/fixcsv.sh $@
    796 
    797 signal.csv:
    798         @echo "signal-1,signal-2,waitfor-1,waitfor-2" > $@
    799         @+make signal-cfa1.runquiet >> $@ && echo -n ',' >> $@
    800         @+make signal-cfa2.runquiet >> $@ && echo -n ',' >> $@
    801         @+make waitfor-cfa1.runquiet >> $@ && echo -n ',' >> $@
    802         @+make waitfor-cfa2.runquiet >> $@
    803         @$(srcdir)/fixcsv.sh $@
     749        @echo -e '\t"ctxswitch": {'
     750        @echo -en '\t\t"coroutine":'
     751        @+make ctxswitch-cfa_coroutine.runquiet
     752        @echo -en '\t\t,"thread":'
     753        @+make ctxswitch-cfa_thread.runquiet
     754        @echo -e '\t},'
     755        @echo -e '\t"mutex": ['
     756        @echo -en '\t\t'
     757        @+make mutex-cfa1.runquiet
     758        @echo -en '\t\t,'
     759        @+make mutex-cfa2.runquiet
     760        @echo -e '\t],'
     761        @echo -e '\t"scheduling": ['
     762        @echo -en '\t\t'
     763        @+make signal-cfa1.runquiet
     764        @echo -en '\t\t,'
     765        @+make signal-cfa2.runquiet
     766        @echo -en '\t\t,'
     767        @+make waitfor-cfa1.runquiet
     768        @echo -en '\t\t,'
     769        @+make waitfor-cfa2.runquiet
     770        @echo -e '\n\t],'
     771        @echo -e '\t"epoch": ' $(shell date +%s)
     772        @echo "}"
    804773
    805774loop$(EXEEXT):
    806         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
     775        $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
    807776
    808777function$(EXEEXT):
    809         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
     778        $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
    810779
    811780fetch_add$(EXEEXT):
    812         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    813 
    814 tls-fetch_add$(EXEEXT):
    815         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
     781        $(AM_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    816782
    817783@WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre$(EXEEXT):
    818 @WITH_LIBFIBRE_TRUE@    $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
     784@WITH_LIBFIBRE_TRUE@    $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
    819785
    820786@WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre2$(EXEEXT):
    821 @WITH_LIBFIBRE_TRUE@    $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre
     787@WITH_LIBFIBRE_TRUE@    $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre
    822788
    823789ctxswitch$(EXEEXT): $(CTXSWITCH_DEPEND)
    824790
    825791ctxswitch-pthread$(EXEEXT):
    826         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
     792        $(AM_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
    827793
    828794ctxswitch-cfa_coroutine$(EXEEXT):
    829         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
     795        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
    830796
    831797ctxswitch-cfa_thread$(EXEEXT):
    832         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
     798        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
    833799
    834800ctxswitch-cfa_thread2$(EXEEXT):
    835         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
     801        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
    836802
    837803ctxswitch-upp_coroutine$(EXEEXT):
    838         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
     804        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
    839805
    840806ctxswitch-upp_thread$(EXEEXT):
    841         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
     807        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
    842808
    843809ctxswitch-goroutine$(EXEEXT):
    844         $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
     810        $(AM_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
    845811
    846812ctxswitch-java_thread$(EXEEXT):
    847         $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
     813        $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
    848814        @echo "#!/bin/sh" > a.out
    849815        @echo "java JavaThread" >> a.out
     
    862828
    863829mutex-pthread_lock$(EXEEXT):
    864         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
     830        $(AM_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
    865831
    866832mutex-upp$(EXEEXT):
    867         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
     833        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
    868834
    869835mutex-cfa1$(EXEEXT):
    870         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
     836        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
    871837
    872838mutex-cfa2$(EXEEXT):
    873         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
     839        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
    874840
    875841mutex-cfa4$(EXEEXT):
    876         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
     842        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
    877843
    878844mutex-java_thread$(EXEEXT):
    879         $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
     845        $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
    880846        @echo "#!/bin/sh" > a.out
    881847        @echo "java JavaThread" >> a.out
     
    891857
    892858signal-pthread_cond$(EXEEXT):
    893         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
     859        $(AM_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
    894860
    895861signal-upp$(EXEEXT):
    896         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
     862        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
    897863
    898864signal-cfa1$(EXEEXT):
    899         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
     865        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
    900866
    901867signal-cfa2$(EXEEXT):
    902         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
     868        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
    903869
    904870signal-cfa4$(EXEEXT):
    905         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
     871        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
    906872
    907873signal-java_thread$(EXEEXT):
    908         $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
     874        $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
    909875        @echo "#!/bin/sh" > a.out
    910876        @echo "java JavaThread" >> a.out
     
    918884
    919885waitfor-upp$(EXEEXT):
    920         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
     886        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
    921887
    922888waitfor-cfa1$(EXEEXT):
    923         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
     889        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
    924890
    925891waitfor-cfa2$(EXEEXT):
    926         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
     892        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
    927893
    928894waitfor-cfa4$(EXEEXT):
    929         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
     895        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
    930896
    931897creation$(EXEEXT) :\
     
    940906
    941907creation-cfa_coroutine$(EXEEXT):
    942         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
     908        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
    943909
    944910creation-cfa_coroutine_eager$(EXEEXT):
    945         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
     911        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
    946912
    947913creation-cfa_thread$(EXEEXT):
    948         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
     914        $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
    949915
    950916creation-upp_coroutine$(EXEEXT):
    951         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
     917        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
    952918
    953919creation-upp_thread$(EXEEXT):
    954         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
     920        $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
    955921
    956922creation-pthread$(EXEEXT):
    957         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
     923        $(AM_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
    958924
    959925creation-goroutine$(EXEEXT):
    960         $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
     926        $(AM_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
    961927
    962928creation-java_thread$(EXEEXT):
    963         $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
     929        $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
    964930        @echo "#!/bin/sh" > a.out
    965931        @echo "java JavaThread" >> a.out
     
    977943
    978944compile-array$(EXEEXT):
    979         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
     945        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
    980946
    981947compile-attributes$(EXEEXT):
    982         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
     948        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
    983949
    984950compile-empty$(EXEEXT):
    985         @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
     951        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
    986952
    987953compile-expression$(EXEEXT):
    988         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
     954        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
    989955
    990956compile-io$(EXEEXT):
    991         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
     957        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
    992958
    993959compile-monitor$(EXEEXT):
    994         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     960        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
    995961
    996962compile-operators$(EXEEXT):
    997         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
     963        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
    998964
    999965compile-thread$(EXEEXT):
    1000         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     966        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
    1001967
    1002968compile-typeof$(EXEEXT):
    1003         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
     969        $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
    1004970
    1005971# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • benchmark/ctxswitch/cfa_cor.cfa

    r933f32f r6a9d4b4  
    1111}
    1212
    13 void main( __attribute__((unused)) GreatSuspender & this ) {
     13void main( GreatSuspender & this ) {
    1414        while( true ) {
    1515                suspend();
  • benchmark/ctxswitch/cfa_thrd2.cfa

    r933f32f r6a9d4b4  
    88thread Fibre {};
    99
    10 void main(__attribute__((unused)) Fibre & this) {
     10void main(Fibre & this) {
    1111        while(!done) {
    1212                yield();
  • configure

    r933f32f r6a9d4b4  
    637637LIBOBJS
    638638CFA_BACKEND_CC
    639 WITH_LIBTCMALLOC_FALSE
    640 WITH_LIBTCMALLOC_TRUE
    641 WITH_LIBPROFILER_FALSE
    642 WITH_LIBPROFILER_TRUE
     639ALLOCA
    643640WITH_LIBFIBRE_FALSE
    644641WITH_LIBFIBRE_TRUE
     
    19641961} # ac_fn_cxx_try_link
    19651962
     1963# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
     1964# -------------------------------------------
     1965# Tests whether TYPE exists after having included INCLUDES, setting cache
     1966# variable VAR accordingly.
     1967ac_fn_c_check_type ()
     1968{
     1969  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
     1970  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
     1971$as_echo_n "checking for $2... " >&6; }
     1972if eval \${$3+:} false; then :
     1973  $as_echo_n "(cached) " >&6
     1974else
     1975  eval "$3=no"
     1976  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     1977/* end confdefs.h.  */
     1978$4
     1979int
     1980main ()
     1981{
     1982if (sizeof ($2))
     1983         return 0;
     1984  ;
     1985  return 0;
     1986}
     1987_ACEOF
     1988if ac_fn_c_try_compile "$LINENO"; then :
     1989  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     1990/* end confdefs.h.  */
     1991$4
     1992int
     1993main ()
     1994{
     1995if (sizeof (($2)))
     1996            return 0;
     1997  ;
     1998  return 0;
     1999}
     2000_ACEOF
     2001if ac_fn_c_try_compile "$LINENO"; then :
     2002
     2003else
     2004  eval "$3=yes"
     2005fi
     2006rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     2007fi
     2008rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     2009fi
     2010eval ac_res=\$$3
     2011               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
     2012$as_echo "$ac_res" >&6; }
     2013  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
     2014
     2015} # ac_fn_c_check_type
     2016
    19662017# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
    19672018# -------------------------------------------------------
     
    20552106} # ac_fn_c_check_header_mongrel
    20562107
    2057 # ac_fn_c_check_type LINENO TYPE VAR INCLUDES
    2058 # -------------------------------------------
    2059 # Tests whether TYPE exists after having included INCLUDES, setting cache
    2060 # variable VAR accordingly.
    2061 ac_fn_c_check_type ()
     2108# ac_fn_c_find_intX_t LINENO BITS VAR
     2109# -----------------------------------
     2110# Finds a signed integer type with width BITS, setting cache variable VAR
     2111# accordingly.
     2112ac_fn_c_find_intX_t ()
    20622113{
    20632114  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
    2064   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
    2065 $as_echo_n "checking for $2... " >&6; }
     2115  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5
     2116$as_echo_n "checking for int$2_t... " >&6; }
    20662117if eval \${$3+:} false; then :
    20672118  $as_echo_n "(cached) " >&6
    20682119else
    20692120  eval "$3=no"
    2070   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     2121     # Order is important - never check a type that is potentially smaller
     2122     # than half of the expected target width.
     2123     for ac_type in int$2_t 'int' 'long int' \
     2124         'long long int' 'short int' 'signed char'; do
     2125       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    20712126/* end confdefs.h.  */
    2072 $4
     2127$ac_includes_default
     2128             enum { N = $2 / 2 - 1 };
    20732129int
    20742130main ()
    20752131{
    2076 if (sizeof ($2))
    2077          return 0;
     2132static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))];
     2133test_array [0] = 0;
     2134return test_array [0];
     2135
    20782136  ;
    20792137  return 0;
     
    20832141  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    20842142/* end confdefs.h.  */
    2085 $4
     2143$ac_includes_default
     2144                enum { N = $2 / 2 - 1 };
    20862145int
    20872146main ()
    20882147{
    2089 if (sizeof (($2)))
    2090             return 0;
     2148static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1)
     2149                 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))];
     2150test_array [0] = 0;
     2151return test_array [0];
     2152
    20912153  ;
    20922154  return 0;
     
    20962158
    20972159else
    2098   eval "$3=yes"
     2160  case $ac_type in #(
     2161  int$2_t) :
     2162    eval "$3=yes" ;; #(
     2163  *) :
     2164    eval "$3=\$ac_type" ;;
     2165esac
    20992166fi
    21002167rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    21012168fi
    21022169rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     2170       if eval test \"x\$"$3"\" = x"no"; then :
     2171
     2172else
     2173  break
     2174fi
     2175     done
    21032176fi
    21042177eval ac_res=\$$3
     
    21072180  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
    21082181
    2109 } # ac_fn_c_check_type
     2182} # ac_fn_c_find_intX_t
     2183
     2184# ac_fn_c_find_uintX_t LINENO BITS VAR
     2185# ------------------------------------
     2186# Finds an unsigned integer type with width BITS, setting cache variable VAR
     2187# accordingly.
     2188ac_fn_c_find_uintX_t ()
     2189{
     2190  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
     2191  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5
     2192$as_echo_n "checking for uint$2_t... " >&6; }
     2193if eval \${$3+:} false; then :
     2194  $as_echo_n "(cached) " >&6
     2195else
     2196  eval "$3=no"
     2197     # Order is important - never check a type that is potentially smaller
     2198     # than half of the expected target width.
     2199     for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \
     2200         'unsigned long long int' 'unsigned short int' 'unsigned char'; do
     2201       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     2202/* end confdefs.h.  */
     2203$ac_includes_default
     2204int
     2205main ()
     2206{
     2207static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)];
     2208test_array [0] = 0;
     2209return test_array [0];
     2210
     2211  ;
     2212  return 0;
     2213}
     2214_ACEOF
     2215if ac_fn_c_try_compile "$LINENO"; then :
     2216  case $ac_type in #(
     2217  uint$2_t) :
     2218    eval "$3=yes" ;; #(
     2219  *) :
     2220    eval "$3=\$ac_type" ;;
     2221esac
     2222fi
     2223rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     2224       if eval test \"x\$"$3"\" = x"no"; then :
     2225
     2226else
     2227  break
     2228fi
     2229     done
     2230fi
     2231eval ac_res=\$$3
     2232               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
     2233$as_echo "$ac_res" >&6; }
     2234  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
     2235
     2236} # ac_fn_c_find_uintX_t
    21102237cat >config.log <<_ACEOF
    21112238This file contains any messages produced by compilers while
     
    25402667
    25412668
    2542 # http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m4
    2543 
    25442669
    25452670# don't use the default CFLAGS as they unconditonnaly add -O2
     
    34023527                "debug") ;;
    34033528                "nolib") ;;
    3404                 "profile") ;;
    34053529                *)
    34063530                        >&2 echo "Configuration must be 'debug', 'nodebug' or 'nolib'"
     
    50595183
    50605184
     5185        # deprecated
    50615186# These are often not installed and people miss seeing the "no", so stop the configure.
    50625187for ac_prog in 'bison -y' byacc
     
    1660916734
    1661016735
     16736{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
     16737$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
     16738set x ${MAKE-make}
     16739ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
     16740if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
     16741  $as_echo_n "(cached) " >&6
     16742else
     16743  cat >conftest.make <<\_ACEOF
     16744SHELL = /bin/sh
     16745all:
     16746        @echo '@@@%%%=$(MAKE)=@@@%%%'
     16747_ACEOF
     16748# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
     16749case `${MAKE-make} -f conftest.make 2>/dev/null` in
     16750  *@@@%%%=?*=@@@%%%*)
     16751    eval ac_cv_prog_make_${ac_make}_set=yes;;
     16752  *)
     16753    eval ac_cv_prog_make_${ac_make}_set=no;;
     16754esac
     16755rm -f conftest.make
     16756fi
     16757if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
     16758  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
     16759$as_echo "yes" >&6; }
     16760  SET_MAKE=
     16761else
     16762  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
     16763$as_echo "no" >&6; }
     16764  SET_MAKE="MAKE=${MAKE-make}"
     16765fi
     16766
    1661116767
    1661216768# Checks for libraries.
     
    1666216818
    1666316819
    16664 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ProfilingIsEnabledForAllThreads in -lprofiler" >&5
    16665 $as_echo_n "checking for ProfilingIsEnabledForAllThreads in -lprofiler... " >&6; }
    16666 if ${ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads+:} false; then :
     16820# Checks for header files.
     16821ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
     16822if test "x$ac_cv_type_size_t" = xyes; then :
     16823
     16824else
     16825
     16826cat >>confdefs.h <<_ACEOF
     16827#define size_t unsigned int
     16828_ACEOF
     16829
     16830fi
     16831
     16832# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
     16833# for constant arguments.  Useless!
     16834{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5
     16835$as_echo_n "checking for working alloca.h... " >&6; }
     16836if ${ac_cv_working_alloca_h+:} false; then :
    1666716837  $as_echo_n "(cached) " >&6
    1666816838else
    16669   ac_check_lib_save_LIBS=$LIBS
    16670 LIBS="-lprofiler  $LIBS"
    16671 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     16839  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    1667216840/* end confdefs.h.  */
    16673 
    16674 /* Override any GCC internal prototype to avoid an error.
    16675    Use char because int might match the return type of a GCC
    16676    builtin and then its argument prototype would still apply.  */
    16677 #ifdef __cplusplus
    16678 extern "C"
    16679 #endif
    16680 char ProfilingIsEnabledForAllThreads ();
     16841#include <alloca.h>
    1668116842int
    1668216843main ()
    1668316844{
    16684 return ProfilingIsEnabledForAllThreads ();
     16845char *p = (char *) alloca (2 * sizeof (int));
     16846                          if (p) return 0;
    1668516847  ;
    1668616848  return 0;
     
    1668816850_ACEOF
    1668916851if ac_fn_c_try_link "$LINENO"; then :
    16690   ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads=yes
    16691 else
    16692   ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads=no
     16852  ac_cv_working_alloca_h=yes
     16853else
     16854  ac_cv_working_alloca_h=no
    1669316855fi
    1669416856rm -f core conftest.err conftest.$ac_objext \
    1669516857    conftest$ac_exeext conftest.$ac_ext
    16696 LIBS=$ac_check_lib_save_LIBS
    16697 fi
    16698 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads" >&5
    16699 $as_echo "$ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads" >&6; }
    16700 if test "x$ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads" = xyes; then :
    16701   HAVE_LIBPROFILER=1
    16702 else
    16703   HAVE_LIBPROFILER=0
    16704 fi
    16705 
    16706  if test "$HAVE_LIBPROFILER" -eq 1; then
    16707   WITH_LIBPROFILER_TRUE=
    16708   WITH_LIBPROFILER_FALSE='#'
    16709 else
    16710   WITH_LIBPROFILER_TRUE='#'
    16711   WITH_LIBPROFILER_FALSE=
    16712 fi
    16713 
    16714 
    16715 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for malloc in -ltcmalloc" >&5
    16716 $as_echo_n "checking for malloc in -ltcmalloc... " >&6; }
    16717 if ${ac_cv_lib_tcmalloc_malloc+:} false; then :
     16858fi
     16859{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5
     16860$as_echo "$ac_cv_working_alloca_h" >&6; }
     16861if test $ac_cv_working_alloca_h = yes; then
     16862
     16863$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h
     16864
     16865fi
     16866
     16867{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5
     16868$as_echo_n "checking for alloca... " >&6; }
     16869if ${ac_cv_func_alloca_works+:} false; then :
    1671816870  $as_echo_n "(cached) " >&6
    1671916871else
    16720   ac_check_lib_save_LIBS=$LIBS
    16721 LIBS="-ltcmalloc  $LIBS"
    16722 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     16872  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    1672316873/* end confdefs.h.  */
    16724 
    16725 /* Override any GCC internal prototype to avoid an error.
    16726    Use char because int might match the return type of a GCC
    16727    builtin and then its argument prototype would still apply.  */
    16728 #ifdef __cplusplus
    16729 extern "C"
     16874#ifdef __GNUC__
     16875# define alloca __builtin_alloca
     16876#else
     16877# ifdef _MSC_VER
     16878#  include <malloc.h>
     16879#  define alloca _alloca
     16880# else
     16881#  ifdef HAVE_ALLOCA_H
     16882#   include <alloca.h>
     16883#  else
     16884#   ifdef _AIX
     16885 #pragma alloca
     16886#   else
     16887#    ifndef alloca /* predefined by HP cc +Olibcalls */
     16888void *alloca (size_t);
     16889#    endif
     16890#   endif
     16891#  endif
     16892# endif
    1673016893#endif
    16731 char malloc ();
     16894
    1673216895int
    1673316896main ()
    1673416897{
    16735 return malloc ();
     16898char *p = (char *) alloca (1);
     16899                                    if (p) return 0;
    1673616900  ;
    1673716901  return 0;
     
    1673916903_ACEOF
    1674016904if ac_fn_c_try_link "$LINENO"; then :
    16741   ac_cv_lib_tcmalloc_malloc=yes
    16742 else
    16743   ac_cv_lib_tcmalloc_malloc=no
     16905  ac_cv_func_alloca_works=yes
     16906else
     16907  ac_cv_func_alloca_works=no
    1674416908fi
    1674516909rm -f core conftest.err conftest.$ac_objext \
    1674616910    conftest$ac_exeext conftest.$ac_ext
    16747 LIBS=$ac_check_lib_save_LIBS
    16748 fi
    16749 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tcmalloc_malloc" >&5
    16750 $as_echo "$ac_cv_lib_tcmalloc_malloc" >&6; }
    16751 if test "x$ac_cv_lib_tcmalloc_malloc" = xyes; then :
    16752   HAVE_LIBTCMALLOC=1
    16753 else
    16754   HAVE_LIBTCMALLOC=0
    16755 fi
    16756 
    16757  if test "$HAVE_LIBTCMALLOC" -eq 1; then
    16758   WITH_LIBTCMALLOC_TRUE=
    16759   WITH_LIBTCMALLOC_FALSE='#'
    16760 else
    16761   WITH_LIBTCMALLOC_TRUE='#'
    16762   WITH_LIBTCMALLOC_FALSE=
    16763 fi
    16764 
    16765 
    16766 # Checks for header files.
    16767 for ac_header in libintl.h malloc.h unistd.h
     16911fi
     16912{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5
     16913$as_echo "$ac_cv_func_alloca_works" >&6; }
     16914
     16915if test $ac_cv_func_alloca_works = yes; then
     16916
     16917$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h
     16918
     16919else
     16920  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
     16921# that cause trouble.  Some versions do not even contain alloca or
     16922# contain a buggy version.  If you still want to use their alloca,
     16923# use ar to extract alloca.o from them instead of compiling alloca.c.
     16924
     16925ALLOCA=\${LIBOBJDIR}alloca.$ac_objext
     16926
     16927$as_echo "#define C_ALLOCA 1" >>confdefs.h
     16928
     16929
     16930{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5
     16931$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; }
     16932if ${ac_cv_os_cray+:} false; then :
     16933  $as_echo_n "(cached) " >&6
     16934else
     16935  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     16936/* end confdefs.h.  */
     16937#if defined CRAY && ! defined CRAY2
     16938webecray
     16939#else
     16940wenotbecray
     16941#endif
     16942
     16943_ACEOF
     16944if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
     16945  $EGREP "webecray" >/dev/null 2>&1; then :
     16946  ac_cv_os_cray=yes
     16947else
     16948  ac_cv_os_cray=no
     16949fi
     16950rm -f conftest*
     16951
     16952fi
     16953{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5
     16954$as_echo "$ac_cv_os_cray" >&6; }
     16955if test $ac_cv_os_cray = yes; then
     16956  for ac_func in _getb67 GETB67 getb67; do
     16957    as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
     16958ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
     16959if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
     16960
     16961cat >>confdefs.h <<_ACEOF
     16962#define CRAY_STACKSEG_END $ac_func
     16963_ACEOF
     16964
     16965    break
     16966fi
     16967
     16968  done
     16969fi
     16970
     16971{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5
     16972$as_echo_n "checking stack direction for C alloca... " >&6; }
     16973if ${ac_cv_c_stack_direction+:} false; then :
     16974  $as_echo_n "(cached) " >&6
     16975else
     16976  if test "$cross_compiling" = yes; then :
     16977  ac_cv_c_stack_direction=0
     16978else
     16979  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     16980/* end confdefs.h.  */
     16981$ac_includes_default
     16982int
     16983find_stack_direction (int *addr, int depth)
     16984{
     16985  int dir, dummy = 0;
     16986  if (! addr)
     16987    addr = &dummy;
     16988  *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1;
     16989  dir = depth ? find_stack_direction (addr, depth - 1) : 0;
     16990  return dir + dummy;
     16991}
     16992
     16993int
     16994main (int argc, char **argv)
     16995{
     16996  return find_stack_direction (0, argc + !argv + 20) < 0;
     16997}
     16998_ACEOF
     16999if ac_fn_c_try_run "$LINENO"; then :
     17000  ac_cv_c_stack_direction=1
     17001else
     17002  ac_cv_c_stack_direction=-1
     17003fi
     17004rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
     17005  conftest.$ac_objext conftest.beam conftest.$ac_ext
     17006fi
     17007
     17008fi
     17009{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5
     17010$as_echo "$ac_cv_c_stack_direction" >&6; }
     17011cat >>confdefs.h <<_ACEOF
     17012#define STACK_DIRECTION $ac_cv_c_stack_direction
     17013_ACEOF
     17014
     17015
     17016fi
     17017
     17018for ac_header in fenv.h float.h inttypes.h libintl.h limits.h malloc.h stddef.h stdlib.h string.h unistd.h
    1676817019do :
    1676917020  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
     
    1677417025_ACEOF
    1677517026
    16776 else
    16777   echo "Error: Missing required header"; exit 1
    1677817027fi
    1677917028
     
    1678217031
    1678317032# Checks for typedefs, structures, and compiler characteristics.
    16784 ac_fn_c_check_type "$LINENO" "_Float32" "ac_cv_type__Float32" "
    16785 "
    16786 if test "x$ac_cv_type__Float32" = xyes; then :
    16787 
    16788 cat >>confdefs.h <<_ACEOF
    16789 #define HAVE__FLOAT32 1
    16790 _ACEOF
    16791 
    16792 
    16793 $as_echo "#define HAVE_KEYWORDS_FLOATXX /**/" >>confdefs.h
    16794 
    16795 fi
    16796 
    16797 
    16798 # Checks for compiler flags.
    16799 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wcast-function-type" >&5
    16800 $as_echo_n "checking whether C compiler accepts -Wcast-function-type... " >&6; }
    16801 if ${m4cfa_cv_check_cflags___Wcast_function_type+:} false; then :
     17033{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5
     17034$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; }
     17035if ${ac_cv_header_stdbool_h+:} false; then :
    1680217036  $as_echo_n "(cached) " >&6
    1680317037else
    16804 
    16805         m4cfa_check_save_flags=$CFLAGS
    16806         CFLAGS="$CFLAGS  -Wcast-function-type"
    16807         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     17038  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    1680817039/* end confdefs.h.  */
     17040
     17041             #include <stdbool.h>
     17042             #ifndef bool
     17043              "error: bool is not defined"
     17044             #endif
     17045             #ifndef false
     17046              "error: false is not defined"
     17047             #endif
     17048             #if false
     17049              "error: false is not 0"
     17050             #endif
     17051             #ifndef true
     17052              "error: true is not defined"
     17053             #endif
     17054             #if true != 1
     17055              "error: true is not 1"
     17056             #endif
     17057             #ifndef __bool_true_false_are_defined
     17058              "error: __bool_true_false_are_defined is not defined"
     17059             #endif
     17060
     17061             struct s { _Bool s: 1; _Bool t; } s;
     17062
     17063             char a[true == 1 ? 1 : -1];
     17064             char b[false == 0 ? 1 : -1];
     17065             char c[__bool_true_false_are_defined == 1 ? 1 : -1];
     17066             char d[(bool) 0.5 == true ? 1 : -1];
     17067             /* See body of main program for 'e'.  */
     17068             char f[(_Bool) 0.0 == false ? 1 : -1];
     17069             char g[true];
     17070             char h[sizeof (_Bool)];
     17071             char i[sizeof s.t];
     17072             enum { j = false, k = true, l = false * true, m = true * 256 };
     17073             /* The following fails for
     17074                HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */
     17075             _Bool n[m];
     17076             char o[sizeof n == m * sizeof n[0] ? 1 : -1];
     17077             char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1];
     17078             /* Catch a bug in an HP-UX C compiler.  See
     17079                http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html
     17080                http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html
     17081              */
     17082             _Bool q = true;
     17083             _Bool *pq = &q;
    1680917084
    1681017085int
    1681117086main ()
    1681217087{
     17088
     17089             bool e = &s;
     17090             *pq |= q;
     17091             *pq |= ! q;
     17092             /* Refer to every declared value, to avoid compiler optimizations.  */
     17093             return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l
     17094                     + !m + !n + !o + !p + !q + !pq);
    1681317095
    1681417096  ;
     
    1681717099_ACEOF
    1681817100if ac_fn_c_try_compile "$LINENO"; then :
    16819   m4cfa_cv_check_cflags___Wcast_function_type=yes
    16820 else
    16821   m4cfa_cv_check_cflags___Wcast_function_type=no
     17101  ac_cv_header_stdbool_h=yes
     17102else
     17103  ac_cv_header_stdbool_h=no
    1682217104fi
    1682317105rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    16824         CFLAGS=$m4cfa_check_save_flags
    16825 fi
    16826 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $m4cfa_cv_check_cflags___Wcast_function_type" >&5
    16827 $as_echo "$m4cfa_cv_check_cflags___Wcast_function_type" >&6; }
    16828 if test "x$m4cfa_cv_check_cflags___Wcast_function_type" = xyes; then :
    16829 
    16830 $as_echo "#define HAVE_CAST_FUNCTION_TYPE /**/" >>confdefs.h
    16831 
    16832 else
    16833   :
    16834 fi
     17106fi
     17107{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5
     17108$as_echo "$ac_cv_header_stdbool_h" >&6; }
     17109   ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default"
     17110if test "x$ac_cv_type__Bool" = xyes; then :
     17111
     17112cat >>confdefs.h <<_ACEOF
     17113#define HAVE__BOOL 1
     17114_ACEOF
     17115
     17116
     17117fi
     17118
     17119
     17120if test $ac_cv_header_stdbool_h = yes; then
     17121
     17122$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h
     17123
     17124fi
     17125
     17126{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
     17127$as_echo_n "checking for inline... " >&6; }
     17128if ${ac_cv_c_inline+:} false; then :
     17129  $as_echo_n "(cached) " >&6
     17130else
     17131  ac_cv_c_inline=no
     17132for ac_kw in inline __inline__ __inline; do
     17133  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     17134/* end confdefs.h.  */
     17135#ifndef __cplusplus
     17136typedef int foo_t;
     17137static $ac_kw foo_t static_foo () {return 0; }
     17138$ac_kw foo_t foo () {return 0; }
     17139#endif
     17140
     17141_ACEOF
     17142if ac_fn_c_try_compile "$LINENO"; then :
     17143  ac_cv_c_inline=$ac_kw
     17144fi
     17145rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     17146  test "$ac_cv_c_inline" != no && break
     17147done
     17148
     17149fi
     17150{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
     17151$as_echo "$ac_cv_c_inline" >&6; }
     17152
     17153case $ac_cv_c_inline in
     17154  inline | yes) ;;
     17155  *)
     17156    case $ac_cv_c_inline in
     17157      no) ac_val=;;
     17158      *) ac_val=$ac_cv_c_inline;;
     17159    esac
     17160    cat >>confdefs.h <<_ACEOF
     17161#ifndef __cplusplus
     17162#define inline $ac_val
     17163#endif
     17164_ACEOF
     17165    ;;
     17166esac
     17167
     17168ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t"
     17169case $ac_cv_c_int16_t in #(
     17170  no|yes) ;; #(
     17171  *)
     17172
     17173cat >>confdefs.h <<_ACEOF
     17174#define int16_t $ac_cv_c_int16_t
     17175_ACEOF
     17176;;
     17177esac
     17178
     17179ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t"
     17180case $ac_cv_c_int32_t in #(
     17181  no|yes) ;; #(
     17182  *)
     17183
     17184cat >>confdefs.h <<_ACEOF
     17185#define int32_t $ac_cv_c_int32_t
     17186_ACEOF
     17187;;
     17188esac
     17189
     17190ac_fn_c_find_intX_t "$LINENO" "8" "ac_cv_c_int8_t"
     17191case $ac_cv_c_int8_t in #(
     17192  no|yes) ;; #(
     17193  *)
     17194
     17195cat >>confdefs.h <<_ACEOF
     17196#define int8_t $ac_cv_c_int8_t
     17197_ACEOF
     17198;;
     17199esac
     17200
     17201{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5
     17202$as_echo_n "checking for C/C++ restrict keyword... " >&6; }
     17203if ${ac_cv_c_restrict+:} false; then :
     17204  $as_echo_n "(cached) " >&6
     17205else
     17206  ac_cv_c_restrict=no
     17207   # The order here caters to the fact that C++ does not require restrict.
     17208   for ac_kw in __restrict __restrict__ _Restrict restrict; do
     17209     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     17210/* end confdefs.h.  */
     17211typedef int * int_ptr;
     17212        int foo (int_ptr $ac_kw ip) {
     17213        return ip[0];
     17214       }
     17215int
     17216main ()
     17217{
     17218int s[1];
     17219        int * $ac_kw t = s;
     17220        t[0] = 0;
     17221        return foo(t)
     17222  ;
     17223  return 0;
     17224}
     17225_ACEOF
     17226if ac_fn_c_try_compile "$LINENO"; then :
     17227  ac_cv_c_restrict=$ac_kw
     17228fi
     17229rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     17230     test "$ac_cv_c_restrict" != no && break
     17231   done
     17232
     17233fi
     17234{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5
     17235$as_echo "$ac_cv_c_restrict" >&6; }
     17236
     17237 case $ac_cv_c_restrict in
     17238   restrict) ;;
     17239   no) $as_echo "#define restrict /**/" >>confdefs.h
     17240 ;;
     17241   *)  cat >>confdefs.h <<_ACEOF
     17242#define restrict $ac_cv_c_restrict
     17243_ACEOF
     17244 ;;
     17245 esac
     17246
     17247ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
     17248if test "x$ac_cv_type_size_t" = xyes; then :
     17249
     17250else
     17251
     17252cat >>confdefs.h <<_ACEOF
     17253#define size_t unsigned int
     17254_ACEOF
     17255
     17256fi
     17257
     17258ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t"
     17259case $ac_cv_c_uint16_t in #(
     17260  no|yes) ;; #(
     17261  *)
     17262
     17263
     17264cat >>confdefs.h <<_ACEOF
     17265#define uint16_t $ac_cv_c_uint16_t
     17266_ACEOF
     17267;;
     17268  esac
     17269
     17270ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t"
     17271case $ac_cv_c_uint32_t in #(
     17272  no|yes) ;; #(
     17273  *)
     17274
     17275$as_echo "#define _UINT32_T 1" >>confdefs.h
     17276
     17277
     17278cat >>confdefs.h <<_ACEOF
     17279#define uint32_t $ac_cv_c_uint32_t
     17280_ACEOF
     17281;;
     17282  esac
     17283
     17284ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t"
     17285case $ac_cv_c_uint8_t in #(
     17286  no|yes) ;; #(
     17287  *)
     17288
     17289$as_echo "#define _UINT8_T 1" >>confdefs.h
     17290
     17291
     17292cat >>confdefs.h <<_ACEOF
     17293#define uint8_t $ac_cv_c_uint8_t
     17294_ACEOF
     17295;;
     17296  esac
     17297
     17298
     17299# Checks for library functions.
     17300for ac_func in memset putenv strchr strtol
     17301do :
     17302  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
     17303ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
     17304if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
     17305  cat >>confdefs.h <<_ACEOF
     17306#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
     17307_ACEOF
     17308
     17309fi
     17310done
    1683517311
    1683617312
     
    1684517321
    1684617322#==============================================================================
    16847 ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile longrun_tests/Makefile tools/Makefile tools/prettyprinter/Makefile"
     17323ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile tests/preempt_longrun/Makefile tools/Makefile tools/prettyprinter/Makefile"
    1684817324
    1684917325
     
    1699617472if test -z "${WITH_LIBFIBRE_TRUE}" && test -z "${WITH_LIBFIBRE_FALSE}"; then
    1699717473  as_fn_error $? "conditional \"WITH_LIBFIBRE\" was never defined.
    16998 Usually this means the macro was only invoked conditionally." "$LINENO" 5
    16999 fi
    17000 if test -z "${WITH_LIBPROFILER_TRUE}" && test -z "${WITH_LIBPROFILER_FALSE}"; then
    17001   as_fn_error $? "conditional \"WITH_LIBPROFILER\" was never defined.
    17002 Usually this means the macro was only invoked conditionally." "$LINENO" 5
    17003 fi
    17004 if test -z "${WITH_LIBTCMALLOC_TRUE}" && test -z "${WITH_LIBTCMALLOC_FALSE}"; then
    17005   as_fn_error $? "conditional \"WITH_LIBTCMALLOC\" was never defined.
    1700617474Usually this means the macro was only invoked conditionally." "$LINENO" 5
    1700717475fi
     
    1799118459    "benchmark/Makefile") CONFIG_FILES="$CONFIG_FILES benchmark/Makefile" ;;
    1799218460    "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
    17993     "longrun_tests/Makefile") CONFIG_FILES="$CONFIG_FILES longrun_tests/Makefile" ;;
     18461    "tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES tests/preempt_longrun/Makefile" ;;
    1799418462    "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
    1799518463    "tools/prettyprinter/Makefile") CONFIG_FILES="$CONFIG_FILES tools/prettyprinter/Makefile" ;;
  • configure.ac

    r933f32f r6a9d4b4  
    139139                "debug") ;;
    140140                "nolib") ;;
    141                 "profile") ;;
    142141                *)
    143142                        >&2 echo "Configuration must be 'debug', 'nodebug' or 'nolib'"
     
    179178AC_PROG_CC
    180179AM_PROG_AS
     180AM_PROG_CC_C_O  # deprecated
    181181# These are often not installed and people miss seeing the "no", so stop the configure.
    182182AC_PROG_YACC
     
    186186AC_PROG_LIBTOOL
    187187AC_PROG_INSTALL
     188AC_PROG_MAKE_SET
    188189
    189190# Checks for libraries.
     
    191192AM_CONDITIONAL([WITH_LIBFIBRE], [test "$HAVE_LIBFIBRE" -eq 1])
    192193
    193 AC_CHECK_LIB([profiler], [ProfilingIsEnabledForAllThreads], [HAVE_LIBPROFILER=1], [HAVE_LIBPROFILER=0])
    194 AM_CONDITIONAL([WITH_LIBPROFILER], [test "$HAVE_LIBPROFILER" -eq 1])
    195 
    196 AC_CHECK_LIB([tcmalloc], [malloc], [HAVE_LIBTCMALLOC=1], [HAVE_LIBTCMALLOC=0])
    197 AM_CONDITIONAL([WITH_LIBTCMALLOC], [test "$HAVE_LIBTCMALLOC" -eq 1])
    198 
    199194# Checks for header files.
    200 AC_CHECK_HEADERS([libintl.h malloc.h unistd.h], [], [echo "Error: Missing required header"; exit 1])
     195AC_FUNC_ALLOCA
     196AC_CHECK_HEADERS([fenv.h float.h inttypes.h libintl.h limits.h malloc.h stddef.h stdlib.h string.h unistd.h])
    201197
    202198# Checks for typedefs, structures, and compiler characteristics.
    203 AC_CHECK_TYPES([_Float32], AC_DEFINE([HAVE_KEYWORDS_FLOATXX], [], [Have keywords _FloatXX.]), [], [[]])
    204 
    205 # Checks for compiler flags.
    206 M4CFA_CHECK_COMPILE_FLAG([-Wcast-function-type], AC_DEFINE([HAVE_CAST_FUNCTION_TYPE], [], [Have compiler warning cast-function-type.]))
     199AC_HEADER_STDBOOL
     200AC_C_INLINE
     201AC_TYPE_INT16_T
     202AC_TYPE_INT32_T
     203AC_TYPE_INT8_T
     204AC_C_RESTRICT
     205AC_TYPE_SIZE_T
     206AC_TYPE_UINT16_T
     207AC_TYPE_UINT32_T
     208AC_TYPE_UINT8_T
     209
     210# Checks for library functions.
     211AC_CHECK_FUNCS([memset putenv strchr strtol])
    207212
    208213#==============================================================================
     
    218223        benchmark/Makefile
    219224        tests/Makefile
    220         longrun_tests/Makefile
     225        tests/preempt_longrun/Makefile
    221226        tools/Makefile
    222227        tools/prettyprinter/Makefile
  • doc/LaTeXmacros/lstlang.sty

    r933f32f r6a9d4b4  
    88%% Created On       : Sat May 13 16:34:42 2017
    99%% Last Modified By : Peter A. Buhr
    10 %% Last Modified On : Tue Jan  8 14:40:33 2019
    11 %% Update Count     : 21
     10%% Last Modified On : Fri Apr  6 23:44:50 2018
     11%% Update Count     : 20
    1212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1313
     
    114114                _Alignas, _Alignof, __alignof, __alignof__, asm, __asm, __asm__, __attribute, __attribute__,
    115115                auto, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,
    116                 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally,
     116                coroutine, disable, dtype, enable, __extension__, exception, fallthrough, fallthru, finally,
    117117                __float80, float80, __float128, float128, forall, ftype, _Generic, _Imaginary, __imag, __imag__,
    118118                inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or,
  • doc/bibliography/pl.bib

    r933f32f r6a9d4b4  
    330330    contributer = {pabuhr@plg},
    331331    author      = {Nissim Francez},
    332     title       = {Another Advantage of Keyword Notation for Parameter Communication with Subprograms},
     332    title       = {Another Advantage of Key word Notation for Parameter Communication with Subprograms},
    333333    journal     = cacm,
    334334    volume      = 20,
     
    831831    year        = 2015,
    832832    howpublished= {\href{http://www.boost.org/doc/libs/1_61_0/libs/coroutine/doc/html/index.html}
    833                   {http://www.boost.org/\-doc/\-libs/1\_61\_0/\-libs/\-coroutine/\-doc/\-html/\-index.html}},
    834 }
    835 
    836 @misc{BoostThreads,
    837     keywords    = {Boost Thread Library},
    838     contributer = {pabuhr@plg},
    839     author      = {Anthony Williams and Vicente J. Botet Escriba},
    840     title       = {Boost Thread Library},
    841     year        = 2015,
    842     howpublished= {\href{https://www.boost.org/doc/libs/1_61_0/doc/html/thread.html}
    843                   {https://\-www.boost.org/\-doc/\-libs/\-1\_61\_0/\-doc/\-html/\-thread.html}},
     833                  {{http://www.boost.org/\-doc/\-libs/1\_61\_0/\-libs/\-coroutine/\-doc/\-html/\-index.html}}},
     834    optnote     = {Accessed: 2016-09},
    844835}
    845836
     
    948939    author      = {{\textsf{C}{$\mathbf{\forall}$} Features}},
    949940    howpublished= {\href{https://plg.uwaterloo.ca/~cforall/features}{https://\-plg.uwaterloo.ca/\-$\sim$cforall/\-features}},
     941    optnote     = {Accessed: 2018-01-01},
    950942}
    951943
     
    967959    year        = 2018,
    968960    howpublished= {\href{https://cforall.uwaterloo.ca/CFAStackEvaluation.zip}{https://cforall.uwaterloo.ca/\-CFAStackEvaluation.zip}},
     961    optnote     = {[Accessed May 2018]},
    969962}
    970963
     
    973966    contributer = {pabuhr@plg},
    974967    author      = {Aaron Moss and Robert Schluntz and Peter A. Buhr},
    975     title       = {\textsf{C}$\mathbf{\forall}$ : Adding Modern Programming Language Features to {C}},
     968    title       = {\textsf{C}$\mathbf{\forall}$ : Adding Modern Programming Language Features to C},
    976969    journal     = spe,
    977970    volume      = 48,
     
    10931086}
    10941087
    1095 @techreport{Prokopec11,
    1096   keywords = {ctrie, concurrent map},
    1097   contributer = {a3moss@uwaterloo.ca},
    1098   title={Cache-aware lock-free concurrent hash tries},
    1099   author={Prokopec, Aleksandar and Bagwell, Phil and Odersky, Martin},
    1100   institution={EPFL},
    1101   year={2011}
    1102 }
    1103 
    11041088@article{Buhr85,
    11051089    keywords    = {goto, multi-exit loop},
     
    11481132    year        = 1998,
    11491133    note        = {{\small\textsf{ftp://\-plg.uwaterloo.ca/\-pub/\-Cforall/\-refrat.ps.gz}}},
    1150 }
    1151 
    1152 @phdthesis{Norrish98,
    1153   title={C formalised in HOL},
    1154   author={Norrish, Michael},
    1155   year={1998},
    1156   school={University of Cambridge}
    1157 }
    1158 
    1159 @inproceedings{Tarditi18,
    1160     keywords    = {Checked C},
    1161     contributer = {a3moss@uwaterloo.ca},
    1162     author      = {Tarditi, David and Elliott, Archibald Samuel and Ruef, Andrew and Hicks, Michael},
    1163     title       = {Checked C: Making C Safe by Extension},
    1164     booktitle   = {2018 IEEE Cybersecurity Development (SecDev)},
    1165     year        = {2018},
    1166     month       = {September},
    1167     pages       = {53-60},
    1168     publisher   = {IEEE},
    1169     url         = {https://www.microsoft.com/en-us/research/publication/checkedc-making-c-safe-by-extension/},
    1170 }
    1171 
    1172 @misc{Clang,
    1173     keywords    = {clang},
    1174     contributer = {a3moss@uwaterloo.ca},
    1175     title       = {Clang: a {C} language family frontend for {LLVM}},
    1176     howpublished= {\href{https://clang.llvm.org/}{https://\-clang.llvm.org/}}
    11771134}
    11781135
     
    12771234}
    12781235
    1279 @inproceedings{Odersky01,
    1280  keywords = {Scala},
    1281  contributer = {a3moss@uwaterloo.ca},
    1282  author = {Odersky, Martin and Zenger, Christoph and Zenger, Matthias},
    1283  title = {Colored Local Type Inference},
    1284  booktitle = {Proceedings of the 28th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages},
    1285  series = {POPL '01},
    1286  year = {2001},
    1287  isbn = {1-58113-336-7},
    1288  location = {London, United Kingdom},
    1289  pages = {41--53},
    1290  numpages = {13},
    1291  url = {http://doi.acm.org/10.1145/360204.360207},
    1292  doi = {10.1145/360204.360207},
    1293  acmid = {360207},
    1294  publisher = {ACM},
    1295  address = {New York, NY, USA},
    1296 }
    1297 
    12981236@book{sml:commentary,
    12991237    author      = {Robin Milner and Mads Tofte},
     
    13561294    journal     = sigplan,
    13571295    year        = 1986,
    1358     month       = oct,
    1359     volume      = 21,
    1360     number      = 10,
    1361     pages       = {19-28},
     1296    month       = oct, volume = 21, number = 10, pages = {19-28},
    13621297    note        = {Object Oriented Programming Workshop}
    13631298}
     
    15241459    title       = {concurrent-locking},
    15251460    howpublished= {\href{https://github.com/pabuhr/concurrent-locking}{https://\-github.com/\-pabuhr/\-concurrent-locking}},
     1461    optnote     = {[Accessed April 2017]},
    15261462}
    15271463
     
    16851621}
    16861622
    1687 @inproceedings{Prokopec12,
    1688   keywords={ctrie, hash trie, concurrent map},
    1689   contributer={a3moss@uwaterloo.ca},
    1690   title={Concurrent tries with efficient non-blocking snapshots},
    1691   author={Prokopec, Aleksandar and Bronson, Nathan Grasso and Bagwell, Phil and Odersky, Martin},
    1692   booktitle={ACM SIGPLAN Notices},
    1693   volume={47},
    1694   number={8},
    1695   pages={151--160},
    1696   year={2012},
    1697   organization={ACM}
    1698 }
    1699 
    17001623@article{Buhr05a,
    17011624    keywords    = {concurrency, myths},
     
    18241747    howpublished= {\href{https://www.airs.com/blog/archives/428}
    18251748                  {https://www.airs.com/\-blog/\-archives/\-428}},
     1749    optnote     = {Accessed: 2018-05},
    18261750}
    18271751
     
    19191843    year        = 1965,
    19201844    note        = {Reprinted in \cite{Genuys68} pp. 43--112.}
    1921 }
    1922 
    1923 @manual{C++20Coroutine19,
    1924     keywords    = {coroutine},
    1925     contributer = {pabuhr@plg},
    1926     title       = {Coroutines (C++20)},
    1927     organization= {cppreference.com},
    1928     month       = apr,
    1929     year        = 2019,
    1930     note        = {\href{https://en.cppreference.com/w/cpp/language/coroutines}{https://\-en.cppreference.com/\-w/\-cpp/\-language/\-coroutines}},
    19311845}
    19321846
     
    23572271}
    23582272
    2359 @article{Ritchie93,
    2360     keywords    = {C, history},
    2361     contributer = {pabuhr@plg},
    2362     author      = {Ritchie, Dennis M.},
    2363     title       = {The Development of the {C} Language},
    2364     journal     = sigplan,
    2365     volume      = 28,
    2366     number      = 3,
    2367     month       = mar,
    2368     year        = 1993,
    2369     pages       = {201--208},
    2370     url         = {http://doi.acm.org/10.1145/155360.155580},
    2371     publisher   = {ACM},
    2372     address     = {New York, NY, USA},
    2373 }
    2374 
    23752273@article{design,
    23762274    keywords    = {Smalltalk, designing classes},
     
    23802278    journal     = joop,
    23812279    year        = 1988,
    2382     volume      = 1,
    2383     number      = 2,
    2384     pages       = {22-35},
     2280    volume      = 1, number = 2, pages = {22-35},
    23852281    comment     = {
    23862282        Abstract classes represent standard protocols.  ``It is better to
     
    24672363    year        = 1990,
    24682364    pages       = {315-323}
    2469 }
    2470 
    2471 @misc{Dotty-github,
    2472     keywords = {dotty,scala},
    2473     contributer = {a3moss@uwaterloo.ca},
    2474     author = {Martin Odersky},
    2475     title = {Dotty},
    2476     howpublished = {\href{https://github.com/lampepfl/dotty}{https://\-github.com/\-lampepfl/\-dotty}},
    2477     note = {Acessed: 2019-02-22}
    24782365}
    24792366
     
    25832470    pages       = {325-361},
    25842471}
    2585 
    2586 @article{Tarjan75,
    2587  keywords = {union-find},
    2588  contributer = {a3moss@uwaterloo.ca},
    2589  author = {Tarjan, Robert Endre},
    2590  title = {Efficiency of a Good But Not Linear Set Union Algorithm},
    2591  journal = {J. ACM},
    2592  issue_date = {April 1975},
    2593  volume = {22},
    2594  number = {2},
    2595  month = apr,
    2596  year = {1975},
    2597  issn = {0004-5411},
    2598  pages = {215--225},
    2599  numpages = {11},
    2600  url = {http://doi.acm.org/10.1145/321879.321884},
    2601  doi = {10.1145/321879.321884},
    2602  acmid = {321884},
    2603  publisher = {ACM},
    2604  address = {New York, NY, USA},
    2605 }
    26062472
    26072473@book{Eiffel,
     
    30402906    year        = 2014,
    30412907    howpublished= {\href{https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/C-Extensions.html}{https://\-gcc.gnu.org/\-onlinedocs/\-gcc-4.7.2/\-gcc/\-C\-Extensions.html}},
     2908    optnote     = {Accessed: 2017-04-02},
    30422909}
    30432910
     
    31232990}
    31242991
    3125 @manual{WindowsFibers,
    3126     keywords    = {threads, fibers},
    3127     contributer = {pabuhr@plg},
    3128     author      = {Windows},
    3129     title       = {Fibers},
    3130     organization= {Microsoft, Windows Development Center},
    3131     address     = {\href{https://docs.microsoft.com/en-us/windows/desktop/ProcThread/fibers}{https://\-docs.microsoft.com/\-en-us/\-windows/\-desktop/\-ProcThread/\-fibers}},
    3132     year        = 2018,
    3133 }
    3134 
    31352992@inproceedings{F-bound,
    31362993    keywords    = {},
     
    31803037}
    31813038
    3182 @manual{Folly,
    3183     keywords    = {Folly},
    3184     contributer = {pabuhr@plg},
    3185     author      = {Folly},
    3186     title       = {Facebook Open-source Library},
    3187     organization= {Facebook},
    3188     address     = {\href{https://github.com/facebook/folly}{https://\-github.com/\-facebook/\-folly}},
    3189     year        = 2018,
    3190 }
    3191 
    3192 @article{Leroy09,
    3193  keywords = {C formalization},
    3194  contributer = {a3moss@uwaterloo.ca},
    3195  author = {Leroy, Xavier},
    3196  title = {Formal Verification of a Realistic Compiler},
    3197  journal = {Commun. ACM},
    3198  issue_date = {July 2009},
    3199  volume = {52},
    3200  number = {7},
    3201  month = jul,
    3202  year = {2009},
    3203  issn = {0001-0782},
    3204  pages = {107--115},
    3205  numpages = {9},
    3206  url = {http://doi.acm.org/10.1145/1538788.1538814},
    3207  doi = {10.1145/1538788.1538814},
    3208  acmid = {1538814},
    3209  publisher = {ACM},
    3210  address = {New York, NY, USA},
    3211 }
    3212 
    32133039@manual{Fortran95,
    32143040    keywords    = {Fortran 95},
     
    32313057    address     = {\href{https://www.iso.org/standard/50459.html}{https://\-www.iso.org/\-standard/\-50459.html}},
    32323058    year        = 2010,
    3233 }
    3234 
    3235 @manual{Fortran18,
    3236     keywords    = {ISO/IEC Fortran 10},
    3237     contributer = {pabuhr@plg},
    3238     author      = {Fortran18},
    3239     title       = {Programming Languages -- {Fortran} Part 1:Base Language ISO/IEC 1539-1:2018},
    3240     edition     = {4rd},
    3241     publisher   = {International Standard Organization},
    3242     address     = {\href{https://www.iso.org/standard/72320.html}{https://\-www.iso.org/\-standard/\-72320.html}},
    3243     year        = 2018,
    32443059}
    32453060
     
    34913306    year        = 2014,
    34923307    howpublished= {https://developer.gnome.org/gobject/stable/},
     3308    optnote     = {Accessed: 2017-04},
    34933309}
    34943310
     
    38053621    year        = {1964},
    38063622    publisher   = {ACM}
    3807 }
    3808 
    3809 @phdthesis{Barghi18,
    3810     keywords    = {concurrency, user threads, actors},
    3811     contributer = {pabuhr@plg},
    3812     author      = {Saman Barghi},
    3813     title       = {Improving the Performance of User-level Runtime Systems for Concurrent Applications},
    3814     school      = {School of Computer Science, University of Waterloo},
    3815     year        = 2018,
    3816     month       = sep,
    3817     optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    3818     note        = {\href{https://uwspace.uwaterloo.ca/handle/10012/13935}{https://\-uwspace.uwaterloo.ca/\-handle/\-10012/\-13935}},
    3819 }
    3820 
    3821 @article{Swift05,
    3822    contributer  = {pabuhr@plg},
    3823    author       = {Michael M. Swift and Brian N. Bershad and Henry M. Levy},
    3824    title        = {Improving the Reliability of Commodity Operating Systems},
    3825    journal      = tocs,
    3826    volume       = 23,
    3827    number       = 1,
    3828    month        = feb,
    3829    year         = 2005,
    3830    pages        = {77-110},
    38313623}
    38323624
     
    41353927}
    41363928
    4137 @article{Morgado13,
    4138   keywords = {expression resolution},
    4139   contributer = {a3moss@uwaterloo.ca},
    4140   title={Iterative and core-guided {MaxSAT} solving: A survey and assessment},
    4141   author={Morgado, Antonio and Heras, Federico and Liffiton, Mark and Planes, Jordi and Marques-Silva, Joao},
    4142   journal={Constraints},
    4143   volume={18},
    4144   number={4},
    4145   pages={478--534},
    4146   year={2013},
    4147   publisher={Springer}
    4148 }
    4149 
    41503929% J
    41513930                 
     
    41693948    year        = 2015,
    41703949    edition     = {{J}ava {SE} 8},
    4171 }
    4172 
    4173 @manual{Java11,
    4174     keywords    = {Java SE 11},
    4175     contributer = {pabuhr@plg},
    4176     author      = {James Gosling and Bill Joy and Guy Steele and Gilad Bracha and Alex Buckley and Daniel Smith},
    4177     title       = {{Java} Language Specification},
    4178     publisher   = {Oracle},
    4179     month       = sep,
    4180     year        = 2018,
    4181     edition     = {{J}ava {SE} 11},
    4182 }
    4183 
    4184 @manual{JDK1.1,
    4185     keywords    = {JDK 1.1},
    4186     contributer = {pabuhr@plg},
    4187     author      = {{Multithreading Models}},
    4188     title       = {JDK 1.1 for Solaris Developer's Guide},
    4189     publisher   = {Oracle},
    4190     address     = {\href{https://docs.oracle.com/cd/E19455-01/806-3461/6jck06gqk/index.html#ch2mt-41}{https://\-docs.oracle.com/\-cd/\-E19455-01/\-806-3461/\-6jck06gqk/\-index.html\#ch2mt-41}},
    4191     year        = 2010,
    41923950}
    41933951
     
    43714129}
    43724130
    4373 @manual{libmill,
    4374     keywords    = {libmill},
    4375     contributer = {pabuhr@plg},
    4376     author      = {libmill},
    4377     title       = {{G}o-style concurrency in {C}, Version 1.18},
    4378     organization= {libmill},
    4379     address     = {\href{http://libmill.org/documentation.html}{http://\-libmill.org/\-documentation.html}},
    4380     month       = jan,
    4381     year        = 2017,
    4382 }
    4383 
    43844131@book{Weissman67,
    43854132    keywords    = {lisp},
     
    43914138}
    43924139
    4393 @article{Pierce00,
    4394  keywords = {Scala},
    4395  contributer = {a3moss@uwaterloo.ca},
    4396  author = {Pierce, Benjamin C. and Turner, David N.},
    4397  title = {Local Type Inference},
    4398  journal = {ACM Trans. Program. Lang. Syst.},
    4399  issue_date = {Jan. 2000},
    4400  volume = {22},
    4401  number = {1},
    4402  month = jan,
    4403  year = {2000},
    4404  issn = {0164-0925},
    4405  pages = {1--44},
    4406  numpages = {44},
    4407  url = {http://doi.acm.org/10.1145/345099.345100},
    4408  doi = {10.1145/345099.345100},
    4409  acmid = {345100},
    4410  publisher = {ACM},
    4411  address = {New York, NY, USA},
    4412  keywords = {polymorphism, subtyping, type inference},
    4413 }
    4414 
    44154140@article{Sundell08,
    44164141    keywords    = {lock free, deque},
     
    44234148    year        = 2008,
    44244149    pages       = {1008-1020},
    4425 }
    4426 
    4427 @misc{Matsakis17,
    4428     keywords    = {Rust, Chalk, PROLOG},
    4429     contributer = {a3moss@uwaterloo.ca},
    4430     author      = {Nicholas Matsakis},
    4431     title       = {Lowering {Rust} traits to logic},
    4432     month       = jan,
    4433     year        = 2017,
    4434     howpublished= {\href{http://smallcultfollowing.com/babysteps/blog/2017/01/26/lowering-rust-traits-to-logic/}
    4435                   {http://smallcultfollowing.com/\-babysteps/\-blog/\-2017/\-01/\-26/\-lowering-rust-traits-to-logic/}},
    4436     optnote     = {Accessed: 2019-01},
    44374150}
    44384151
     
    44514164}
    44524165
    4453 @manual{Lua,
    4454     keywords    = {Lua},
    4455     contributer = {pabuhr@plg},
    4456     author      = {Lua},
    4457     title       = {Lua 5.3 Reference Manual},
    4458     address     = {\href{https://www.lua.org/manual/5.3}{https://\-www.lua.org/\-manual/\-5.3}},
    4459     year        = 2018,
    4460 }
    4461 
    44624166% M
    44634167
     
    44694173    publisher   = {Motorola},
    44704174    year        = 1992,
    4471 }
    4472 
    4473 @misc{Haberman16,
    4474     keywords    = {C++ template expansion},
    4475     contributer = {a3moss@uwaterloo.ca},
    4476     author      = {Josh Haberman},
    4477     title       = {Making arbitrarily-large binaries from fixed-size {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} code},
    4478     year        = 2016,
    4479     howpublished= {\href{http://blog.reverberate.org/2016/01/making-arbitrarily-large-binaries-from.html}
    4480                   {
    4481           {http://blog.reverberate.org/\-2016/\-01/\-making-arbitrarily-large-binaries-from.html}
    4482           }},
    4483     optnote     = {Accessed: 2016-09},
    44844175}
    44854176
     
    48004491}
    48014492%    editor     = {Allen Kent and James G. Williams},
    4802 
    4803 @incollection{MPC,
    4804     keywords    = {user-level threading},
    4805     contributer = {pabuhr@plg},
    4806     author      = {Marc P\'erache and Herv\'e Jourdren and Raymond Namyst},
    4807     title       = {MPC: A Unified Parallel Runtime for Clusters of {NUMA} Machines},
    4808     booktitle   = {Euro-Par 2008},
    4809     pages       = {329-342},
    4810     publisher   = {Springer},
    4811     address     = {Berlin, Heidelberg},
    4812     year        = 2008,
    4813     volume      = 5168,
    4814     series      = {Lecture Notes in Computer Science},
    4815 }
    48164493
    48174494@manual{MPI,
     
    52404917    year        = 2014,
    52414918    howpublished= {\href{https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC}{https://\-developer.apple.com/\-library/archive/\-documentation/\-Cocoa/\-Conceptual/\-ProgrammingWithObjectiveC}},
     4919    optnote     = {Accessed: 2018-03}
    52424920}
    52434921
     
    52494927    year        = 2015,
    52504928    howpublished= {\href{https://developer.apple.com/library/content/documentation/Xcode/Conceptual/RN-Xcode-Archive/Chapters/xc7_release_notes.html}{https://\-developer.apple.com/\-library/\-content/\-documentation/\-Xcode/\-Conceptual/\-RN-Xcode-Archive/\-Chapters/\-xc7\_release\_notes.html}},
     4929    optnote     = {Accessed: 2017-04}
    52514930}
    52524931
     
    53835062    note        = {\href{https://www.openmp.org/wp-content/uploads/openmp-4.5.pdf}{https://\-www.openmp.org/\-wp-content/\-uploads/\-openmp-4.5.pdf}},
    53845063}
    5385 
    5386 @inproceedings{Krebbers14,
    5387  keywords = {c formalization},
    5388  contributer = {a3moss@uwaterloo.ca},
    5389  author = {Krebbers, Robbert},
    5390  title = {An Operational and Axiomatic Semantics for Non-determinism and Sequence Points in C},
    5391  booktitle = {Proceedings of the 41st ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages},
    5392  series = {POPL '14},
    5393  year = {2014},
    5394  isbn = {978-1-4503-2544-8},
    5395  location = {San Diego, California, USA},
    5396  pages = {101--112},
    5397  numpages = {12},
    5398  url = {http://doi.acm.org/10.1145/2535838.2535878},
    5399  doi = {10.1145/2535838.2535878},
    5400  acmid = {2535878},
    5401  publisher = {ACM},
    5402  address = {New York, NY, USA},
    5403 }
    54045064
    54055065@book{Deitel04,
     
    57805440    year        = 2012,
    57815441    howpublished= {\href{http://cs.brown.edu/research/pubs/theses/masters/2012/verch.pdf}{http://cs.brown.edu/\-research/\-pubs/\-theses/\-masters/\-2012/\-verch.pdf}},
     5442    optnote     = {Accessed: 2013-10-4}
    57825443}
    57835444
     
    61035764    address     = {\href{https://www.iso.org/standard/64029.html}{https://\-www.iso.org/\-standard/\-64029.html}},
    61045765    year        = 2014,
    6105 }
    6106 
    6107 @manual{C++17,
    6108     keywords    = {ISO/IEC C++ 17},
    6109     contributer = {pabuhr@plg},
    6110     key         = {C++17},
    6111     title       = {{C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Programming Language ISO/IEC 14882:2017},
    6112     edition     = {5th},
    6113     publisher   = {International Standard Organization},
    6114     address     = {\href{https://www.iso.org/standard/68564.html}{https://\-www.iso.org/\-standard/\-68564.html}},
    6115     year        = 2017,
    61165766}
    61175767
     
    62675917    institution = {Carnegie Mellon University},
    62685918    year        = 1991,
    6269     month       = feb,
    6270     number      = {CMU-CS-91-106},
     5919    month       = feb, number = "CMU-CS-91-106",
    62715920    annote      = {
    62725921        Discusses a typed lambda calculus with
     
    63255974    journal     = sigplan,
    63265975    year        = 1988,
    6327     month       = jul,
    6328     volume      = 23,
    6329     number      = 7,
    6330     pages       = {260-267},
    6331     note        = {Proceedings of the SIGPLAN '88 Conference on Programming Language Design and Implementation},
     5976    month       = jul, volume = 23, number = 7, pages = {260-267},
     5977    note        = {Proceedings of the SIGPLAN '88 Conference on Programming Language
     5978         Design and Implementation},
    63325979    abstract    = {
    63335980        This paper deals with the integration of an efficient asynchronous
     
    63796026}
    63806027
    6381 @misc{Pthreads,
    6382     keywords    = {pthreads, C concurrency},
    6383     contributer = {pabuhr@plg},
    6384     key         = {pthreads},
    6385     title       = {{Pthread}.h, Specifications Issue 7, {IEEE} Std 1003.1-2017},
    6386     author      = {IEEE and {The Open Group}},
    6387     year        = 2018,
    6388     howpublished= {\href{http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/pthread.h.html}
    6389                   {http://\-pubs.opengroup.org/\-onlinepubs/\-9699919799/\-basedefs/\-pthread.h.html}},
    6390 }
    6391 
    63926028@manual{Python,
    63936029    keywords    = {Python},
    63946030    contributer = {pabuhr@plg},
    6395     author      = {Python},
    6396     title       = {Python Language Reference, Release 3.7.2},
     6031    title       = {Python Reference Manual, Release 2.5},
     6032    author      = {Guido van Rossum},
    63976033    organization= {Python Software Foundation},
    6398     address     = {\href{https://docs.python.org/3/reference/index.html}{https://\-docs.python.org/\-3/\-reference/\-index.html}},
    6399     year        = 2018,
     6034    month       = sep,
     6035    year        = 2006,
     6036    note        = {Fred L. Drake, Jr., editor},
    64006037}
    64016038
    64026039% Q
    6403 
    6404 @inproceedings{Qthreads,
    6405     keywords    = {user-level threading},
    6406     author      = {Kyle B. Wheeler and Richard C. Murphy and Douglas Thain},
    6407     title       = {Qthreads: An API for Programming with Millions of Lightweight Threads},
    6408     booktitle   = {International Symposium on Parallel and Distributed Processing},
    6409     organization= {IEEE},
    6410     address     = {Miami, FL, USA},
    6411     month       = apr,
    6412     year        = 2008,
    6413 }
    64146040
    64156041@article{Grossman06,
     
    64486074}
    64496075
    6450 @manual{Quasar,
    6451     keywords    = {Quasar},
    6452     contributer = {pabuhr@plg},
    6453     author      = {Quasar},
    6454     title       = {Quasar Documentation, Release 0.8.0},
    6455     organization= {Parallel Universe},
    6456     address     = {\href{http://docs.paralleluniverse.co/quasar}{http://\-docs.paralleluniverse.co/\-quasar}},
    6457     year        = 2018,
    6458 }
    6459 
    64606076% R
    64616077
     
    65716187    number      = 10,
    65726188    pages       = {27-32},
    6573 }
    6574 
    6575 @article{Hesselink06,
    6576     author      = {Wim H. Hesselink},
    6577     title       = {Refinement Verification of the Lazy Caching Algorithm},
    6578     journal     = acta,
    6579     year        = 2006,
    6580     month       = oct,
    6581     volume      = 43,
    6582     number      = 3,
    6583     pages       = {195--222},
    65846189}
    65856190
     
    67206325}
    67216326
    6722 @manual{Ruby,
    6723     keywords    = {Ruby},
    6724     contributer = {pabuhr@plg},
    6725     author      = {Ruby},
    6726     title       = {Ruby Documentation, Release 2.6.0},
    6727     organization= {Python Software Foundation},
    6728     address     = {\href{https://www.ruby-lang.org/en/documentation}{https://\-www.ruby-lang.org/\-en/\-documentation}},
    6729     year        = 2018,
    6730 }
    6731 
    67326327% S
    67336328
     
    74667061}
    74677062
    7468 @article{SysVABI,
    7469   keywords = {System V ABI},
    7470   contributer = {a3moss@uwaterloo.ca},
    7471   title={System {V} application binary interface},
    7472   author={Matz, Michael and Hubicka, Jan and Jaeger, Andreas and Mitchell, Mark},
    7473   journal={AMD64 Architecture Processor Supplement, Draft v0},
    7474   volume={99},
    7475   year={2013}
    7476 }
    7477 
    74787063% T
    74797064
     
    75307115    author      = {{TIOBE Index}},
    75317116    howpublished= {\href{http://www.tiobe.com/tiobe_index}{http://\-www.tiobe.com/\-tiobe\_index}},
    7532 }
    7533 
    7534 @misc{ThreadModel,
    7535     contributer = {pabuhr@plg},
    7536     key         = {ThreadModel},
    7537     title       = {Thread (computing)},
    7538     author      = {{Threading Model}},
    7539     howpublished= {\href{https://en.wikipedia.org/wiki/Thread_(computing)}{https://\-en.wikipedia.org/\-wiki/\-Thread\_(computing)}},
     7117    optnote     = {Accessed: 2018-09},
    75407118}
    75417119
     
    76997277}
    77007278
    7701 @techreport{Black90,
    7702   title={Typechecking polymorphism in {Emerald}},
    7703   author={Black, Andrew P and Hutchinson, Norman C},
    7704   year={1990},
    7705   institution={Cambridge Research Laboratory, Digital Equipment Corporation}
    7706 }
    7707 
    77087279@article{Cormack90,
    77097280    keywords    = {polymorphism},
     
    78767447    year        = 2017,
    78777448    howpublished= {\url{https://wiki.gnome.org/Projects/Vala/Manual}},
     7449    optnote     = {Accessed: 2017-04}
    78787450}
    78797451
     
    80497621% Y
    80507622
    8051 @article{Boehm12,
    8052     keywords    = {memory model, race condition},
    8053     contributer = {pabuhr@plg},
    8054     author      = {Boehm, Hans-J. and Adve, Sarita V.},
    8055     title       = {You Don'T Know Jack About Shared Variables or Memory Models},
    8056     journal     = cacm,
    8057     volume      = 55,
    8058     number      = 2,
    8059     month       = feb,
    8060     year        = 2012,
    8061     pages       = {48--54},
    8062     publisher   = {ACM},
    8063     address     = {New York, NY, USA},
    8064 }
    8065 
    80667623% Z
    80677624
  • doc/papers/concurrency/Paper.tex

    r933f32f r6a9d4b4  
    215215{}
    216216\lstnewenvironment{Go}[1][]
    217 {\lstset{language=go,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
    218 {}
    219 \lstnewenvironment{python}[1][]
    220 {\lstset{language=python,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
     217{\lstset{#1}}
    221218{}
    222219
     
    231228}
    232229
    233 \title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}}
     230\title{\texorpdfstring{Concurrency in \protect\CFA}{Concurrency in Cforall}}
    234231
    235232\author[1]{Thierry Delisle}
     
    241238\corres{*Peter A. Buhr, Cheriton School of Computer Science, University of Waterloo, 200 University Avenue West, Waterloo, ON, N2L 3G1, Canada. \email{pabuhr{\char`\@}uwaterloo.ca}}
    242239
    243 % \fundingInfo{Natural Sciences and Engineering Research Council of Canada}
     240\fundingInfo{Natural Sciences and Engineering Research Council of Canada}
    244241
    245242\abstract[Summary]{
    246 \CFA is a polymorphic, non-object-oriented, concurrent, backwards-compatible extension of the C programming language.
    247 This paper discusses the design philosophy and implementation of its advanced control-flow and concurrent/parallel features, along with the supporting runtime.
    248 These features are created from scratch as ISO C has only low-level and/or unimplemented concurrency, so C programmers continue to rely on library features like C pthreads.
    249 \CFA introduces modern language-level control-flow mechanisms, like coroutines, user-level threading, and monitors for mutual exclusion and synchronization.
    250 Library extension for executors, futures, and actors are built on these basic mechanisms.
    251 The runtime provides significant programmer simplification and safety by eliminating spurious wakeup and reducing monitor barging.
    252 The runtime also ensures multiple monitors can be safely acquired \emph{simultaneously} (deadlock free), and this feature is fully integrated with all monitor synchronization mechanisms.
    253 All language features integrate with the \CFA polymorphic type-system and exception handling, while respecting the expectations and style of C programmers.
     243\CFA is a modern, polymorphic, \emph{non-object-oriented} extension of the C programming language.
     244This paper discusses the design of the concurrency and parallelism features in \CFA, and its concurrent runtime-system.
     245These features are created from scratch as ISO C lacks concurrency, relying largely on the pthreads library for concurrency.
     246Coroutines and lightweight (user) threads are introduced into \CFA;
     247as well, monitors are added as a high-level mechanism for mutual exclusion and synchronization.
     248A unique contribution of this work is allowing multiple monitors to be safely acquired \emph{simultaneously}.
     249All features respect the expectations of C programmers, while being fully integrate with the \CFA polymorphic type-system and other language features.
    254250Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming-languages.
    255251}%
    256252
    257 \keywords{coroutines, concurrency, parallelism, threads, monitors, runtime, C, \CFA (Cforall)}
     253\keywords{concurrency, parallelism, coroutines, threads, monitors, runtime, C, Cforall}
    258254
    259255
     
    266262\section{Introduction}
    267263
    268 This paper discusses the design philosophy and implementation of advanced language-level control-flow and concurrent/parallel features in \CFA~\cite{Moss18} and its runtime.
    269 \CFA is a modern, polymorphic, non-object-oriented\footnote{
    270 \CFA has features often associated with object-oriented programming languages, such as constructors, destructors, virtuals and simple inheritance.
    271 However, functions \emph{cannot} be nested in structures, so there is no lexical binding between a structure and set of functions (member/method) implemented by an implicit \lstinline@this@ (receiver) parameter.},
    272 backwards-compatible extension of the C programming language.
    273 Within the \CFA framework, new control-flow features are created from scratch.
    274 ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}.
    275 However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}.
    276 Furthermore, \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and a few locks, which is low-level and error prone;
    277 no high-level language concurrency features are defined.
    278 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-8 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach.
    279 Finally, while the \Celeven standard does not state a threading model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}.
    280 
    281 In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages.
    282 As multi-core hardware became available in the 1980/90s, both user and kernel threading were examined.
    283 Kernel threading was chosen, largely because of its simplicity and fit with the simpler operating systems and hardware architectures at the time, which gave it a performance advantage~\cite{Drepper03}.
    284 Libraries like pthreads were developed for C, and the Solaris operating-system switched from user (JDK 1.1~\cite{JDK1.1}) to kernel threads.
    285 As a result, languages like Java, Scala~\cite{Scala}, Objective-C~\cite{obj-c-book}, \CCeleven~\cite{C11}, and C\#~\cite{Csharp} adopt the 1:1 kernel-threading model, with a variety of presentation mechanisms.
    286 From 2000 onwards, languages like Go~\cite{Go}, Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, D~\cite{D}, and \uC~\cite{uC++,uC++book} have championed the M:N user-threading model, and many user-threading libraries have appeared~\cite{Qthreads,MPC,BoostThreads}, including putting green threads back into Java~\cite{Quasar}.
    287 The main argument for user-level threading is that they are lighter weight than kernel threads (locking and context switching do not cross the kernel boundary), so there is less restriction on programming styles that encourage large numbers of threads performing smaller work-units to facilitate load balancing by the runtime~\cite{Verch12}.
    288 As well, user-threading facilitates a simpler concurrency approach using thread objects that leverage sequential patterns versus events with call-backs~\cite{vonBehren03}.
    289 Finally, performant user-threading implementations (both time and space) are largely competitive with direct kernel-threading implementations, while achieving the programming advantages of high concurrency levels and safety.
    290 
    291 A further effort over the past two decades is the development of language memory-models to deal with the conflict between language features and compiler/hardware optimizations, i.e., some language features are unsafe in the presence of aggressive sequential optimizations~\cite{Buhr95a,Boehm05}.
    292 The consequence is that a language must provide sufficient tools to program around safety issues, as inline and library code is all sequential to the compiler.
    293 One solution is low-level qualifiers and functions (e.g., @volatile@ and atomics) allowing \emph{programmers} to explicitly write safe (race-free~\cite{Boehm12}) programs.
    294 A safer solution is high-level language constructs so the \emph{compiler} knows the optimization boundaries, and hence, provides implicit safety.
    295 This problem is best know with respect to concurrency, but applies to other complex control-flow, like exceptions\footnote{
    296 \CFA exception handling will be presented in a separate paper.
    297 The key feature that dovetails with this paper is non-local exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++}
    298 } and coroutines.
    299 Finally, solutions in the language allows matching constructs with language paradigm, i.e., imperative and functional languages have different presentations of the same concept.
    300 
    301 Finally, it is important for a language to provide safety over performance \emph{as the default}, allowing careful reduction of safety for performance when necessary.
    302 Two concurrency violations of this philosophy are \emph{spurious wakeup} and \emph{barging}, i.e., random wakeup~\cite[\S~8]{Buhr05a} and signalling-as-hints~\cite[\S~8]{Buhr05a}, where one begats the other.
    303 If you believe spurious wakeup is a foundational concurrency property, than unblocking (signalling) a thread is always a hint.
    304 If you \emph{do not} believe spurious wakeup is foundational, than signalling-as-hints is a performance decision.
    305 Most importantly, removing spurious wakeup and signals-as-hints makes concurrent programming significantly safer because it removes local non-determinism.
    306 Clawing back performance where the local non-determinism is unimportant, should be an option not the default.
    307 
    308 \begin{comment}
    309 For example, it is possible to provide exceptions, coroutines, monitors, and tasks as specialized types in an object-oriented language, integrating these constructs to allow leveraging the type-system (static type-checking) and all other object-oriented capabilities~\cite{uC++}.
    310 It is also possible to leverage call/return for blocking communication via new control structures, versus switching to alternative communication paradigms, like channels or message passing.
    311 As well, user threading is often a complementary feature, allowing light-weight threading to match with low-cost objects, while hiding the application/kernel boundary.
    312 User threading also allows layering of implicit concurrency models (no explicit thread creation), such executors, data-flow, actors, into a single language, so programmers can chose the model that best fits an algorithm.\footnote{
    313 All implicit concurrency models have explicit threading in their implementation, and hence, can be build from explicit threading;
    314 however, the reverse is seldom true, i.e., given implicit concurrency, e.g., actors, it is virtually impossible to create explicit concurrency, e.g., blocking thread objects.}
    315 Finally, with extended language features and user-level threading it is possible to discretely fold locking and non-blocking I/O multiplexing into the language's I/O libraries, so threading implicitly dovetails with the I/O subsystem.
    316 \CFA embraces language extensions and user-level threading to provide advanced control-flow (exception handling\footnote{
    317 \CFA exception handling will be presented in a separate paper.
    318 The key feature that dovetails with this paper is non-local exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++}
    319 } and coroutines) and concurrency.
    320 
    321 Most augmented traditional (Fortran 18~\cite{Fortran18}, Cobol 14~\cite{Cobol14}, Ada 12~\cite{Ada12}, Java 11~\cite{Java11}) and new languages (Go~\cite{Go}, Rust~\cite{Rust}, and D~\cite{D}), except \CC, diverge from C with different syntax and semantics, only interoperate indirectly with C, and are not systems languages, for those with managed memory.
    322 As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten.
    323 While \CC, like \CFA, takes an evolutionary approach to extend C, \CC's constantly growing complex and interdependent features-set (e.g., objects, inheritance, templates, etc.) mean idiomatic \CC code is difficult to use from C, and C programmers must expend significant effort learning \CC.
    324 Hence, rewriting and retraining costs for these languages, even \CC, are prohibitive for companies with a large C software-base.
    325 \CFA with its orthogonal feature-set, its high-performance runtime, and direct access to all existing C libraries circumvents these problems.
    326 \end{comment}
    327 
    328 \CFA embraces user-level threading, language extensions for advanced control-flow, and safety as the default.
    329 We present comparative examples so the reader can judge if the \CFA control-flow extensions are better and safer than those in or proposed for \Celeven, \CC and other concurrent, imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms.
    330 The main contributions of this work are:
    331 \begin{itemize}
    332 \item
    333 expressive language-level coroutines and user-level threading, which respect the expectations of C programmers.
    334 \item
    335 monitor synchronization without barging.
    336 \item
    337 safely acquiring multiple monitors \emph{simultaneously} (deadlock free), while seamlessly integrating this capability with all monitor synchronization mechanisms.
    338 \item
    339 providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features.
    340 \item
    341 library extensions for executors, futures, and actors built on the basic mechanisms.
    342 \item
    343 a runtime system with no spurious wakeup.
    344 \item
    345 experimental results showing comparable performance of the new features with similar mechanisms in other concurrent programming-languages.
    346 \end{itemize}
    347 
    348 \begin{comment}
    349264This paper provides a minimal concurrency \newterm{Application Program Interface} (API) that is simple, efficient and can be used to build other concurrency features.
    350265While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master.
     
    366281The proposed concurrency API is implemented in a dialect of C, called \CFA (pronounced C-for-all).
    367282The paper discusses how the language features are added to the \CFA translator with respect to parsing, semantics, and type checking, and the corresponding high-performance runtime-library to implement the concurrent features.
    368 \end{comment}
    369 
    370 
    371 \begin{comment}
     283
     284
    372285\section{\CFA Overview}
    373286
     
    638551\end{cfa}
    639552where the return type supplies the type/size of the allocation, which is impossible in most type systems.
    640 \end{comment}
    641 
    642 
    643 \section{Coroutines: Stepping Stone}
    644 \label{coroutine}
    645 
     553
     554
     555\section{Concurrency}
     556\label{s:Concurrency}
     557
     558At its core, concurrency is based on multiple call-stacks and scheduling threads executing on these stacks.
     559Multiple call stacks (or contexts) and a single thread of execution, called \newterm{coroutining}~\cite{Conway63,Marlin80}, does \emph{not} imply concurrency~\cite[\S~2]{Buhr05a}.
     560In coroutining, the single thread is self-scheduling across the stacks, so execution is deterministic, \ie the execution path from input to output is fixed and predictable.
     561A \newterm{stackless} coroutine executes on the caller's stack~\cite{Python} but this approach is restrictive, \eg preventing modularization and supporting only iterator/generator-style programming;
     562a \newterm{stackful} coroutine executes on its own stack, allowing full generality.
     563Only stackful coroutines are a stepping stone to concurrency.
     564
     565The transition to concurrency, even for execution with a single thread and multiple stacks, occurs when coroutines also context switch to a \newterm{scheduling oracle}, introducing non-determinism from the coroutine perspective~\cite[\S~3]{Buhr05a}.
     566Therefore, a minimal concurrency system is possible using coroutines (see Section \ref{coroutine}) in conjunction with a scheduler to decide where to context switch next.
     567The resulting execution system now follows a cooperative threading-model, called \newterm{non-preemptive scheduling}.
     568
     569Because the scheduler is special, it can either be a stackless or stackful coroutine.
     570For stackless, the scheduler performs scheduling on the stack of the current coroutine and switches directly to the next coroutine, so there is one context switch.
     571For stackful, the current coroutine switches to the scheduler, which performs scheduling, and it then switches to the next coroutine, so there are two context switches.
     572A stackful scheduler is often used for simplicity and security.
     573
     574Regardless of the approach used, a subset of concurrency related challenges start to appear.
     575For the complete set of concurrency challenges to occur, the missing feature is \newterm{preemption}, where context switching occurs randomly between any two instructions, often based on a timer interrupt, called \newterm{preemptive scheduling}.
     576While a scheduler introduces uncertainty in the order of execution, preemption introduces uncertainty about where context switches occur.
     577Interestingly, uncertainty is necessary for the runtime (operating) system to give the illusion of parallelism on a single processor and increase performance on multiple processors.
     578The reason is that only the runtime has complete knowledge about resources and how to best utilized them.
     579However, the introduction of unrestricted non-determinism results in the need for \newterm{mutual exclusion} and \newterm{synchronization} to restrict non-determinism for correctness;
     580otherwise, it is impossible to write meaningful programs.
     581Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows.
     582
     583An important missing feature in C is threading\footnote{While the C11 standard defines a \protect\lstinline@threads.h@ header, it is minimal and defined as optional.
     584As such, library support for threading is far from widespread.
     585At the time of writing the paper, neither \protect\lstinline@gcc@ nor \protect\lstinline@clang@ support \protect\lstinline@threads.h@ in their standard libraries.}.
     586In modern programming languages, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore existing and new programming languages must have tools for writing efficient concurrent programs to take advantage of parallelism.
     587As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers familiar with imperative languages.
     588Furthermore, because C is a system-level language, programmers expect to choose precisely which features they need and which cost they are willing to pay.
     589Hence, concurrent programs should be written using high-level mechanisms, and only step down to lower-level mechanisms when performance bottlenecks are encountered.
     590
     591
     592\subsection{Coroutines: A Stepping Stone}\label{coroutine}
     593
     594While the focus of this discussion is concurrency and parallelism, it is important to address coroutines, which are a significant building block of a concurrency system (but not concurrent among themselves).
    646595Coroutines are generalized routines allowing execution to be temporarily suspended and later resumed.
    647596Hence, unlike a normal routine, a coroutine may not terminate when it returns to its caller, allowing it to be restarted with the values and execution location present at the point of suspension.
     
    667616\centering
    668617\newbox\myboxA
    669 % \begin{lrbox}{\myboxA}
    670 % \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    671 % `int fn1, fn2, state = 1;`   // single global variables
    672 % int fib() {
    673 %       int fn;
    674 %       `switch ( state )` {  // explicit execution state
    675 %         case 1: fn = 0;  fn1 = fn;  state = 2;  break;
    676 %         case 2: fn = 1;  fn2 = fn1;  fn1 = fn;  state = 3;  break;
    677 %         case 3: fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;  break;
    678 %       }
    679 %       return fn;
    680 % }
    681 % int main() {
    682 %
    683 %       for ( int i = 0; i < 10; i += 1 ) {
    684 %               printf( "%d\n", fib() );
    685 %       }
    686 % }
    687 % \end{cfa}
    688 % \end{lrbox}
    689618\begin{lrbox}{\myboxA}
    690619\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    691 #define FIB_INIT { 0, 1 }
    692 typedef struct { int fn1, fn; } Fib;
     620`int f1, f2, state = 1;`   // single global variables
     621int fib() {
     622        int fn;
     623        `switch ( state )` {  // explicit execution state
     624          case 1: fn = 0;  f1 = fn;  state = 2;  break;
     625          case 2: fn = 1;  f2 = f1;  f1 = fn;  state = 3;  break;
     626          case 3: fn = f1 + f2;  f2 = f1;  f1 = fn;  break;
     627        }
     628        return fn;
     629}
     630int main() {
     631
     632        for ( int i = 0; i < 10; i += 1 ) {
     633                printf( "%d\n", fib() );
     634        }
     635}
     636\end{cfa}
     637\end{lrbox}
     638
     639\newbox\myboxB
     640\begin{lrbox}{\myboxB}
     641\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     642#define FIB_INIT `{ 0, 1 }`
     643typedef struct { int f2, f1; } Fib;
    693644int fib( Fib * f ) {
    694645
    695         int ret = f->fn1;
    696         f->fn1 = f->fn;
    697         f->fn = ret + f->fn;
     646        int ret = f->f2;
     647        int fn = f->f1 + f->f2;
     648        f->f2 = f->f1; f->f1 = fn;
     649
    698650        return ret;
    699651}
    700 
    701 
    702 
    703652int main() {
    704653        Fib f1 = FIB_INIT, f2 = FIB_INIT;
    705654        for ( int i = 0; i < 10; i += 1 ) {
    706                 printf( "%d %d\n",
    707                                 fib( &f1 ), fib( &f2 ) );
     655                printf( "%d %d\n", fib( &f1 ), fib( &f2 ) );
    708656        }
    709657}
     
    711659\end{lrbox}
    712660
     661\subfloat[3 States: global variables]{\label{f:GlobalVariables}\usebox\myboxA}
     662\qquad
     663\subfloat[1 State: external variables]{\label{f:ExternalState}\usebox\myboxB}
     664\caption{C Fibonacci Implementations}
     665\label{f:C-fibonacci}
     666
     667\bigskip
     668
     669\newbox\myboxA
     670\begin{lrbox}{\myboxA}
     671\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     672`coroutine` Fib { int fn; };
     673void main( Fib & fib ) with( fib ) {
     674        int f1, f2;
     675        fn = 0;  f1 = fn;  `suspend()`;
     676        fn = 1;  f2 = f1;  f1 = fn;  `suspend()`;
     677        for ( ;; ) {
     678                fn = f1 + f2;  f2 = f1;  f1 = fn;  `suspend()`;
     679        }
     680}
     681int next( Fib & fib ) with( fib ) {
     682        `resume( fib );`
     683        return fn;
     684}
     685int main() {
     686        Fib f1, f2;
     687        for ( int i = 1; i <= 10; i += 1 ) {
     688                sout | next( f1 ) | next( f2 );
     689        }
     690}
     691\end{cfa}
     692\end{lrbox}
    713693\newbox\myboxB
    714694\begin{lrbox}{\myboxB}
    715695\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    716 `coroutine` Fib { int fn1; };
    717 void main( Fib & fib ) with( fib ) {
    718         int fn;
    719         [fn1, fn] = [0, 1];
    720         for () {
    721                 `suspend();`
    722                 [fn1, fn] = [fn, fn1 + fn];
     696`coroutine` Fib { int ret; };
     697void main( Fib & f ) with( fib ) {
     698        int fn, f1 = 1, f2 = 0;
     699        for ( ;; ) {
     700                ret = f2;
     701
     702                fn = f1 + f2;  f2 = f1;  f1 = fn; `suspend();`
    723703        }
    724704}
    725 int ?()( Fib & fib ) with( fib ) {
    726         `resume( fib );`  return fn1;
    727 }
    728 int main() {
    729         Fib f1, f2;
    730         for ( 10 ) {
    731                 sout | f1() | f2();
    732 }
     705int next( Fib & fib ) with( fib ) {
     706        `resume( fib );`
     707        return ret;
     708}
     709
     710
     711
     712
    733713
    734714
    735715\end{cfa}
    736716\end{lrbox}
    737 
    738 \newbox\myboxC
    739 \begin{lrbox}{\myboxC}
    740 \begin{python}[aboveskip=0pt,belowskip=0pt]
    741 
    742 def Fib():
    743 
    744     fn1, fn = 0, 1
    745     while True:
    746         `yield fn1`
    747         fn1, fn = fn, fn1 + fn
    748 
    749 
    750 // next prewritten
    751 
    752 
    753 f1 = Fib()
    754 f2 = Fib()
    755 for i in range( 10 ):
    756         print( next( f1 ), next( f2 ) )
    757 
    758 
    759 
    760 \end{python}
    761 \end{lrbox}
    762 
    763 \subfloat[C]{\label{f:GlobalVariables}\usebox\myboxA}
    764 \hspace{3pt}
    765 \vrule
    766 \hspace{3pt}
    767 \subfloat[\CFA]{\label{f:ExternalState}\usebox\myboxB}
    768 \hspace{3pt}
    769 \vrule
    770 \hspace{3pt}
    771 \subfloat[Python]{\label{f:ExternalState}\usebox\myboxC}
    772 \caption{Fibonacci Generator}
    773 \label{f:C-fibonacci}
    774 
    775 % \bigskip
    776 %
    777 % \newbox\myboxA
    778 % \begin{lrbox}{\myboxA}
    779 % \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    780 % `coroutine` Fib { int fn; };
    781 % void main( Fib & fib ) with( fib ) {
    782 %       fn = 0;  int fn1 = fn; `suspend()`;
    783 %       fn = 1;  int fn2 = fn1;  fn1 = fn; `suspend()`;
    784 %       for () {
    785 %               fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `suspend()`; }
    786 % }
    787 % int next( Fib & fib ) with( fib ) { `resume( fib );` return fn; }
    788 % int main() {
    789 %       Fib f1, f2;
    790 %       for ( 10 )
    791 %               sout | next( f1 ) | next( f2 );
    792 % }
    793 % \end{cfa}
    794 % \end{lrbox}
    795 % \newbox\myboxB
    796 % \begin{lrbox}{\myboxB}
    797 % \begin{python}[aboveskip=0pt,belowskip=0pt]
    798 %
    799 % def Fibonacci():
    800 %       fn = 0; fn1 = fn; `yield fn`  # suspend
    801 %       fn = 1; fn2 = fn1; fn1 = fn; `yield fn`
    802 %       while True:
    803 %               fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `yield fn`
    804 %
    805 %
    806 % f1 = Fibonacci()
    807 % f2 = Fibonacci()
    808 % for i in range( 10 ):
    809 %       print( `next( f1 )`, `next( f2 )` ) # resume
    810 %
    811 % \end{python}
    812 % \end{lrbox}
    813 % \subfloat[\CFA]{\label{f:Coroutine3States}\usebox\myboxA}
    814 % \qquad
    815 % \subfloat[Python]{\label{f:Coroutine1State}\usebox\myboxB}
    816 % \caption{Fibonacci input coroutine, 3 states, internal variables}
    817 % \label{f:cfa-fibonacci}
     717\subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA}
     718\qquad\qquad
     719\subfloat[1 State, internal variables]{\label{f:Coroutine1State}\usebox\myboxB}
     720\caption{\CFA Coroutine Fibonacci Implementations}
     721\label{f:cfa-fibonacci}
    818722\end{figure}
    819723
     
    855759\begin{lrbox}{\myboxA}
    856760\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    857 `coroutine` Fmt {
    858         char ch;   // communication variables
    859         int g, b;   // needed in destructor
     761`coroutine` Format {
     762        char ch;   // used for communication
     763        int g, b;  // global because used in destructor
    860764};
    861 void main( Fmt & fmt ) with( fmt ) {
    862         for () {
    863                 for ( g = 0; g < 5; g += 1 ) { // groups
    864                         for ( b = 0; b < 4; b += 1 ) { // blocks
     765void main( Format & fmt ) with( fmt ) {
     766        for ( ;; ) {
     767                for ( g = 0; g < 5; g += 1 ) {      // group
     768                        for ( b = 0; b < 4; b += 1 ) { // block
    865769                                `suspend();`
    866                                 sout | ch; } // print character
    867                         sout | "  "; } // block separator
    868                 sout | nl; }  // group separator
    869 }
    870 void ?{}( Fmt & fmt ) { `resume( fmt );` } // prime
    871 void ^?{}( Fmt & fmt ) with( fmt ) { // destructor
    872         if ( g != 0 || b != 0 ) // special case
    873                 sout | nl; }
    874 void send( Fmt & fmt, char c ) { fmt.ch = c; `resume( fmt )`; }
     770                                sout | ch;              // separator
     771                        }
     772                        sout | "  ";               // separator
     773                }
     774                sout | nl;
     775        }
     776}
     777void ?{}( Format & fmt ) { `resume( fmt );` }
     778void ^?{}( Format & fmt ) with( fmt ) {
     779        if ( g != 0 || b != 0 ) sout | nl;
     780}
     781void format( Format & fmt ) {
     782        `resume( fmt );`
     783}
    875784int main() {
    876         Fmt fmt;
    877         sout | nlOff;   // turn off auto newline
    878         for ( 41 )
    879                 send( fmt, 'a' );
     785        Format fmt;
     786        eof: for ( ;; ) {
     787                sin | fmt.ch;
     788          if ( eof( sin ) ) break eof;
     789                format( fmt );
     790        }
    880791}
    881792\end{cfa}
     
    884795\newbox\myboxB
    885796\begin{lrbox}{\myboxB}
    886 \begin{python}[aboveskip=0pt,belowskip=0pt]
    887 
    888 
    889 
    890 def Fmt():
    891         try:
    892                 while True:
    893                         for g in range( 5 ):
    894                                 for b in range( 4 ):
    895 
    896                                         print( `(yield)`, end='' )
    897                                 print( '  ', end='' )
    898                         print()
    899 
    900 
    901         except GeneratorExit:
    902                 if g != 0 | b != 0:
    903                         print()
    904 
    905 
    906 fmt = Fmt()
    907 `next( fmt )`                    # prime
    908 for i in range( 41 ):
    909         `fmt.send( 'a' );`      # send to yield
    910 
    911 \end{python}
     797\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     798struct Format {
     799        char ch;
     800        int g, b;
     801};
     802void format( struct Format * fmt ) {
     803        if ( fmt->ch != -1 ) {      // not EOF ?
     804                printf( "%c", fmt->ch );
     805                fmt->b += 1;
     806                if ( fmt->b == 4 ) {  // block
     807                        printf( "  " );      // separator
     808                        fmt->b = 0;
     809                        fmt->g += 1;
     810                }
     811                if ( fmt->g == 5 ) {  // group
     812                        printf( "\n" );     // separator
     813                        fmt->g = 0;
     814                }
     815        } else {
     816                if ( fmt->g != 0 || fmt->b != 0 ) printf( "\n" );
     817        }
     818}
     819int main() {
     820        struct Format fmt = { 0, 0, 0 };
     821        for ( ;; ) {
     822                scanf( "%c", &fmt.ch );
     823          if ( feof( stdin ) ) break;
     824                format( &fmt );
     825        }
     826        fmt.ch = -1;
     827        format( &fmt );
     828}
     829\end{cfa}
    912830\end{lrbox}
    913 \subfloat[\CFA]{\label{f:CFAFmt}\usebox\myboxA}
     831\subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}
    914832\qquad
    915 \subfloat[Python]{\label{f:CFmt}\usebox\myboxB}
    916 \caption{Output formatting text}
     833\subfloat[C Linearized]{\label{f:CFmt}\usebox\myboxB}
     834\caption{Formatting text into lines of 5 blocks of 4 characters.}
    917835\label{f:fmt-line}
    918836\end{figure}
     
    935853void main( Prod & prod ) with( prod ) {
    936854        // 1st resume starts here
    937         for ( i; N ) {
     855        for ( int i = 0; i < N; i += 1 ) {
    938856                int p1 = random( 100 ), p2 = random( 100 );
    939857                sout | p1 | " " | p2;
     
    951869}
    952870void start( Prod & prod, int N, Cons &c ) {
    953         &prod.c = &c; // reassignable reference
     871        &prod.c = &c;
    954872        prod.[N, receipt] = [N, 0];
    955873        `resume( prod );`
     
    966884        Prod & p;
    967885        int p1, p2, status;
    968         bool done;
     886        _Bool done;
    969887};
    970888void ?{}( Cons & cons, Prod & p ) {
    971         &cons.p = &p; // reassignable reference
     889        &cons.p = &p;
    972890        cons.[status, done ] = [0, false];
    973891}
     
    1027945@start@ returns and the program main terminates.
    1028946
    1029 One \emph{killer} application for a coroutine is device drivers, which at one time caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}.
    1030 Many device drivers are a finite state-machine parsing a protocol, e.g.:
    1031 \begin{tabbing}
    1032 \ldots STX \= \ldots message \ldots \= ESC \= ETX \= \ldots message \ldots  \= ETX \= 2-byte crc \= \ldots      \kill
    1033 \ldots STX \> \ldots message \ldots \> ESC \> ETX \> \ldots message \ldots  \> ETX \> 2-byte crc \> \ldots
    1034 \end{tabbing}
    1035 where a network message begins with the control character STX and ends with an ETX, followed by a 2-byte cyclic-redundancy check.
    1036 Control characters may appear in a message if preceded by an ESC.
    1037 Because FSMs can be complex and occur frequently in important domains, direct support of the coroutine is crucial in a systems programminglanguage.
    1038 
    1039 \begin{figure}
    1040 \begin{cfa}
    1041 enum Status { CONT, MSG, ESTX, ELNTH, ECRC };
    1042 `coroutine` Driver {
    1043         Status status;
    1044         char * msg, byte;
    1045 };
    1046 void ?{}( Driver & d, char * m ) { d.msg = m; }         $\C[3.0in]{// constructor}$
    1047 Status next( Driver & d, char b ) with( d ) {           $\C{// 'with' opens scope}$
    1048         byte = b; `resume( d );` return status;
    1049 }
    1050 void main( Driver & d ) with( d ) {
    1051         enum { STX = '\002', ESC = '\033', ETX = '\003', MaxMsg = 64 };
    1052         unsigned short int crc;                                                 $\C{// error checking}$
    1053   msg: for () {                                                                         $\C{// parse message}$
    1054                 status = CONT;
    1055                 unsigned int lnth = 0, sum = 0;
    1056                 while ( byte != STX ) `suspend();`
    1057           emsg: for () {
    1058                         `suspend();`                                                    $\C{// process byte}$
    1059                         choose ( byte ) {                                               $\C{// switch with default break}$
    1060                           case STX:
    1061                                 status = ESTX; `suspend();` continue msg;
    1062                           case ETX:
    1063                                 break emsg;
    1064                           case ESC:
    1065                                 suspend();
    1066                         } // choose
    1067                         if ( lnth >= MaxMsg ) {                                 $\C{// buffer full ?}$
    1068                                 status = ELNTH; `suspend();` continue msg; }
    1069                         msg[lnth++] = byte;
    1070                         sum += byte;
    1071                 } // for
    1072                 msg[lnth] = '\0';                                                       $\C{// terminate string}\CRT$
    1073                 `suspend();`
    1074                 crc = (unsigned char)byte << 8; // prevent sign extension for signed char
    1075                 `suspend();`
    1076                 status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;
    1077                 `suspend();`
    1078         } // for
    1079 }
    1080 \end{cfa}
    1081 \caption{Device driver for simple communication protocol}
    1082 \end{figure}
    1083 
    1084947
    1085948\subsection{Coroutine Implementation}
     
    11971060\end{cquote}
    11981061The combination of these two approaches allows an easy and concise specification to coroutining (and concurrency) for normal users, while more advanced users have tighter control on memory layout and initialization.
    1199 
    1200 
    1201 \section{Concurrency}
    1202 \label{s:Concurrency}
    1203 
    1204 At its core, concurrency is based on multiple call-stacks and scheduling threads executing on these stacks.
    1205 Multiple call stacks (or contexts) and a single thread of execution, called \newterm{coroutining}~\cite{Conway63,Marlin80}, does \emph{not} imply concurrency~\cite[\S~2]{Buhr05a}.
    1206 In coroutining, the single thread is self-scheduling across the stacks, so execution is deterministic, \ie the execution path from input to output is fixed and predictable.
    1207 A \newterm{stackless} coroutine executes on the caller's stack~\cite{Python} but this approach is restrictive, \eg preventing modularization and supporting only iterator/generator-style programming;
    1208 a \newterm{stackful} coroutine executes on its own stack, allowing full generality.
    1209 Only stackful coroutines are a stepping stone to concurrency.
    1210 
    1211 The transition to concurrency, even for execution with a single thread and multiple stacks, occurs when coroutines also context switch to a \newterm{scheduling oracle}, introducing non-determinism from the coroutine perspective~\cite[\S~3]{Buhr05a}.
    1212 Therefore, a minimal concurrency system is possible using coroutines (see Section \ref{coroutine}) in conjunction with a scheduler to decide where to context switch next.
    1213 The resulting execution system now follows a cooperative threading-model, called \newterm{non-preemptive scheduling}.
    1214 
    1215 Because the scheduler is special, it can either be a stackless or stackful coroutine.
    1216 For stackless, the scheduler performs scheduling on the stack of the current coroutine and switches directly to the next coroutine, so there is one context switch.
    1217 For stackful, the current coroutine switches to the scheduler, which performs scheduling, and it then switches to the next coroutine, so there are two context switches.
    1218 A stackful scheduler is often used for simplicity and security.
    1219 
    1220 Regardless of the approach used, a subset of concurrency related challenges start to appear.
    1221 For the complete set of concurrency challenges to occur, the missing feature is \newterm{preemption}, where context switching occurs randomly between any two instructions, often based on a timer interrupt, called \newterm{preemptive scheduling}.
    1222 While a scheduler introduces uncertainty in the order of execution, preemption introduces uncertainty about where context switches occur.
    1223 Interestingly, uncertainty is necessary for the runtime (operating) system to give the illusion of parallelism on a single processor and increase performance on multiple processors.
    1224 The reason is that only the runtime has complete knowledge about resources and how to best utilized them.
    1225 However, the introduction of unrestricted non-determinism results in the need for \newterm{mutual exclusion} and \newterm{synchronization} to restrict non-determinism for correctness;
    1226 otherwise, it is impossible to write meaningful programs.
    1227 Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows.
    1228 
    1229 An important missing feature in C is threading\footnote{While the C11 standard defines a \protect\lstinline@threads.h@ header, it is minimal and defined as optional.
    1230 As such, library support for threading is far from widespread.
    1231 At the time of writing the paper, neither \protect\lstinline@gcc@ nor \protect\lstinline@clang@ support \protect\lstinline@threads.h@ in their standard libraries.}.
    1232 In modern programming languages, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore existing and new programming languages must have tools for writing efficient concurrent programs to take advantage of parallelism.
    1233 As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers familiar with imperative languages.
    1234 Furthermore, because C is a system-level language, programmers expect to choose precisely which features they need and which cost they are willing to pay.
    1235 Hence, concurrent programs should be written using high-level mechanisms, and only step down to lower-level mechanisms when performance bottlenecks are encountered.
    12361062
    12371063
  • doc/papers/concurrency/mail

    r933f32f r6a9d4b4  
    2727
    2828Software: Practice and Experience Editorial Office
    29 
    30 
    31 
    32 Date: Wed, 3 Oct 2018 21:25:28 +0000
    33 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    34 Reply-To: R.E.Jones@kent.ac.uk
    35 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    36 Subject: Software: Practice and Experience - Decision on Manuscript ID
    37  SPE-18-0205
    38 
    39 03-Oct-2018
    40 
    41 Dear Dr Buhr,
    42 
    43 Many thanks for submitting SPE-18-0205 entitled "Concurrency in C∀" to Software: Practice and Experience.
    44 
    45 In view of the comments of the referees found at the bottom of this letter, I cannot accept your paper for publication in Software: Practice and Experience. I hope that you find the referees' very detailed comments helpful.
    46 
    47 Thank you for considering Software: Practice and Experience for the publication of your research.  I hope the outcome of this specific submission will not discourage you from submitting future manuscripts.
    48 
    49 Yours sincerely,
    50 
    51 
    52 Prof. Richard Jones
    53 Editor, Software: Practice and Experience
    54 R.E.Jones@kent.ac.uk
    55 
    56 Referee(s)' Comments to Author:
    57 
    58 Reviewing: 1
    59 
    60 Comments to the Author
    61 "Concurrency in Cforall" presents a design and implementation of a set of standard concurrency features, including coroutines, user-space and kernel-space threads, mutexes, monitors, and a scheduler, for a polymorphic derivation of C called Cforall.
    62 
    63 Section 2 is an overview of sequential Cforall that does not materially contribute to the paper. A brief syntax explanation where necessary in examples would be plenty.
    64 
    65 Section 3 begins with with an extensive discussion of concurrency that also does not materially contribute to the paper. A brief mention of whether a particular approach implements cooperative or preemptive scheduling would be sufficient. Section 3 also makes some unfortunate claims, such as C not having threads -- C does in fact define threads, and this is noted as being true in a footnote, immediately after claiming that it does not. The question remains why the C11 parallelism design is insufficient and in what way this paper proposes to augment it. While I am personally a proponent of parallel programming languages, backing the assertion that all modern languages must have threading with citations from 2005 ignores the massive popularity of modern non-parallel languages (Javascript, node.js, Typescript, Python, Ruby, etc.) and parallel languages that are not thread based, although the authors are clearly aware of such approaches.
    66 
    67 Sections 3.1 and 3.2 dicusses assymetric and symmetric coroutines. This also does not seem to materially contribute to a paper that is ostensibly about concurrency in a modern systems programming language. The area of coroutines, continuations, and generators is already well explored in the context of systems languages, including compilation techniques for these constructs that are more advanced than the stack instantiation model discussed in the paper.
    68 
    69 Section 3.3 describes threads in Cforall, briefly touching on user-space vs. kernel-space thread implementations without detailing the extensive practical differences. It is unclear how the described interface differes from C++11 threads, as the description seems to center on an RAII style approach to joining in the destructor.
    70 
    71 Section 4 briefly touches on a collection of well known synchronisation primitives. Again, this discussion does not materially contribute to the paper.
    72 
    73 Section 5 describes monitors, which are a well known and well researched technique. The Cforall implementation is unsurprising. The "multi-acquire semantics" described are not a contribution of this paper, as establishing a stable order for lock acquisition is a well known technique, one example of which is the C++ std::scoped_lock.
    74 
    75 Section 6 is a discussion of scheduling that does not appear to be informed by the literature. There is no discussion of work-stealing vs. work-scheduling, static vs. dynamic priorities, priority inversion, or fairness. There is a claim in secion 6.1 for a novel technique, partial signalling, that appears to be a form of dynamic priority, but no comparison is made. In section 6.6, a very brief mention of other synchronisation techniques is made, without reference to current techniques such as array-based locks, CLH or MCS queue locks, RCU and other epoch-based mechanisms, etc. Perhaps these are considered out of scope.
    76 
    77 Section 7 discusses parallelism, but does not materially contribute to the paper. It is claimed that preemption is necessary to implement spinning, which is not correct, since two cores can implement a spinning based approach without preemption. It is claimed that with thread pools "concurrency errors return", but no approach to removing concurrency errors with either preemptive or cooperatively scheduled user threads has been proposed in the paper that would not also apply to thread pools.
    78 
    79 Section 8 is intended to describe the Cforall runtime structure, but does so in a way that uses terminology in an unfamiliar way. The word cluster is more usually used in distributed systems, but here refers to a process. The term virtual processor is more usually used in hardware virtualisation, but here refers to a kernel thread. The term debug kernel is more usually used in operating systems to refer to kernels that have both debug info and a method for using a debugger in kernel space, but here refers to a debug build of a user-space process. This section does not materially contribute to the paper.
    80 
    81 Section 9 is intended to describe the Cforall runtime implementation. It makes some unusual claims, such as C libraries migrating to stack chaining (stack chaining was an experimental GCC feature that has been abandoned, much as it has been abandoned in both Go and Rust).
    82 
    83 The performance measurements in section 10 are difficult to evaluate. While I appreciate that comparable concurrency benchmarks are very difficult to write, and the corpus of existing benchmarks primarily boils down to the parallel programs in the Computer Language Benchmark Game, the lack of detail as to what is being measured in these benchmarks (particularly when implemented in other languages) is unfortunate. For example, in table 3, the benchmark appears to measure uncontended lock access, which is not a useful micro-benchmark.
    84 
    85 It is not clear what the contributions of this paper are intended to be. A concise listing of the intended contributions would be helpful. Currently, it appears that the paper makes neither PL contributions in terms of novel features in Cforall, nor does it make systems contributions in terms of novel features in the runtime.
    86 
    87 
    88 Reviewing: 2
    89 
    90 Comments to the Author
    91 This article presents the design and rationale behind the concurrency
    92 features of C-forall, a new low-level programming language.  After an
    93 introduction that defines a selection of standard terminology, section
    94 2 gives crucial background on the design of the C-forall language.
    95 Section 3 then starts the core of the article, discussing the
    96 language's support for "concurrency" which in this case means
    97 coroutines and threads; a very brief Section 4 builds on section 3
    98 with a discussion of lower level synchronizations.  Section 5 the
    99 presents the main features of concurrency control in C-forall:
    100 monitors and mutexes. Section 6 then extends monitors with condition
    101 variables to to support scheduling, and a very brief section 7
    102 discusses preemption and pooling. Section 8 discusses the runtime
    103 conceptual model, section 9 gives implementation detail, and section
    104 10 briefly evaluates C-forall's performance via five concurrent
    105 micro benchmarks. Finally section 11 concludes the article, and then
    106 section 12 presents some future work. 
    107 
    108 
    109 At the start of section 7, article lays out its rationale: that while
    110 "historically, computer performance was about processor speeds" but
    111 "Now, high-performance applications must care about parallelism,
    112 which requires concurrency". The doomsayers trumpeting the death of
    113 Moore's law have been proved correct at last, with CPUs sequential
    114 performance increasing much more slowly than the number of cores
    115 within each die. This means programmers --- especially low-level,
    116 systems programmers --- must somehow manage the essential complexity
    117 of writing concurrent programs to run in parallel in multiple threads
    118 across multiple cores. Unfortunately, the most venerable widely used
    119 systems programming language, C, supports parallelism only via an
    120 e.g. the threads library.  This article aims to integrate concurrent
    121 programming mechanisms more closely into a novel low-level C-based
    122 programming language, C-forall. The article gives an outline of much of
    123 C-forall, presents a series of concurrency mechanisms, and finally
    124 some microbenchmark results.  The article is detailed, comprehensive,
    125 and generally well written in understandable English.
    126 
    127 My main concern about the article are indicated by the fact that the
    128 best summary of the problem the design of concurrent C-forall sets
    129 out to solve is buried more than halfway through the article in section
    130 7, as above, and then the best overview of the proposed solution is
    131 given in the 2nd, 4th and 5th sentence of the conclusion:
    132 
    133    "The approach provides concurrency based on a preemptive M:N
    134     user-level threading-system, executing in clusters, which
    135     encapsulate scheduling of work on multiple kernel threads
    136     providing parallelism... High-level objects (monitor/task) are the
    137     core mechanism for mutual exclusion and synchronization. A novel
    138     aspect is allowing multiple mutex-objects to be accessed
    139     simultaneously reducing the potential for deadlock for this
    140     complex scenario."
    141 
    142 That is, in my reading of the article, it proceeds bottom up rather
    143 than top down, and so my main recommendation is to essentially reverse
    144 the order of the article, proceeding from the problem to be solved,
    145 the high level architecture of the proposed solutions, and then going
    146 down to the low-level mechanisms.  My biggest problem reading the
    147 article was for explanations of why a particular decision was taken,
    148 or why a particular mechanism may be used --- often this description
    149 is actually later in the article, but at that point it's too late for
    150 the reader.  I have tried to point out most of these places in the
    151 detailed comments below.
    152 
    153 My second concern is that the article makes several claims that are
    154 not really justified by the design or implementation in the article.
    155 These include claims that this approach meets the expectations of C
    156 programmers, is minimal, is implemented in itself, etc.  The article
    157 doesn't generally offer evidence to support these assertions (for many
    158 of them, that would require empirical studies of programmers, or at
    159 least corpus studies). The solution here is to talk about motivations
    160 for the design choices "we made these decisions hoping that C
    161 programmers would be comfortable" rather than claims of fact "C
    162 programmers are comfortable".  Again I attempt to point these out below.
    163 
    164 * abstract: needs to characterize the work top down, and not make
    165   claims "features respect the expectations of C programmers" that
    166   are not supported empirically.
    167 
    168 * p1 line 14 "integrated"
    169 
    170 * introduction needs to introduce the big ideas and scope of the
    171   article, not define terms.  Some of the terms / distinctions are
    172   non-standard (e.g. the distinction between "concurrency" and
    173   "parallelism") and can be avoided by using more specific terms
    174   (mutual exclusion, synchronization, parallel execution. etc).
    175 
    176 * to me this article introduces novel language features, not just an
    177   API.  Similarly, it doesn't talk about any additions "to the
    178   language translator" - i.e compiler changes! - rather about language
    179   features.
    180 
    181 
    182 * section 2 lines 6-9 why buy this fight against object-orientation?
    183   this article doesn't need to make this argument, but needs to do a
    184   better job of it if it does (see other comments below)
    185 
    186 * sec 2.1 - are these the same as C++. IF so, say so, if not, say why
    187   not.
    188 
    189 * 2.2 calling it a "with statement" was confusing, given that a with
    190   clause can appear in a routine declaration with a shorthand syntax.
    191 
    192 * 2.3 again compare with C++ and Java (as well as Ada)
    193 
    194 * line 9 "as we will see in section 3"
    195 
    196 * 2.4 I really quite like this syntax for operators, destructors not
    197   so much.
    198 
    199 * 2.5 and many places elsewhere. Always first describe the semantics
    200   of your language constructs, then describe their properties, then
    201   compare with e.g. related languages (mostly C++ & Java?).  E.g in
    202   this case, something like:
    203 
    204   "C-forall includes constructors, which are called to initialize
    205   newly allocated objects, and constructors, which are called when
    206   objects are deallocated. Constructors and destructors are written as
    207   functions returning void, under the special names "?{}" for
    208   constructors and "^{}" for destructors: constructors may be
    209   overridden, but destructors may not be.  The semantics of C-forall's
    210   constructors and destructors are essentially those of C++."
    211 
    212   this problem repeats many times throughout the article and should be
    213   fixed everywhere.
    214 
    215 
    216 * 2.6 again, first describe then properties then comparison.
    217    in this case, compare e.g. with C++ templates, Java/Ada generics
    218    etc.
    219 
    220 * why special case forward declarations? It's not 1970 any more.
    221 
    222 * what are traits?  structural interfaces (like Go interfaces) or
    223   nominal bindings?
    224 
    225 * section 3 - lines 2-30, also making very specific global definitions
    226   as in the introduction. The article does not need to take on this
    227   fight either, rather make clear that this is the conceptual model in
    228   C-forall. (If the article starts at the top and works down, that may
    229   well follow anyway).
    230 
    231 * "in modern programming languages... unacceptable"; "in a
    232   system-level language.. concurrent programs should be written with
    233   high-level features" - again, no need to take on these fights.
    234 
    235 * 3.1 onwards; I found all this "building" up hard to follow.
    236   also it's not clear a "minimal" API must separately support
    237   coroutines, threads, fibres, etc
    238 
    239 * FIG 2B - where's the output?
    240   syntax "sout | next(f1) | next(f2) | endl" nowhere explained
    241     why not use C++s' << and >>
    242 
    243 * FIG 3 be clearer, earlier about the coroutine" constructor syntax
    244 
    245 ** ensure all figures are placed *after* their first mention in the
    246    text. consider interleaving smaller snippets of text rather than
    247    just referring to large figures
    248 
    249 * sec 3.1 p7 etc,. need more context / comparison e.g. Python
    250   generators etc.
    251 
    252 * FIGURE 4 is this right?  should there a constructor for Cons taking
    253   a Prod?
    254 
    255 
    256 * sec 3.2 order of constructors depends on the language.  more
    257   generally, if the article is going to make arguments against OO
    258   (e.g. section 2) then the article needs to explain, in detail, why
    259   e.g. coroutine, thread, etc *cannot* be classes / objects.
    260 
    261 * "type coroutine_t must be an abstract handle.. descriptor and is
    262   stack are non-copyable" - too many assumptions in here (and other
    263   similar passages) that are not really spelled out in detail.
    264 
    265 * p10 line 4 introduces "coroutine" keyword. needs to give its
    266   semantics. also needs to introduce and define properties and compare
    267   before all the examples using coroutines.
    268 
    269 * p10 again, trait semantics need to be better defined
    270 
    271 * 3.3 should be an introduction to this section. Note that section
    272   titles are not part of the text of the article.
    273 
    274 * what's the difference between "coroutines" and "user threads" (and
    275   "fibres?")
    276 
    277 * what's a "task type" or an "interface routine"  or "underlying
    278   thread"
    279 
    280 * section 4 - "... meaningless". nope some semantics are possible
    281   e.g. if there's a memory model.
    282 
    283 * whatare "call/return based languages"
    284 
    285 * p12 - what if a programmer wants to join e.g. "1st of N" or "1st 3 of N"
    286   threads rather than all threads in order
    287 
    288 * 4.1 p12 13-25, again it's not clear where this is going.  presenting the model
    289   top down may hopefully resolve this
    290 
    291 * section 4 should be merged e.g. into sec 3 (or 5)
    292 
    293 
    294 
    295 * section 5 p13 what's "routine" scope. "call/return paradigm"
    296 
    297 * thread/ coroutine declarations, traits etc, all look pretty close to
    298   inheritance. why wouldn't inheritance work?
    299 
    300 * open/closed locks = free/acquired free locks?
    301 
    302 * testability?
    303 
    304 * p14 lines 14-20 I had trouble following this.  e.g/. what's the
    305   difference between "a type that is a monitor" and "a type that looks
    306   like a monitor"?  why?
    307 
    308 * line 39 - what's an "object-oriented monitor"?    Java?
    309     there is no one OO model of such things.
    310 
    311 * line 47 significant asset - how do you know?
    312 
    313 * how could this e.g. build a reader/writer lock
    314 
    315 * *p15 what's the "bank account transfer problem"
    316 
    317 *p16 lines6-10  why? explain?
    318 
    319 *p17 semantics of arrays of conditions is unclear
    320      given e.g. previous comments about arrays of mutexes.
    321 
    322 *p18 define "spurious wakeup"
    323 
    324 *p18 line 44 - "a number of approaches were examined"?  which
    325  approaches? examined by whom?  if this is a novel contribution, needs
    326  rather more there, and more comparison with related work
    327 
    328 * FIG 8 consider e.g. sequence diagrams rather than code to show these
    329   cases
    330 
    331 * 6.2 p19 line 5 "similarly, monitor routines can be added at any
    332   time" really?  I thought C-forall was compiled? there's a big
    333   difference between "static" and "dynamic" inheritance. which is this
    334   closer to?
    335 
    336 * line 25 "FIgure 9 (B) shows the monitor implementation"
    337    I didn't understand this, especially not as an implementation.
    338 
    339 * section 6.6 - if the article is to make claims about completeness,
    340   about supporting low and high level operations, then this must be
    341   expanded to give enough detail to support that argument
    342 
    343 * "truest realization" huh?
    344 
    345 * section 7 should be merged into 6 or 8.
    346   it's not clear if this is exploring rejected alternatives,
    347   out outlining different features offered by C-forall, or what.
    348 
    349 
    350 * sec 7.2 how do the other threads in sections 5 & 6 relate to the
    351   user threads, fibres, etc here;
    352 
    353 * sec 8.1 I found these sections hard to follow. how is a cluster a
    354   "collection of threads and virtual processors... like a virtual
    355   machine"? Where do the thread pools from 7.3 fit in?
    356 
    357 *  sec 8.3 is out of place, probably unneeded in the paper
    358 
    359 * section 9 dives straight into details with no overview.  Section 9
    360   seems very detailed, and depends on assumptions or details that are
    361   not in the article.
    362 
    363 * section 10 covers only microbenchmarks. are there any moderate sized
    364   macrobenchmarks that can compare across the different systems?
    365   (e.g the Erlang Ring?)
    366 
    367 * sec 11 claims that "the entire C-forall runtime system are written
    368   in C-forall". The article doesn't
    369 
    370 
    371 * future work should precede conclusion, not follow it
    372 
    373 * the article should have a related work section (2-3 pages) comparing
    374   the design overall with various competing designs (C++, Java, go,
    375   Rust,...)
    376 
    377 To encourage accountability, I'm signing my reviews in 2018. For the record, I am James Noble, kjx@ecs.vuw.ac.nz.
    378 
    379 Reviewing: 3
    380 
    381 Comments to the Author
    382 This paper describes the design and implementation of coroutine- and thread-based concurrency in the C-for-all (I will write "C\/") system, a considerably extended form of the C language with many concurrency features.
    383 
    384 It first provides an overview of the non-concurrency-related aspects of the host language (references, operator overloading, generics, etc.), then addresses several technical issues around concurrency, including the multi-monitor design, bulk acquiring of locks (including deadlock-avoiding management of acquisition order), solutions to difficult scheduling problems around these, and implementation of monitors in the presence of separate compilation. It also presents empirical data showing the execution times of several microbenchmarks in comparison with other threaded concurrency systems, in support of the claim that the implementation is competitive with them.
    385 
    386 Overall the impression I gained is that this is a substantial system into which have gone much thought and effort.
    387 
    388 However, the present paper is not written so as to communicate sufficiently clearly the novel practices or experiences that emerged from that effort. This manifests itself in several ways.
    389 
    390 The system is described in general, rather than with a focus on novel insights or experiences. It was not until page 18 that I found a statement that hinted at a possible core contribution: "Supporting barging prevention as well as extending internal scheduling to multiple monitors is the main source of complexity in design and implementation of C\/ concurrency." Even then, it is unclear whether such challenges have already been surmounted in prior systems, or what other challenges the paper may also be covering. The most complete list of claims appears to be in the Conclusion (section 11; oddly not the last section), although not everything listed is a novel feature of the work (e.g. N:M threading models are an old idea). This presentation needs to be completely inverted, to focus from the outset on the claimed novel/noteworthy experiences that the work embodies.
    391 
    392 The text describing the system's motivation is unconvincing on one point: the claim that library support for threading in C is "far from widespread" (p5, footnote A). The pthreads library API is standardised, albeit not in the C language specification but rather in POSIX -- a widespread standard indeed. (With systems languages, even if the language does not define a feature, it of course does not follow that that feature is not available -- since such languages permit extension of their own runtime and/or toolchain.) Of course, the combination of C and pthreads does not provide close to the full complement of C\/-supported features, so it is easy to make a case for C\/'s targeted "gap in the market". But again, a presentation focused on novel aspects would bring this out and enable the reader to learn from the authors' efforts much more readily.
    393 
    394 Certain sections of the text read like a tutorial on concurrency... which is potentially valuable, but does not seem to belong here. For example, much effort is spent introducing the notions of "synchronization" and "mutual exclusion", including the whole of Section 4.2. Presently it is unclear how this content supports the findings/experiences that the paper is detailing.
    395 
    396 Similarly, section 8 reads mostly as a basic introduction to user versus kernel threading implementations (including hybrid models such as N:M scheduling), and appears superfluous to this paper. Mixed into this are details of C\/'s specific approach. These could instead be stated directly, with references to handle the unlikely case where the reader is unfamiliar.
    397 
    398 I also found the definitions of certain terms through the paper a bit non-standard, for unclear reasons. For example, why "condition lock" rather than the standard "condition variable" (if indeed that is what is intended)? To say that "synchronisation" is about "timing" strikes me as potentially confusing, since in truth synchronisation concerns only relative timing, i.e. ordering. (Even ordering is something of a derived concept -- since of course, most commonly, control over ordering is built atop synchronisation primitives, rather than being provided directly by them.)
    399 
    400 The empirical data presented is a reasonable start at characterising the implementation's performance. However, it currently suffers certain flaws.
    401 
    402 Firstly, it is not clear what is being claimed. The data cannot really be said to "verify the implementation" (section 10). Presumably the claim is that the system is competitive with other systems offering reasonably high-level concurrency constructs (Java monitors, Go channels, etc.) and/or on low-level facilities (mutexes, coroutines). A claim of this form, emphasising the latter, does eventually appear in the Conclusion, but it needs to be made explicitly during the presentation of the experiments. Shifting the focus towards higher-level features may be a better target, since this appears to be C\/'s main advance over pthreads and similar libraries.
    403 
    404 It appears some additional or alternative competitor systems might be a better match. For example, many green-thread or N:M libraries for C exist (libdill/libmill, Marcel, even GNU Pth). It would be instructive to compare with these.
    405 
    406 It would help greatly if the "functionally identical" benchmark code that was run on the competing systems were made available somewhere. Omitting it from the main text of the paper is understandable, since it would take too much space, but its details may still have a critical bearing on the results.
    407 
    408 In some cases it simply wasn't clear what is being compared. In Table 3, what are "FetchAdd + FetchSub"? I'm guessing this is some open-coded mutex using C++ atomics, but (unless I'm missing something) I cannot see an explanation in the text.
    409 
    410 The reports of variance (or, rather, standard deviation) are not always plausible. Is there really no observable variation in three of Table 3's cases? At the least, I would appreciate more detail on the measures taken to reduce run-time variance (e.g. disabling CPU throttling perhaps?).
    411 
    412 The text habitually asserts the benefits of C\/'s design without convincing argument. For example, in 2.1, do C\/'s references really reduce "syntactic noise"? I am sympathetic to the problem here, because many design trade-offs simply cannot be evaluated without very large-scale or long-term studies. However, the authors could easily refrain from extrapolating to a grand claim that cannot be substantiated. For example, instead of saying C\/ is "expressive" or "flexible" or "natural", or (say) that fork/join concurrency is "awkward and unnecessary" (p11), it would be preferable simply to give examples of the cases are captured well in the C\/ design (ideally together with any less favourable examples that illustrate the design trade-off in question) and let them speak for themselves.
    413 
    414 One thing I found confusing in the presentation of coroutines is that it elides the distinction between "coroutines" (i.e. their definitions) and activations thereof. It would be helpful to make this clearer, since at present this makes some claims/statements hard to understand. For example, much of 3.2 talks about "adding fields", which implies that a coroutine's activation state exists as fields in a structured object -- as, indeed, it does in C\/. This is non-obvious because in a more classical presentation of coroutines, their state would live not in "fields" but in local variables. Similarly, the text also talks about composition of "coroutines" as fields within other "coroutines", and so on, whereas if I understand correctly, these are also activations. (By later on in the text, the "C\/ style" of such constructs is clear, but not at first.)
    415 
    416 I was expecting a reference to Adya et al's 2002 Usenix ATC paper, on the topic of "fibers" and cooperative threading generally but also for its illustrative examples of stack ripping (maybe around "linearized code is the bane of device drivers", p7, which seems to be making a similar observation).
    417 
    418 Minor comments:
    419 
    420 The writing is rather patchy. It has many typos, and also some cases of "not meaning what is said", unclear allusions, etc.. The following is a non-exhaustive list.
    421 
    422 - p2 line 7: "C has a notion of objects" -- true, but this is not intended as "object" in anything like the same sense as "object-oriented", so raising it here is somewhere between confusing and meaningless.
    423 
    424 - lots of extraneous hyphenation e.g "inheritance-relationships", "critical-section", "mutual-exclusion", "shared-state" (as a general rule, only hyphenate noun phrases when making an adjective out of them)
    425 
    426 - p4 "impossible in most type systems" -- this is not a property of the "type system" as usually understood, merely the wider language design
    427 
    428 - p17: "release all acquired mutex types in the parameter list" should just say "release all acquired mutexes that are designated in the parameter list" (it is not "types" that are being released or acquired);
    429 
    430 - p19: "a class includes an exhaustive list of operations" -- except it is definitively *not* exhaustive, for the reasons given immediately afterwards. I do see the problem here, about separate compilation meaning that the space of functions using a particular type is not bounded at compile time, but that needs to be identified clearly as the problem. (Incidentally, one idea is that perhaps this mapping onto a dense space could be solved at link- or load-time, in preference to run-time indirection.)
    431 
    432 - p22: in 6.5, the significance of this design decision ("threads... are monitors") was still not clear to me.
    433 
    434 - p22: [user threads are] "the truest realization of concurrency" sounds like unnecessary editorializing (many systems can exist that can also encode all others, without necessarily giving one supremacy... e.g. actors can be used to encode shared-state concurrency).
    435 
    436 - p24: on line 19, the necessary feature is not "garbage collection" but precise pointer identification (which is distinct; not all GCs have it, and it has other applications besides GC)
    437 
    438 - p24: lines 32-39 are very dense and of unclear significance; an example, including code, would be much clearer.
    439 
    440 - p25: "current UNIX systems" seems to mean "Linux", so please say that or give the behaviour or some other modern Unix (I believe Solaris is somewhat different, and possibly the BSDs too). Also, in the explanation of signal dynamics, it would be useful to adopt the quotation's own terminology of "process-directed" signals. Presumably the "internal" thread-directed signals were generated using tgkill()? And presumably the timer expiry signal is left unblocked only on the thread (virtual processor) running the "simulation"? (Calling it a "simulation" is a bit odd, although I realise it is borrowing the concept of a discrete event queue.)
    441 
  • doc/proposals/vtable.md

    r933f32f r6a9d4b4  
    22==================================
    33
     4This is an adaptation of the earlier virtual proposal, updating it with new
     5ideas, re-framing it and laying out more design decisions. It should
     6eventually replace the earlier proposal, but not all features and syntax have
     7been converted to the new design.
     8
    49The basic concept of a virtual table (vtable) is the same here as in most
    5 other languages that use them. They will mostly contain function pointers
    6 although they should be able to store anything that goes into a trait.
    7 
    8 I also include notes on a sample implementation, which primarily exists to show
    9 there is a reasonable implementation. The code samples for that are in a slight
    10 pseudo-code to help avoid name mangling and keeps some CFA features while they
    11 would actually be written in C.
     10other languages. They will mostly contain function pointers although they
     11should be able to store anything that goes into a trait.
    1212
    1313Trait Instances
     
    1515
    1616Currently traits are completely abstract. Data types might implement a trait
    17 but traits are not themselves data types. Which is to say you cannot have an
    18 instance of a trait. This proposal will change that and allow instances of
    19 traits to be created from instances of data types that implement the trait.
    20 
    21 For example:
     17but traits are not themselves data types. This will change that and allow
     18instances of traits to be created from instances of data types that implement
     19the trait.
    2220
    2321    trait combiner(otype T) {
    24         void combine(T&, int);
    25     };
     22                void combine(T&, int);
     23        };
    2624
    2725    struct summation {
    28         int sum;
    29     };
     26                int sum;
     27        };
    3028
    31     void ?{}( struct summation & this ) {
    32         this.sum = 0;
    33     }
     29        void ?{}( struct summation & this ) {
     30                this.sum = 0;
     31        }
    3432
    3533    void combine( struct summation & this, int num ) {
    36         this.sum = this.sum + num;
    37     }
     34                this.sum = this.sum + num;
     35        }
    3836
    39     trait combiner obj = struct summation{};
    40     combine(obj, 5);
     37        trait combiner obj = struct summation{};
     38        combine(obj, 5);
    4139
    4240As with `struct` (and `union` and `enum`), `trait` might be optional when
     
    4442before.
    4543
    46 For traits to be used this way they should meet two requirements. First they
    47 should only have a single polymorphic type and each assertion should use that
    48 type once as a parameter. Extensions may later loosen these requirements.
     44Internally a trait object is a pair of pointers. One to an underlying object
     45and the other to the vtable. All calls on an trait are implemented by looking
     46up the matching function pointer and passing the underlying object and the
     47remaining arguments to it.
    4948
    50 Also note this applies to the final expanded list of assertions. Consider:
    51 
    52     trait foo(otype T, otype U) {
    53         ... functions that use T once ...
    54     }
    55 
    56     trait bar(otype S | foo(S, char)) {
    57         ... functions that use S once ...
    58     }
    59 
    60 In this example `bar` may be used as a type but `foo` may not.
    61 
    62 When a trait is used as a type it creates a generic object which combines
    63 the base structure (an instance of `summation` in this case) and the vtable,
    64 which is currently created and provided by a hidden mechanism.
    65 
    66 The generic object type for each trait also implements that trait. This is
    67 actually the only means by which it can be used. The type of these functions
    68 look something like this:
    69 
    70     void combine(trait combiner & this, int num);
    71 
    72 The main use case for trait objects is that they can be stored. They can be
    73 passed into functions, but using the trait directly is preferred in this case.
    74 
    75     trait drawable(otype T) {
    76         void draw(Surface & to, T & draw);
    77         Rect(int) drawArea(T & draw);
    78     };
    79 
    80     struct UpdatingSurface {
    81         Surface * surface;
    82         vector(trait drawable) drawables;
    83     };
    84 
    85     void updateSurface(UpdatingSurface & us) {
    86         for (size_t i = 0 ; i < us.drawables.size ; ++i) {
    87             draw(us.surface, us.drawables[i]);
    88         }
    89     }
    90 
    91 With a more complete widget trait you could, for example, construct a UI tool
    92 kit that can declare containers that hold widgets without knowing about the
    93 widget types. Making it reasonable to extend the tool kit.
    94 
    95 The trait types can also be used in the types of assertions on traits as well.
    96 In this usage they passed as the underlying object and vtable pair as they
    97 are stored. The trait types can also be used in that trait's definition, which
    98 means you can pass two instances of a trait to a single function. However the
    99 look-up of the one that is not used to look up any functions, until another
    100 function that uses that object in the generic/look-up location is called.
    101 
    102     trait example(otype T) {
    103         bool test(T & this, trait example & that);
    104     }
    105 
    106 ### Explanation Of Restrictions
    107 
    108 The two restrictions on traits that can be used as trait objects are:
    109 
    110 1.  Only one generic parameter may be defined in the trait's header.
    111 2.  Each function assertion must have one parameter with the type of the
    112     generic parameter. They may or may not return a value of that type.
    113 
    114 Elsewhere in this proposal I suggest ways to broaden these requirements.
    115 A simple example would be if a trait meets requirement 1 but not 2, then
    116 the assertions that do not satisfy the exactly one parameter requirement can
    117 be ignored.
    118 
    119 However I would like to talk about why these two rules are in place in the
    120 first place and the problems that any exceptions to these rules must avoid.
    121 
    122 The problems appear when the dispatcher function which operates on the
    123 generic object.
    124 
    125     trait combiner(otype T, otype U) {
    126         void combine(T&, U);
    127     }
    128 
    129 This one is so strange I don't have proper syntax for it but let us say that
    130 the concrete dispatcher would be typed as
    131 `void combine(combiner(T) &, combiner(U));`. Does the function that combine
    132 the two underlying types exist to dispatch too?
    133 
    134 Maybe not. If `combiner(T)` works with ints and `combiner(U)` is a char then
    135 they could not be. It would have to enforce that all pairs of any types
    136 that are wrapped in this way. Which would pretty much destroy any chance of
    137 separate compilation.
    138 
    139 Even then it would be more expensive as the wrappers would have to carry ids
    140 that you use to look up on an <number of types>+1 dimensional table.
    141 
    142 The second restriction has a similar issue but makes a bit more sense to
    143 write out.
    144 
    145     trait Series(otype T) {
    146         ... size, iterators, getters ...
    147         T join(T const &, T const &);
    148     }
    149 
    150 With the dispatcher typed as:
    151 
    152     Series join(Series const &, Series const &);
    153 
    154 Because these instances are generic and hide the underlying implementation we
    155 do not know what that implementation is. Unfortunately this also means the
    156 implementation for the two parameters might not be the same. Once we have
    157 two different types involved this devolves into the first case.
    158 
    159 We could check at run-time that the have the same underlying type, but this
    160 would likely time and space overhead and there is no clear recovery path.
    161 
    162 #### Sample Implementation
    163 A simple way to implement trait objects is by a pair of pointers. One to the
    164 underlying object and one to the vtable.
    165 
    166     struct vtable_drawable {
    167         void (*draw)(Surface &, void *);
    168         Rect(int) (*drawArea)(void *);
    169     };
    170 
    171     struct drawable {
    172         void * object;
    173         vtable_drawable * vtable;
    174     };
    175 
    176 The functions that run on the trait object would generally be generated using
    177 the following pattern:
    178 
    179     void draw(Surface & surface, drawable & traitObj) {
    180         return traitObj.vtable->draw(surface, traitObj.object);
    181     }
    182 
    183 There may have to be special cases for things like copy construction, that
    184 might require a more significant wrapper. On the other hand moving could be
    185 implemented by moving the pointers without any need to refer to the base
    186 object.
    187 
    188 ### Extension: Multiple Trait Parameters
    189 The base proposal in effect creates another use for the trait syntax that is
    190 related to the ones currently in the language but is also separate from them.
    191 The current uses generic functions and generic types, this new use could be
    192 described as generic objects.
    193 
    194 A generic object is of a concrete type and has concrete functions that work on
    195 it. It is generic in that it is a wrapper for an unknown type. Traits serve
    196 a similar role here as in generic functions as they limit what the function
    197 can be generic over.
    198 
    199 This combines the use allowing to have a generic type that is a generic
    200 object. All but one of the trait's parameters is given a concrete type,
    201 conceptually currying the trait to create a trait with on generic parameter
    202 that fits the original restrictions. The resulting concrete generic object
    203 type is different with each set of provided parameters and their values.
    204 
    205 Then it just becomes a question of where this is done. Again both examples use
    206 a basic syntax to show the idea.
    207 
    208     trait iterator(virtual otype T, otype Item) {
    209         bool has_next(T const &);
    210         Item get_next(T const *);
    211     }
    212 
    213     iterator(int) int_it = begin(container_of_ints);
    214 
    215 The first option is to do it at the definition of the trait. One parameter
    216 is selected (here with the `virtual` keyword, but other rules like "the first"
    217 could also be used) and when an instance of the trait is created all the
    218 other parameters must be provided.
    219 
    220     trait iterator(otype T, otype Item) {
    221         bool has_next(T const &);
    222         Item get_next(T const *);
    223     }
    224 
    225     iterator(virtual, int) int_it = begin(container_of_ints);
    226 
    227 The second option is to skip a parameter as part of the type instance
    228 definition. One parameter is explicitly skipped (again with the `virtual`
    229 keyword) and the others have concrete types. The skipped one is the one we
    230 are generic on.
    231 
    232 Incidentally in both examples `container_of_ints` may itself be a generic
    233 object and `begin` returns a generic iterator with unknown implementation.
    234 
    235 These options are not exclusive. Defining a default on the trait allows for
    236 an object to be created as in the first example. However, whether the
    237 default is provided or not, the second syntax can be used to pick a
    238 parameter on instantiation.
     49Trait objects can be moved by moving the pointers. Almost all other operations
     50require some functions to be implemented on the underlying type. Depending on
     51what is in the virtual table a trait type could be a dtype or otype.
    23952
    24053Hierarchy
    24154---------
    24255
    243 We would also like to implement hierarchical relations between types.
     56Virtual tables by them selves are not quite enough to implement the planned
     57hierarchy system. An addition of type ids, implemented as pointers which
     58point to your parent's type id, is required to actually create the shape of
     59the hierarchy. However vtables would allow behaviour to be carried with the
     60tree.
    24461
    245     ast_node
    246     |-expression_node
    247     | |-operator_expression
    248     |
    249     |-statement_node
    250     | |-goto_statement
    251     |
    252     |-declaration_node
    253       |-using_declaration
    254       |-variable_declaration
     62The hierarchy would be a tree of types, of traits and structs. Currently we do
     63not support structural extension, so traits form the internal nodes and
     64structures the leaf nodes.
    25565
    256 Virtual tables by themselves are not quite enough to implement this system.
    257 A vtable is just a list of functions and there is no way to check at run-time
    258 what these functions, we carry that knowledge with the table.
     66The syntax is undecided but it will include a clause like `virtual (PARENT)`
     67on trait and struct definitions. It marks out all types in a hierarchy.
     68PARENT may be omitted, if it is this type is the root of a hierarchy. Otherwise
     69it is the name of the type that is this type's parent in the hierarchy.
    25970
    260 This proposal adds type ids to check for position in the hierarchy and an
    261 explicate syntax for establishing a hierarchical relation between traits and
    262 their implementing types. The ids should uniquely identify each type and
    263 allow retrieval of the type's parent if one exists. By recursion this allows
    264 the ancestor relation between any two hierarchical types can be checked.
     71Traits define a trait instance type that implements all assertions in this
     72trait and its parents up until the root of the hierarchy. Each trait then
     73defines a vtable type. Structures will also have a vtable type but it should
     74be the same as their parent's.
    26575
    266 The hierarchy is created with traits as the internal nodes and structures
    267 as the leaf nodes. The structures may be used normally and the traits can
    268 be used to create generic objects as in the first section (the same
    269 restrictions apply). However these type objects store their type id which can
    270 be recovered to figure out which type they are or at least check to see if
    271 they fall into a given sub-tree at run-time.
     76Trait objects within the tree can be statically cast to a parent type. Casts
     77from a parent type to a child type are conditional, they check to make sure
     78the underlying instance is an instance of the child type, or an instance of
     79one of its children. The type then is recoverable at run-time.
    27280
    273 Here is an example of part of a hierarchy. The `virtual(PARENT)` syntax is
    274 just an example. But when used it give the name of the parent type or if
    275 empty it shows that this type is the root of its hierarchy.
    276 (Also I'm not sure where I got these casing rules.)
     81As with regular trait objects, calling a function on a trait object will cause
     82a look-up on the the virtual table. The casting rules make sure anything that
     83can be cast to a trait type will have all the function implementations for
     84that trait.
    27785
    278     trait ast_node(otype T) virtual() {
    279         void print(T & this, ostream & out);
    280         void visit(T & this, Visitor & visitor);
    281         CodeLocation const & get_code_location(T & this);
    282     }
     86Converting from a concrete type (structures at the edge of the hierarchy) to
     87an abstract type works the same as with normal trait objects, the underlying
     88object is packaged with a virtual table pointer. Converting back to an abstract
     89type requires confirming the underlying type matches, but then simply extracts
     90the pointer to it.
    28391
    284     trait expression_node(otype T) virtual(ast_node) {
    285         Type eval_type(T const & this);
    286     }
     92### Inline vtables
     93Since the structures here are usually made to be turned into trait objects
     94it might be worth it to have fields on them to store the virtual table
     95pointer. This would have to be declared on the trait as an assertion, but if
     96it is the trait object could be a single pointer.
    28797
    288     struct operator_expression virtual(expression_node) {
    289         enum operator_kind kind;
    290         trait expression_node rands[2];
    291     }
    292 
    293     trait statement_node(otype T) virtual(ast_node) {
    294         vector(Label) & get_labels(T & this);
    295     }
    296 
    297     struct goto_statement virtual(statement_node) {
    298         vector(Label) labels;
    299         Label target;
    300     }
    301 
    302     trait declaration_node(otype T) virtual(ast_node) {
    303         string name_of(T const & this);
    304         Type type_of(T const & this);
    305     }
    306 
    307     struct using_declaration virtual(declaration_node) {
    308         string new_type;
    309         Type old_type;
    310     }
    311 
    312     struct variable_declaration virtual(declaration_node) {
    313         string name;
    314         Type type;
    315     }
    316 
    317 This system does not support multiple inheritance. The system could be
    318 extended to support it or a limited form (ex. you may have multiple parents
    319 but they may not have a common ancestor). However this proposal focuses just
    320 on using hierachy as organization. Other uses for reusable/genaric code or
    321 shared interfaces is left for other features of the language.
    322 
    323 ### Extension: Structural Inheritance
    324 An extension would be allow structures to be used as internal nodes on the
    325 inheritance tree. Its child types would have to implement the same fields.
    326 
    327 The weaker restriction would be to convert the fields into field assertions
    328 (Not implemented yet: `U T.x` means there is a field of type you on the type
    329 T. Offset unknown and passed in/stored with function pointers.)
    330 A concrete child would have to declare the same set of fields with the same
    331 types. This is of a more functional style.
    332 
    333 The stronger restriction is that the fields of the parent are a prefix of the
    334 child's fields. Possibly automatically inserted. This the imperative view and
    335 may also have less overhead.
    336 
    337 ### Extension: Unions and Enumerations
    338 Currently there is no reason unions and enumerations, in the cases they
    339 do implement the trait, could not be in the hierarchy as leaf nodes.
    340 
    341 It does not work with structural induction, but that could just be a compile
    342 time check that all ancestors are traits or do not add field assertions.
    343 
    344 #### Sample Implementation
    345 The type id may be as little as:
    346 
    347     struct typeid {
    348         struct typeid const * const parent;
    349     };
    350 
    351 Some linker magic would have to be used to ensure exactly one copy of each
    352 structure for each type exists in memory. There seem to be special once
    353 sections that support this and it should be easier than generating unique
    354 ids across compilation units.
    355 
    356 The structure could be extended to contain any additional type information.
    357 
    358 There are two general designs for vtables with type ids. The first is to put
    359 the type id at the top of the vtable, this is the most compact and efficient
    360 solution but only works if we have exactly 1 vtable for each type. The second
    361 is to put a pointer to the type id in each vtable. This has more overhead but
    362 allows multiple vtables per type.
    363 
    364     struct <trait>_vtable {
    365         struct typeid const id;
    366 
    367         // Trait dependent list of vtable members.
    368     };
    369 
    370     struct <trait>_vtable {
    371         struct typeid const * const id;
    372 
    373         // Trait dependent list of vtable members.
    374     };
    375 
    376 One important restriction is that only one instance of each typeid in memory.
    377 There is a ".gnu.linkonce" feature in the linker that might solve the issue.
    378 
    379 ### Virtual Casts
    380 The generic objects may be cast up and down the hierarchy.
    381 
    382 Casting to an ancestor type always succeeds. From one generic type to another
    383 is just a reinterpretation and could be implicate. Wrapping and unwrapping
    384 a concrete type will probably use the same syntax as in the first section.
    385 
    386 Casting from an ancestor to a descendent requires a check. The underlying
    387 type may or may not belong to the sub-tree headed by that descendent. For this
    388 we introduce a new cast operator, which returns the pointer unchanged if the
    389 check succeeds and null otherwise.
    390 
    391     trait SubType * new_value = (virtual trait SubType *)super_type;
    392 
    393 For the following example I am using the as of yet finished exception system.
    394 
    395     trait exception(otype T) virtual() {
    396         char const * what(T & this);
    397     }
    398 
    399     trait io_error(otype T) virtual(exception) {
    400         FILE * which_file(T & this);
    401     }
    402 
    403     struct eof_error(otype T) virtual(io_error) {
    404         FILE * file;
    405     }
    406 
    407     char const * what(eof_error &) {
    408         return "Tried to read from an empty file.";
    409     }
    410 
    411     FILE * which_file(eof_error & this) {
    412         return eof_error.file;
    413     }
    414 
    415     bool handleIoError(exception * exc) {
    416         io_error * error = (virtual io_error *)exc;
    417         if (NULL == error) {
    418             return false;
    419         }
    420         ...
    421         return true;
    422     }
    423 
    424 ### Extension: Implicate Virtual Cast Target
    425 This is a small extension, even in the example above `io_error *` is repeated
    426 in the cast and the variable being assigned to. Using return type inference
    427 would allow the second type to be skipped in cases it is clear what type is
    428 being checked against.
    429 
    430 The line then becomes:
    431 
    432     io_error * error = (virtual)exc;
    433 
    434 #### Sample Implementation
    435 This cast implementation assumes a type id layout similar to the one given
    436 above. Also this code is definitely in the underlying C. Functions that give
    437 this functionality could exist in the standard library but these are meant to
    438 be produced by code translation of the virtual cast.
    439 
    440     bool is_in_subtree(typeid const * root, typeid const * id) {
    441         if (root == id) {
    442             return true
    443         } else if (NULL == id->parent) {
    444             return false;
    445         } else {
    446             return is_in_subtree(root, id->parent);
    447         }
    448     }
    449 
    450     void * virtual_cast(typeid const * target, void * value) {
    451         return is_in_subtree(target, *(typeid const **)value) ? value : NULL;
    452     }
    453 
    454 The virtual cast function might have to be wrapped with some casts to make it
    455 compile without warning.
    456 
    457 For the implicate target type we may be able to lean on the type resolution
    458 system that already exists. If the casting to ancestor type is built into
    459 the resolution then the impicate target could be decided by picking an
    460 overload, generated for each hierarchial type (here io_error and its root
    461 type exception).
    462 
    463     io_error * virtual_cast(exception * value) {
    464         return virtual_cast(io_error_typeid, value);
    465     }
    466 
    467 ### Extension: Inline vtables
    468 Since the structures here are usually made to be turned into trait objects
    469 it might be worth it to have fields in them to store the virtual table
    470 pointer. This would have to be declared on the trait as an assertion (example:
    471 `vtable;` or `T.vtable;`), but if it is the trait object could be a single
    472 pointer.
    473 
    474 There are also three options for where the pointer to the vtable. It could be
    475 anywhere, a fixed location for each trait or always at the front. For the per-
    476 trait solution an extension to specify what it is (example `vtable[0];`) which
    477 could also be used to combine it with others. So these options can be combined
    478 to allow access to all three options.
    479 
    480 The pointer to virtual table field on structures might implicately added (the
    481 types have to declare they are a child here) or created with a declaration,
    482 possibly like the one used to create the assertion.
     98It is trivial to do if the field with the virtual table pointer is fixed.
     99Otherwise some trickery with pointing to the field and storing the offset in
     100the virtual table to recover the main object would have to be used.
    483101
    484102### Virtual Tables as Types
    485 Here we consider encoding plus the implementation of functions on it to be a
    486 type. Which is to say in the type hierarchy structures aren't concrete types
    487 anymore, instead they are parent types to vtables, which combine the encoding
    488 and implementation.
    489 
    490 ### Question: Wrapping Structures
    491 One issue is what to do with concrete types at the base of the type tree.
    492 When we are working with the concrete type generally it would like them to be
    493 regular structures with direct calls. On the other hand for interactions with
    494 other types in the hierarchy it is more convenent for the type already to be
    495 cast.
    496 
    497 Which of these two should we use? Should we support both and if so how do we
    498 choose which one is being used at any given time.
    499 
    500 On a related note I have been using pointers two trait types here, as that
    501 is how many existing languages handle it. However the generic objects might
    502 be only one or two pointers wide passing the objects as a whole would not
    503 be very expensive and all operations on the generic objects probably have
    504 to be defined anyways.
     103Here we consider encoding plus the implementation of functions on it. Which
     104is to say in the type hierarchy structures aren't concrete types anymore,
     105instead they are parent types to vtables, which combine the encoding and
     106implementation.
    505107
    506108Resolution Scope
     
    518120the type declaration, including the functions that satisfy the trait, are
    519121all defined. Currently there are many points where this can happen, not all
    520 of them have the same definitions and no way to select one over the other.
     122of them will have the same definitions and no way to select one over the
     123other.
    521124
    522 Some syntax would have to be added to specify the resolution point. To ensure
    523 a single instance there may have to be two variants, one forward declaration
    524 and one to create the instance. With some compiler magic the forward
    525 declaration maybe enough.
    526 
    527     extern trait combiner(struct summation) vtable;
    528     trait combiner(struct summation) vtable;
    529 
    530 Or (with the same variants):
    531 
    532     vtable combiner(struct summation);
    533 
    534 The extern variant promises that the vtable will exist while the normal one
    535 is where the resolution actually happens.
     125Some syntax would have to be added. All resolutions can be found at compile
     126time and a single vtable created for each type at compilation time.
    536127
    537128### Explicit Resolution Points:
     
    549140However this also means that stack-allocated functions can end up in the
    550141vtable.
    551 
    552     extern trait combiner(struct summation) vtable sum;
    553     trait combiner(struct summation) vtable sum;
    554 
    555     extern trait combiner(struct summation) vtable sum default;
    556     trait combiner(struct summation) vtable sum default;
    557 
    558 The extern difference is the same before. The name (sum in the samples) is
    559 used at the binding site to say which one is picked. The default keyword can
    560 be used in only some of the declarations.
    561 
    562     trait combiner fee = (summation_instance, sum);
    563     trait combiner foe = summation_instance;
    564 
    565 (I am not really happy about this syntax, but it kind of works.)
    566 The object being bound is required. The name of the vtable is optional if
    567 there is exactly one vtable name marked with default.
    568 
    569 These could also be placed inside functions. In which case both the name and
    570 the default keyword might be optional. If the name is omitted in an assignment
    571 the closest vtable is chosen (returning to the global default rule if no
    572 appropriate local vtable is in scope).
    573142
    574143### Site Based Resolution:
     
    596165Stack allocated functions interact badly with this because they are not
    597166static. There are several ways to try to resolve this, however without a
    598 general solution most can keep vtables from making the existing thunk problem
    599 worse, they don't do anything to solve it.
     167general solution most can only buy time.
    600168
    601169Filling in some fields of a static vtable could cause issues on a recursive
     
    612180shortest lifetime of a function assigned to it. However this still limits the
    613181lifetime "implicitly" and returns to the original problem with thunks.
    614 
    615 Odds And Ends
    616 -------------
    617 
    618 In addition to the main design there are a few extras that should be
    619 considered. They are not part of the core design but make the new uses fully
    620 featured.
    621 
    622 ### Extension: Parent-Child Assertion
    623 For hierarchy types in regular traits, generic functions or generic structures
    624 we may want to be able to check parent-child relationships between two types
    625 given. For this we might have to add another primitive assertion. It would
    626 have the following form if declared in code:
    627 
    628     trait is_parent_child(dtype Parent, dtype Child) { <built-in magic> }
    629 
    630 This assertion is satified if Parent is an ancestor of Child in a hierarchy.
    631 In other words Child can be statically cast to Parent. The cast from Parent
    632 to child would be dynamically checked as usual.
    633 
    634 However in this form there are two concerns. The first that Parent will
    635 usually be consistent for a given use, it will not be a variable. Second is
    636 that we may also need the assertion functions. To do any casting/conversions
    637 anyways.
    638 TODO: Talk about when we wrap a concrete type and how that leads to "may".
    639 
    640 To this end it may be better that the parent trait combines the usual
    641 assertions plus this new primitive assertion. There may or may not be use
    642 cases for accessing just one half and providing easy access to them may be
    643 required depending on how that turns out.
    644 
    645     trait Parent(dtype T | interface(T)) virtual(<grand-parent?>) { }
    646 
    647 ### Extension: sizeof Compatablity
    648 Trait types are always sized, it may even be a fixed size like how pointers
    649 have the same size regardless of what they point at. However their contents
    650 may or may not be of a known size (if the `sized(...)` assertion is used).
    651 
    652 Currently there is no way to access this information. If it is needed a
    653 special syntax would have to be added. Here a special case of `sizeof` is
    654 used.
    655 
    656     struct line aLine;
    657     trait drawable widget = aLine;
    658 
    659     size_t x = sizeof(widget);
    660     size_t y = sizeof(trait drawable);
    661 
    662 As usual `y`, size of the type, is the size of the local storage used to put
    663 the value into. The other case `x` checks the saved stored value in the
    664 virtual table and returns that.
  • doc/theses/aaron_moss_PhD/phd/Makefile

    r933f32f r6a9d4b4  
    22BIBDIR = ../../../bibliography
    33EVALDIR = evaluation
    4 FIGDIR = figures
    54TEXLIB = .:${BUILD}:${BIBDIR}:
    65
     
    98BIBTEX = BIBINPUTS=${TEXLIB} && export BIBINPUTS && bibtex
    109
    11 VPATH = ${EVALDIR} ${FIGDIR}
     10VPATH = ${EVALDIR}
    1211
    1312BASE = thesis
     
    2322background \
    2423generic-types \
     24type-environment \
    2525resolution-heuristics \
    26 type-environment \
    27 experiments \
    2826conclusion \
    29 generic-bench \
    30 }
    31 
    32 FIGURES = ${addsuffix .eps, \
    33 safe-conv-graph \
    34 resolution-dag \
    35 union-find-with-classes \
    36 persistent-union-find \
    3727}
    3828
    3929GRAPHS = ${addsuffix .tex, \
    4030generic-timing \
    41 tests-completed \
    42 per-prob-histo \
    43 per-prob-depth \
    44 cfa-time \
    4531}
    4632
     
    6147        dvips ${BUILD}/$< -o ${BUILD}/$@
    6248
    63 ${BASE}.dvi : Makefile ${SOURCES} ${GRAPHS} ${FIGURES} ${BIBFILE} ${BUILD}
     49${BASE}.dvi : Makefile ${SOURCES} ${GRAPHS} ${BIBFILE} ${BUILD}
    6450        ${LATEX} ${BASE}
    6551        ${BIBTEX} ${BUILD}/${BASE}
     
    6753        ${LATEX} ${BASE}
    6854
    69 generic-timing.tex : generic-timing.gp generic-timing.dat ${BUILD}
     55${GRAPHS} : generic-timing.gp generic-timing.dat ${BUILD}
    7056        gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/generic-timing.gp
    71        
    72 tests-completed.tex : algo-summary.gp algo-summary.dat bu-summary.dat ${BUILD}
    73         gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/algo-summary.gp
    74 
    75 per-prob-histo.tex : per-prob.gp per-prob.tsv ${BUILD}
    76         gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/per-prob.gp
    77 
    78 per-prob-depth.tex : per-prob-scatter.gp ${BUILD}
    79         gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/per-prob-scatter.gp
    80 
    81 cfa-time.tex : cfa-plots.gp cfa-time.tsv cfa-mem.tsv ${BUILD}
    82         gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/cfa-plots.gp
    8357
    8458${BUILD}:
  • doc/theses/aaron_moss_PhD/phd/background.tex

    r933f32f r6a9d4b4  
    11\chapter{\CFA{}}
    2 \label{cfa-chap}
    32
    43\CFA{} adds a number of features to C, some of them providing significant increases to the expressive power of the language, but all designed to maintain the existing procedural programming paradigm of C and to be as orthogonal as possible to each other.
    54To provide background for the contributions in subsequent chapters, this chapter provides a summary of the features of \CFA{} at the time this work was conducted.
    65
    7 Glen Ditchfield laid out the core design of \CFA{} in his 1992 PhD thesis, \emph{Contextual Polymorphism} \cite{Ditchfield92}; in that thesis, Ditchfield presents the theoretical underpinnings of the \CFA{} polymorphism model.
    8 Building on Ditchfield's design for contextual polymorphism as well as KW-C \cite{Buhr94a}, an earlier set of (largely syntactic) extensions to C, Richard Bilson \cite{Bilson03} built the first version of the \CFA{} compiler, \CFACC{}, in the early 2000's.
    9 This early \CFACC{} provided basic functionality, but incorporated a number of algorithmic choices that have failed to scale as \CFA{} has developed, lacking the runtime performance for practical use; this thesis is substantially concerned with rectifying those deficits.
    10 
    11 The \CFA{} project was revived in 2015 with the intention of building a production-ready language and compiler; at the time of this writing, both \CFA{} and \CFACC{} remain under active development.
    12 As this development has been proceeding concurrently with the work described in this thesis, the state of \CFA{} has been somewhat of a moving target; however, Moss~\etal~\cite{Moss18} provides a reasonable summary of the current design.
    13 Notable features added during this period include generic types (Chapter~\ref{generic-chap}), constructors and destructors \cite{Schluntz17}, improved support for tuples \cite{Schluntz17}, reference types \cite{Moss18}, first-class concurrent and parallel programming support \cite{Delisle18}, as well as numerous pieces of syntactic sugar and the start of an idiomatic standard library \cite{Moss18}.
    14 
    15 This thesis is primarily concerned with the \emph{expression resolution} portion of \CFA{} type-checking; resolution is discussed in more detail in Chapter~\ref{resolution-chap}, but is essentially determining which declarations the identifiers in each expression correspond to.
    16 In C, no simultaneously-visible declarations share identifiers, hence expression resolution in C is not difficult.
    17 In \CFA{}, multiple added features make the resolution process significantly more complex.
    18 Due to this complexity, the expression-resolution pass in \CFACC{} requires 95\% of compiler runtime on some source files, making a new, more efficient procedure for expression resolution a requirement for a performant \CFA{} compiler.
    19 
    20 The features presented in this chapter are chosen to elucidate the design constraints of the work presented in this thesis.
    21 In some cases the interactions of multiple features make this design a significantly more complex problem than any individual feature; in other cases a feature that does not by itself add any complexity to expression resolution triggers previously rare edge cases more frequently.
    22 
    23 \section{Procedural Paradigm}
     6The core design of \CFA{} is laid out in Glen Ditchfield's 1992 PhD thesis, \emph{Contextual Polymorphism}\cite{Ditchfield92}; in that thesis, Ditchfield presents the theoretical underpinnings of the \CFA{} polymorphism model.
     7Building on Ditchfield's design for contextual polymorphism as well as KW-C\cite{Buhr94a}, an earlier set of (largely syntactic) extensions to C, Richard Bilson\cite{Bilson03} built the first version of the \CFA{} compiler, \CFACC{}, in the early 2000's.
     8This early \CFACC{} provided basic functionality, but incorporated a number of poor algorithmic choices due to a rushed implementation time frame, and as such lacked the runtime performance required for practical use; this thesis is substantially concerned with rectifying those deficits.
     9
     10The \CFA{} project was revived in 2015 with the intention of building a production-ready language and compiler; at the time of this writing, both \CFA{} and \CFACC{} have been under active development continuously since.
     11As this development has been proceeding concurrently with the work described in this thesis, the state of \CFA{} has been somewhat of a moving target; however, Moss~\etal\cite{Moss18} provides a reasonable summary of the current design.
     12Notable features added during this period include generic types (Chapter~\ref{generic-chap}), constructors and destructors\cite{Schluntz17}, improved support for tuples\cite{Schluntz17}, reference types\cite{Moss18}, first-class concurrent and parallel programming support\cite{Delisle18}, as well as numerous pieces of syntactic sugar and the start of an idiomatic standard library\cite{Moss18}.
     13
     14\section{\CFA{} Features}
     15
     16The selection of features presented in this chapter are chosen to elucidate the design constraints of the work presented in this thesis.
     17In some cases the interactions of multiple features make this design a significantly more complex problem than any individual feature would; in other cases a feature that does not by itself add any complexity to expression resolution triggers previously rare edge cases more frequently.
     18
     19\subsection{Procedural Paradigm}
    2420
    2521It is important to note that \CFA{} is not an object-oriented language.
    26 This is a deliberate choice intended to maintain the applicability of the programming model and language idioms already possessed by C programmers.
    27 This choice is in marked contrast to \CC{}, which is a much larger and more complex language, and requires extensive developer re-training to write idiomatic, efficient code in \CC{}'s object-oriented paradigm.
    28 
     22This is a deliberate choice intended to maintain the applicability of the mental model and language idioms already possessed by C programmers.
     23This choice is in marked contrast to \CC{}, which, though it has backward-compatibility with C on the source code level, is a much larger and more complex language, and requires extensive developer re-training to write idiomatic, efficient code in \CC{}'s object-oriented paradigm.
     24
     25\CFA{} does have a system of implicit type conversions derived from C's ``usual arithmetic conversions''; while these conversions may be thought of as something like an inheritance hierarchy, the underlying semantics are significantly different and such an analogy is loose at best.
    2926Particularly, \CFA{} has no concept of \emph{subclass}, and thus no need to integrate an inheritance-based form of polymorphism with its parametric and overloading-based polymorphism.
    30 While \CFA{} does have a system of implicit type conversions derived from C's ``usual arithmetic conversions'' \cite[\S{}6.3.1.8]{C11} and these conversions may be thought of as something like an inheritance hierarchy, the underlying semantics are significantly different and such an analogy is loose at best.
    31 The graph structure of the \CFA{} type conversions (discussed in Section~\ref{conv-cost-sec}) is also markedly different than an inheritance hierarchy; it has neither a top nor a bottom type, and does not satisfy the lattice properties typical of inheritance hierarchies.
     27The graph structure of the \CFA{} type conversions is also markedly different than an inheritance hierarchy; it has neither a top nor a bottom type, and does not satisfy the lattice properties typical of inheritance hierarchies.
    3228
    3329Another aspect of \CFA{}'s procedural paradigm is that it retains C's translation-unit-based encapsulation model, rather than class-based encapsulation such as in \CC{}.
    34 As such, any language feature that requires code to be exposed in header files (\eg{} \CC{} templates) also eliminates encapsulation in \CFA{}.
    35 Given this constraint, \CFA{} is carefully designed to allow separate compilation for its added language features under the existing C usage patterns.
    36 
    37 \section{Name Overloading} \label{overloading-sec}
    38 
    39 In C, no more than one variable or function in the same scope may share the same name\footnote{Technically, C has multiple separated namespaces, one holding \lstinline{struct}, \lstinline{union}, and \lstinline{enum} tags, one holding labels, one holding \lstinline{typedef} names, variable, function, and enumerator identifiers, and one for each \lstinline{struct} and \lstinline{union} type holding the field names \cite[\S{}6.2.3]{C11}.}, and variable or function declarations in inner scopes with the same name as a declaration in an outer scope hide the outer declaration.
    40 This restriction makes finding the proper declaration to match to a variable expression or function application a simple matter of lexically-scoped name lookup, which can be easily and efficiently implemented.
     30This choice implies that that separate compilation must be maintained to allow headers to act as an encapsulation boundary, rather than the header-only libraries used by \CC{} templates.
     31
     32\subsection{Name Overloading} \label{overloading-sec}
     33
     34In C, no more than one variable or function in the same scope may share the same name\footnote{Technically, C has multiple separated namespaces, one holding \lstinline{struct}, \lstinline{union}, and \lstinline{enum} tags, one holding labels, one holding \lstinline{typedef} names, variable, function, and enumerator identifiers, and one for each \lstinline{struct} and \lstinline{union} type holding the field names\cit{}.}, and variable or function declarations in inner scopes with the same name as a declaration in an outer scope hide the outer declaration.
     35This restriction makes finding the proper declaration to match to a variable expression or function application a simple matter of symbol-table lookup, which can be easily and efficiently implemented.
    4136\CFA{}, on the other hand, allows overloading of variable and function names so long as the overloaded declarations do not have the same type, avoiding the multiplication of variable and function names for different types common in the C standard library, as in the following example:
    4237
     
    5550\end{cfa}
    5651
    57 The final expression in the preceding example includes a feature of \CFA{} name overloading not shared by \CC{}, the ability to disambiguate expressions based on their return type. This provides greater flexibility and power than the parameter-based overload selection of \CC{}, though at the cost of greater complexity in the resolution algorithm.
    58 
    59 While the wisdom of giving both the maximum value of a type and the function to take the maximum of two values the same name in the example above is debatable, \eg{} some developers may prefer !MAX! for the former, the guiding philosophy of \CFA{} is ``describe, don't prescribe'' --- we prefer to trust programmers with powerful tools, and there is no technical reason to restrict overloading between variables and functions.
    60 However, the expressivity of \CFA{}'s name overloading does have the consequence that simple table lookup is insufficient to match identifiers to declarations, and a type-matching algorithm must be part of expression resolution.
    61 
    62 \subsection{Operator Overloading}
     52While the wisdom of giving both the maximum value of a type and the function to take the maximum of two values the same name is debatable, \eg{} some developers may prefer !MAX! for the former, the guiding philosophy of \CFA{} is ``describe, don't prescribe'' --- we prefer to trust programmers with powerful tools, and there is no technical reason to restrict overloading between variables and functions.
     53However, the expressivity of \CFA{}'s name overloading has the consequence that simple table lookup is insufficient to match identifiers to declarations, and a type-matching algorithm must be part of expression resolution.
     54
     55\subsubsection{Operator Overloading}
    6356
    6457C does allow name overloading in one context: operator overloading.
    6558From the perspective of the type system, there is nothing special about operators as opposed to other functions, nor is it desirable to restrict the clear and readable syntax of operators to only the built-in types.
    66 For these reasons, \CFA{}, like \CC{} and many other programming languages, allows overloading of operators by writing specially-named functions where !?! stands in for the operands.
    67 This syntax is more natural than the operator overloading syntax of \CC{}, which requires ``dummy'' parameters to disambiguate overloads of similarly-named pre- and postfix operators\footnote{This example uses \CFA{}'s reference types, described in Section~\ref{type-features-sec}}:
     59For these reasons, \CFA{} also allows overloading of operators by writing specially-named functions where !?! stands in for the operands\footnote{This example uses \CFA{}'s reference types, described in Section~\ref{type-features-sec}}:
    6860
    6961\begin{cfa}
     
    7971\end{cfa}
    8072
    81 Together, \CFA{}'s backward-compatibility with C and the inclusion of this operator overloading feature imply that \CFA{} must select among function overloads using a method compatible with C's ``usual arithmetic conversions'' \cite[\S{}6.3.1.8]{C11}, so as to present user programmers with only a single set of overloading rules.
    82 
    83 \subsection{Special Literal Types}
     73Together, \CFA{}'s backward-compatibility with C and the inclusion of this operator overloading feature imply that \CFA{} must select among function overloads using a method compatible with C's ``usual arithmetic conversions''\cit{}, so as to present user programmers with only a single set of overloading rules.
     74
     75\subsubsection{Special Literal Types}
    8476
    8577Literal !0! is also used polymorphically in C; it may be either integer zero or the null value of any pointer type.
    86 \CFA{} provides a special type for the !0! literal, !zero_t!, so that users can define a zero value for their own types without being forced to create a conversion from an integer or pointer type; \CFA{} also includes implicit conversions from !zero_t! to the !int! and pointer type constructors\footnote{See Section~\ref{type-features-sec}} from !zero_t! for backward compatibility.
    87 
    88 According to the C standard \cite[\S{}6.8.4.1]{C11}, !0! is the only false value; any value that compares equal to zero is false, while any value that does not is true.
    89 By this rule, Boolean contexts such as !if ( x )! can always be equivalently rewritten as \lstinline{if ( (x) != 0 )}.
    90 \CFACC{} applies this rewriting in all Boolean contexts, so any type !T! can be made ``truthy'' (that is, given a Boolean interpretation) in \CFA{} by defining an operator overload \lstinline{int ?!=?(T, zero_t)}.
    91 \CC{} takes a different approach to user-defined truthy types, allowing definition of an implicit conversion operator to !bool!; prior to the introduction of the !explicit! keyword for conversion operators in \CCeleven{} this approach also allowed undesired implicit conversions to all other arithmetic types, a shortcoming not shared by the \CFA{} design.
     78\CFA{} provides a special type for the !0! literal, !zero_t!, so that users can define a zero value for their own types without being forced to create a conversion from an integer or pointer type (though \CFA{} also includes implicit conversions from !zero_t! to the integer and pointer types for backward compatibility).
     79
     80According to the C standard\cit{}, !0! is the only false value; any value that compares equal to zero is false, while any value that does not is true.
     81By this rule, boolean contexts such as !if ( x )! can always be equivalently rewritten as \lstinline{if ( (x) != 0 )}.
     82\CFACC{} applies this rewriting in all boolean contexts, so any type !T! can be made ``truthy'' (that is, given a boolean interpretation) in \CFA{} by defining an operator overload \lstinline{int ?!=?(T, zero_t)}; unlike \CC{} prior to the addition of explicit casts in \CCeleven{}, this design does not add comparability or convertablity to arbitrary integer types.
    9283
    9384\CFA{} also includes a special type for !1!, !one_t!; like !zero_t!, !one_t! has built-in implicit conversions to the various integral types so that !1! maintains its expected semantics in legacy code.
    9485The addition of !one_t! allows generic algorithms to handle the unit value uniformly for types where it is meaningful; a simple example of this is that polymorphic functions\footnote{discussed in Section~\ref{poly-func-sec}} in the \CFA{} prelude define !++x! and !x++! in terms of !x += 1!, allowing users to idiomatically define all forms of increment for a type !T! by defining the single function !T& ?+=?(T&, one_t)!; analogous overloads for the decrement operators are also present, and programmers can override any of these functions for a particular type if desired.
    9586
    96 \CFA{} previously allowed !0! and !1! to be the names of polymorphic variables, with separate overloads for !int 0!, !int 1!, and the polymorphic variable !forall(dtype T) T* 0!.
    97 While designing \CFA{} generic types (see Chapter~\ref{generic-chap}), it was discovered that the parametric polymorphic zero variable is not generalizable to other types; though all null pointers have the same in-memory representation, the same cannot be said of the zero values of arbitrary types.
    98 As such, polymorphic variables, and in particular variables for !0! and !1!, were phased out in favour of functions that could generate those values for a given type as appropriate.
    99 
    100 \section{Polymorphic Functions} \label{poly-func-sec}
    101 
    102 The most significant type-system feature \CFA{} adds is parametric-polymorphic functions.
     87\CFA{} previously allowed !0! and !1! to be the names of polymorphic variables, with separate overloads for !int 0!, !int 1!, and !forall(dtype T) T* 0!.
     88As revealed in my own work on generic types (Chapter~\ref{generic-chap}), the parameteric polymorphic zero variable was not generalizable to other types; though all null pointers have the same in-memory representation, the same cannot be said of the zero values of arbitrary types.
     89As such, variables that could represent !0! and !1! were phased out in favour of functions that could generate those values for a given type as appropriate.
     90
     91\subsection{Polymorphic Functions} \label{poly-func-sec}
     92
     93The most significant feature \CFA{} adds is parametric-polymorphic functions.
    10394Such functions are written using a !forall! clause (which gives the language its name):
    10495
     
    111102The type variable !T! is transformed into a set of additional implicit parameters to !identity!, which encode sufficient information about !T! to create and return a variable of that type.
    112103\CFA{} passes the size and alignment of the type represented by an !otype! parameter, as well as a default constructor, copy constructor, assignment operator, and destructor.
    113 Types that do not have one or more of these operators visible cannot be bound to !otype! parameters, but may be bound to un-constrained !dtype! (``data type'') type variables.
    114 In this design, the runtime cost of polymorphism is spread over each polymorphic call, due to passing more arguments to polymorphic functions; the experiments in Chapter~\ref{generic-chap} indicate that this overhead is comparable to that of \CC{} virtual function calls.
    115 % \TODO{rerun experiments, possibly look at vtable variant}
     104Types which do not have one or more of these operators visible cannot be bound to !otype! parameters.
     105In this design, the runtime cost of polymorphism is spread over each polymorphic call, due to passing more arguments to polymorphic functions; experiments have shown this overhead to be similar to \CC{} virtual function calls. \TODO{rerun experiments, possibly look at vtable variant}
    116106
    117107One benefit of this design is that it allows polymorphic functions to be separately compiled.
     
    119109The fact that there is only one implementation of each polymorphic function also reduces compile times relative to the template-expansion approach taken by \CC{}, as well as reducing binary sizes and runtime pressure on instruction cache by re-using a single version of each function.
    120110
    121 \subsection{Type Assertions}
    122 
    123 Since bare polymorphic types do not provide a great range of available operations, \CFA{} provides a \emph{type assertion} mechanism to provide further information about a type\footnote{This example introduces a convention used throughout this thesis of disambiguating overloaded names with subscripts; the subscripts do not appear in \CFA{} source code.}:
     111\subsubsection{Type Assertions}
     112
     113Since bare polymorphic types do not provide a great range of available operations, \CFA{} provides a \emph{type assertion} mechanism to provide further information about a type:
    124114
    125115\begin{cfa}
    126116forall(otype T `| { T twice(T); }`)
    127117T four_times(T x) { return twice( twice(x) ); }
    128 double twice$\(_1\)$(double d) { return d * 2.0; }
     118double twice(double d) { return d * 2.0; }  $\C[2.75in]{// (1)}$
    129119
    130120double ans = four_times( 10.5 );  $\C[2.75in]{// T bound to double, ans == 42.0}$
     
    139129\begin{cfa}
    140130forall(otype S | { S ?+?(S, S); })
    141 S twice$\(_2\)$(S x) { return x + x; }
    142 \end{cfa}
    143 
    144 Specializing this polymorphic function with !S = double! produces a monomorphic function which can be used to satisfy the type assertion on !four_times!.
    145 \CFACC{} accomplishes this by creating a wrapper function calling !twice!$_2$ with !S! bound to !double!, then providing this wrapper function to !four_times!\footnote{\lstinline{twice}$_2$ could also have had a type parameter named \lstinline{T}; \CFA{} specifies renaming of the type parameters, which would avoid the name conflict with the type variable \lstinline{T} of \lstinline{four_times}}.
    146 However, !twice!$_2$ also works for any type !S! that has an addition operator defined for it.
    147 
    148 Finding appropriate functions to satisfy type assertions is essentially a recursive case of expression resolution, as it takes a name (that of the type assertion) and attempts to match it to a suitable declaration in the current scope\footnote{\CFACC{} actually performs a type-unification computation for assertion satisfaction rather than an expression resolution computation; see Section~\ref{assn-sat-sec} for details.}.
     131S twice(S x) { return x + x; }  $\C[2.75in]{// (2)}
     132\end{cfa}
     133
     134This version of !twice! works for any type !S! that has an addition operator defined for it, and it could be used to satisfy the type assertion on !four_times!.
     135\CFACC{} accomplishes this by creating a wrapper function calling !twice//(2)! with !S! bound to !double!, then providing this wrapper function to !four_times!\footnote{\lstinline{twice // (2)} could also have had a type parameter named \lstinline{T}; \CFA{} specifies renaming of the type parameters, which would avoid the name conflict with the type variable \lstinline{T} of \lstinline{four_times}}.
     136
     137Finding appropriate functions to satisfy type assertions is essentially a recursive case of expression resolution, as it takes a name (that of the type assertion) and attempts to match it to a suitable declaration in the current scope.
    149138If a polymorphic function can be used to satisfy one of its own type assertions, this recursion may not terminate, as it is possible that that function is examined as a candidate for its own assertion unboundedly repeatedly.
    150 To avoid such infinite loops, \CFACC{} imposes a fixed limit on the possible depth of recursion, similar to that employed by most \CC{} compilers for template expansion; this restriction means that there are some otherwise semantically well-typed expressions that cannot be resolved by \CFACC{}.
    151 
    152 \subsection{Traits}
    153 
    154 \CFA{} provides \emph{traits} as a means to name a group of type assertions, as in the example below\footnote{This example uses \CFA{}'s reference types and constructors, described in Section~\ref{type-features-sec}.}:
     139To avoid such infinite loops, \CFACC{} imposes a fixed limit on the possible depth of recursion, similar to that employed by most \CC{} compilers for template expansion; this restriction means that there are some semantically well-typed expressions that cannot be resolved by \CFACC{}.
     140\TODO{Update this with final state} One contribution made in the course of this thesis was modifying \CFACC{} to use the more flexible expression resolution algorithm for assertion matching, rather than the simpler but limited previous approach of unification on the types of the functions.
     141
     142\subsubsection{Deleted Declarations}
     143
     144Particular type combinations can be exempted from matching a given polymorphic function through use of a \emph{deleted function declaration}:
     145
     146\begin{cfa}
     147int somefn(char) = void;
     148\end{cfa}
     149
     150This feature is based on a \CCeleven{} feature typically used to make a type non-copyable by deleting its copy constructor and assignment operator\footnote{In previous versions of \CC{}, a type could be made non-copyable by declaring a private copy constructor and assignment operator, but not defining either. This idiom is well-known, but depends on some rather subtle and \CC{}-specific rules about private members and implicitly-generated functions; the deleted function form is both clearer and less verbose.} or forbidding some interpretations of a polymorphic function by specifically deleting the forbidden overloads\footnote{Specific polymorphic function overloads can also be forbidden in previous \CC{} versions through use of template metaprogramming techniques, though this advanced usage is beyond the skills of many programmers. A similar effect can be produced on an ad-hoc basis at the appropriate call sites through use of casts to determine the function type. In both cases, the deleted-function form is clearer and more concise.}.
     151Deleted function declarations are implemented in \CFACC{} by adding them to the symbol table as usual, but with a flag set that indicates that the function is deleted.
     152If this deleted declaration is selected as the unique minimal-cost interpretation of an expression than an error is produced. \TODO{Check this is implemented at print.}
     153
     154\subsubsection{Traits}
     155
     156\CFA{} provides \emph{traits} as a means to name a group of type assertions, as in the example below\footnote{This example uses \CFA{}'s reference types, constructors, and zero type, described in Section~\ref{type-features-sec}.}:
    155157
    156158\begin{cfa}
     
    169171
    170172Semantically, traits are simply a named list of type assertions, but they may be used for many of the same purposes that interfaces in Java or abstract base classes in \CC{} are used for.
    171 Unlike Java interfaces or \CC{} base classes, \CFA{} types do not explicitly state any inheritance relationship to traits they satisfy; this can be considered a form of structural inheritance, similar to interface implementation in Go, as opposed to the nominal inheritance model of Java and \CC{}.
     173Unlike Java interfaces or \CC{} base classes, \CFA{} types do not explicitly state any inheritance relationship to traits they satisfy; this can be considered a form a structural inheritance, similar to interface implementation in Go, as opposed to the nominal inheritance model of Java and \CC{}.
    172174Nominal inheritance can be simulated in \CFA{} using marker variables in traits:
    173175
     
    184186
    185187Traits, however, are significantly more powerful than nominal-inheritance interfaces; firstly, due to the scoping rules of the declarations that satisfy a trait's type assertions, a type may not satisfy a trait everywhere that that type is declared, as with !char! and the !nominal! trait above.
    186 Secondly, because \CFA{} is not object-oriented and types do not have a closed set of methods, existing C library types can be extended to implement a trait simply by writing the requisite functions\footnote{\CC{} only allows partial extension of C types, because constructors, destructors, conversions, and the assignment, indexing, and function-call operators may only be defined in a class; \CFA{} does not have any of these restrictions.}.
     188Secondly, because \CFA{} is not object-oriented and types do not have a closed set of methods, existing C library types can be extended to implement a trait simply by writing the requisite functions.
    187189Finally, traits may be used to declare a relationship among multiple types, a property that may be difficult or impossible to represent in nominal-inheritance type systems\footnote{This example uses \CFA{}'s reference types, described in Section~\ref{type-features-sec}.}:
    188190
     
    204206\end{cfa}
    205207
    206 In this example above, !(list_iterator, int)! satisfies !pointer_like! by the user-defined dereference function, and !(list_iterator, list)! also satisfies !pointer_like! by the built-in dereference operator for pointers.
     208In the example above, !(list_iterator, int)! satisfies !pointer_like! by the user-defined dereference function, and !(list_iterator, list)! also satisfies !pointer_like! by the built-in dereference operator for pointers.
    207209Given a declaration !list_iterator it!, !*it! can be either an !int! or a !list!, with the meaning disambiguated by context (\eg{} !int x = *it;! interprets !*it! as !int!, while !(*it).value = 42;! interprets !*it! as !list!).
    208 While a nominal-inheritance system with associated types could model one of those two relationships by making !El! an associated type of !Ptr! in the !pointer_like! implementation,
    209 I am unaware of any nominal-inheritance system that can model both relationships simultaneously.
    210 Further comparison of \CFA{} polymorphism with other languages can be found in Section~\ref{generic-related-sec}.
     210While a nominal-inheritance system with associated types could model one of those two relationships by making !El! an associated type of !Ptr! in the !pointer_like! implementation, few such systems could model both relationships simultaneously.
    211211
    212212The flexibility of \CFA{}'s implicit trait-satisfaction mechanism provides programmers with a great deal of power, but also blocks some optimization approaches for expression resolution.
    213 The ability of types to begin or cease to satisfy traits when declarations go into or out of scope makes caching of trait satisfaction judgments difficult, and the ability of traits to take multiple type parameters can lead to a combinatorial explosion of work in any attempt to pre-compute trait satisfaction relationships.
    214 
    215 \subsection{Deleted Declarations}
    216 
    217 Particular type combinations can be exempted from matching a given polymorphic function through the use of a \emph{deleted function declaration}:
    218 
    219 \begin{cfa}
    220 int somefn(char) = void;
    221 \end{cfa}
    222 
    223 This feature is based on a \CCeleven{} feature typically used to make a type non-copyable by deleting its copy constructor and assignment operator\footnote{In previous versions of \CC{}, a type could be made non-copyable by declaring a private copy constructor and assignment operator, but not defining either. This idiom is well-known, but depends on some rather subtle and \CC{}-specific rules about private members and implicitly-generated functions; the deleted function form is both clearer and less verbose.} or forbidding some interpretations of a polymorphic function by specifically deleting the forbidden overloads\footnote{Specific polymorphic function overloads can also be forbidden in previous \CC{} versions through use of template metaprogramming techniques, though this advanced usage is beyond the skills of many programmers.}.
    224 Deleted function declarations are implemented in \CFACC{} by adding them to the symbol table as usual, but with a flag set that indicates that the function is deleted.
    225 If this deleted declaration is selected as the unique minimal-cost interpretation of an expression then an error is produced, allowing \CFA{} programmers to guide the expression resolver away from undesirable solutions.
    226 
    227 \section{Implicit Conversions} \label{implicit-conv-sec}
    228 
    229 In addition to the multiple interpretations of an expression produced by name overloading and polymorphic functions, \CFA{} must support all of the implicit conversions present in C for backward compatibility, producing further candidate interpretations for expressions.
    230 As mentioned above, C does not have an inheritance hierarchy of types, but the C standard's rules for the ``usual arithmetic conversions'' \cite[\S{}6.3.1.8]{C11} define which of the built-in types are implicitly convertible to which other types, as well as which implicit conversions to apply for mixed arguments to binary operators.
     213The ability of types to begin or cease to satisfy traits when declarations go into or out of scope makes caching of trait satisfaction judgements difficult, and the ability of traits to take multiple type parameters can lead to a combinatorial explosion of work in any attempt to pre-compute trait satisfaction relationships.
     214
     215\subsection{Implicit Conversions} \label{implicit-conv-sec}
     216
     217In addition to the multiple interpretations of an expression produced by name overloading and polymorphic functions, for backward compatibility \CFA{} must support all of the implicit conversions present in C, producing further candidate interpretations for expressions.
     218As mentioned above, C does not have an inheritance hierarchy of types, but the C standard's rules for the ``usual arithmetic conversions'\cit{} define which of the built-in types are implicitly convertible to which other types, and the relative cost of any pair of such conversions from a single source type.
    231219\CFA{} adds rules to the usual arithmetic conversions defining the cost of binding a polymorphic type variable in a function call; such bindings are cheaper than any \emph{unsafe} (narrowing) conversion, \eg{} !int! to !char!, but more expensive than any \emph{safe} (widening) conversion, \eg{} !int! to !double!.
    232 One contribution of this thesis, discussed in Section~\ref{conv-cost-sec}, is a number of refinements to this cost model to more efficiently resolve polymorphic function calls.
    233 
    234 In the context of these implicit conversions, the expression resolution problem can be restated as finding the unique minimal-cost interpretation of each expression in the program, where all identifiers must be matched to a declaration, and implicit conversions or polymorphic bindings of the result of an expression may increase the cost of the expression.
    235 While semantically valid \CFA{} code always has such a unique minimal-cost interpretation, \CFACC{} must also be able to detect and report as errors expressions that have either no interpretation or multiple ambiguous minimal-cost interpretations.
     220One contribution of this thesis, discussed in Section \TODO{add to resolution chapter}, is a number of refinements to this cost model to more efficiently resolve polymorphic function calls.
     221
     222The expression resolution problem which is the focus of Chapter~\ref{resolution-chap} is to find the unique minimal-cost interpretation of each expression in the program, where all identifiers must be matched to a declaration, and implicit conversions or polymorphic bindings of the result of an expression may increase the cost of the expression.
     223While semantically valid \CFA{} code always has such a unique minimal-cost interpretation, \CFACC{} must also be able to detect and report as errors expressions which have either no interpretation or multiple ambiguous minimal-cost interpretations.
    236224Note that which subexpression interpretation is minimal-cost may require contextual information to disambiguate.
    237225For instance, in the example in Section~\ref{overloading-sec}, !max(max, -max)! cannot be unambiguously resolved, but !int m = max(max, -max)! has a single minimal-cost resolution.
    238 While the interpretation !int m = (int)max((double)max, -(double)max)! is also a valid interpretation, it is not minimal-cost due to the unsafe cast from the !double! result of !max! to !int!\footnote{The two \lstinline{double} casts function as type ascriptions selecting \lstinline{double max} rather than casts from \lstinline{int max} to \lstinline{double}, and as such are zero-cost. The \lstinline{int} to \lstinline{double} conversion could be forced if desired with two casts: \lstinline{(double)(int)max}}.
     226While the interpretation !int m = (int)max((double)max, -(double)max)! is also a valid interpretation, it is not minimal-cost due to the unsafe cast from the !double! result of !max! to !int!\footnote{The two \lstinline{double} casts function as type ascriptions selecting \lstinline{double max} rather than casts from \lstinline{int max} to \lstinline{double}, and as such are zero-cost.}.
    239227These contextual effects make the expression resolution problem for \CFA{} both theoretically and practically difficult, but the observation driving the work in Chapter~\ref{resolution-chap} is that of the many top-level expressions in a given program, most are straightforward and idiomatic so that programmers writing and maintaining the code can easily understand them; it follows that effective heuristics for common cases can bring down compiler runtime enough that a small proportion of harder-to-resolve expressions does not inordinately increase overall compiler runtime or memory usage.
    240228
    241 \section{Type Features} \label{type-features-sec}
    242 
    243 The name overloading and polymorphism features of \CFA{} have the greatest effect on language design and compiler runtime, but there are a number of other features in the type system that have a smaller effect but are useful for code examples.
     229\subsection{Type Features} \label{type-features-sec}
     230
     231The name overloading and polymorphism features of \CFA{} have the greatest effect on language design and compiler runtime, but there are a number of other features in the type system which have a smaller effect but are useful for code examples.
    244232These features are described here.
    245233
    246 \subsection{Reference Types}
    247 
    248 One of the key ergonomic improvements in \CFA{} is reference types, designed and implemented by Robert Schluntz \cite{Schluntz17}.
     234\subsubsection{Reference Types}
     235
     236One of the key ergonomic improvements in \CFA{} is reference types, designed and implemented by Robert Schluntz\cite{Schluntz17}.
    249237Given some type !T!, a !T&! (``reference to !T!'') is essentially an automatically dereferenced pointer.
    250 These types allow seamless pass-by-reference for function parameters, without the extraneous dereferencing syntax present in C; they also allow easy aliasing of nested values with a similarly convenient syntax.
    251 The addition of reference types also eliminated two syntactic special-cases present in previous versions of \CFA{}.
    252 Consider the a call !a += b! to a compound assignment operator.
    253 The previous declaration for that operator is !lvalue int ?+=?(int*, int)!.
    254 To mutate the left argument, the built-in operators were special-cased to implicitly take the address of that argument, while the special !lvalue! syntax was used to mark the return type of a function as a mutable reference.
    255 With references, this declaration is re-written as !int& ?+=?(int&, int)!.
    256 The reference semantics generalize the implicit address-of on the left argument and allow it to be used in user-declared functions, while also subsuming the (now removed) !lvalue! syntax for function return types.
    257 
    258 The C standard makes heavy use of the concept of \emph{lvalue}, an expression with a memory address; its complement, \emph{rvalue} (a non-addressable expression) is not explicitly named in the standard.
    259 In \CFA{}, the distinction between lvalue and rvalue can be re-framed in terms of reference and non-reference types, with the benefit of being able to express the difference in user code.
    260 \CFA{} references preserve the existing qualifier-dropping implicit lvalue-to-rvalue conversion from C (\eg{} a !const volatile int&! can be implicitly copied to a bare !int!).
    261 To make reference types more easily usable in legacy pass-by-value code, \CFA{} also adds an implicit rvalue-to-lvalue conversion, implemented by storing the value in a compiler-generated temporary variable and passing a reference to that temporary.
    262 To mitigate the ``!const! hell'' problem present in \CC{}, there is also a qualifier-dropping lvalue-to-lvalue conversion implemented by copying into a temporary:
     238These types allow seamless pass-by-reference for function parameters, without the extraneous dereferencing syntax present in C; they also allow easy easy aliasing of nested values with a similarly convenient syntax.
     239A particular improvement is removing syntactic special cases for operators which take or return mutable values; for example, the use !a += b! of a compound assignment operator now matches its signature, !int& ?+=?(int&, int)!, as opposed to the previous syntactic special cases to automatically take the address of the first argument to !+=! and to mark its return value as mutable.
     240
     241The C standard makes heavy use of the concept of \emph{lvalue}, an expression with a memory address; its complement, \emph{rvalue} (a non-addressable expression) is not explicitly named.
     242In \CFA{}, the distinction between lvalue and rvalue can be reframed in terms of reference and non-reference types, with the benefit of being able to express the difference in user code.
     243\CFA{} references preserve the existing qualifier-dropping implicit lvalue-to-rvalue conversion from C (\eg{} a !const volatile int&! can be implicitly copied to a bare !int!)
     244To make reference types more easily usable in legacy pass-by-value code, \CFA{} also adds an implicit rvalue-to-lvalue conversion, implemented by storing the value in a fresh compiler-generated temporary variable and passing a reference to that temporary.
     245To mitigate the ``!const! hell'' problem present in \CC{}, there is also a qualifier-dropping lvalue-to-lvalue conversion, also implemented by copying into a temporary:
    263246
    264247\begin{cfa}
    265248const int magic = 42;
     249
    266250void inc_print( int& x ) { printf("%d\n", ++x); }
    267251
    268 inc_print( magic ); $\C{// legal; implicitly generated code in red below:}$
     252print_inc( magic ); $\C{// legal; implicitly generated code in red below:}$
    269253
    270254`int tmp = magic;` $\C{// to safely strip const-qualifier}$
    271 `inc_print( tmp );` $\C{// tmp is incremented, magic is unchanged}$
     255`print_inc( tmp );` $\C{// tmp is incremented, magic is unchanged}$
    272256\end{cfa}
    273257
     
    275259The primary issue with \CC{} references is that it is impossible to extract the address of the reference variable rather than the address of the referred-to variable.
    276260This breaks a number of the usual compositional properties of the \CC{} type system, \eg{} a reference cannot be re-bound to another variable, nor is it possible to take a pointer to, array of, or reference to a reference.
    277 \CFA{} supports all of these use cases without further added syntax.
     261\CFA{} supports all of these use cases \TODO{test array} without further added syntax.
    278262The key to this syntax-free feature support is an observation made by the author that the address of a reference is a lvalue.
    279 In C, the address-of operator !&x! can only be applied to lvalue expressions, and always produces an immutable rvalue; \CFA{} supports reference re-binding by assignment to the address of a reference\footnote{The syntactic difference between reference initialization and reference assignment is unfortunate, but preserves the ability to pass function arguments by reference (a reference initialization context) without added syntax.}, and pointers to references by repeating the address-of operator:
     263In C, the address-of operator !&x! can only be applied to lvalue expressions, and always produces an immutable rvalue; \CFA{} supports reference re-binding by assignment to the address of a reference, and pointers to references by repeating the address-of operator:
    280264
    281265\begin{cfa}
     
    286270\end{cfa}
    287271
    288 For better compatibility with C, the \CFA{} team has chosen not to differentiate function overloads based on top-level reference types, and as such their contribution to the difficulty of \CFA{} expression resolution is largely restricted to the implementation details of matching reference to non-reference types during type-checking.
    289 
    290 \subsection{Resource Management} \label{ctor-sec}
    291 
    292 \CFA{} also supports the RAII (``Resource Acquisition is Initialization'') idiom originated by \CC{}, thanks to the object lifetime work of Robert Schluntz \cite{Schluntz17}.
     272For better compatibility with C, the \CFA{} team has chosen not to differentiate function overloads based on top-level reference types, and as such their contribution to the difficulty of \CFA{} expression resolution is largely restricted to the implementation details of normalization conversions and adapters.
     273
     274\subsubsection{Resource Management}
     275
     276\CFA{} also supports the RAII (``Resource Acquisition is Initialization'') idiom originated by \CC{}, thanks to the object lifetime work of Robert Schluntz\cite{Schluntz17}.
    293277This idiom allows a safer and more principled approach to resource management by tying acquisition of a resource to object initialization, with the corresponding resource release executed automatically at object finalization.
    294278A wide variety of conceptual resources may be conveniently managed by this scheme, including heap memory, file handles, and software locks.
     
    341325\end{cfa}
    342326
    343 \subsection{Tuple Types}
     327\subsubsection{Tuple Types}
    344328
    345329\CFA{} adds \emph{tuple types} to C, a syntactic facility for referring to lists of values anonymously or with a single identifier.
    346330An identifier may name a tuple, a function may return one, and a tuple may be implicitly \emph{destructured} into its component values.
    347331The implementation of tuples in \CFACC{}'s code generation is based on the generic types introduced in Chapter~\ref{generic-chap}, with one compiler-generated generic type for each tuple arity.
    348 This reuse allows tuples to take advantage of the same runtime optimizations available to generic types, while reducing code bloat.
    349 An extended presentation of the tuple features of \CFA{} can be found in \cite{Moss18}, but the following example demonstrates the basic features:
    350 
    351 \begin{cfa}
    352 [char, char] x$\(_1\)$ = ['!', '?']; $\C{// tuple type and expression syntax}$
    353 int x$\(_2\)$ = 2;
     332This allows tuples to take advantage of the same runtime optimizations available to generic types, while reducing code bloat.
     333An extended presentation of the tuple features of \CFA{} can be found in \cite{Moss18}, but the following example shows the basics:
     334
     335\begin{cfa}
     336[char, char] x = ['!', '?']; $\C{// (1); tuple type and expression syntax}$
     337int x = 2; $\C{// (2)}$
    354338
    355339forall(otype T)
    356 [T, T] swap$\(_1\)$( T a, T b ) {
     340[T, T] swap( T a, T b ) { $\C{// (3)}$
    357341        return [b, a]; $\C{// one-line swap syntax}$
    358342}
    359343
    360 x = swap( x ); $\C{// destructure x\(_1\) into two elements}$
    361 $\C{// cannot use x\(_2\), not enough arguments}$
    362 
    363 void swap$\(_2\)$( int, char, char );
    364 
    365 swap( x, x ); $\C{// swap\(_2\)( x\(_2\), x\(_1\) )}$
    366 $\C{// not swap\(_1\)( x\(_2\), x\(_2\) ) due to polymorphism cost}$
     344x = swap( x ); $\C{// destructure [char, char] x into two elements}$
     345$\C{// cannot use int x, not enough arguments}$
     346
     347void swap( int, char, char ); $\C{// (4)}$
     348
     349swap( x, x ); $\C{// (4) on (2), (1)}$
     350$\C{// not (3) on (2), (2) due to polymorphism cost}$
    367351\end{cfa}
    368352
    369353Tuple destructuring breaks the one-to-one relationship between identifiers and values.
    370 Hence, some argument-parameter matching strategies for expression resolution are precluded, as well as cheap interpretation filters based on comparing number of parameters and arguments.
    371 As an example, in the call to !swap( x, x )! above, the second !x! can be resolved starting at the second or third parameter of !swap!$_2$, depending which interpretation of !x! is chosen for the first argument.
    372 
    373 \section{Conclusion}
    374 
    375 \CFA{} adds a significant number of features to standard C, increasing the expressivity and re-usability of \CFA{} code while maintaining backwards compatibility for both code and larger language paradigms.
    376 This flexibility does incur significant added compilation costs, however, the mitigation of which are the primary concern of this thesis.
     354This precludes some argument-parameter matching strategies for expression resolution, as well as cheap interpretation filters based on comparing number of parameters and arguments.
     355As an example, in the call to !swap( x, x )! above, the second !x! can be resolved starting at the second or third parameter of !swap!, depending which interpretation of !x! was chosen for the first argument.
  • doc/theses/aaron_moss_PhD/phd/conclusion.tex

    r933f32f r6a9d4b4  
    11\chapter{Conclusion}
    22
    3 Decades after its first standardization, the C language remains a widely-used tool and a vital part of the software development landscape.
    4 The \CFA{} language under development at the University of Waterloo represents an evolutionary modernization of C with expressive modern language features paired with strong C backwards-compatibility.
    5 This thesis has contributed to these project goals in a variety of ways, including the addition of a generic-types language feature (Chapter~\ref{generic-chap}) and refinement of the \CFA{} overload selection rules to produce a more expressive and intuitive model (Section~\ref{conv-cost-sec}).
    6 Based on the technical contribution of the resolver prototype system (Section~\ref{rp-features-sec}), I have also made significant improvements to \CFA{} compilation performance, including un-combined bottom-up expression traversal (Section~\ref{arg-parm-matching-sec}), deferred-cached assertion satisfaction (Section~\ref{assn-sat-sec}), and a novel persistent union-find type environment data structure (Section~\ref{env-persistent-union-find}).
    7 The combination of these practical improvements and added features significantly improve the viability of \CFA{} as a practical programming language.
    8 
    9 Further improvements to the \CFA{} type system are still possible, however.
    10 One area suggested by this work is development of a scheme for user-defined conversions; to integrate properly with the \CFA{} conversion model, there would need to be a distinction between safe and unsafe conversions, and possibly a way to denote conversions as explicit-only or non-chainable.
    11 Another place for ongoing effort is improvement of compilation performance; I believe the most promising direction for that effort is rebuilding the \CFA{} compiler on a different framework than Bilson's \CFACC{}.
    12 The resolver prototype presented in this work has good performance and already has the basics of \CFA{} semantics implemented, as well as many of the necessary core data structures, and would be a viable candidate for a new compiler architecture.
    13 An alternate approach would be to fork an existing C compiler such as Clang~\cite{Clang}, which would need to be modified to use one of the resolution algorithms discussed here, as well as various other features introduced by Bilson~\cite{Bilson03}.
    14 
    15 More generally, the algorithmic techniques described in this thesis may be useful to implementors of other programming languages.
    16 In particular, the demonstration of practical performance for polymorphic return-type inference suggests the possibility of eliding return-type-only template parameters in \CC{} function calls, though integrating such an extension into \CC{} expression resolution in a backwards-compatible manner may be challenging.
    17 The \CFA{} expression resolution problem also bears some similarity to the \emph{local type inference} model put forward by Pierce \& Turner \cite{Pierce00} and Odersky \etal{} \cite{Odersky01}; compiler implementors for languages like Scala \cite{Scala}, which performs type inference based on this model, may be able to profitably adapt the algorithms and data structures presented in this thesis.
     3Wrap it up --- Done, done done.
  • doc/theses/aaron_moss_PhD/phd/evaluation/generic-timing.dat

    r933f32f r6a9d4b4  
    88"clear\npair"   2840    773     748     3511
    99"pop\npair"     3025    5414    813     23867
     10
  • doc/theses/aaron_moss_PhD/phd/frontpgs.tex

    r933f32f r6a9d4b4  
    6262        \bigskip
    6363       
    64         \noindent
    65   \begin{tabbing}
    66   Internal-External Member: \=  \kill % using longest text to define tab length
    67   External Examiner: \>  Doug Lea \\
    68   \> Professor, Computer Science Department, \\
    69   \> State University of New York at Oswego \\
    70   \end{tabbing}
    71         \bigskip
     64%       \noindent
     65%   \begin{tabbing}
     66%   Internal-External Member: \=  \kill % using longest text to define tab length
     67%   External Examiner: \>  Bruce Bruce \\
     68%   \> Professor, Dept. of Philosophy of Zoology, University of Wallamaloo \\
     69%   \end{tabbing}
     70%       \bigskip
    7271       
    7372        \noindent
     
    7574  Internal-External Member: \=  \kill % using longest text to define tab length
    7675  Supervisor: \> Peter Buhr \\
    77   \> Associate Professor, School of Computer Science, \\
    78   \> University of Waterloo \\
     76  \> Professor, School of Computer Science, University of Waterloo \\
    7977  \end{tabbing}
    8078        \bigskip
     
    8381  \begin{tabbing}
    8482  Internal-External Member: \=  \kill % using longest text to define tab length
    85   Internal Members: \> Ond\v{r}ej Lhot\a'ak \\
    86   \> Associate Professor, School of Computer Science, \\
    87   \>University of Waterloo \\
    88   \\
    89   \> Gregor Richards \\
    90   \> Assistant Professor, School of Computer Science, \\
    91   \> University of Waterloo \\
     83  Internal Members: \> Gregor Richards \\
     84  \> Professor, School of Computer Science, University of Waterloo \\
     85  \> Ond\v{r}ej Lhot\a'ak \\
     86  \> Professor, School of Computer Science, University of Waterloo \\
    9287  \end{tabbing}
    93         \bigskip
     88%       \bigskip
    9489       
    95         \noindent
    96   \begin{tabbing}
    97   Internal-External Member: \=  \kill % using longest text to define tab length
    98   Internal-External Member: \> Werner Dietl \\
    99   \> Assistant Professor, Electrical and Computer Engineering, \\
    100   \> University of Waterloo \\
    101   \end{tabbing}
    102 %       \bigskip
     90%       \noindent
     91%   \begin{tabbing}
     92%   Internal-External Member: \=  \kill % using longest text to define tab length
     93%   Internal-External Member: \> Deepa Thotta \\
     94%   \> Professor, Dept. of Philosophy, University of Waterloo \\
     95%   \end{tabbing}
     96%       \bigskip
    10397       
    10498%       \noindent
     
    130124\begin{center}\textbf{Abstract}\end{center}
    131125
    132         The C programming language has been an important software development tool for decades.
    133         \CFA{} is a new programming language designed with strong backwards-compatibility to take advantage of widely distributed C programming expertise and the large deployed base of C code, paired with modern language features to improve developer productivity.
    134        
    135         This thesis presents a number of improvements to \CFA{}.
    136         The author has developed one major new language feature, generic types, in a way that integrates naturally with both the existing polymorphism features of \CFA{} and the translation-unit-based encapsulation model of C.
    137         This thesis also presents a number of smaller refinements to the \CFA{} overload resolution rules, each of which improves the expressivity or intuitive nature of the language.
    138        
    139         This thesis also includes a number of practical improvements to \CFA{} compilation performance, focused on the expression resolution pass, which is the main bottleneck.
    140         These include better algorithms for argument-parameter matching and type assertion satisfaction, as well as a new type-environment data-structure based on a novel variant of union-find.
    141         The compilation performance improvements have all been experimentally validated with a new prototype system that encapsulates the key aspects of the \CFA{} language; this prototype is a promising basis for future research and a technical contribution of this work.
    142 
    143         \CFA{}, extended and refined in this thesis, presents both an independently interesting combination of language features and a comprehensive approach to the modernization of C.
    144         This work demonstrates the hitherto unproven compiler-implementation viability of the \CFA{} language design, and provides a number of useful tools to implementors of other languages.
     126This is the abstract.
    145127
    146128\cleardoublepage
     
    149131% -------------------------------
    150132
    151 \begin{center}\textbf{Acknowledgements}\end{center}
     133% \begin{center}\textbf{Acknowledgements}\end{center}
    152134
    153 Though a doctoral thesis is an individual project, I could not have completed it without the help and support of many members of my community.
    154 This thesis would not exist in the form it does without the mentorship of my advisor, Peter Buhr, who has ably led the \CFA{} team while giving me both the advantage of his decades of experience and the freedom to follow my own interests.
    155 
    156 My work on \CFA{} does not exist in a vacuum, and it has been a pleasure and a privilege to collaborate with the members of the \CFA{} team: Andrew Beach, Richard Bilson, Michael Brooks, Bryan Chan, Thierry Delisle, Glen Ditchfield, Brice Dobry, Rob Schluntz, and others.
    157 I gratefully acknowledge the financial support of the National Science and Engineering Council of Canada and Huawei Ltd.\ for this project.
    158 I would also like to thank of my thesis committee, Werner Dietl, Doug Lea, Ond\v{r}ej Lhot\a'ak, and Gregor Richards, for the time and effort they have invested in providing constructive feedback to refine this work.
    159 I am indebted to Peter van Beek and Ian Munro for their algorithmic expertise and willingness to share their time with me.
    160 I have far too many colleagues in the Programming Languages Group and School of Computer Science to name, but I deeply appreciate their camaraderie; specifically with regard to the production of this thesis, I would like to thank Nathan Fish for recommending my writing soundtrack, and Sharon Choy for her unfailing supply of encouraging rabbit animations.
    161 
    162 Finally, to all my friends and family who have supported me and made Kitchener-Waterloo home these past seven years, thank you, I could not have done it without you; most especially, Christina Moss, you are the best of wives and best of women, your support has kept me going through the ups and downs of research, and your partnership is key to all my successes.
    163 
    164 \cleardoublepage
     135% I would like to thank all the little people who made this thesis possible.
     136% \cleardoublepage
    165137
    166138% D E D I C A T I O N
     
    169141% \begin{center}\textbf{Dedication}\end{center}
    170142
    171 % To Christina, who has spent too many hours politely listening to me work out the technical minutiae of this thesis, I love you, and I won't make you read it.
    172 
     143% This is dedicated to the one I love.
    173144% \cleardoublepage
    174145
  • doc/theses/aaron_moss_PhD/phd/generic-types.tex

    r933f32f r6a9d4b4  
    77While this approach is flexible and supports integration with the C type checker and tooling, it is also tedious and error prone, especially for more complex data structures.
    88A second approach is to use !void*!-based polymorphism, \eg{} the C standard library functions !bsearch! and !qsort!, which allow for the reuse of common functionality.
    9 However, basing all polymorphism on !void*! eliminates the type checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that is otherwise unnecessary.
     9However, basing all polymorphism on !void*! eliminates the type checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that is otherwise not needed.
    1010A third approach to generic code is to use preprocessor macros, which does allow the generated code to be both generic and type checked, but errors in such code may be difficult to locate and debug.
    1111Furthermore, writing and using preprocessor macros is unnatural and inflexible.
    12 Figure~\ref{bespoke-generic-fig} demonstrates the bespoke approach for a simple linked list with !insert! and !head! operations, while Figure~\ref{void-generic-fig} and Figure~\ref{macro-generic-fig} show the same example using !void*! and !#define!-based polymorphism, respectively.
     12Figure~\ref{bespoke-generic-fig} demonstrates the bespoke approach for a simple linked list with !insert! and !head! operations, while Figure~\ref{void-generic-fig} and Figure~\ref{macro-generic-fig} show the same example using !void*!- and !#define!-based polymorphism, respectively.
    1313
    1414\begin{figure}
    1515        \begin{cfa}
    16                 #include <stdlib.h> $\C{// for malloc}$
    17                 #include <stdio.h>  $\C{// for printf}$
    18 
    1916                struct int_list { int value; struct int_list* next; };
    2017
     
    2724                int int_list_head( const struct int_list* ls ) { return ls->value; }
    2825
    29                 // all code must be duplicated for every generic instantiation
     26                $\C[\textwidth]{// all code must be duplicated for every generic instantiation}$
    3027
    3128                struct string_list { const char* value; struct string_list* next; };
     
    4037                        { return ls->value; }
    4138
    42                 // use is efficient and idiomatic
     39                $\C[\textwidth]{// use is efficient and idiomatic}$
    4340
    4441                int main() {
     
    5855\begin{figure}
    5956        \begin{cfa}
    60                 #include <stdlib.h> $\C{// for malloc}$
    61                 #include <stdio.h>  $\C{// for printf}$
    62 
    6357                // single code implementation
    6458
    6559                struct list { void* value; struct list* next; };
    6660
    67                 // internal memory management requires helper functions
     61                $\C[\textwidth]{// internal memory management requires helper functions}$
    6862
    6963                void list_insert( struct list** ls, void* x, void* (*copy)(void*) ) {
     
    7569                void* list_head( const struct list* ls ) { return ls->value; }
    7670
    77                 // helpers duplicated per type
     71                $\C[\textwidth]{// helpers duplicated per type}$
    7872
    7973                void* int_copy(void* x) {
     
    10296\begin{figure}
    10397        \begin{cfa}
    104                 #include <stdlib.h> $\C{// for malloc}$
    105                 #include <stdio.h>  $\C{// for printf}$
    106 
    107                 // code is nested in macros
     98                $\C[\textwidth]{// code is nested in macros}$
    10899
    109100                #define list(N) N ## _list
     
    127118                define_list(string, const char*); $\C[3in]{// defines string\_list}$
    128119
    129                 // use is efficient, but syntactically idiosyncratic
     120                $\C[\textwidth]{// use is efficient, but syntactically idiosyncratic}$
    130121
    131122                int main() {
     
    143134\end{figure}
    144135
    145 \CC{}, Java, and other languages use \emph{generic types} (or \emph{parameterized types}) to produce type-safe abstract data types.
    146 Design and implementation of generic types for \CFA{} is the first major contribution of this thesis, a summary of which is published in \cite{Moss18} and on which this chapter is closely based.
     136\CC{}, Java, and other languages use \emph{generic types} to produce type-safe abstract data types.
     137Design and implementation of generic types for \CFA{} is the first major contribution of this thesis, a summary of which is published in \cite{Moss18} and from which this chapter is closely based.
    147138\CFA{} generic types integrate efficiently and naturally with the existing polymorphic functions in \CFA{}, while retaining backward compatibility with C in layout and support for separate compilation.
    148139A generic type can be declared in \CFA{} by placing a !forall! specifier on a !struct! or !union! declaration, and instantiated using a parenthesized list of types after the generic name.
    149 An example comparable to the C polymorphism examples in Figures~\ref{bespoke-generic-fig}, \ref{void-generic-fig}, and \ref{macro-generic-fig} can be seen in Figure~\ref{cfa-generic-fig}.
     140An example comparable to the C polymorphism examples in Figures~\ref{bespoke-generic-fig}, \ref{void-generic-fig}, and \ref{macro-generic-fig} can be seen in Figure~\ref{cfa-generic-fig} \TODO{test this code}.
    150141
    151142\begin{figure}
    152143        \begin{cfa}
    153                 #include <stdlib.hfa> $\C{// for alloc}$
    154                 #include <stdio.h>  $\C{// for printf}$
    155 
    156144                forall(otype T) struct list { T value; list(T)* next; };
    157145
    158                 // single polymorphic implementation of each function
    159                 // overloading reduces need for namespace prefixes
     146                $\C[\textwidth]{// single polymorphic implementation of each function}$
     147                $\C[\textwidth]{// overloading reduces need for namespace prefixes}$
    160148
    161149                forall(otype T) void insert( list(T)** ls, T x ) {
     
    167155                forall(otype T) T head( const list(T)* ls ) { return ls->value; }
    168156
    169                 // use is clear and efficient
     157                $\C[\textwidth]{// use is clear and efficient}$
    170158
    171159                int main() {
     
    185173\section{Design}
    186174
    187 Though a number of languages have some implementation of generic types, backward compatibility with both C and existing \CFA{} polymorphism present some unique design constraints for \CFA{} generics.
    188 The guiding principle is to maintain an unsurprising language model for C programmers without compromising runtime efficiency.
    189 A key insight for this design is that C already possesses a handful of built-in generic types (\emph{derived types} in the language of the standard \cite[\S{}6.2.5]{C11}), notably pointer (!T*!) and array (!T[]!), and that user-definable generics should act similarly.
    190 
    191 \subsection{Related Work} \label{generic-related-sec}
    192 
    193 One approach to the design of generic types is that taken by \CC{} templates \cite{C++}.
     175Though a number of languages have some implementation of generic types, backward compatibility with both C and existing \CFA{} polymorphism presented some unique design constraints for this project.
     176The guiding principle was to maintain an unsurprising language model for C programmers without compromising runtime efficiency.
     177A key insight for this design was that C already possesses a handful of built-in generic types (\emph{compound types} in the language of the standard\cit{}), notably pointer (!T*!) and array (!T[]!), and that user-definable generics should act similarly.
     178
     179\subsection{Related Work}
     180
     181One approach to the design of generic types is that taken by \CC{} templates\cite{C++}.
    194182The template approach is closely related to the macro-expansion approach to C polymorphism demonstrated in Figure~\ref{macro-generic-fig}, but where the macro-expansion syntax has been given first-class language support.
    195183Template expansion has the benefit of generating code with near-optimal runtime efficiency, as distinct optimizations can be applied for each instantiation of the template.
    196 On the other hand, template expansion can also lead to significant code bloat, exponential in the worst case \cite{Haberman16}, and the costs of increased compilation time and instruction cache pressure cannot be ignored.
     184On the other hand, template expansion can also lead to significant code bloat, exponential in the worst case\cit{}, and the costs of increased instruction cache pressure at runtime and wasted developer time when compiling cannot be discounted.
    197185The most significant restriction of the \CC{} template model is that it breaks separate compilation and C's translation-unit-based encapsulation mechanisms.
    198 Because a \CC{} template is not actually code, but rather a ``recipe'' to generate code, template code must be visible at its call site to be used.
    199 Furthermore, \CC{} template code cannot be type-checked without instantiating it, a time consuming process with no hope of improvement until \CC{} concepts \cite{C++Concepts} are standardized in \CCtwenty{}.
    200 C code, by contrast, only needs a function declaration to call that function or a !struct! declaration to use (by-pointer) values of that type, desirable properties to maintain in \CFA{}.
    201 
    202 Java \cite{Java8} has another prominent implementation for generic types, introduced in Java~5 and based on a significantly different approach than \CC{}.
     186Because a \CC{} template is not actually code, but rather a sort of ``recipe'' to generate code, template code must be visible at its call site to be used.
     187Furthermore, \CC{} template code cannot be type-checked without instantiating it, a time consuming process with no hope of improvement until \CC{} concepts\cite{C++Concepts} are standardized in \CCtwenty{}.
     188C code, by contrast, only needs a !struct! or function declaration to call that function or use (by-pointer) values of that type, a desirable property to maintain for \CFA{}.
     189
     190Java\cite{Java8} has another prominent implementation for generic types, introduced in Java~5 and based on a significantly different approach than \CC{}.
    203191The Java approach has much more in common with the !void*!-polymorphism shown in Figure~\ref{void-generic-fig}; since in Java nearly all data is stored by reference, the Java approach to polymorphic data is to store pointers to arbitrary data and insert type-checked implicit casts at compile-time.
    204 This process of \emph{type erasure} has the benefit of allowing a single instantiation of polymorphic code, but relies heavily on Java's object model.
     192This process of \emph{type erasure} has the benefit of allowing a single instantiation of polymorphic code, but relies heavily on Java's object model and garbage collector.
    205193To use this model, a more C-like language such as \CFA{} would be required to dynamically allocate internal storage for variables, track their lifetime, and properly clean them up afterward.
    206194
    207 Cyclone \cite{Grossman06} extends C and also provides capabilities for polymorphic functions and existential types which are similar to \CFA{}'s !forall! functions and generic types.
     195Cyclone\cite{Grossman06} is another language extending C, and also provides capabilities for polymorphic functions and existential types, similar to \CFA{}'s !forall! functions and generic types.
    208196Cyclone existential types can include function pointers in a construct similar to a virtual function table, but these pointers must be explicitly initialized at some point in the code, which is tedious and error-prone compared to \CFA{}'s implicit assertion satisfaction.
    209197Furthermore, Cyclone's polymorphic functions and types are restricted to abstraction over types with the same layout and calling convention as !void*!, \ie{} only pointer types and !int!.
     
    212200
    213201Many other languages include some form of generic types.
    214 As a brief survey, ML \cite{ML} was the first language to support parametric polymorphism, but unlike \CFA{} does not support the use of assertions and traits to constrain type arguments.
    215 Haskell \cite{Haskell10} combines ML-style polymorphism with the notion of type classes, similar to \CFA{} traits, but requiring an explicit association with their implementing types, unlike \CFA{}.
    216 Objective-C \cite{obj-c-book} is an extension to C which has had some industrial success; however, it did not support type-checked generics until recently \cite{xcode7}, and its garbage-collected, message-passing object-oriented model is a radical departure from C.
    217 Go \cite{Go}, and Rust \cite{Rust} are modern compiled languages with abstraction features similar to \CFA{} traits: \emph{interfaces} in Go and \emph{traits} in Rust.
    218 Go has implicit interface implementation and uses a ``fat pointer'' construct to pass polymorphic objects to functions, similar in principle to \CFA{}'s implicit forall parameters.
     202As a brief survey, ML\cite{ML} was the first language to support parameteric polymorphism, but unlike \CFA{} does not support the use of assertions and traits to constrain type arguments.
     203Haskell\cite{Haskell10} combines ML-style polymorphism with the notion of type classes, similar to \CFA{} traits, but requiring an explicit association with their implementing types, unlike \CFA{}.
     204Objective-C\cite{obj-c-book} is an extension to C which has had some industrial success; however, it did not support type-checked generics until recently\cite{xcode7}, and it's garbage-collected, message-passing object-oriented model is a radical departure from C.
     205Go\cite{Go}, and Rust\cite{Rust} are modern compiled languages with abstraction features similar to \CFA{} traits, \emph{interfaces} in Go and \emph{traits} in Rust.
     206Go has implicit interface implementation and uses a ``fat pointer'' construct to pass polymorphic objects to functions, similar in principle to \CFA{}'s implicit forall paramters.
    219207Go does not, however, allow user code to define generic types, restricting Go programmers to the small set of generic types defined by the compiler.
    220 Rust has powerful abstractions for generic programming, including explicit implementation of traits and options for both separately-compiled virtual dispatch and template-instantiated static dispatch in functions.
     208Rust has powerful abstractions for generic programming, including explicit implemenation of traits and options for both separately-compiled virtual dispatch and template-instantiated static dispatch in functions.
    221209On the other hand, the safety guarantees of Rust's \emph{lifetime} abstraction and borrow checker impose a distinctly idiosyncratic programming style and steep learning curve; \CFA{}, with its more modest safety features, allows direct ports of C code while maintaining the idiomatic style of the original source.
    222210
    223211\subsection{\CFA{} Generics}
    224212
    225 The generic types design in \CFA{} draws inspiration from both \CC{} and Java generics, capturing useful aspects of each.
    226 Like \CC{} template types, generic !struct! and !union! types in \CFA{} have macro-expanded storage layouts, but, like Java generics, \CFA{} generic types can be used with separately-compiled polymorphic functions without requiring either the type or function definition to be visible to the other.
     213The generic types design in \CFA{} draws inspiration from both \CC{} and Java generics, capturing the better aspects of each.
     214Like \CC{} template types, generic !struct!s and !union!s in \CFA{} have macro-expanded storage layouts, but, like Java generics, \CFA{} generic types can be used with separately-compiled polymorphic functions without requiring either the type or function definition to be visible to the other.
    227215The fact that the storage layout of any instantiation of a \CFA{} generic type is identical to that of the monomorphic type produced by simple macro replacement of the generic type parameters is important to provide consistent and predictable runtime performance, and to not impose any undue abstraction penalty on generic code.
    228 As an example, consider the following generic type and function:
    229 
    230 % TODO whatever the bug is with initializer-expressions not working, it affects this
     216As an example, consider the following generic type and function \TODO{test this}:
     217
    231218\begin{cfa}
    232219forall( otype R, otype S ) struct pair { R first; S second; };
    233220
    234221pair(const char*, int) with_len( const char* s ) {
    235         return (pair(const char*, int)){ s, strlen(s) };
     222        return (pair(const char*), int){ s, strlen(s) };
    236223}
    237224\end{cfa}
    238225
    239226In this example, !with_len! is defined at the same scope as !pair!, but it could be called from any context that can see the definition of !pair! and a declaration of !with_len!.
    240 If its return type were !pair(const char*, int)*!, callers of !with_len! would only need the declaration !forall(otype R, otype S) struct pair! to call it, in accordance with the usual C rules for opaque types.
    241 
    242 !with_len! is itself a monomorphic function, returning a type that is structurally identical to !struct { const char* first; int second; }!, and as such could be called from C given appropriate re-declarations and demangling flags.
    243 However, the definition of !with_len! depends on a polymorphic function call to the !pair! constructor, which only needs to be written once (in this case, implicitly by the compiler according to the usual \CFA{} constructor generation \cite{Schluntz17}) and can be re-used for a wide variety of !pair! instantiations.
    244 Since the parameters to this polymorphic constructor call are all statically known, compiler inlining can in principle eliminate any runtime overhead of this polymorphic call.
     227If its return type was !pair(const char*, int)*!, callers of !with_len! would only need the declaration !forall(otype R, otype S) struct pair! to call it, in accordance with the usual C rules for opaque types.
     228
     229!with_len! is itself a monomorphic function, returning a type that is structurally identical to !struct { const char* first; int second; }!, and as such could be called from C given an appropriate redeclaration and demangling flags.
     230However, the definition of !with_len! depends on a polymorphic function call to the !pair! constructor, which only needs to be written once (in this case, implicitly by the compiler according to the usual \CFA{} constructor generation\cite{Moss18}) and can be re-used for a wide variety of !pair! instantiations.
     231Since the parameters to this polymorphic constructor call are all statically known, compiler inlining can eliminate any runtime overhead of this polymorphic call.
    245232
    246233\CFA{} deliberately does not support \CC{}-style partial specializations of generic types.
    247 A particularly infamous example in the \CC{} standard library is !vector<bool>!, which is represented as a bit-string rather than the array representation of the other !vector! instantiations.
     234A particularly infamous example in the \CC{} standard library is !vector<bool>!, which is represented as a bitstring rather than the array representation of the other !vector! instantiations.
    248235Complications from this inconsistency (chiefly the fact that a single bit is not addressable, unlike an array element) make the \CC{} !vector! unpleasant to use in generic contexts due to the break in its public interface.
    249 Rather than attempting to plug leaks in the template specialization abstraction with a detailed method interface, \CFA{} takes the more consistent position that two types with an unrelated data layout are in fact unrelated types, and should be handled with different code.
    250 Of course, to the degree that distinct types are similar enough to share an interface, the \CFA{} !trait! system allows such an interface to be defined, and objects of types implementing that !trait! to be operated on using the same polymorphic functions.
     236Rather than attempting to plug leaks in the template specialization abstraction with a detailed method interface, \CFA{} takes the more principled position that two types with an unrelated data layout are in fact unrelated types, and should be handled with different code.
     237Of course, to the degree that distinct types are similar enough to share an interface, the \CFA{} !trait! system allows one to be defined, and objects of types implementing that !trait! to be operated on in the same polymorphic functions.
    251238
    252239Since \CFA{} polymorphic functions can operate over polymorphic generic types, functions over such types can be partially or completely specialized using the usual overload selection rules.
    253 As an example, the following generalization of !with_len! is a semantically-equivalent function which works for any type that has a !len! function declared, making use of both the ad-hoc (overloading) and parametric (!forall!) polymorphism features of \CFA{}:
     240As an example, the !with_len! function above could be an optimization of the following more general function:
    254241
    255242\begin{cfa}
     
    260247\end{cfa}
    261248
    262 \CFA{} generic types also support type constraints, as in !forall! functions.
     249\CFA{} generic types also support the type constraints from !forall! functions.
    263250For example, the following declaration of a sorted set type ensures that the set key implements equality and relational comparison:
    264251
     
    267254\end{cfa}
    268255
    269 These constraints are enforced by applying equivalent constraints to the compiler-generated constructors for this type.
     256These constraints are implemented by applying equivalent constraints to the compiler-generated constructors for this type.
    270257
    271258\section{Implementation} \label{generic-impl-sec}
    272259
    273 The ability to use generic types in polymorphic contexts means that the \CFA{} implementation must support a mechanism for accessing fields of generic types dynamically.
    274 While \CFACC{} could in principle use this same mechanism for accessing fields of generic types in monomorphic contexts as well, such an approach would throw away compiler knowledge of static types and impose an unnecessary runtime cost.
    275 Instead, my design for generic types in \CFACC{} distinguishes between \emph{concrete} generic types that have a fixed memory layout regardless of type parameters and \emph{dynamic} generic types that may vary in memory layout depending on their type parameters.
    276 
     260The ability to use generic types in polymorphic contexts means that the \CFA{} implementation in \CFACC{} must support a mechanism for accessing fields of generic types dynamically at runtime.
     261While \CFACC{} could in principle use this same mechanism for accessing fields of all generic types, such an approach would throw away compiler knowledge of static types and impose an unnecessary runtime cost, limiting the utility of the generic type design.
     262Instead, my design for generic type support in \CFACC{} distinguishes between \emph{concrete} generic types that have a fixed memory layout regardless of type parameters and \emph{dynamic} generic types that may vary in memory layout depending on their type parameters.
    277263A \emph{dtype-static} type has polymorphic parameters but is still concrete.
    278 Polymorphic pointers are an example of dtype-static types; given some type variable !T!, !T! is a polymorphic type, but !T*! has a fixed size and can therefore be represented by a !void*! in code generation.
    279 In particular, generic types where all parameters are un-!sized! (\ie{} they do not conform to the built-in !sized! trait, which is satisfied by all types the compiler knows the size and alignment of) are always concrete, as there is no possibility for their layout to vary based on type parameters of unknown size and alignment.
     264Polymorphic pointers are an example of dtype-static types; given some type variable !T!, T is a polymorphic type, but !T*! has a fixed size and can therefore be represented by a !void*! in code generation.
     265In particular, generic types where all parameters are un-!sized! (\ie{} they do not conform to the built-in !sized! trait because the compiler does not know their size and alignment) are always concrete, as there is no possibility for their layout to vary based on type parameters of unknown size and alignment.
    280266More precisely, a type is concrete if and only if all of its !sized! type parameters are concrete, and a concrete type is dtype-static if any of its type parameters are (possibly recursively) polymorphic.
    281 To illustrate, the following code using the !pair! type from above has each use of !pair! commented with its class:
    282 
    283 % TODO constructor bugs here too
     267To illustrate, the following code using the !pair! type from above \TODO{test this} has each use of !pair! commented with its class:
     268
    284269\begin{cfa}
    285270//dynamic, layout varies based on T
    286 forall(otype T) T value$\(_1\)$( pair(const char*, T) p ) { return p.second; }
     271forall(otype T) T value( pair(const char*, T) p ) { return p.second; }
    287272
    288273// dtype-static, F* and T* are concrete but recursively polymorphic
    289 forall(dtype F, otype T) T value$\(_2\)$( pair(F*, T*) ) { return *p.second; }
     274forall(dtype F, otype T) T value( pair(F*, T*) ) { return *p.second; }
    290275
    291276pair(const char*, int) p = {"magic", 42}; $\C[2.5in]{// concrete}$
    292277int i = value(p);
    293 pair(void*, int*) q = {0, &i}; $\C[2.5in]{// concrete}$
     278pair(void*, int*) q = {0, &p.second}; $\C[2.5in]{// concrete}$
    294279i = value(q);
    295280double d = 1.0;
     
    300285\subsection{Concrete Generic Types}
    301286
    302 The \CFACC{} translator template-expands concrete generic types into new structure types, affording maximal inlining.
     287The \CFACC{} translator template expands concrete generic types into new structure types, affording maximal inlining.
    303288To enable interoperation among equivalent instantiations of a generic type, \CFACC{} saves the set of instantiations currently in scope and reuses the generated structure declarations where appropriate.
    304289In particular, tuple types are implemented as a single compiler-generated generic type definition per tuple arity, and can be instantiated and reused according to the usual rules for generic types.
    305290A function declaration that accepts or returns a concrete generic type produces a declaration for the instantiated structure in the same scope, which all callers may reuse.
    306 As an example, the concrete instantiation for !pair(const char*, int)! is\footnote{Field name mangling for overloading purposes is omitted.\label{mangle-foot}}:
     291As an example, the concrete instantiation for !pair(const char*, int)! is\footnote{This omits the field name mangling performed by \CFACC{} for overloading purposes.\label{mangle-foot}}
    307292
    308293\begin{cfa}
     
    311296
    312297A concrete generic type with dtype-static parameters is also expanded to a structure type, but this type is used for all matching instantiations.
    313 In the example above, the !pair(F*, T*)! parameter to !value! is such a type; its expansion is below\footref{mangle-foot}, and it is used as the type of the variables !q! and !r! as well, with casts for member access where appropriate:
     298In the example above, the !pair(F*, T*)! parameter to !value! is such a type; its expansion is below\footref{mangle-foot}, and it is used as the type of the variables !q! and !r! as well, with casts for member access where appropriate.
    314299
    315300\begin{cfa}
     
    323308The design for generic types presented here adds an \emph{offset array} containing structure-member offsets for dynamic generic !struct! types.
    324309A dynamic generic !union! needs no such offset array, as all members are at offset 0, but size and alignment are still necessary.
    325 Access to members of a dynamic structure is provided at runtime via base-displacement addressing of the structure pointer and the member offset (similar to the !offsetof! macro), moving a compile-time offset calculation to runtime.
    326 
    327 The offset arrays are statically generated where possible.
     310Access to members of a dynamic structure is provided at runtime via base displacement addressing the structure pointer and the member offset (similar to the !offsetof! macro), moving a compile-time offset calculation to runtime.
     311
     312the offset arrays are statically generated where possible.
    328313If a dynamic generic type is passed or returned by value from a polymorphic function, \CFACC{} can safely assume that the generic type is complete (\ie{} has a known layout) at any call site, and the offset array is passed from the caller; if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C !offsetof! macro.
    329 As an example, the body of !value!$_2$ above is implemented as:
     314As an example, the body of the second !value! function above is implemented as
    330315
    331316\begin{cfa}
     
    333318\end{cfa}
    334319
    335 Here, !_assign_T! is passed in as an implicit parameter from !otype T! and takes two !T*! (!void*! in the generated code\footnote{A GCC extension allows arithmetic on \lstinline{void*}, calculated as if \lstinline{sizeof(void) == 1}.}), a destination and a source, and !_retval! is the pointer to a caller-allocated buffer for the return value, the usual \CFA{} method to handle dynamically-sized return types.
    336 !_offsetof_pair! is the offset array passed into !value!; this array is statically generated at the call site as:
     320Here, !_assign_T! is passed in as an implicit parameter from !otype T! and takes two !T*! (!void*! in the generated code), a destination and a source, and !_retval! is the pointer to a caller-allocated buffer for the return value, the usual \CFA{} method to handle dynamically-sized return types.
     321!_offsetof_pair! is the offset array passed into !value!; this array is generated at the call site as
    337322
    338323\begin{cfa}
     
    345330For instance, modularity is generally provided in C by including an opaque forward declaration of a structure and associated accessor and mutator functions in a header file, with the actual implementations in a separately-compiled \texttt{.c} file.
    346331\CFA{} supports this pattern for generic types, implying that the caller of a polymorphic function may not know the actual layout or size of a dynamic generic type and only holds it by pointer.
    347 \CFACC{} automatically generates \emph{layout functions} for cases where the size, alignment, and offset array of a generic struct cannot be passed into a function from that function's caller.
     332\CFACC{} automatically generates \emph{layout functions} for cases where the size, alignment, and offset array of a generic struct cannot be passed into a function from that functions's caller.
    348333These layout functions take as arguments pointers to size and alignment variables and a caller-allocated array of member offsets, as well as the size and alignment of all !sized! parameters to the generic structure.
    349 Un-!sized! parameters are not passed because they are forbidden from being used in a context that affects layout by C's usual rules about incomplete types.
    350 Similarly, the layout function can only safely be called from a context where the generic type definition is visible, because otherwise the caller does not know how large to allocate the array of member offsets.
    351 
    352 The C standard does not specify a memory layout for structs, but the System V ABI \cite{SysVABI} does; compatibility with this standard is sufficient for \CFA{}'s currently-supported architectures, though future ports may require different layout-function generation algorithms.
     334Un!sized! parameters not passed because they are forbidden from being used in a context that affects layout by C's usual rules about incomplete types.
     335Similarly, the layout function can only safely be called from a context where the generic type definition is visible, because otherwise the caller will not know how large to allocate the array of member offsets.
     336
     337The C standard does not specify a memory layout for structs, but the POSIX ABI for x86\cit{} does; this memory layout is common for C implementations, but is a platform-specific issue for porting \CFA{}.
    353338This algorithm, sketched below in pseudo-\CFA{}, is a straightforward mapping of consecutive fields into the first properly-aligned offset in the !struct! layout; layout functions for !union! types omit the offset array and simply calculate the maximum size and alignment over all union variants.
    354339Since \CFACC{} generates a distinct layout function for each type, constant-folding and loop unrolling are applied.
     
    357342forall(dtype T1, dtype T2, ... | sized(T1) | sized(T2) | ...)
    358343void layout(size_t* size, size_t* align, size_t* offsets) {
     344        // initialize values
    359345        *size = 0; *align = 1;
    360346        // set up members
     
    374360\end{cfa}
    375361
    376 Results of layout-function calls are cached so that they are only computed once per type per function.
    377 Layout functions also allow generic types to be used in a function definition without reflecting them in the function signature, an important implementation-hiding constraint of the design.
     362Results of layout function calls are cached so that they are only computed once per type per function.
     363Layout functions also allow generic types to be used in a function definition without reflecting them in the function signature, an important implemenation-hiding constraint of the design.
    378364For instance, a function that strips duplicate values from an unsorted !list(T)! likely has a reference to the list as its only explicit parameter, but uses some sort of !set(T)! internally to test for duplicate values.
    379365This function could acquire the layout for !set(T)! by calling its layout function, providing as an argument the layout of !T! implicitly passed into that function.
    380366
    381 Whether a type is concrete, dtype-static, or dynamic is decided solely on the basis of the type arguments and !forall! clause type parameters.
    382 This design allows opaque forward declarations of generic types, \eg{} !forall(otype T) struct Box;! like in C, all uses of !Box(T)! can be separately compiled, and callers from other translation units know the proper calling conventions.
    383 In an alternate design, where the definition of a structure type is included in deciding whether a generic type is dynamic or concrete, some further types may be recognized as dtype-static --- \eg{} !Box! could be defined with a body !{ T* p; }!, and would thus not depend on !T! for its layout.
    384 However, the existence of an !otype! parameter !T! means that !Box! \emph{could} depend on !T! for its layout if this definition is not visible, and preserving separate compilation (and the associated C compatibility) is a more important design metric.
     367Whether a type is concrete, dtype-static, or dynamic is decided solely on the basis of the type arguments and !forall! clause type paramters.
     368This design allows opaque forward declarations of generic types, \eg{} !forall(otype T) struct Box;! like in C, all uses of $Box(T)$ can be separately compiled, and callers from other translation units know the proper calling conventions to use.
     369In an alternate design where the definition of a structure type is included in deciding whether a generic type is dynamic or concrete, some further types may be recognized as dtype-static --- \eg{} !Box! could be defined with a body !{ T* p; }!, and would thus not depend on !T! for its layout.
     370However, the existence of an !otype! parameter !T! means that !Box! \emph{could} depend on !T! for its layout if this definition is not visible, and we judged preserving separate compilation (and the associated C compatibility) in the implemented design to be an acceptable trade-off.
    385371
    386372\subsection{Applications of Dtype-static Types} \label{dtype-static-sec}
     
    401387Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \emph{tag structures}.
    402388Sometimes, information is only used for type checking and can be omitted at runtime.
    403 In the example below, !scalar! is a dtype-static type; hence, all uses have a single structure definition containing !unsigned long! and can share the same implementations of common functions, like !?+?!.
     389In the example below, !scalar! is a dtype-static type; hence, all uses have a single structure definition containing !unsigned long! and can share the same implementations of common functions like !?+?!.
    404390These implementations may even be separately compiled, unlike \CC{} template functions.
    405391However, the \CFA{} type checker ensures matching types are used by all calls to !?+?!, preventing nonsensical computations like adding a length to a volume.
     
    422408\section{Performance Experiments} \label{generic-performance-sec}
    423409
    424 To validate the practicality of this generic type design, microbenchmark-based tests were conducted against a number of comparable code designs in C and \CC{}, first published in \cite{Moss18}.
    425 Since these languages are all C-based and compiled with the same compiler backend, maximal-performance benchmarks should show little runtime variance, differing only in length and clarity of source code.
     410To validate the practicality of this generic type design I have conducted microbenchmark-based tests against a number of comparable code designs in C and \CC{}, first published in \cite{Moss18}.
     411Since all these languages are compiled with the same compiler backend and share a subset essentially comprising standard C, maximal-performance benchmarks should show little runtime variance, differing only in length and clarity of source code.
    426412A more illustrative comparison measures the costs of idiomatic usage of each language's features.
    427 The code below shows the \CFA{} benchmark tests for a generic stack based on a singly-linked list; the test suite is equivalent for the other languages, code for which is included in Appendix~\ref{generic-bench-app}.
    428 The experiment uses element types !int! and !pair(short, char)! and pushes $N = 4M$ elements on a generic stack, copies the stack, clears one of the stacks, and finds the maximum value in the other stack.
    429 
    430 \begin{cfa}
    431 #define N 4000000
     413The code below shows the \CFA{} benchmark tests for a generic stack based on a singly-linked list; the test suite is equivalent for the other other languages.
     414The experiment uses element types !int! and !pair(short, char)! and pushes $N = 40M$ elements on a generic stack, copies the stack, clears one of the stacks, and finds the maximum value in the other stack.
     415
     416\begin{cfa}
    432417int main() {
    433418        int max = 0, val = 42;
     
    450435\end{cfa}
    451436
    452 The four versions of the benchmark implemented are C with !void*!-based polymorphism, \CFA{} with parametric polymorphism, \CC{} with templates, and \CC{} using only class inheritance for polymorphism, denoted \CCV{}.
    453 The \CCV{} variant illustrates an alternative object-oriented idiom where all objects inherit from a base !object! class, a language design similar to Java 4; in particular, runtime checks are necessary to safely downcast objects.
     437The four versions of the benchmark implemented are C with !void*!-based polymorphism, \CFA{} with parameteric polymorphism, \CC{} with templates, and \CC{} using only class inheritance for polymorphism, denoted \CCV{}.
     438The \CCV{} variant illustrates an alternative object-oriented idiom where all objects inherit from a base !object! class, mimicking a Java-like interface; in particular, runtime checks are necessary to safely downcast objects.
    454439The most notable difference among the implementations is the memory layout of generic types: \CFA{} and \CC{} inline the stack and pair elements into corresponding list and pair nodes, while C and \CCV{} lack such capability and, instead, must store generic objects via pointers to separately allocated objects.
    455440Note that the C benchmark uses unchecked casts as C has no runtime mechanism to perform such checks, whereas \CFA{} and \CC{} provide type safety statically.
     
    464449\centering
    465450\input{generic-timing}
    466 \caption[Benchmark timing results]{Benchmark timing results (smaller is better)} \label{generic-eval-fig}
     451\caption{Benchmark timing results (smaller is better)} \label{generic-eval-fig}
    467452\end{figure}
    468453
     
    481466
    482467The C and \CCV{} variants are generally the slowest and have the largest memory footprint, due to their less-efficient memory layout and the pointer indirection necessary to implement generic types in those languages; this inefficiency is exacerbated by the second level of generic types in the pair benchmarks.
    483 By contrast, the \CFA{} and \CC{} variants run in noticeably less time for both the integer and pair because of the equivalent storage layout, with the inlined libraries (\ie{} no separate compilation) and greater maturity of the \CC{} compiler contributing to its lead.
     468By contrast, the \CFA{} and \CC{} variants run in roughly equivalent time for both the integer and pair because of the equivalent storage layout, with the inlined libraries (\ie{} no separate compilation) and greater maturity of the \CC{} compiler contributing to its lead.
    484469\CCV{} is slower than C largely due to the cost of runtime type checking of downcasts (implemented with !dynamic_cast!); the outlier for \CFA{}, pop !pair!, results from the complexity of the generated-C polymorphic code.
    485470The gcc compiler is unable to optimize some dead code and condense nested calls; a compiler designed for \CFA{} could more easily perform these optimizations.
    486 Finally, the binary size for \CFA{} is larger because of static linking with the \CFA{} prelude library, which includes function definitions for all the built-in operators.
     471Finally, the binary size for \CFA{} is larger because of static linking with \CFA{} libraries.
    487472
    488473\CFA{} is also competitive in terms of source code size, measured as a proxy for programmer effort.
     
    490475Use of these standard library types has minimal impact on the performance benchmarks, but shrinks the \CFA{} and \CC{} code to 39 and 42 lines, respectively.
    491476The difference between the \CFA{} and \CC{} line counts is primarily declaration duplication to implement separate compilation; a header-only \CFA{} library is similar in length to the \CC{} version.
    492 On the other hand, due to the language shortcomings mentioned at the beginning of the chapter, C does not have a generic collections library in its standard distribution, resulting in frequent re-implementation of such collection types by C programmers.
     477On the other hand, due to the language shortcomings mentioned at the beginning of the chapter, C does not have a generic collections library in its standard distribution, resulting in frequent reimplementation of such collection types by C programmers.
    493478\CCV{} does not use the \CC{} standard template library by construction, and, in fact, includes the definition of !object! and wrapper classes for !char!, !short!, and !int! in its line count, which inflates this count somewhat, as an actual object-oriented language would include these in the standard library.
    494479I justify the given line count by noting that many object-oriented languages do not allow implementing new interfaces on library types without subclassing or wrapper types, which may be similarly verbose.
     
    496481Line count is a fairly rough measure of code complexity; another important factor is how much type information the programmer must specify manually, especially where that information is not type-checked.
    497482Such unchecked type information produces a heavier documentation burden and increased potential for runtime bugs and is much less common in \CFA{} than C, with its manually specified function pointer arguments and format codes, or \CCV{}, with its extensive use of un-type-checked downcasts, \eg{} !object! to !integer! when popping a stack.
    498 To quantify this manual typing, the ``redundant type annotations'' line in Table~\ref{generic-eval-table} counts the number of lines on which the known type of a variable is re-specified, either as a format specifier, explicit downcast, type-specific function, or by name in a !sizeof!, !struct! literal, or !new! expression.
     483To quantify this manual typing, the ``redundant type annotations'' line in Table~\ref{generic-eval-table} counts the number of lines on which the known type of a variable is respecified, either as a format specifier, explicit downcast, type-specific function, or by name in a !sizeof!, !struct! literal, or !new! expression.
    499484The \CC{} benchmark uses two redundant type annotations to create new stack nodes, whereas the C and \CCV{} benchmarks have several such annotations spread throughout their code.
    500485The \CFA{} benchmark is able to eliminate \emph{all} redundant type annotations through use of the return-type polymorphic !alloc! function in the \CFA{} standard library.
     
    502487\section{Future Work}
    503488
    504 The generic types presented here are already sufficiently expressive to implement a variety of useful library types.
     489The generic types design presented here is already sufficiently expressive to implement a variety of useful library types.
    505490However, some other features based on this design could further improve \CFA{}.
    506491
    507492The most pressing addition is the ability to have non-type generic parameters.
    508 C already supports fixed-length array types, \eg{} !int[10]!; these types are essentially generic types with unsigned integer parameters (\ie{} array dimension), and allowing \CFA{} users the capability to build similar types is a requested feature.
    509 % More exotically, the ability to have these non-type parameters depend on dynamic runtime values rather than static compile-time constants opens up interesting opportunities for type-checking problematic code patterns.
    510 % For example, if a collection iterator was parameterized over the pointer to the collection it was drawn from, then a sufficiently powerful static analysis pass could ensure that that iterator was only used for that collection, eliminating one source of hard-to-find bugs.
    511 
    512 The implementation mechanisms behind generic types can also be used to add new features to \CFA{}.
    513 One such potential feature is \emph{field assertions}, an addition to the existing function and variable assertions on polymorphic type variables.
    514 These assertions could be specified using this proposed syntax:
    515 
    516 \begin{cfa}
    517 trait hasXY(dtype T) {
    518         int T.x;  $\C{// T has a field x of type int}$
    519         int T.y;  $\C{// T has a field y of type int}$
    520 };
    521 \end{cfa}
    522 
     493C already supports fixed-length array types, \eg{} !int[10]!; these types are essentially generic types with unsigned integer parameters, and allowing \CFA{} users the capability to build similar types is a requested feature.
     494More exotically, the ability to have these non-type parameters depend on dynamic runtime values rather than static compile-time constants opens up interesting opportunities for type-checking problematic code patterns.
     495For example, if a collection iterator was parameterized over the pointer to the collection it was drawn from, then a sufficiently powerful static analysis pass could ensure that that iterator was only used for that collection, eliminating one source of hard-to-find bugs.
     496
     497The implementation mechanisms behind this generic types design can also be used to add new features to \CFA{}.
     498One such potential feature would be to add \emph{field assertions} to the existing function and variable assertions on polymorphic type variables.
    523499Implementation of these field assertions would be based on the same code that supports member access by dynamic offset calculation for dynamic generic types.
    524500Simulating field access can already be done more flexibly in \CFA{} by declaring a trait containing an accessor function to be called from polymorphic code, but these accessor functions impose some overhead both to write and call, and directly providing field access via an implicit offset parameter would be both more concise and more efficient.
    525 Of course, there are language design trade-offs to such an approach, notably that providing the two similar features of field and function assertions would impose a burden of choice on programmers writing traits, with field assertions more efficient, but function assertions more general; given this open design question a decision on field assertions is deferred until \CFA{} is more mature.
    526 
    527 If field assertions are included in the language, a natural extension would be to provide a structural inheritance mechanism for every !struct! type that simply turns the list of !struct! fields into a list of field assertions, allowing monomorphic functions over that type to be generalized to polymorphic functions over other similar types with added or reordered fields, for example:
    528 
    529 \begin{cfa}
    530 struct point { int x, y; };  $\C{// traitof(point) is equivalent to hasXY above}$
    531 struct coloured_point { int x, y; enum { RED, BLACK } colour };
    532 
    533 // works for both point and coloured_point
    534 forall(dtype T | traitof(point)(T) )
    535 double hypot( T& p ) { return sqrt( p.x*p.x + p.y*p.y ); }
    536 \end{cfa}
    537 
    538 \CFA{} could also support a packed or otherwise size-optimized representation for generic types based on a similar mechanism --- nothing in the use of the offset arrays implies that the field offsets need to be monotonically increasing.
     501Of course, there are language design trade-offs to such an approach, notably that providing the two similar features of field and function assertions would impose a burden of choice on programmers writing traits, with field assertions more efficient, but function assertions more general; given this open design question we have deferred a decision on field assertions until we have more experience using \CFA{}.
     502If field assertions are included in the language, a natural extension would be to provide a structural inheritance mechanism for every !struct! type that simply turns the list of !struct! fields into a list of field assertions, allowing monomorphic functions over that type to be generalized to polymorphic functions over other similar types with added or reordered fields.
     503\CFA{} could also support a packed or otherwise size-optimized representation for generic types based on a similar mechanism --- the layout function would need to be re-written, but nothing in the use of the offset arrays implies that the field offsets need be monotonically increasing.
    539504
    540505With respect to the broader \CFA{} polymorphism design, the experimental results in Section~\ref{generic-performance-sec} demonstrate that though the runtime impact of \CFA{}'s dynamic virtual dispatch is low, it is not as low as the static dispatch of \CC{} template inlining.
    541 However, rather than subject all \CFA{} users to the compile-time costs of ubiquitous template expansion, it is better to target performance-sensitive code more precisely.
    542 Two promising approaches are an !inline! annotation at polymorphic function call sites to create a template specialization of the function (provided the code is visible) or placing a different !inline! annotation on polymorphic function definitions to instantiate a specialized version of the function for some set of types.
    543 These approaches are complementary and allow performance optimizations to be applied only when necessary, without suffering global code bloat.
     506However, rather than subject all \CFA{} users to the compile-time costs of ubiquitous template expansion, we are considering more targeted mechanisms for performance-sensitive code.
     507Two promising approaches are are an !inline! annotation at polymorphic function call sites to create a template specialization of the function (provided the code is visible) or placing a different !inline! annotation on polymorphic function definitions to instantiate a specialized version of the function for some set of types.
     508These approaches are not mutually exclusive and allow performance optimizations to be applied only when necessary, without suffering global code bloat.
     509In general, the \CFA{} team believes that separate compilation works well with loaded hardware caches by producing smaller code, which may offset the benefit of larger inlined code.
  • doc/theses/aaron_moss_PhD/phd/introduction.tex

    r933f32f r6a9d4b4  
    11\chapter{Introduction}
    22
    3 The C programming language~\cite{C11} has had a wide-ranging impact on the design of software and programming languages.
    4 In the 30 years since its first standardization, it has consistently been one of the most popular programming languages, with billions of lines of C code still in active use, and tens of thousands of trained programmers producing it. The TIOBE index~\cite{TIOBE} tracks popularity of programming languages over time, and C has never dropped below second place:
     3The C programming language has had a wide-ranging impact on the design of software and programming languages.
     4In the 30 years since its first standardization, it has consistently been one of the most popular programming languages, with millions of lines of C code still in active use, and tens of thousands of trained programmers producing it. The TIOBE index\cite{TIOBE} tracks popularity of programming languages over time, and C has never dropped below second place:
    55
    66\begin{table}[h]
     
    1818\end{table}
    1919
    20 The impact of C on programming language design is also obvious from Table~\ref{tiobe-table}; with the exception of Python, all of the top five languages use C-like syntax and control structures.
    21 \CC{}~\cite{C++} is even a largely backwards-compatible extension of C.
    22 Though its lasting popularity and wide impact on programming language design point to the continued relevance of C, there is also widespread desire of programmers for languages with more expressive power and programmer-friendly features; accommodating both maintenance of legacy C code and development of the software of the future is a difficult task for a single programming language.
     20The impact of C on programming language design is also obvious from Table~\ref{tiobe-table}; with the exception of Python, all of the top five languages use C-like syntax and procedural control structures.
     21\CC{} is even a largely backwards-compatible extension of C, with development dating back nearly as far as C itself.
     22Though its lasting popularity and wide impact on programming language design point to the continued relevance of C, they also highlight the widespread desire of programmers for languages with more expressive power and programmer-friendly features; accommodating both low-impact maintenance of legacy C code and low-effort development of the software of the future is a difficult task for a single programming language.
    2323
    24 \CFA{}\footnote{Pronounced ``C-for-all'', and written \CFA{} or \CFL{}.} is an evolutionary modernization of the C programming language that aims to fulfill both these ends well.
     24\CFA{}\footnote{Pronounced ``C-for-all'', and written \CFA{} or \CFL{}.} is an evolutionary modernization of the C programming language which aims to fulfill both these ends well.
    2525\CFA{} both fixes existing design problems and adds multiple new features to C, including name overloading, user-defined operators, parametric-polymorphic routines, and type constructors and destructors, among others.
    2626The new features make \CFA{} more powerful and expressive than C, while maintaining strong backward-compatibility with both C code and the procedural paradigm expected by C programmers.
    27 Unlike other popular C extensions like \CC{} and Objective-C, \CFA{} adds modern features to C without imposing an object-oriented paradigm to use them.
    28 However, these new features do impose a compile-time cost, particularly in the expression resolver, which must evaluate the typing rules of a significantly more complex type system.
     27However, these new features do impose a compile-time cost, particularly in the expression resolver, which must evaluate the typing rules of a significantly more complex type-system.
    2928
    3029This thesis is focused on making \CFA{} a more powerful and expressive language, both by adding new features to the \CFA{} type system and ensuring that both added and existing features can be efficiently implemented in \CFACC{}, the \CFA{} reference compiler.
    31 Particular contributions of this work include:
    32 \begin{itemize}
    33 \item design and implementation of parametric-polymorphic (``generic'') types in a manner compatible with the existing polymorphism design of \CFA{} (Chapter~\ref{generic-chap}),
    34 \item a new expression resolution algorithm designed to quickly locate the optimal declarations for a \CFA{} expression (Chapter~\ref{resolution-chap}),
    35 \item a type environment data structure based on a novel variant of the union-find algorithm (Chapter~\ref{env-chap}),
    36 \item and as a technical contribution, a prototype system for compiler algorithm development which encapsulates the essential aspects of the \CFA{} type system without incurring the technical debt of the existing system or the friction-inducing necessity of maintaining a working compiler (Chapter~\ref{expr-chap}).
    37 \end{itemize}
     30Particular contributions of this work include design and implementation of
     31parametric-polymorphic (``generic'') types in a manner compatible with the existing polymorphism design of \CFA{} (Chapter~\ref{generic-chap}), a type environment data structure based on a novel variant of the union-find algorithm (Chapter~\ref{env-chap}), and a new expression resolution algorithm designed to quickly locate the optimal declarations for a \CFA{} expression (Chapter~\ref{resolution-chap}).
     32This expression resolution algorithm was designed with the aid of a purpose-built prototype system which encapsulates the essential aspects of the \CFA{} type system without incurring the technical debt of the existing system or the friction-inducing necessity of maintaining a working compiler; the goal of this prototype system was to discover effective heuristics to avoid performing unnecessary work in the process of locating the optimal \CFA{} expression resolution.
    3833
    39 The prototype system, which implements the algorithmic contributions of this thesis, is the first performant type-checker implementation for a \CFA{}-style type system.
    40 As the existence of an efficient compiler is necessary for the practical viability of a programming language, the contributions of this thesis comprise a validation of the \CFA{} language design that was previously lacking.
    41 
    42 Though the direction and experimental validation of this work is fairly narrowly focused on the \CFA{} programming language, the tools used and results obtained should be of interest to a wider compiler and programming language design community.
    43 In particular, with the addition of \emph{concepts} in \CCtwenty{}~\cite{C++Concepts}, conforming \CC{} compilers must support a model of type assertions very similar to that in \CFA{}, and the algorithmic techniques used here may prove useful.
    44 Much of the difficulty of type-checking \CFA{} stems from the language design choice to allow overload selection from the context of a function call based on function return type in addition to the type of the arguments to the call; this feature allows the programmer to specify fewer redundant type annotations on functions that are polymorphic in their return type.
    45 As an example in \CC{}:
    46 \begin{C++}
    47 template<typename T> T* zero() { return new T( 0 ); }
    48 
    49 int* z = zero<int>();  $\C{// must specify int twice}$
    50 \end{C++}
    51 
    52 \CFA{} allows !int* z = zero()!, which elides the second !int!.
    53 While the !auto! keyword in \CCeleven{} supports similar inference in a limited set of contexts (\eg{} !auto z = zero<int>()!), the demonstration of the richer inference in \CFA{} raises possibilities for similar features in future versions of \CC{}.
    54 By contrast to \CC{}, Java~8~\cite{Java8} and Scala~\cite{Scala} use comparably powerful forms of type inference to \CFA{}, so the algorithmic techniques in this thesis may be effective for those languages' compiler implementors.
    55 Type environments are also widely modelled in compiler implementations, particularly for functional languages, though also increasingly commonly for other languages (such as Rust~\cite{Rust}) that perform type inference; the type environment presented here may be useful to those language implementors.
    56 
    57 One area of inquiry that is outside the scope of this thesis is formalization of the \CFA{} type system.
    58 Ditchfield~\cite{Ditchfield92} defined the $F_\omega^\ni$ polymorphic lambda calculus, which is the theoretical basis for the \CFA{} type system.
    59 Ditchfield did not, however, prove any soundness or completeness properties for $F_\omega^\ni$; such proofs remain future work.
    60 A number of formalisms other than $F_\omega^\ni$ could potentially be adapted to model \CFA{}.
    61 One promising candidate is \emph{local type inference} \cite{Pierce00,Odersky01}, which describes similar contextual propagation of type information; another is the polymorphic conformity-based model of the Emerald~\cite{Black90} programming language, which defines a subtyping relation on types that is conceptually similar to \CFA{} traits.
    62 These modelling approaches could potentially be used to extend an existing formal semantics for C such as Cholera \cite{Norrish98}, CompCert \cite{Leroy09}, or Formalin \cite{Krebbers14}.
     34Though the direction and validation of this work was fairly narrowly focused on the \CFA{} programming language, the tools used and results obtained should be of interest to a wider compiler and programming language design community.
     35In particular, with the addition of \emph{concepts} in \CCtwenty{}, conforming \CC{} compilers must support a model of type assertions very similar to that in \CFA{}, and the algorithmic techniques used in the expression resolution algorithm presented here may prove useful.
     36Type environments are also widely modelled in compiler implementations, particularly of functional languages, though also increasingly commonly in other languages (such as Rust) which perform type inference; the type environment presented here may be useful to those language implementers.
  • doc/theses/aaron_moss_PhD/phd/macros.tex

    r933f32f r6a9d4b4  
    1515\newcommand{\Csharp}{C\raisebox{-0.7ex}{\Large$^\sharp$}} % C# symbolic name
    1616
    17 \newcommand{\ie}{\textit{i.e.}\@}
    18 \newcommand{\eg}{\textit{e.g.}\@}
    19 \newcommand{\etc}{\textit{etc.}\@}
    20 \newcommand{\etal}{\textit{et~al.}\@}
    21 \newcommand{\vs}{\textit{vs.}\@}
     17\newcommand{\ie}{\textit{i.e.}}
     18\newcommand{\eg}{\textit{e.g.}}
     19\newcommand{\etc}{\textit{etc.}}
     20\newcommand{\etal}{\textit{et~al.}}
    2221
    2322\newcommand{\myset}[1]{\left\{#1\right\}}
  • doc/theses/aaron_moss_PhD/phd/resolution-heuristics.tex

    r933f32f r6a9d4b4  
    1 \chapter{Resolution Algorithms}
     1\chapter{Resolution Heuristics}
    22\label{resolution-chap}
    33
    4 The main task of the \CFACC{} type-checker is \emph{expression resolution}: determining which declarations the identifiers in each expression correspond to.
    5 Resolution is a straightforward task in C, as no simultaneously-visible declarations share identifiers, but in \CFA{}, the name overloading features discussed in Section~\ref{overloading-sec} generate multiple candidate declarations for each identifier.
    6 A given matching between identifiers and declarations in an expression is an \emph{interpretation}; an interpretation also includes information about polymorphic type bindings and implicit casts to support the \CFA{} features discussed in Sections~\ref{poly-func-sec} and~\ref{implicit-conv-sec}, each of which increase the number of valid candidate interpretations.
    7 To choose among valid interpretations, a \emph{conversion cost} is used to rank interpretations.
    8 This conversion cost is summed over all subexpression interpretations in the interpretation of a top-level expression.
    9 Hence, the expression resolution problem is to find the unique minimal-cost interpretation for an expression, reporting an error if no such unique interpretation exists.
     4The main task of the \CFACC{} type-checker is \emph{expression resolution}, determining which declarations the identifiers in each expression correspond to.
     5Resolution is a straightforward task in C, as each declaration has a unique identifier, but in \CFA{} the name overloading features discussed in Section~\ref{overloading-sec} generate multiple candidate declarations for each identifier.
     6I refer to a given matching between identifiers and declarations in an expression as an \emph{interpretation}; an interpretation also includes information about polymorphic type bindings and implicit casts to support the \CFA{} features discussed in Sections~\ref{poly-func-sec} and~\ref{implicit-conv-sec}, each of which increase the proportion of feasible candidate interpretations.
     7To choose between feasible interpretations, \CFA{} defines a \emph{conversion cost} to rank interpretations; the expression resolution problem is thus to find the unique minimal-cost interpretation for an expression, reporting an error if no such interpretation exists.
    108
    11 \section{Expression Resolution}
     9\section{Conversion Cost}
    1210
    13 The expression resolution pass in \CFACC{} must traverse an input expression, match identifiers to available declarations, rank candidate interpretations according to their conversion cost, and check type assertion satisfaction for these candidates.
    14 Once the set of valid interpretations for the top-level expression is found, the expression resolver selects the unique minimal-cost candidate or reports an error.
    1511
    16 The expression resolution problem in \CFA{} is more difficult than the analogous problems in C or \CC{}.
    17 As mentioned above, the lack of name overloading in C (except for built-in operators) makes its resolution problem substantially easier.
    18 A comparison of the richer type systems in \CFA{} and \CC{} highlights some of the challenges in \CFA{} expression resolution.
    19 The key distinction between \CFA{} and \CC{} resolution is that \CC{} uses a greedy algorithm for selection of candidate functions given their argument interpretations, whereas \CFA{} allows contextual information from superexpressions to influence the choice among candidate functions.
    20 One key use of this contextual information is for type inference of polymorphic return types; \CC{} requires explicit specification of template parameters that only occur in a function's return type, while \CFA{} allows the instantiation of these type parameters to be inferred from context (and in fact does not allow explicit specification of type parameters to a function), as in the following example:
    2112
    22 \begin{cfa}
    23 forall(dtype T) T& deref(T*); $\C{// dereferences pointer}$
    24 forall(otype T) T* def(); $\C{// new heap-allocated default-initialized value}$
     13% Discuss changes to cost model, as promised in Ch. 2
    2514
    26 int& i = deref( def() );
    27 \end{cfa}
    28 
    29 In this example, the \CFA{} compiler infers the type arguments of !deref! and !def! from the !int&! type of !i!; \CC{}, by contrast, requires a type parameter on !def!\footnote{The type parameter of \lstinline{deref} can be inferred from its argument.}, \ie{} !deref( def<int>() )!.
    30 Similarly, while both \CFA{} and \CC{} rank candidate functions based on a cost metric for implicit conversions, \CFA{} allows a suboptimal subexpression interpretation to be selected if it allows a lower-cost overall interpretation, while \CC{} requires that each subexpression interpretation have minimal cost.
    31 Because of this use of contextual information, the \CFA{} expression resolver must consider multiple interpretations of each function argument, while the \CC{} compiler has only a single interpretation for each argument\footnote{With the exception of address-of operations on functions.}.
    32 Additionally, until the introduction of concepts in \CCtwenty{} \cite{C++Concepts}, \CC{} expression resolution has no analogue to \CFA{} assertion satisfaction checking, a further  complication for a \CFA{} compiler.
    33 The precise definition of \CFA{} expression resolution in this section further expands on the challenges of this problem.
    34 
    35 \subsection{Type Unification}
    36 
    37 The polymorphism features of \CFA{} require binding of concrete types to polymorphic type variables.
    38 Briefly, \CFACC{} keeps a mapping from type variables to the concrete types they are bound to as an auxiliary data structure during expression resolution; Chapter~\ref{env-chap} describes this \emph{environment} data structure in more detail.
    39 A \emph{unification} algorithm is used to simultaneously check two types for equivalence with respect to the substitutions in an environment and update that environment.
    40 Essentially, unification recursively traverses the structure of both types, checking them for equivalence, and when it encounters a type variable, it replaces it with the concrete type it is bound to; if the type variable has not yet been bound, the unification algorithm assigns the equivalent type as the bound type of the variable, after performing various consistency checks.
    41 Ditchfield~\cite{Ditchfield92} and Bilson~\cite{Bilson03} describe the semantics of \CFA{} unification in more detail.
    42 
    43 \subsection{Conversion Cost} \label{conv-cost-sec}
    44 
    45 \CFA{}, like C, allows inexact matches between the type of function parameters and function call arguments.
    46 Both languages insert \emph{implicit conversions} in these situations to produce an exact type match, and \CFA{} also uses the relative \emph{cost} of different conversions to select among overloaded function candidates.
    47 C does not have an explicit cost model for implicit conversions, but the ``usual arithmetic conversions'' \cite[\S{}6.3.1.8]{C11} used to decide which arithmetic operators to apply define one implicitly.
    48 The only context in which C has name overloading is the arithmetic operators, and the usual arithmetic conversions define a \emph{common type} for mixed-type arguments to binary arithmetic operators.
    49 Since for backward-compatibility purposes the conversion costs of \CFA{} must produce an equivalent result to these common type rules, it is appropriate to summarize \cite[\S{}6.3.1.8]{C11} here:
    50 
    51 \begin{itemize}
    52 \item If either operand is a floating-point type, the common type is the size of the largest floating-point type. If either operand is !_Complex!, the common type is also \linebreak !_Complex!.
    53 \item If both operands are of integral type, the common type has the same size\footnote{Technically, the C standard defines a notion of \emph{rank} in \cite[\S{}6.3.1.1]{C11}, a distinct value for each \lstinline{signed} and \lstinline{unsigned} pair; integral types of the same size thus may have distinct ranks. For instance, though \lstinline{int} and \lstinline{long} may have the same size, \lstinline{long} always has greater rank. The standard-defined types are declared to have greater rank than any types of the same size added as compiler extensions.} as the larger type.
    54 \item If the operands have opposite signedness, the common type is !signed! if the !signed! operand is strictly larger, or !unsigned! otherwise. If the operands have the same signedness, the common type shares it.
    55 \end{itemize}
    56 
    57 Beginning with the work of Bilson~\cite{Bilson03}, \CFA{} defines a \emph{conversion cost} for each function call in a way that generalizes C's conversion rules.
    58 Loosely defined, the conversion cost counts the implicit conversions utilized by an interpretation.
    59 With more specificity, the cost is a lexicographically-ordered tuple, where each element corresponds to a particular kind of conversion.
    60 In Bilson's design, conversion cost is a 3-tuple, $(unsafe, poly, safe)$, where $unsafe$ is the count of unsafe (narrowing) conversions, $poly$ is the count of polymorphic type bindings, and $safe$ is the sum of the degree of safe (widening) conversions.
    61 Degree of safe conversion is calculated as path weight in a directed graph of safe conversions between types; Bilson's version of this graph is in Figure~\ref{bilson-conv-fig}.
    62 The safe conversion graph is designed such that the common type $c$ of two types $u$ and $v$ is compatible with the C standard definitions from \cite[\S{}6.3.1.8]{C11} and can be calculated as the unique type minimizing the sum of the path weights of $\overrightarrow{uc}$ and $\overrightarrow{vc}$.
    63 The following example lists the cost in the Bilson model of calling each of the following functions with two !int! parameters, where the interpretation with the minimum total cost will be selected:
    64 
    65 \begin{cfa}
    66 void f$\(_1\)$(char, long); $\C{// (1,0,1)}$
    67 void f$\(_2\)$(short, long); $\C{// (1,0,1)}$
    68 forall(otype T) void f$\(_3\)$(T, long); $\C{// (0,1,1)}$
    69 void f$\(_4\)$(long, long); $\C{// (0,0,2)}$
    70 void f$\(_5\)$(int, unsigned long); $\C{// (0,0,2)}$
    71 void f$\(_6\)$(int, long); $\C{// (0,0,1)}$
    72 \end{cfa}
    73 
    74 Note that safe and unsafe conversions are handled differently; \CFA{} counts distance of safe conversions (\eg{} !int! to !long! is cheaper than !int! to !unsigned long!), while only counting the number of unsafe conversions (\eg{} !int! to !char! and !int! to !short! both have unsafe cost 1, as in !f!$_1$ and !f!$_2$ above).
    75 These costs are summed over the parameters in a call; in the example above, the cost of the two !int! to !long! conversions for !f!$_4$ sum equal to the one !int! to !unsigned long! conversion for !f!$_5$.
    76 
    77 \begin{figure}
    78         \centering
    79         \begin{subfigure}[h]{3in}
    80                 \includegraphics{figures/bilson-conv-graph}
    81                 \caption{Bilson} \label{bilson-conv-fig}
    82         \end{subfigure}~\begin{subfigure}[h]{3in}
    83                 \includegraphics{figures/extended-conv-graph}
    84                 \caption{Extended} \label{extended-conv-fig}
    85         \end{subfigure}
    86         % \includegraphics{figures/safe-conv-graph}
    87         \caption[Safe conversion graphs.]{Safe conversion graphs. In both graphs, plain arcs have cost $safe = 1, sign = 0$ while dashed sign-conversion arcs have cost $safe = 1, sign = 1$. As per \cite[\S{}6.3.1.8]{C11}, types promote to types of the same signedness with greater rank, from \lstinline{signed} to \lstinline{unsigned} with the same rank, and from \lstinline{unsigned} to \lstinline{signed} with greater size. The arc from \lstinline{unsigned long} to \lstinline{long long} (highlighted in red in \ref{bilson-conv-fig}) is deliberately omitted in \ref{extended-conv-fig}, as on the presented system \lstinline{sizeof(long) == sizeof(long long)}.}
    88         \label{safe-conv-fig}
    89 \end{figure}
    90 
    91 As part of adding reference types to \CFA{} (see Section~\ref{type-features-sec}), Schluntz added a new $reference$ element to the cost tuple, which counts the number of implicit reference-to-rvalue conversions performed so that candidate interpretations can be distinguished by how closely they match the nesting of reference types; since references are meant to act almost indistinguishably from lvalues, this $reference$ element is the least significant in the lexicographic comparison of cost tuples.
    92 
    93 I also refined the \CFA{} cost model as part of this thesis work.
    94 Bilson's \CFA{} cost model includes the cost of polymorphic type bindings from a function's type assertions in the $poly$ element of the cost tuple; this has the effect of making more-constrained functions more expensive than less-constrained functions, as in the following example, based on differing iterator types:
    95 
    96 \begin{cfa}
    97 forall(dtype T | { T& ++?(T&); }) T& advance$\(_1\)$(T& i, int n);
    98 forall(dtype T | { T& ++?(T&); T& ?+=?(T&, int)}) T& advance$\(_2\)$(T& i, int n);
    99 \end{cfa}
    100 
    101 In resolving a call to !advance!, the binding to the !T&! parameter in the assertions is added to the $poly$ cost in Bilson's model.
    102 However, type assertions actually make a function \emph{less} polymorphic, and as such functions with more type assertions should be preferred in type resolution.
    103 In the example above, if the meaning of !advance! is ``increment !i! !n! times'', !advance!$_1$ requires an !n!-iteration loop, while !advance!$_2$ can be implemented more efficiently with the !?+=?! operator; as such, !advance!$_2$ should be chosen over !advance!$_1$ whenever its added constraint can be satisfied.
    104 Accordingly, a $specialization$ element is now included in the \CFA{} cost tuple, the values of which are always negative.
    105 Each type assertion subtracts 1 from $specialization$, so that more-constrained functions cost less, and thus are chosen over less-constrained functions, all else being equal.
    106 A more sophisticated design would define a partial order over sets of type assertions by set inclusion (\ie{} one function would only cost less than another if it had a strict superset of assertions,  rather than just more total assertions), but I did not judge the added complexity of computing and testing this order to be worth the gain in specificity.
    107 
    108 I also incorporated an unimplemented aspect of Ditchfield's earlier cost model.
    109 In the example below, adapted from \cite[p.89]{Ditchfield92}, Bilson's cost model only distinguished between the first two cases by accounting extra cost for the extra set of !otype! parameters, which, as discussed above, is not a desirable solution:
    110 
    111 \begin{cfa}
    112 forall(otype T, otype U) void f$\(_1\)$(T, U);  $\C[3.125in]{// polymorphic}$
    113 forall(otype T) void f$\(_2\)$(T, T);  $\C[3.125in]{// less polymorphic}$
    114 forall(otype T) void f$\(_3\)$(T, int);  $\C[3.125in]{// even less polymorphic}$
    115 forall(otype T) void f$\(_4\)$(T*, int); $\C[3.125in]{// least polymorphic}$
    116 \end{cfa}
    117 
    118 The new cost model accounts for the fact that functions with more polymorphic variables are less constrained by introducing a $var$ cost element that counts the number of type variables on a candidate function.
    119 In the example above, !f!$_1$ has $var = 2$, while the others have $var = 1$.
    120 
    121 The new cost model also accounts for a nuance unhandled by Ditchfield or Bilson, in that it makes the more specific !f!$_4$ cheaper than the more generic !f!$_3$; !f!$_4$ is presumably somewhat optimized for handling pointers, but the prior \CFA{} cost model could not account for the more specific binding, as it simply counted the number of polymorphic unifications.
    122 In the modified model, each level of constraint on a polymorphic type in the parameter list results in a decrement of the $specialization$ cost element, which is shared with the count of assertions due to their common nature as constraints on polymorphic type bindings.
    123 Thus, all else equal, if both a binding to !T! and a binding to !T*! are available, the model chooses the more specific !T*! binding with $specialization = -1$.
    124 This process is recursive, such that !T**! has $specialization = -2$.
    125 This calculation works similarly for generic types, \eg{} !box(T)! also has specialization cost $-1$.
    126 For multi-argument generic types, the least-specialized polymorphic parameter sets the specialization cost, \eg{} the specialization cost of !pair(T, S*)! is $-1$ (from !T!) rather than $-2$ (from !S!).
    127 Specialization cost is not counted on the return type list; since $specialization$ is a property of the function declaration, a lower specialization cost prioritizes one declaration over another.
    128 User programmers can choose between functions with varying parameter lists by adjusting the arguments, but the same is not true in general of varying return types\footnote{In particular, as described in Section~\ref{expr-cost-sec}, cast expressions take the cheapest valid and convertible interpretation of the argument expression, and expressions are resolved as a cast to \lstinline{void}. As a result of this, including return types in the $specialization$ cost means that a function with return type \lstinline{T*} for some polymorphic type \lstinline{T} would \emph{always} be chosen over a function with the same parameter types returning \lstinline{void}, even for \lstinline{void} contexts, an unacceptably counter-intuitive result.}, so the return types are omitted from the $specialization$ element.
    129 Since both $vars$ and $specialization$ are properties of the declaration rather than any particular interpretation, they are prioritized less than the interpretation-specific conversion costs from Bilson's original 3-tuple.
    130 
    131 A final refinement I have made to the \CFA{} cost model is with regard to choosing among arithmetic conversions.
    132 The C standard \cite[\S{}6.3.1.8]{C11} states that the common type of !int! and !unsigned int! is !unsigned int! and that the common type of !int! and !long! is !long!, but does not provide guidance for making a choice among conversions.
    133 Bilson's \CFACC{} uses conversion costs based off Figure~\ref{bilson-conv-fig}.
    134 However, Bilson's design results in inconsistent and somewhat surprising costs, with conversion to the next-larger same-sign type generally (but not always) double the cost of conversion to the !unsigned! type of the same size.
    135 In the redesign, for consistency with the approach of the usual arithmetic conversions, which select a common type primarily based on size, but secondarily on sign, arcs in the new graph are annotated with whether they represent a sign change, and such sign changes are summed in a new $sign$ cost element that lexicographically succeeds $safe$.
    136 This means that sign conversions are approximately the same cost as widening conversions, but slightly more expensive (as opposed to less expensive in Bilson's graph), so maintaining the same signedness is consistently favoured.
    137 This refined conversion graph is shown in Figure~\ref{extended-conv-fig}.
    138 
    139 With these modifications, the current \CFA{} cost tuple is as follows:
    140 
    141 \begin{equation*}
    142         (unsafe, poly, safe, sign, vars, specialization, reference)
    143 \end{equation*}
    144 
    145 \subsection{Expression Cost} \label{expr-cost-sec}
    146 
    147 The mapping from \CFA{} expressions to cost tuples is described by Bilson in \cite{Bilson03}, and remains effectively unchanged with the exception of the refinements to the cost tuple described above.
    148 Nonetheless, some salient details are repeated here for the sake of completeness.
    149 
    150 On a theoretical level, the resolver treats most expressions as if they were function calls.
    151 Operators in \CFA{} (both those existing in C and added features like constructors) are all modelled as function calls.
    152 In terms of the core argument-parameter matching algorithm, overloaded variables are handled the same as zero-argument function calls, aside from a different pool of candidate declarations and setup for different code generation.
    153 Similarly, an aggregate member expression !a.m! can be modelled as a unary function !m! that takes one argument of the aggregate type.
    154 Literals do not require sophisticated resolution, as in C the syntactic form of each implies their result types: !42! is !int!, !"hello"! is !char*!, \etc{}\footnote{Struct literals (\eg{} \lstinline|(S)\{ 1, 2, 3 \}| for some struct \lstinline{S}) are a somewhat special case, as they are known to be of type \lstinline{S}, but require resolution of the implied constructor call described in Section~\ref{ctor-sec}.}.
    155 
    156 Since most expressions can be treated as function calls, nested function calls are the primary component of complexity in expression resolution.
    157 Each function call has an \emph{identifier} that must match the name of the corresponding declaration, and a possibly-empty list of \emph{arguments}.
    158 These arguments may be function call expressions themselves, producing a tree of function-call expressions to resolve, where the leaf expressions are generally nullary functions, variable expressions, or literals.
    159 A single instance of expression resolution consists of matching declarations to all the identifiers in the expression tree of a top-level expression, along with inserting any conversions and satisfying all assertions necessary for that matching.
    160 The cost of a function-call expression is the sum of the conversion costs of each argument type to the corresponding parameter and the total cost of each subexpression, recursively calculated.
    161 \CFA{} expression resolution must produce either the unique lowest-cost interpretation of the top-level expression, or an appropriate error message if none exists.
    162 The cost model of \CFA{} precludes a greedy bottom-up resolution pass, as constraints and costs introduced by calls higher in the expression tree can change the interpretation of those lower in the tree, as in the following example:
    163 
    164 \begin{cfa}
    165 void f(int);
    166 double g$\(_1\)$(int);
    167 int g$\(_2\)$(long);
    168 
    169 f( g(42) );
    170 \end{cfa}
    171 
    172 Considered independently, !g!$_1$!(42)! is the cheapest interpretation of !g(42)!, with cost $(0,0,0,0,0,0,0)$ since the argument type is an exact match.
    173 However, in context, an unsafe conversion is required to downcast the return type of !g!$_1$ to an !int! suitable for !f!, for a total cost of $(1,0,0,0,0,0,0)$ for !f( g!$_1$!(42) )!.
    174 If !g!$_2$ is chosen, on the other hand, there is a safe upcast from the !int! type of !42! to !long!, but no cast on the return of !g!$_2$, for a total cost of $(0,0,1,0,0,0,0)$ for !f( g!$_2$!(42) )!; as this is cheaper, !g!$_2$ is chosen.
    175 Due to this design, all valid interpretations of subexpressions must in general be propagated to the top of the expression tree before any can be eliminated, a lazy form of expression resolution, as opposed to the eager expression resolution allowed by C or \CC{}, where each expression can be resolved given only the resolution of its immediate subexpressions.
    176 
    177 If there are no valid interpretations of the top-level expression, expression resolution fails and must produce an appropriate error message.
    178 If any subexpression has no valid interpretations, the process can be short-circuited and the error produced at that time.
    179 If there are multiple valid interpretations of a top-level expression, ties are broken based on the conversion cost, calculated as above.
    180 If there are multiple minimal-cost valid interpretations of a top-level expression, that expression is said to be \emph{ambiguous}, and an error must be produced.
    181 Multiple minimal-cost interpretations of a subexpression do not necessarily imply an ambiguous top-level expression, however, as the subexpression interpretations may be disambiguated based on their return type or by selecting a more-expensive interpretation of that subexpression to reduce the overall expression cost, as in the example above.
    182 
    183 The \CFA{} resolver uses type assertions to filter out otherwise-valid subexpression interpretations.
    184 An interpretation can only be selected if all the type assertions in the !forall! clause on the corresponding declaration can be satisfied with a unique minimal-cost set of satisfying declarations.
    185 Type assertion satisfaction is tested by performing type unification on the type of the assertion and the type of the declaration satisfying the assertion.
    186 That is, a declaration that satisfies a type assertion must have the same name and type as the assertion after applying the substitutions in the type environment.
    187 Assertion-satisfying declarations may be polymorphic functions with assertions of their own that must be satisfied recursively.
    188 This recursive assertion satisfaction has the potential to introduce infinite loops into the type resolution algorithm, a situation which \CFACC{} avoids by imposing a hard limit on the depth of recursive assertion satisfaction (currently 4); this approach is also taken by \CC{} to prevent infinite recursion in template expansion, and has proven to be effective and not unduly restrictive of the expressive power of \CFA{}.
    189 
    190 Cast expressions must be treated somewhat differently than functions for backwards compatibility purposes with C.
    191 In C, cast expressions can serve two purposes, \emph{conversion} (\eg{} !(int)3.14!), which semantically converts a value to another value in a different type with a different bit representation, or \emph{coercion} (\eg{} !void* p; (int*)p;!), which assigns a different type to the same bit value.
    192 C provides a set of built-in conversions and coercions, and user programmers are able to force a coercion over a conversion if desired by casting pointers.
    193 The overloading features in \CFA{} introduce a third cast semantic, \emph{ascription} (\eg{} !int x; double x; (int)x;!), which selects the overload that most-closely matches the cast type.
    194 However, since ascription does not exist in C due to the lack of overloadable identifiers, if a cast argument has an unambiguous interpretation as a conversion argument then it must be interpreted as such, even if the ascription interpretation would have a lower overall cost.
    195 This is demonstrated in the following example, adapted from the C standard library:
    196 
    197 \begin{cfa}
    198 unsigned long long x;
    199 (unsigned)(x >> 32);
    200 \end{cfa}
    201 
    202 In C semantics, this example is unambiguously upcasting !32! to !unsigned long long!, performing the shift, then downcasting the result to !unsigned!, at cost $(1,0,3,1,0,0,0)$.
    203 If ascription were allowed to be a first-class interpretation of a cast expression, it would be cheaper to select the !unsigned! interpretation of !?>>?! by downcasting !x! to !unsigned! and upcasting !32! to !unsigned!, at a total cost of $(1,0,1,1,0,0,0)$.
    204 However, this break from C semantics is not backwards compatible, so to maintain C compatibility, the \CFA{} resolver selects the lowest-cost interpretation of the cast argument for which a conversion or coercion to the target type exists (upcasting to !unsigned long long! in the example above, due to the lack of unsafe downcasts), using the cost of the conversion itself only as a tie-breaker.
    205 For example, in !int x; double x; (int)x;!, both declarations have zero-cost interpretations as !x!, but the !int x! interpretation is cheaper to cast to !int!, and is thus selected.
    206 Thus, in contrast to the lazy resolution of nested function-call expressions discussed above, where final interpretations for each subexpression are not chosen until the top-level expression is reached, cast expressions introduce eager resolution of their argument subexpressions, as if that argument was itself a top-level expression.
    207 
    208 \section{Resolution Algorithms}
    209 
    210 \CFA{} expression resolution is not, in general, polynomial in the size of the input expression, as shown in Section~\ref{resn-analysis-sec}.
    211 While this theoretical result is daunting, its implications can be mitigated in practice.
    212 \CFACC{} does not solve one instance of expression resolution in the course of compiling a program, but rather thousands; therefore, if the worst case of expression resolution is sufficiently rare, worst-case instances can be amortized by more-common easy instances for an acceptable overall runtime, as shown in Section~\ref{instance-expr-sec}.
    213 Secondly, while a programmer \emph{can} deliberately generate a program designed for inefficient compilation\footnote{See for instance \cite{Haberman16}, which generates arbitrarily large \CC{} template expansions from a fixed-size source file.}, source code tends to follow common patterns.
    214 Programmers generally do not want to run the full compiler algorithm in their heads, and as such keep mental shortcuts in the form of language idioms.
    215 If the compiler can be tuned to handle idiomatic code more efficiently, then the reduction in runtime for idiomatic (but otherwise difficult) resolution instances can make a significant difference in total compiler runtime.
    216 
    217 \subsection{Worst-case Analysis} \label{resn-analysis-sec}
    218 
    219 Expression resolution has a number of components that contribute to its runtime, including argument-parameter type unification, recursive traversal of the expression tree, and satisfaction of type assertions.
    220 
    221 If the bound type for a type variable can be looked up or mutated in constant time (as asserted in Table~\ref{env-bounds-table}), then the runtime of the unification algorithm to match an argument to a parameter is usually proportional to the complexity of the types being unified.
    222 In C, complexity of type representation is bounded by the most-complex type explicitly written in a declaration, effectively a small constant; in \CFA{}, however, polymorphism can generate more-complex types:
    223 
    224 \begin{cfa}
    225         forall(otype T) pair(T) wrap(T x, T y);
    226 
    227         wrap(wrap(wrap(1, 2), wrap(3, 4)), wrap(wrap(5, 6), wrap(7, 8)));
    228 \end{cfa}
    229 
    230 To resolve the outermost !wrap!, the resolver must check that !pair(pair(int))! unifies with itself, but at three levels of nesting, !pair(pair(int))! is more complex than either !pair(T)! or !T!, the types in the declaration of !wrap!.
    231 Accordingly, the cost of a single argument-parameter unification is $O(d)$, where $d$ is the depth of the expression tree, and the cost of argument-parameter unification for a single candidate for a given function call expression is $O(pd)$, where $p$ is the number of parameters.
    232 This bound does not, however, account for the higher costs of unifying two polymorphic type variables, which may in the worst case result in a recursive unification of all type variables in the expression (as discussed in Chapter~\ref{env-chap}).
    233 Since this recursive unification reduces the number of type variables, it may happen at most once, for an added $O(p^d)$ cost for a top-level expression with $O(p^d)$ type variables.
    234 
    235 Implicit conversions are also checked in argument-parameter matching, but the cost of checking for the existence of an implicit conversion is again proportional to the complexity of the type, $O(d)$.
    236 Polymorphism also introduces a potential expense here; for a monomorphic function there is only one potential implicit conversion from argument type to parameter type, while if the parameter type is an unbound polymorphic type-variable then any implicit conversion from the argument type could potentially be considered a valid binding for that type variable.
    237 \CFA{}, however, requires exact matches for the bound type of polymorphic parameters, removing this problem.
    238 An interesting question for future work is whether loosening this requirement incurs a significant compiler runtime cost in practice; preliminary results from the prototype system described in Chapter~\ref{expr-chap} suggest it does not.
    239 
    240 Considering the recursive traversal of the expression tree, polymorphism again greatly expands the worst-case runtime.
    241 Let $i$ be the number of candidate declarations for each function call; if all of these candidates are monomorphic, then there are no more than $i$ unambiguous interpretations of the subexpression rooted at that function call.
    242 Ambiguous minimal-cost subexpression interpretations may also be collapsed into a single \emph{ambiguous interpretation}, as the presence of such a subexpression interpretation in the final solution is an error condition.
    243 One safe pruning operation during expression resolution is to discard all subexpression interpretations with greater-than-minimal cost for their return type, as such interpretations cannot beat the minimal-cost interpretation with their return type for the overall optimal solution.
    244 As such, with no polymorphism, each declaration can generate no more than one minimal-cost interpretation with its return type, so the number of possible subexpression interpretations is $O(i)$ (note that in C, which lacks overloading, $i \leq 1$).
    245 With polymorphism, however, a single declaration (like !wrap! above) can have many concrete return types after type variable substitution, and could in principle have a different concrete return type for each combination of argument interpretations.
    246 Calculated recursively, the bound on the total number of candidate interpretations is $O(i^{p^d})$, each with a distinct type.
    247 
    248 Given these calculations of number of subexpression interpretations and matching costs, the upper bound on runtime for generating candidates for a single subexpression $d$ levels up from the leaves is $O( i^{p^d} \cdot pd )$.
    249 Since there are $O(p^d)$ subexpressions in a single top-level expression, the total worst-case cost of argument-parameter matching with the overloading and polymorphism features of \CFA{} is $O( i^{p^d} \cdot pd \cdot p^d )$.
    250 Since the size of the expression is $O(p^d)$, letting $n = p^d$ this simplifies to $O(i^n \cdot n^2)$
    251 
    252 This bound does not yet account for the cost of assertion satisfaction, however.
    253 \CFA{} uses type unification on the assertion type and the candidate declaration type to test assertion satisfaction; this unification calculation has cost proportional to the complexity of the declaration type after substitution of bound type variables; as discussed above, this cost is $O(d)$.
    254 If there are $O(a)$ type assertions on each declaration, there are $O(i)$ candidates to satisfy each assertion, for a total of $O(ai)$ candidates to check for each declaration.
    255 However, each assertion candidate may generate another $O(a)$ assertions, recursively until the assertion recursion limit $r$ is reached, for a total cost of $O((ai)^r \cdot d)$.
    256 Now, $a$ and $i$ are properties of the set of declarations in scope, while $r$ is defined by the language spec, so $(ai)^r$ is essentially a constant for purposes of expression resolution, albeit a very large one.
    257 It is not uncommon in \CFA{} to have functions with dozens of assertions, and common function names (\eg{} !?{}!, the constructor) can have hundreds of overloads.
    258 
    259 It is clear that assertion satisfaction costs can be very large, and in fact a method for heuristically reducing these costs is one of the key contributions of this thesis, but it should be noted that the worst-case analysis is a particularly poor match for actual code in the case of assertions.
    260 It is reasonable to assume that most code compiles without errors, as an actively-developed project is compiled many times, generally with relatively few new errors introduced between compiles.
    261 However, the worst-case bound for assertion satisfaction is based on recursive assertion satisfaction calls exceeding the limit, which is an error case.
    262 In practice, then, the depth of recursive assertion satisfaction should be bounded by a small constant for error-free code, which accounts for the vast majority of problem instances.
    263 
    264 Similarly, uses of polymorphism like those that generate the $O(d)$ bound on unification or the $O(i^{p^d})$ bound on number of candidates are rare, but not completely absent.
    265 This analysis points to type unification, argument-parameter matching, and assertion satisfaction as potentially costly elements of expression resolution, and thus profitable targets for algorithmic investigation.
    266 Type unification is discussed in Chapter~\ref{env-chap}, while the other aspects are covered below.
    267 
    268 \subsection{Argument-Parameter Matching} \label{arg-parm-matching-sec}
    269 
    270 Pruning possible interpretations as early as possible is one way to reduce the real-world cost of expression resolution, provided that a sufficient proportion of interpretations are pruned to pay for the cost of the pruning algorithm.
    271 One opportunity for interpretation pruning is by the argument-parameter type matching, but the literature \cite{Baker82,Bilson03,Cormack81,Ganzinger80,Pennello80,PW:overload} provides no clear answers on whether candidate functions should be chosen according to their available arguments, or whether argument resolution should be driven by the available function candidates.
    272 For programming languages without implicit conversions, argument-parameter matching is essentially the entirety of the expression resolution problem, and is generally referred to as ``overload resolution'' in the literature.
    273 All expression-resolution algorithms form a DAG of interpretations, some explicitly, some implicitly; in this DAG, arcs point from function-call interpretations to argument interpretations, as in Figure~\ref{res-dag-fig}
    274 
    275 \begin{figure}[h]
    276         \centering
    277         \begin{subfigure}[h]{3in}
    278         \begin{cfa}
    279         char *p$\(_1\)$;
    280         int *p$\(_2\)$;
    281        
    282         char *f$\(_1\)$(char*, int*);
    283         double *f$\(_2\)$(int*, int*);
    284        
    285         f$\(_A\)$( f$\(_B\)$( p$\(_A\)$, p$\(_B\)$ ), p$\(_C\)$ );
    286         \end{cfa}
    287         \end{subfigure}~\begin{subfigure}[h]{2.5in}
    288         \includegraphics{figures/resolution-dag}
    289         \end{subfigure}
    290         \caption[Resolution DAG for a simple expression.]{Resolution DAG for a simple expression, annotated with explanatory subscripts. Functions that do not have a valid argument matching are covered with an \textsf{X}.} \label{res-dag-fig}
    291 \end{figure}
    292 
    293 Note that some interpretations may be part of more than one super-interpretation, as with the !p!$_2$ interpretation of !p!$_B$, while some valid subexpression interpretations, like the !f!$_2$ interpretation of !f!$_B$, are not used in any interpretation of their superexpression.
    294 
    295 Overload resolution was first seriously considered in the development of compilers for the Ada programming language, with different algorithms making various numbers of passes over the expression DAG, these passes being either top-down or bottom-up.
    296 Baker's algorithm~\cite{Baker82} takes a single pass from the leaves of the expression tree up, pre-computing argument candidates at each step.
    297 For each candidate function, Baker attempts to match argument types to parameter types in sequence, failing if any parameter cannot be matched.
    298 
    299 Bilson~\cite{Bilson03} similarly pre-computes argument-candidates in a single bottom-up pass in the original \CFACC{}, but then explicitly enumerates all possible argument combinations for a multi-parameter function.
    300 These argument combinations are matched to the parameter types of the candidate function as a unit rather than individual arguments.
    301 Bilson's approach is less efficient than Baker's, as the same argument may be compared to the same parameter many times, but does allow a more straightforward handling of polymorphic type-binding and tuple-typed expressions.
    302 
    303 Unlike Baker and Bilson, Cormack's algorithm~\cite{Cormack81} requests argument candidates that match the type of each parameter of each candidate function, in a single pass from the top-level expression down; memoization of these requests is presented as an optimization.
    304 As presented, this algorithm requires the parameter to have a known type, which is a poor fit for polymorphic type parameters in \CFA{}.
    305 Cormack's algorithm can be modified to request argument interpretations of \emph{any} type when provided an unbound parameter type, but this eliminates any pruning gains that could be provided by the algorithm.
    306 
    307 Ganzinger and Ripken~\cite{Ganzinger80} propose an approach (later refined by Pennello~\etal{}~\cite{Pennello80}) that uses a top-down filtering pass followed by a bottom-up filtering pass to reduce the number of candidate interpretations; they prove that a small number of such iterations is sufficient to converge to a solution for the overload resolution problem in the Ada programming language.
    308 Persch~\etal{}~\cite{PW:overload} developed a similar two-pass approach where the bottom-up pass is followed by the top-down pass.
    309 These approaches differ from Baker, Bilson, or Cormack in that they take multiple passes over the expression tree to yield a solution by applying filtering heuristics to all expression nodes.
    310 This approach of filtering out invalid types is unsuited to \CFA{} expression resolution, however, due to the presence of polymorphic functions and implicit conversions.
    311 
    312 Some other language designs solve the matching problem by forcing a bottom-up order.
    313 \CC{}, for instance, defines its overload-selection algorithm in terms of a partial order between function overloads given a fixed list of argument candidates, implying that the arguments must be selected before the function.
    314 This design choice improves worst-case expression resolution time by only propagating a single candidate for each subexpression, but type annotations must be provided for any function call that is polymorphic in its return type, and these annotations are often redundant:
    315 
    316 \begin{C++}
    317 template<typename T> T* malloc() { /* ... */ }
    318 
    319 int* p = malloc<int>(); $\C{// T = int must be explicitly supplied}$
    320 \end{C++}
    321 
    322 \CFA{} saves programmers from redundant annotations with its richer inference:
    323 
    324 \begin{cfa}
    325 forall(dtype T | sized(T)) T* malloc();
    326 
    327 int* p = malloc(); $\C{// Infers T = int from left-hand side}$
    328 \end{cfa}
    329 
    330 Baker~\cite{Baker82} left empirical comparison of different overload resolution algorithms to future work; Bilson~\cite{Bilson03} described an extension of Baker's algorithm to handle implicit conversions and polymorphism, but did not further explore the space of algorithmic approaches to handle both overloaded names and implicit conversions.
    331 This thesis closes that gap in the literature by performing performance comparisons of both top-down and bottom-up expression resolution algorithms, with results reported in Chapter~\ref{expr-chap}.
    332 
    333 \subsection{Assertion Satisfaction} \label{assn-sat-sec}
    334 
    335 The assertion satisfaction algorithm designed by Bilson~\cite{Bilson03} for the original \CFACC{} is the most-relevant prior work to this project.
    336 Before accepting any subexpression candidate, Bilson first checks that that candidate's assertions can all be resolved; this is necessary due to Bilson's addition of assertion satisfaction costs to candidate costs (discussed in Section~\ref{conv-cost-sec}).
    337 If this subexpression interpretation ends up not being used in the final resolution, then the (sometimes substantial) work of checking its assertions ends up wasted.
    338 Bilson's assertion checking function recurses on two lists, !need! and !newNeed!, the current declaration's assertion set and those implied by the assertion-satisfying declarations, respectively, as detailed in the pseudo-code below (ancillary aspects of the algorithm are omitted for clarity):
    339 
    340 \begin{cfa}
    341 List(List(Declaration)) checkAssertions(
    342                 List(Assertion) need, List(Assertion) newNeed, List(Declaration) have,
    343                 Environment env ) {
    344         if ( is_empty(need) ) {
    345                 if ( is_empty( newNeed ) ) return { have };
    346                 else return checkAssertions( newNeed, {}, have, env );
    347         }
    348 
    349         Assertion a = head(need);
    350         Type adjType = substitute( a.type, env );
    351         List(Declaration) candidates = decls_matching( a.name );
    352         List(List(Declaration)) alternatives = {}
    353         for ( Declaration c : candidates ) {
    354                 Environment newEnv = env;
    355                 if ( unify( adjType, c.type, newEnv ) ) {
    356                         append( alternatives,
    357                                 checkAssertions(
    358                                         tail(need), append(newNeed, c.need), append(have, c), newEnv ) );
    359                 }
    360         }
    361         return alternatives;
    362 }
    363 \end{cfa}
    364 
    365 One shortcoming of this approach is that if an earlier assertion has multiple valid candidates, later assertions may be checked many times due to the structure of the recursion.
    366 Satisfying declarations for assertions are not completely independent of each other, since the unification process may produce new type bindings in the environment, and these bindings may not be compatible between independently-checked assertions.
    367 Nonetheless, with the environment data-structures discussed in Chapter~\ref{env-chap}, I have found it more efficient to produce a list of possibly-satisfying declarations for each assertion once, then check their respective environments for mutual compatibility when combining lists of assertions together.
    368 
    369 Another improvement I have made to the assertion resolution scheme in \CFACC{} is to consider all assertion-satisfying combinations at one level of recursion before attempting to recursively satisfy any !newNeed! assertions.
    370 Monomorphic functions are cheaper than polymorphic functions for assertion satisfaction because they are an exact match for the environment-adjusted assertion type, whereas polymorphic functions require an extra type binding.
    371 Thus, if there is any mutually-compatible set of assertion-satisfying declarations that does not include any polymorphic functions (and associated recursive assertions), then the optimal set of assertions does not require any recursive !newNeed! satisfaction.
    372 More generally, due to the \CFA{} cost-model changes I introduced in Section~\ref{conv-cost-sec}, the conversion cost of an assertion-satisfying declaration is no longer dependent on the conversion cost of its own assertions.
    373 As such, all sets of mutually-compatible assertion-satisfying declarations can be sorted by their summed conversion costs, and the recursive !newNeed! satisfaction pass is required only to check the feasibility of the minimal-cost sets.
    374 This optimization significantly reduces wasted work relative to Bilson's approach, as well as avoiding generation of deeply-recursive assertion sets, for a significant performance improvement relative to Bilson's \CFACC{}.
    375 
    376 Making the conversion cost of an interpretation independent of the cost of satisfying its assertions has further benefits.
    377 Bilson's algorithm checks assertions for all subexpression interpretations immediately, including those that are not ultimately used; I have developed a \emph{deferred} variant of assertion checking that waits until a top-level interpretation has been generated to check any assertions.
    378 If the assertions of the minimal-cost top-level interpretation cannot be satisfied then the next-most-minimal-cost interpretation's assertions are checked, and so forth until a minimal-cost satisfiable interpretation (or ambiguous set thereof) is found, or no top-level interpretations are found to have satisfiable assertions.
    379 In the common case where the code actually does compile, this saves the work of checking assertions for ultimately-rejected interpretations, though it does rule out some pruning opportunities for subinterpretations with unsatisfiable assertions or which are more expensive than a minimal-cost polymorphic function with the same return type.
    380 The experimental results in Chapter~\ref{expr-chap} indicate that this is a worthwhile trade-off.
    381 
    382 Optimizing assertion satisfaction for common idioms has also proved effective in \CFA{}; the code below is an unexceptional print statement derived from the \CFA{} test suite that nonetheless is a very difficult instance of expression resolution:
    383 
    384 \begin{cfa}
    385 sout | "one" | 1 | "two" | 2 | "three" | 3 | "four" | 4 | "five" | 5 | "six" | 6
    386         | "seven" | 7 | "eight" | 8 | "nine" | 9 | "ten" | 10 | "end" | nl | nl;
    387 \end{cfa}
    388 
    389 The first thing that makes this expression so difficult is that it is 23 levels deep; Section~\ref{resn-analysis-sec} indicates that the worst-case bounds on expression resolution are exponential in expression depth.
    390 Secondly, the !?|?! operator is significantly overloaded in \CFA{} --- there are 74 such operators in the \CFA{} standard library, and while 9 are arithmetic operators inherited from C, the rest are polymorphic I/O operators that look similar to:
    391 
    392 \begin{cfa}
    393 forall( dtype ostype | ostream( ostype ) )
    394 ostype& ?|? ( ostype&, int );
    395 \end{cfa}
    396 
    397 Note that !ostream! is a trait with 25 type assertions, and that the output operators for the other arithmetic types are also valid for the !int!-type parameters due to implicit conversions.
    398 On this instance, deferred assertion satisfaction saves wasted work checking assertions on the wrong output operators, but does nothing about the 23 repeated checks of the 25 assertions to determine that !ofstream! (the type of !sout!) satisfies !ostream!.
    399 
    400 To solve this problem, I have developed a \emph{cached} variant of assertion checking.
    401 During the course of checking the assertions of a single top-level expression, the results are cached for each assertion checked.
    402 The search key for this cache is the assertion declaration with its type variables substituted according to the type environment to distinguish satisfaction of the same assertion for different types.
    403 This adjusted assertion declaration is then run through the \CFA{} name-mangling algorithm to produce an equivalent string-type key.
    404 
    405 One superficially-promising optimization, which I did not pursue, is caching assertion-satisfaction judgments among top-level expressions.
    406 This approach would be difficult to correctly implement in a \CFA{} compiler, due to the lack of a closed set of operations for a given type.
    407 New declarations related to a particular type can be introduced in any lexical scope in \CFA{}, and these added declarations may cause an assertion that was previously satisfiable to fail due to an introduced ambiguity.
    408 Furthermore, given the recursive nature of assertion satisfaction and the possibility of this satisfaction judgment depending on an inferred type, an added declaration may break satisfaction of an assertion with a different name and that operates on different types.
    409 Given these concerns, correctly invalidating a cross-expression assertion satisfaction cache for \CFA{} is a non-trivial problem, and the overhead of such an approach may possibly outweigh any benefits from such caching.
    410 
    411 The assertion satisfaction aspect of \CFA{} expression resolution bears some similarity to satisfiability problems from logic, and as such other languages with similar trait and assertion mechanisms make use of logic-program solvers in their compilers.
    412 For instance, Matsakis~\cite{Matsakis17} and the Rust team have developed a PROLOG-based engine to check satisfaction of Rust traits.
    413 The combination of the assertion satisfaction elements of the problem with the conversion-cost model of \CFA{} makes this logic-solver approach difficult to apply in \CFACC{}, however.
    414 Expressing assertion resolution as a satisfiability problem ignores the cost optimization aspect, which is necessary to decide among what are often many possible satisfying assignments of declarations to assertions.
    415 (MaxSAT solvers \cite{Morgado13}, which allow weights on solutions to satisfiability problems, may be a productive avenue for future investigation.)
    416 On the other hand, the deeply-recursive nature of the satisfiability problem makes it difficult to adapt to optimizing solver approaches such as linear programming.
    417 To maintain a well-defined programming language, any optimization algorithm used must provide an exact (rather than approximate) solution; this constraint also rules out a whole class of approximately-optimal generalized solvers.
    418 As such, I opted to continue Bilson's approach of designing a bespoke solver for \CFA{} assertion satisfaction, rather than attempting to re-express the problem in some more general formalism.
    419 
    420 \section{Conclusion \& Future Work} \label{resn-conclusion-sec}
    421 
    422 As the results in Chapter~\ref{expr-chap} show, the algorithmic approaches I have developed for \CFA{} expression resolution are sufficient to build a practically-performant \CFA{} compiler.
    423 This work may also be of use to other compiler construction projects, notably to members of the \CC{} community as they implement the new Concepts \cite{C++Concepts} standard, which includes type assertions similar to those used in \CFA{}, as well as the C-derived implicit conversion system already present in \CC{}.
    424 
    425 I have experimented with using expression resolution rather than type unification to check assertion satisfaction; this variant of the expression resolution problem should be investigated further in future work.
    426 This approach is more flexible than type unification, allowing for conversions to be applied to functions to satisfy assertions.
    427 Anecdotally, this flexibility matches user-programmer expectations better, as small type differences (\eg{} the presence or absence of a reference type, or the usual conversion from !int! to !long!) no longer break assertion satisfaction.
    428 Practically, the resolver prototype discussed in Chapter~\ref{expr-chap} uses this model of assertion satisfaction, with no apparent deficit in performance; the generated expressions that are resolved to satisfy the assertions are easier than the general case because they never have nested subexpressions, which eliminates much of the theoretical differences between unification and resolution.
    429 The main challenge to implement this approach in \CFACC{} is applying the implicit conversions generated by the resolution process in the code-generation for the thunk functions that \CFACC{} uses to pass type assertions to their requesting functions with the proper signatures.
    430 
    431 One \CFA{} feature that could be added to improve the ergonomics of overload selection is an \emph{ascription cast}; as discussed in Section~\ref{expr-cost-sec}, the semantics of the C cast operator are to choose the cheapest argument interpretation which is convertible to the target type, using the conversion cost as a tie-breaker.
    432 An ascription cast would reverse these priorities, choosing the argument interpretation with the cheapest conversion to the target type, only using interpretation cost to break ties\footnote{A possible stricter semantics would be to select the cheapest interpretation with a zero-cost conversion to the target type, reporting a compiler error otherwise.}.
    433 This would allow ascription casts to the desired return type to be used for overload selection:
    434 
    435 \begin{cfa}
    436 int f$\(_1\)$(int);
    437 int f$\(_2\)$(double);
    438 int g$\(_1\)$(int);
    439 double g$\(_2\)$(long);
    440 
    441 f((double)42);  $\C[4.5in]{// select f\(_2\) by argument cast}$
    442 (as double)g(42); $\C[4.5in]{// select g\(_2\) by return ascription cast}$
    443 (double)g(42); $\C[4.5in]{// select g\(_1\) NOT g\(_2\) because of parameter conversion cost}$
    444 \end{cfa}
    445 
    446 Though performance of the existing resolution algorithms is promising, some further optimizations do present themselves.
    447 The refined cost model discussed in Section~\ref{conv-cost-sec} is more expressive, but requires more than twice as many fields; it may be fruitful to investigate more tightly-packed in-memory representations of the cost-tuple, as well as comparison operations that require fewer instructions than a full lexicographic comparison.
    448 Integer or vector operations on a more-packed representation may prove effective, though dealing with the negative-valued $specialization$ field may require some effort.
    449 
    450 Parallelization of various phases of expression resolution may also be useful.
    451 The algorithmic variants I have introduced for both argument-parameter matching and assertion satisfaction are essentially divide-and-conquer algorithms, which solve subproblem instances for each argument or assertion, respectively, then check mutual compatibility of the solutions.
    452 While the checks for mutual compatibility are naturally more serial, there may be some benefit to parallel resolution of the subproblem instances.
    453 
    454 The resolver prototype built for this project and described in Chapter~\ref{expr-chap} would be a suitable vehicle for many of these further experiments, and thus a technical contribution of continuing utility.
     15% Mention relevance of work to C++20 concepts
  • doc/theses/aaron_moss_PhD/phd/thesis.tex

    r933f32f r6a9d4b4  
    2929\usepackage{footmisc} % for double refs to the same footnote
    3030
    31 \usepackage{caption} % for subfigure
    32 \usepackage{subcaption}
    33 
    3431% Hyperlinks make it very easy to navigate an electronic document.
    3532% In addition, this is where you should specify the thesis title
     
    3734% Use the "hyperref" package
    3835% N.B. HYPERREF MUST BE THE LAST PACKAGE LOADED; ADD ADDITIONAL PKGS ABOVE
    39 %\usepackage[pdftex,pagebackref=false]{hyperref} % with basic options\
    40 \usepackage[breaklinks,pagebackref=false]{hyperref}
     36%\usepackage[pdftex,pagebackref=false]{hyperref} % with basic options
     37\usepackage[pagebackref=false]{hyperref}
    4138% N.B. pagebackref=true provides links back from the References to the body text. This can cause trouble for printing.
    4239
     
    132129\input{resolution-heuristics}
    133130\input{type-environment}
    134 \input{experiments}
    135131\input{conclusion}
    136132
     
    160156% \nocite{*}
    161157
    162 % APPENDICIES
    163 % -----------
    164 \appendix
    165 \input{generic-bench}
    166 
    167158\end{document}
  • doc/theses/aaron_moss_PhD/phd/type-environment.tex

    r933f32f r6a9d4b4  
    44One key data structure for expression resolution is the \emph{type environment}.
    55As discussed in Chapter~\ref{resolution-chap}, being able to efficiently determine which type variables are bound to which concrete types or whether two type environments are compatible is a core requirement of the resolution algorithm.
    6 Furthermore, expression resolution involves a search through many related possible solutions, so the ability to re-use shared subsets of type-environment data and to switch between environments quickly is desirable for performance.
    7 In this chapter, I discuss a number of type-environment data-structure variants, including some novel variations on the union-find \cite{Galler64} data structure introduced in this thesis.
    8 Chapter~\ref{expr-chap} contains empirical comparisons of the performance of these data structures when integrated into the resolution algorithm.
     6Furthermore, expression resolution involves a search through many related possible solutions, so being able to re-use shared subsets of type environment data and to switch between environments quickly is desirable for performance.
     7In this chapter I discuss and empirically compare a number of type environment data structure variants, including some novel variations on the union-find\cite{Galler64} data structure introduced in this thesis.
    98
    109\section{Definitions} \label{env-defn-sec}
    1110
    1211For purposes of this chapter, a \emph{type environment} $T$ is a set of \emph{type classes} $\myset{T_1, T_2, \cdots, T_{|T|}}$.
    13 Each type class $T_i$ contains a set of \emph{type variables} $\myset{v_{i,1}, v_{i,2}, \cdots, v_{i,|T_i|}}$.
    14 Since the type classes represent an equivalence relation over the type variables the sets of variables contained in two distinct classes in the same environment must be \emph{disjoint}.
    15 Each individual type class $T_i$ may also be associated with a \emph{bound}, $b_i$; this bound contains the \emph{bound type} that the variables in the type class are replaced with, but also includes other information in \CFACC{}, including whether type conversions are permissible on the bound type and what sort of type variables are contained in the class (data types, function types, or variadic tuples).
    16 
    17 The following example demonstrates the use of a type environment for unification:
    18 
    19 \begin{cfa}
    20 forall(otype F) F f(F, F);
    21 forall(otype G) G g(G);
    22 
    23 f( g(10), g(20) );
    24 \end{cfa}
    25 
    26 Expression resolution starts from an empty type environment; from this empty environment, the calls to !g! can be independently resolved.
    27 These resolutions result in two new type environments, $T = \{ \myset{\mathsf{G}_1} \rightarrow$ !int!$\}$ and $T' = \{ \myset{\mathsf{G}_2} \rightarrow$ !int!$\}$; the calls to !g! have generated distinct type variables !G!$_1$ and !G!$_2$, each bound to !int! by unification with the type of its argument (!10! and !20!, both !int!).
    28 To complete resolution of the call to !f!, both environments must be combined; resolving the first argument to !f! produces a new type environment $T'' = \{ \myset{\mathsf{G}_1, \mathsf{F}_1} \rightarrow$ !int!$\}$: the new type variable !F!$_1$ has been introduced and unified with !G!$_1$ (the return type of !g(10)!), and consequently bound to !int!.
    29 To resolve the second argument to !f!, $T''$ must be checked for compatibility with $T'$; since !F!$_1$ unifies with !G!$_2$, their type classes must be merged.
    30 Since both !F!$_1$ and !G!$_2$ are bound to !int!, this merge succeeds, producing the final environment $T'' = \{ \myset{\mathsf{G}_1, \mathsf{F}_1, \mathsf{G}_2} \rightarrow$ !int!$\}$.
     12Each type class $T_i$ contains a set of \emph{type variables} $\myset{v_{i,1}, v_{i,2}, \cdots, v_{i,|T_i|}}$; note that the sets of variables contained in two distinct classes in the same environment must be disjoint.
     13Each individual type class $T_i$ may also be associated with a \emph{bound}, $b_i$; this bound contains the \emph{bound type} which the variables in the type class are replaced with, but also includes other information in \CFACC{}, including whether type conversions are permissible on the bound type and what sort of type variables are contained in the class (data types, function types, or variadic tuples).
    3114
    3215\begin{table}
     
    3518\centering
    3619\begin{tabular}{r@{\hskip 0.25em}ll}
    37         \hline
    38         $find(T, v_{i,j})$ & $\rightarrow T_i~|~\mathsf{fail}$          & Locate class for variable             \\
     20        $find(T, v_{i,j})$ & $\rightarrow T_i | \bot$           & Locate class for variable             \\
    3921        $report(T_i)$ & $\rightarrow \{ v_{i,j} \cdots \}$      & List variables for class              \\
    40         $bound(T_i)$ & $\rightarrow b_i~|~\mathsf{fail}$                                & Get bound for class                   \\
    41         $insert(T, v_{i,1})$ &                                                          & New single-variable class             \\
     22        $bound(T_i)$ & $\rightarrow b_i | \bot$                         & Get bound for class                   \\
     23        $insert(v_{i,1})$ &                                                                     & New single-variable class             \\
    4224        $add(T_i, v_{i,j})$ &                                                           & Add variable to class                 \\
    4325        $bind(T_i, b_i)$ &                                                                      & Set or update class bound             \\
    44         \hline
    45         $unify(T, T_i, T_j)$ & $\rightarrow \mathsf{pass}~|~\mathsf{fail}$      & Combine two type classes              \\
     26        $unify(T, T_i, T_j)$ & $\rightarrow \top | \bot$        & Combine two type classes              \\
    4627        $split(T, T_i)$ & $\rightarrow T'$                                      & Revert the last $unify$ operation on $T_i$            \\
    47         $combine(T, T')$ & $\rightarrow \mathsf{pass}~|~\mathsf{fail}$          & Merge two environments                \\
     28        $combine(T, T')$ & $\rightarrow \top | \bot$            & Merge two environments                \\
    4829        $save(T)$ & $\rightarrow H$                                                     & Get handle for current state  \\
    49         $backtrack(T, H)$ &                                                                     & Return to handle state                \\
    50         \hline
     30        $backtrack(T, H)$ &                                                                     & Return to handle state
    5131\end{tabular}
    5232\end{table}
    5333
    54 Type environments in \CFACC{} need to support eleven basic operations, summarized in Table~\ref{env-op-table}.
    55 The first six operations are straightforward queries and updates on these data structures:
    56 The lookup operation $find(T, v_{i,j})$ produces $T_i$, the type class in $T$ that contains variable $v_{i,j}$, or an invalid sentinel value for no such class.
     34Given this basic structure, type environments in \CFACC{} need to support eleven basic operations, summarized in Table~\ref{env-op-table}.
     35The first seven operations are straightforward queries and updates on these data structures:
     36The lookup operation $find(T, v_{i,j})$ produces $T_i$, the type class in $T$ which contains variable $v_{i,j}$, or an invalid sentinel value for no such class.
    5737The other two query operations act on type classes, where $report(T_i)$ produces the set $\myset{v_{i,1}, v_{i,2}, \cdots, v_{i,|T_i|}}$ of all type variables in a class $T_i$ and $bound(T_i)$ produces the bound $b_i$ of that class, or a sentinel indicating no bound is set.
    5838
    59 The update operation $insert(T, v_{i,1})$ creates a new type class $T_i$ in $T$ that contains only the variable $v_{i,1}$ and no bound; due to the disjointness property, $v_{i,1}$ must not belong to any other type class in $T$.
     39The update operation $insert(T, v_{i,1})$ creates a new type class $T_i$ in $T$ that contains only the variable $v_{i,1}$ and no bound; due to the disjointness property $v_{i,1}$ cannot belong to any other type class in $T$.
    6040The $add(T_i, v_{i,j})$ operation adds a new type variable $v_{i,j}$ to class $T_i$; again, $v_{i,j}$ cannot exist elsewhere in $T$.
    6141$bind(T_i, b_i)$ mutates the bound for a type class, setting or updating the current bound.
    6242
    63 The $unify$ operation is the fundamental non-trivial operation a type-environment data-structure must support.
     43The $unify$ operation is the fundamental non-trivial operation a type environment data structure must support.
    6444$unify(T, T_i, T_j)$ merges a type class $T_j$ into another $T_i$, producing a failure result and leaving $T$ in an invalid state if this merge fails.
    6545It is always possible to unify the type variables of both classes by simply taking the union of both sets; given the disjointness property, no checks for set containment are required, and the variable sets can simply be concatenated if supported by the underlying data structure.
    66 $unify$ depends on an internal $unifyBound$ operation, which may fail.
    67 In \CFACC{}, $unifyBound(b_i, b_j) \rightarrow b'_i~|~\mathsf{fail}$ checks that the type classes contain the same sort of variable, takes the tighter of the two conversion permissions, and checks if the bound types can be unified.
     46$unify$ depends on an internal $unifyBound$ operation which may fail.
     47In \CFACC{}, $unifyBound(b_i, b_j) \rightarrow b'_i|\bot$ checks that the type classes contain the same sort of variable, takes the tighter of the two conversion permissions, and checks if the bound types can be unified.
    6848If the bound types cannot be unified (\eg{} !struct A! with !int*!), then $unifyBound$ fails, while other combinations of bound types may result in recursive calls.
    69 For instance, unifying !R*! with !S*! for type variables !R! and !S! results in a call to $unify(T, find($!R!$), find($!S!$))$, while unifying !R*! with !int*! results in a call to $unifyBound$ on !int! and the bound type of the class containing !R!.
     49For instance, unifying !R*! with !S*! for type variables !R! and !S! will result in a call to $unify(T, find($!R!$), find($!S!$))$, while unifying !R*! with !int*! will result in a call to $unifyBound$ on !int! and the bound type of the class containing !R!.
    7050As such, a call to $unify(T, T_i, T_j)$ may touch every type class in $T$, not just $T_i$ and $T_j$, collapsing the entirety of $T$ into a single type class in extreme cases.
    7151For more information on \CFA{} unification, see \cite{Bilson03}.
    72 The inverse of $unify$ is $split(T, T_i)$, which produces a new environment $T'$ that is the same as $T$ except that $T_i$ has been replaced by two classes corresponding to the arguments to the previous call to $unify$ on $T_i$.
    73 If there is no prior call to $unify$ on $T_i$ (\ie{} $T_i$ is a single-element class) $T_i$ is absent in $T'$.
    74 
    75 Given the nature of the expression resolution problem as a backtracking search, caching and concurrency are both useful tools to decrease runtime.
     52The inverse of $unify$ is $split(T, T_i)$, which produces a new environment $T'$ which is the same as $T$ except that $T_i$ has been replaced by two classes corresponding to the arguments to the previous call to $unify$ on $T_i$.
     53If there has been no call to $unify$ on $T_i$ (\ie{} $T_i$ is a single-element class) $T_i$ is absent in $T'$.
     54
     55Given the nature of the expression resolution problem as backtracking search, caching and concurrency are both useful tools to decrease runtime.
    7656However, both of these approaches may produce multiple distinct descendants of the same initial type environment, which have possibly been mutated in incompatible ways.
    77 As such, to effectively employ either caching or concurrency, the type environment data structure must support an efficient method to check if two type environments are compatible and merge them if so.
    78 $combine(T,T')$ attempts to merge an environment $T'$ into another environment $T$, producing $\mathsf{pass}$ if successful or leaving $T$ in an invalid state and producing $\mathsf{fail}$ otherwise.
    79 The invalid state of $T$ on failure is not important, given that a combination failure results in the resolution algorithm backtracking to a different environment.
     57As such, to effectively employ either concurrency or caching, the type environment data structure must support an efficient method to check if two type environments are compatible and merge them if so.
     58$combine(T,T')$ attempts to merge an environment $T'$ into another environment $T$, producing $\top$ if successful or leaving $T$ in an invalid state and producing $\bot$ otherwise.
     59The invalid state of $T$ on failure is not important, given that a combination failure will result in the resolution algorithm backtracking to a different environment.
    8060$combine$ proceeds by calls to $insert$, $add$, and $unify$ as needed, and can be roughly thought of as calling $unify$ on every pair of classes in $T$ that have variables $v'_{i,j}$ and $v'_{i,k}$ in the same class $T'_i$ in $T'$.
    8161Like $unify$, $combine$ can always find a mutually-consistent partition of type variables into classes (in the extreme case, all type variables from $T$ and $T'$ in a single type class), but may fail due to inconsistent bounds on merged type classes.
     
    8464The set of mutations to a type environment across the execution of the resolution algorithm produce an implicit tree of related environments, and the backtracking search typically focuses only on one leaf of the tree at once, or at most a small number of closely-related nodes as arguments to $combine$.
    8565As such, the ability to save and restore particular type environment states is useful, and supported by the $save(T) \rightarrow H$ and $backtrack(T, H)$ operations, which produce a handle for the current environment state and mutate an environment back to a previous state, respectively.
    86 These operations can be naively implemented by a deep copy of $T$ into $H$ and vice versa, but have more efficient implementations in persistency-aware data structures such as the persistent union-find introduced in Section~\ref{env-persistent-union-find}.
    87 
    88 \section{Approaches} \label{env-approaches-sec}
    89 
    90 \subsection{Na\"{\i}ve} \label{naive-env-sec}
    91 
    92 The type environment data structure used in Bilson's~\cite{Bilson03} original implementation of \CFACC{} is a simple translation of the definitions in Section~\ref{env-defn-sec} to \CC{} code; a !TypeEnvironment! contains a list of !EqvClass! type equivalence classes, each of which contains the type bound information and a tree-based sorted set of type variables.
     66These operations can be naively implemented by a deep copy of $T$ into $H$ and vice versa, but have more efficient implementations in persistency-aware data structures.
     67
     68\section{Approaches}
     69
     70\subsection{Na\"{\i}ve}
     71
     72The type environment data structure used in Bilson's\cite{Bilson03} original implementation of \CFACC{} is a straightforward translation of the definitions in Section~\ref{env-defn-sec} to \CC{} code; a !TypeEnvironment! contains a list of !EqvClass! type equivalence classes, each of which contains the type bound information and a tree-based sorted set of type variables.
    9373This approach has the benefit of being easy to understand and not imposing life-cycle or inheritance constraints on its use, but, as can be seen in Table~\ref{env-bounds-table}, does not support many of the desired operations with any particular efficiency.
    94 Some variations on this structure may improve performance somewhat; for instance, replacing the !EqvClass! variable storage with a hash-based set reduces search and update times from $O(\log n)$ to amortized $O(1)$, while adding an index for the type variables in the entire environment removes the need to check each type class individually to maintain the disjointness property.
     74Some variations on this structure may improve performance somewhat; for instance, replacing the !EqvClass! variable storage with a hash-based set would reduce search and update times from $O(\log n)$ to amortized $O(1)$, while adding an index for the type variables in the entire environment would remove the need to check each type class individually to maintain the disjointness property.
    9575These improvements do not change the fundamental issues with this data structure, however.
    9676
    97 \subsection{Incremental Inheritance} \label{inc-env-sec}
    98 
    99 One more invasive modification to this data structure that I investigated is to support swifter combinations of closely-related environments in the backtracking tree by storing a reference to a \emph{parent} environment within each environment, and having that environment only store type classes that have been modified with respect to the parent.
     77\subsection{Incremental Inheritance}
     78
     79One more invasive modification to this data structure which I investigated is to support swifter combinations of closely-related environments in the backtracking tree by storing a reference to a \emph{parent} environment within each environment, and having that environment only store type classes which have been modified with respect to the parent.
    10080This approach provides constant-time copying of environments, as a new environment simply consists of an empty list of type classes and a reference to its (logically identical) parent; since many type environments are no different than their parent, this speeds backtracking in this common case.
    101 Since all mutations made to a child environment are by definition compatible with the parent environment, two descendants of a common ancestor environment can be combined by iteratively combining the changes made in one environment, then that environment's parent, until the common ancestor is reached, again re-using storage and reducing computation in many cases.
    102 
    103 For this environment, I also employed a lazily-generated index of type variables to their containing class, which could be in either the current environment or an ancestor.
    104 Any mutation of a type class in an ancestor environment causes that class to be copied into the current environment before mutation, as well as added to the index, ensuring all local changes to the type environment are listed in its index.
     81Since all mutations made to a child environment are by definition compatible with the parent environment, two descendants of a common ancestor environment can be combined by iteratively combining the changes made in one environment then that environment's parent until the common ancestor is reached, again re-using storage and reducing computation in many cases.
     82
     83For this environment I also employed a lazily-generated index of type variables to their containing class, which could be in either the current environment or an ancestor.
     84Any mutation of a type class in an ancestor environment would cause that class to be copied into the current environment before mutation, as well as added to the index, ensuring that all local changes to the type environment are listed in its index.
    10585However, not adding type variables to the index until lookup or mutation preserves the constant-time environment copy operation in the common case in which the copy is not mutated from its parent during its life-cycle.
    10686
    107 This approach imposes some performance penalty on $combine$ if related environments are not properly linked together, as the entire environment needs to be combined rather than just the difference, but is correct as long as the ``null parent'' base-case is properly handled.
     87This approach imposes some performance penalty on $combine$ if related environments are not properly linked together, as the entire environment needs to be combined rather than just the diff, but is correct as long as the ``null parent'' base case is properly handled.
    10888The life-cycle issues are somewhat more complex, as many environments may descend from a common parent, and all of these need their parent to stay alive for purposes of lookup.
    109 These issues can be solved by ``flattening'' parent nodes into their children before the parent's scope ends, but given the tree structure of the inheritance graph it is more straightforward to store the parent nodes in reference-counted or otherwise automatically garbage-collected heap storage.
     89These issues can be solved by ``flattening'' parent nodes into their children before the parents leave scope, but given the tree structure of the inheritance graph it is more straightforward to store the parent nodes in reference-counted or otherwise automatically garbage-collected heap storage.
    11090
    11191\subsection{Union-Find} \label{env-union-find-approach}
    11292
    113 Given the nature of the classes of type variables as disjoint sets, another natural approach to implementing a type environment is the union-find disjoint-set data-structure~\cite{Galler64}.
     93Given the nature of the classes of type variables as disjoint sets, another natural approach to implementing a type environment is the union-find disjoint set data structure\cite{Galler64}.
    11494Union-find efficiently implements two operations over a partition of a collection of elements into disjoint sets; $find(x)$ locates the \emph{representative} of $x$, the element which canonically names its set, while $union(r, s)$ merges two sets represented by $r$ and $s$, respectively.
    11595The union-find data structure is based on providing each element with a reference to its parent element, such that the root of a tree of elements is the representative of the set of elements contained in the tree.
    11696$find$ is then implemented by a search up to the parent, generally combined with a \emph{path compression} step that links nodes more directly to their ancestors to speed up subsequent searches.
    11797$union$ involves making the representative of one set a child of the representative of the other, generally employing a rank- or size-based heuristic to ensure that the tree remains somewhat balanced.
    118 If both path compression and a balancing heuristic are employed, both $union$ and $find$ run in amortized $O(\alpha(n))$ worst-case time; this inverse Ackermann bound is a small constant for all practical values of $n$ \cite{Tarjan75}.
     98If both path compression and a balancing heuristic are employed, both $union$ and $find$ run in amortized $O(\alpha(n))$ worst-case time; this bound by the inverse Ackermann function is a small constant for all practical values of $n$.
    11999
    120100The union-find $find$ and $union$ operations have obvious applicability to the $find$ and $unify$ type environment operations in Table~\ref{env-op-table}, but the union-find data structure must be augmented to fully implement the type environment operations.
    121 In particular, the type-class bound cannot be easily included in the union-find data structure, as the requirement to make it the class representative breaks the balancing properties of $union$, and requires too-close integration of the type environment $unifyBound$ internal operation.
    122 This issue can be solved by including a side map from class representatives to the type-class bound.
    123 If placeholder values are inserted in this map for type classes without bounds then this also has the useful property that the key set of the map provides an easily obtainable list of all the class representatives, a list which cannot be derived from the union-find data structure without a linear search for class representatives through all elements.
     101In particular, the type class bound cannot be easily included in the union-find data structure, as the requirement to make it the class representative breaks the balancing properties of $union$, and requires too-close integration of the type environment $unifyBound$ internal operation.
     102This issue can be solved by including a side map from class representatives to the type class bound.
     103If placeholder values are inserted in this map for type classes without bounds than this also has the useful property that the key set of the map provides an easily obtainable list of all the class representatives, a list which cannot be derived from the union-find data structure without a linear search for class representatives through all elements.
    124104
    125105\subsection{Union-Find with Classes} \label{env-union-find-classes-approach}
     
    127107Another type environment operation not supported directly by the union-find data structure is $report$, which lists the type variables in a given class, and similarly $split$, which reverts a $unify$ operation.
    128108Since the union-find data structure stores only links from children to parents and not vice-versa, there is no way to reconstruct a class from one of its elements without a linear search over the entire data structure, with $find$ called on each element to check its membership in the class.
    129 The situation is even worse for the $split$ operation, which requires extra information to maintain the order that each child is added to its parent node.
    130 Unfortunately, the literature \cite{Tarjan84,Galil91,Patwary10} on union-find does not present a way to keep references to children without breaking the asymptotic time bounds of the algorithm; I have discovered a method to do so, which, despite its simplicity, seems to be novel.
     109The situation is even worse for the $split$ operation, which would require extra information to maintain the order that each child was added to its parent node.
     110Unfortunately, the literature\cite{Tarjan84,Galil91,Patwary10} on union-find does not present a way to keep references to children without breaking the asymptotic time bounds of the algorithm; I have discovered a method to do so which, despite its simplicity, seems to be novel.
     111
     112\TODO{port figure from slideshow}
    131113
    132114The core idea of this ``union-find with classes'' data structure and algorithm is to keep the members of each class stored in a circularly-linked list.
     
    135117In my version, the list data structure does not affect the layout of the union-find tree, maintaining the same asymptotic bounds as union-find.
    136118In more detail, each element is given a !next! pointer to another element in the same class; this !next! pointer initially points to the element itself.
    137 When two classes are unified, the !next! pointers of the representatives of those classes are swapped, splicing the two circularly-linked lists together as illustrated in Figure~\ref{union-find-classes-fig}.
     119When two classes are unified, the !next! pointers of the representatives of those classes are swapped, splicing the two circularly-linked lists together.
    138120Importantly, though this approach requires an extra pointer per element, it does maintain the linear space bound of union-find, and because it only requires updating the two root nodes in $union$ it does not asymptotically increase runtime either.
    139121The basic approach is compatible with all path-compression techniques, and allows the members of any class to be retrieved in time linear in the size of the class simply by following the !next! pointers from any element.
    140 
    141 \begin{figure}
    142         \centering
    143         \includegraphics{figures/union-find-with-classes}
    144         \caption[Union operation for union-find with classes.]{Union operation for union-find with classes. Solid lines indicate parent pointers, dashed lines are \lstinline{next} pointers.}
    145         \label{union-find-classes-fig}
    146 \end{figure}
    147122
    148123If the path-compression optimization is abandoned, union-find with classes also encodes a reversible history of all the $union$ operations applied to a given class.
     
    152127
    153128\begin{theorem} \label{env-reverse-thm}
    154 The !next! pointer of a class representative in the union-find with classes algorithm, without path compression, points to a leaf from the most-recently-added subtree.
     129The !next! pointer of a class representative in the union-find with classes algorithm without path compression points to a leaf from the most-recently-added subtree.
    155130\end{theorem}
    156131
     
    158133        By induction on the height of the tree. \\
    159134        \emph{Base case:} A height 1 tree by definition includes only a single item. In such a case, the representative's !next! pointer points to itself by construction, and the representative is the most-recently-added (and only) leaf in the tree. \\
    160         \emph{Inductive case:} By construction, a tree $T$ of height greater than 1 has children of the root (representative) node that were representative nodes of classes merged by $union$. By definition, the most-recently-added subtree $T'$ has a smaller height than $T$, thus by the inductive hypothesis before the most-recent $union$ operation, the !next! pointer of the root of $T'$ pointed to one of the leaf nodes of $T'$; by construction the !next! pointer of the root of $T$ points to this leaf after the $union$ operation.
     135        \emph{Inductive case:} By construction, a tree $T$ of height greater than 1 has children of the root (representative) node that were representative nodes of classes merged by $union$. By definition, the most-recently-added subtree $T'$ has a smaller height than $T$, thus by the inductive hypothesis before the most-recent $union$ operation the !next! pointer of the root of $T'$ pointed to one of the leaf nodes of $T'$; by construction the !next! pointer of the root of $T$ points to this leaf after the $union$ operation.
    161136\end{proof}
    162137
     
    164139
    165140\subsection{Persistent Union-Find}
    166 \label{env-persistent-union-find}
    167 
    168 Given the backtracking nature of the resolution algorithm discussed in Section~\ref{env-defn-sec}, the abilities to quickly switch between related versions of a type environment and to de-duplicate shared data among environments are both assets to performance.
     141
     142Given the backtracking nature of the resolution algorithm discussed in Section~\ref{env-defn-sec}, the abilities to quickly switch between related versions of a type environment and to de-duplicate shared data between environments are both assets to performance.
    169143Conchon and Filli\^{a}tre~\cite{Conchon07} present a persistent union-find data structure based on the persistent array of Baker~\cite{Baker78,Baker91}.
    170144
    171 In Baker's persistent array, an \emph{array reference} contains either a pointer to the array or a pointer to an \emph{edit node}; these edit nodes contain an array index, the value in that index, and another array reference pointing either to the array or a different edit node.
    172 By construction, these array references always point to a node more like the actual array, forming a tree of edits rooted at the actual array.
    173 Reads from the actual array at the root can be performed in constant time, as with a non-persistent array.
     145\TODO{port figure from slideshow}
     146
     147In Baker's persistent array, an array reference contains either a pointer to the array or a pointer to an \emph{edit node}; these edit nodes contain an array index, the value in that index, and another array reference pointing either to the array or a different edit node.
     148In this manner, a tree of edits is formed, rooted at the actual array.
     149Read from the actual array at the root can be performed in constant time, as with a non-persistent array.
    174150The persistent array can be mutated in constant time by directly modifying the underlying array, then replacing its array reference with an edit node containing the mutated index, the previous value at that index, and a reference to the mutated array. If the current array reference is not the root, mutation consists simply of constructing a new edit node encoding the change and referring to the current array reference. 
    175 
    176 The mutation algorithm at the root is a special case of the key operation on persistent arrays, $reroot$.
     151The mutation algorithm at the root is in some sense a special case of the key operation on persistent arrays, $reroot$.
     152
    177153A rerooting operation takes any array reference and makes it the root node of the array.
    178 This operation is accomplished by tracing the path from some edit node to actual array at the root node, recursively applying the edits to the underlying array and replacing each edit node's successor with the inverse edit.
     154This is accomplished by tracing the path from some edit node to the root node of the array (always the underlying array), recursively applying the edits to the underlying array and replacing each edit node's successor with the inverse edit.
    179155In this way, any previous state of the persistent array can be restored in time proportional to the number of edits to the current state of the array.
    180 While $reroot$ does maintain the same value mapping in every version of the persistent array, the internal mutations it performs break thread-safety, and thus it must be used behind a lock in a concurrent context.
     156While $reroot$ does maintain the same value mapping in every version of the persistent array, the internal mutations it performs means that it is not thread-safe, and must be used behind a lock in a concurrent context.
    181157Also, the root node with the actual array may in principle be anywhere in the tree, and does not provide information to report its leaf nodes, so some form of automatic garbage collection is generally required for the data structure.
    182158Since the graph of edit nodes is tree-structured, reference counting approaches suffice for garbage collection; Conchon and Filli\^{a}tre~\cite{Conchon07} also observe that if the only $reroot$ operations are for backtracking then the tail of inverse edit nodes may be elided, suggesting the possibility of stack-based memory management.
    183159
    184160While Conchon and Filli\^{a}tre~\cite{Conchon07} implement their persistent union-find data structure over a universe of integer elements in the fixed range $[1,N]$, the type environment problem needs more flexibility.
    185 In particular, an arbitrary number of type variables may be added to the environment.
    186 As such, a persistent hash table is a more suitable structure than a persistent array, providing the same expected asymptotic time bounds, while allowing a dynamic number of elements.
    187 Besides replacing the underlying array with a hash table, the other major change in this approach is to replace the two types of array references, !Array! and !Edit!, with four node types, !Table!,  !Edit!, !Add!, and !Remove!, where !Add! adds a new key-value pair, !Remove! removes a key-value pair, and !Edit! mutates an existing key-value pair.
    188 In this variant of \CFACC{}, this persistent hash-table is used as the side map discussed in Section~\ref{env-union-find-approach} for class bounds.
     161In particular, an arbitrary number of type variables must be added to the environment.
     162As such, a persistent hash table is a more suitable structure than a persistent array, providing the same expected asymptotic time bounds while allowing a dynamic number of elements.
     163Besides replacing the underlying array with a hash table, the other major change in this approach is to replace the two types of array references, !Array! and !Edit!, with four node types, !Table!,  !Edit!, !Add!, and !Remove!, where !Add! adds a new key-value pair, !Remove! removes a key, and !Edit! mutates an existing key-value pair.
     164In this variant of \CFACC{}, this persistent hash table is used as the side map discussed in Section~\ref{env-union-find-approach} for class bounds.
    189165The actual union-find data structure is slightly modified from this approach, with a !Base! node containing the root union-find data structure, !Add! nodes adding new elements, !AddTo! nodes defining the union of two type classes, and !Remove! and !RemoveFrom! nodes as inverses of the previous two elements, for purposes of maintaining the edit list.
    190 Figure~\ref{persistent-union-find-fig} demonstrates the structure of a simple example.
    191 Making !AddTo! and !RemoveFrom! single nodes provides semantic information missing from the raw array updates in Conchon and Filli\^{a}tre's data structure.
    192 !RemoveFrom! is implemented using the ``leaf of last union'' approach discussed in Section~\ref{env-union-find-classes-approach}; this does, however, preclude the use of path-compression algorithms in this persistent union-find data structure.
    193 
    194 \begin{figure}
    195         \centering
    196         \includegraphics{figures/persistent-union-find}
    197         \caption[Persistent union-find data structure.]{Persistent union-find data structure. Shows the edit nodes to reverse back to an empty structure.}
    198         \label{persistent-union-find-fig}
    199 \end{figure}
    200 
    201 This added semantic information on $union$ operations in the persistent union-find edit tree exposes a new option for combining type environments.
     166Making !AddTo! and !RemoveFrom! single nodes shortens the edit path for improved performance, while also providing semantic information missing from the raw array updates in Conchon and Filli\^{a}tre's data structure.
     167The single-node approach, does, however, break under most path-compression algorithms; !RemoveFrom! can be applied to the underlying data structure using the ``leaf of last union'' approach discussed in in Section~\ref{env-union-find-classes-approach}; this was judged an acceptable trade-off for the added semantic information and shortened paths.
     168
     169Maintaining explicit information on $union$ operations in the persistent union-find edit tree in the form of !AddTo! and !RemoveFrom! nodes exposes a new option for combining type environments.
    202170If the type environments are part of the same edit tree, one environment $T'$ can be combined with another $T$ by only testing the edits on the path from $T'$ to $T$ in both the persistent union-find data structure describing the classes and the persistent hash table containing the class bounds.
    203 This approach is generally more efficient than testing the compatibility of all type classes in $T'$, as only those that are actually different than those in $T$ must be considered.
    204 However, the improved performance comes at the cost of some flexibility, as the edit-tree link must be maintained between any two environments to be combined under this algorithm.
     171This is generally more efficient than testing the compatibility of all type classes in $T'$, as only those that are actually different than those in $T$ must be considered.
    205172
    206173The procedure for $combine(T, T')$ based on edit paths is as follows:
    207174The shared edit trees for classes and bindings are rerooted at $T$, and the path from $T'$ to $T$ is followed to create a list of actual edits.
    208175By tracking the state of each element, redundant changes such as an !Edit! followed by an !Edit! can be reduced to their form in $T'$ by dropping the later (more like $T$) !Edit! for the same key; !Add! and !Remove! cancel similarly.
    209 This procedure is repeated for both the class edit-tree and the binding edit-tree.
    210 When the list of net changes to the environment is produced, the additive changes are applied to $T$.
    211 For example, if a type class exists in $T'$ but not $T$, the corresponding !Add! edit is applied to $T$, but in the reverse situation the !Remove! edit is not applied to $T$, as the intention is to produce a new environment representing the union of the two sets of type classes; similarly, !AddTo! edits are applied to unify type-classes in $T$ that are united in $T'$, but !RemoveFrom! edits that split type classes are not.
    212 A new environment, $T''$, can always be constructed with a consistent partitioning of type variables; in the extreme case, all variables from both $T$ and $T'$ are united in a single type class in $T''$.
    213 $combine$ can fail to unify the bound types; if any class in $T'$ has a class bound that does not unify with the merged class in $T''$, then $combine$ fails.
    214 
    215 \section{Analysis} \label{env-analysis-sec}
    216 
    217 In this section, I present asymptotic analyses of the various approaches to the type environment data structure discussed in the previous section.
    218 My results are summarized in Table~\ref{env-bounds-table}; in all cases, $n$ is the number of type classes, $m$ is the maximum size of a type class, and $p$ the number of edits between two environments or one environment and the empty environment.
    219 $u(n)$ captures the recursive cost of class unification, which is kept separate so that the $O(n)$ number of recursive class unifications can be distinguished from the direct cost of each recursive step.
     176This procedure is repeated for both the class edit tree and the binding edit tree.
     177When the list of net changes to the environment has been produced, the additive changes are applied to $T$.
     178For example, if a type class exists in $T'$ but not $T$, the corresponding !Add! edit will be applied to $T$, but in the reverse situation the !Remove! edit will not be applied to $T$, as the intention is to produce a new environment representing the union of the two sets of type classes; similarly, !AddTo! edits are applied to unify type-classes in $T$ that are united in $T'$, but !RemoveFrom! edits that split type classes are not.
     179The new environment, $T''$ can always be constructed with a consistent partitioning of type variables; in the extreme case, all variables from both $T$ and $T'$ will be united in a single type class in $T''$.
     180Where $combine$ can fail is in unifying the bound types; if any class in $T'$ has a class bound which does not unify with the merged class in $T''$ than $combine$ fails.
     181
     182\section{Analysis}
     183
     184In this section I present asymptotic analyses of the various approaches to a type environment data structure discussed in the previous section.
    220185
    221186\begin{table}
     
    225190\begin{tabular}{rllll}
    226191        \hline
    227                                 & \textbf{Na\"{\i}ve} & \textbf{Incremental} & \textbf{Union-Find} & \textbf{Persistent U-F} \\
     192                                & \textbf{Na\"{\i}ve}   & \textbf{Incremental}  & \textbf{Union-Find}           & \textbf{U-F with Classes}             \\
    228193        \hline
    229         $find$          & $O(n)$                        & $O(p)$                        & $O(\alpha(m))$        & $O(\log m)$           \\
    230         $report$        & $O(m)$                        & $O(m)$                        & $O(nm\alpha(m))$      & $O(m)$                        \\
    231         $bound$         & $O(1)$                        & $O(1)$                        & $O(1)$                        & $O(1)$                        \\
    232         $insert$        & $O(1)$                        & $O(1)$                        & $O(1)$                        & $O(1)$                        \\
    233         $add$           & $O(1)$                        & $O(m)$                        & $O(1)$                        & $O(1)$                        \\
    234         $bind$          & $O(1)$                        & $O(1)$                        & $O(1)$                        & $O(1)$                        \\
    235         $unify$         & $O(m + u(n))$         & $O(m + u(n))$         & $O(1 + u(n))$         & $O(1 + u(n))$         \\
    236         $split$         & ---                           & ---                           & ---                           & $O(\log m)$           \\
    237         $combine$       & $O(n^2m $                     & $O(p^2m $                     & $O(nm\alpha(m) $      & $O(p \log m $         \\
    238                                 & $~~~+ nu(n))$         & $~~~+ pu(n))$         & $~~~+ nu(n))$         & $~~~+ pu(n))$         \\
    239         $save$          & $O(nm)$                       & $O(1)$                        & $O(nm)$                       & $O(1)$                        \\
    240         $backtrack$     & $O(nm)$                       & $O(pm)$                       & $O(nm)$                       & $O(p)$                        \\
     194        $find$          & $O(n)$                                & $O(p)$                                & $O(\alpha(m))$                        & $O(\log m)$                                   \\
     195        $report$        & $O(m)$                                & $O(m)$                                & $O(n \log m)$                         & $O(m)$                                                \\
     196        $bound$         & $O(1)$                                & $O(1)$                                & $O(1)$                                        & $O(1)$                                                \\
     197        $insert$        & $O(1)$                                & $O(1)$                                & $O(1)$                                        & $O(1)$                                                \\
     198        $add$           & $O(1)$                                & $O(1)$                                & $O(1)$                                        & $O(1)$                                                \\
     199        $bind$          & $O(1)$                                & $O(1)$                                & $O(1)$                                        & $O(1)$                                                \\
     200        $unify$         & $O(m + u(n))$                 & $O(m + u(n))$                 & $O(\log m + u(n))$            & $O(\log m + u(n))$                    \\
     201        $split$         & ---                                   & ---                                   & ---                                           & $O(\log m)$                                   \\
     202        $combine$       & $O(nm \cdot u(n))$    & $O(pm \cdot u(n))$    & $O(n \log m \cdot u(n))$      & $O(p \log m \cdot u(n))$              \\
     203        $save$          & $O(nm)$                               & $O(1)$                                & $O(nm)$                                       & $O(1)$                                                \\
     204        $backtrack$     & $O(nm)$                               & $O(pm)$                               & $O(nm)$                                       & $O(p)$                                                \\
    241205        \hline
    242206\end{tabular}
    243207\end{table}
    244208
    245 \subsection{Na\"{\i}ve and Incremental}
    246 \label{naive-incremental-analysis}
    247 
    248 The na\"{\i}ve type environment data structure does not have an environment-wide index for type variables, but does have an index for each type class, assumed to be hash-based here.
    249 As a result, every class's index must be consulted for a $find$ operation, at an overall cost of $O(n)$.
    250 The incremental variant builds an overall hash-based index as it is queried, but may need to recursively check its parent environments if its local index does not contain a type variable, and may have as many parents as times it has been modified, for cost $O(p)$.
    251 It should be noted that subsequent queries for the same variable execute in constant time.
    252 
    253 Since both na\"{\i}ve and incremental variants store complete type classes, the cost of a $report$ operation is simply the time needed to output the contained variables, $O(m)$.
    254 Since the type classes store their bounds, $bound$ and $bind$ are both $O(1)$ given a type class.
    255 Once a $find$ operation has already been performed to verify that a type variable does not exist in the environment, the data structures for both these variants support adding new type classes (the $insert$ operation) in $O(1)$.
    256 Adding a variable to a type class (the $add$ operation) can be done in $O(1)$ for the na\"{\i}ve implementation, but the incremental implementation may need to copy the edited type class from a parent at cost $O(m)$.
    257 
    258 The linear storage of type classes in both variants also leads to $O(m)$ time for the variable-merging step in $unify$, plus the usual $u(n)$ recursion term for $unifyBound$.
    259 The na\"{\i}ve $combine$ operation must traverse each of the classes of one environment, merging in any class of the other environment that shares a type variable.
    260 Since there are at most $n$ classes to unify, the unification cost is $O(nm + nu(n))$, while traversal and $find$ costs to locate classes to merge total $O(n^2m)$, for an overall cost of $O(n^2m + nu(n))$.
    261 The incremental $combine$ operation works similarly, but only needs to consider classes modified in either environment with respect to the common ancestor of both environments, allowing the $n$ cost terms to be substituted for $p$, for an overall cost of $O(p^2m + pu(n))$.
    262 Neither variant supports the $split$ operation to undo a $unify$.
    263 
    264 The na\"{\i}ve environment does nothing to support $save$ and $backtrack$, so these operations must be implemented by making a deep copy of the environment on $save$, then a destructive overwrite on $backtrack$, each at a cost of $O(nm)$.
    265 The incremental environment supports $O(1)$ $save$ by simply setting aside a reference to the current environment, then proceeding with a new, empty environment with the former environment as a parent.
    266 $backtrack$ to a parent environment may involve destroying all the intermediate environments if this backtrack removes the last reference to the backtracked-from environment; this cost is $O(pm)$.
    267 
    268 \subsection{Union-Find}
    269 
    270 The union-find data structure is designed to support $find$ efficiently, and thus for any variant, the cost is simply the distance up the tree to the representative element.
    271 For basic union-find, this is amortized to the inverse Ackermann function, $O(\alpha(m))$, essentially a small constant, though the loss of path compression in persistent union-find raises this cost to $O(\log m)$.
    272 Basic union-find is not designed to support the $report$ operation, however, so it must be simulated by checking the representative of every type variable, at cost $O(nm\alpha(m))$.
    273 Persistent union-find, on the other hand, uses the ``with classes'' extension to union-find described in Section~\ref{env-union-find-classes-approach} to run $report$ in $O(m)$ time.
    274 
    275 All union-find environment variants described here use a secondary hash table to map from class representatives to bindings, and as such can perform $bound$ and $bind$ in $O(1)$, given the representative.
    276 $insert$ is also a $O(1)$ operation for both basic and persistent union-find.
    277 Since $add$ simply involves attaching a new child to the class root, it is also a $O(1)$ operation for all union-find environment variants.
    278 
    279 Union-find is also designed to support $unify$ in constant time, and as such, given class representatives, the variable-merging cost of $unify$ for both variants is $O(1)$ to make one representative the child of the other, plus the $O(u(n))$ term for $unifyBound$.
    280 Basic union-find does not support $split$, but persistent union-find can accomplish it using the mechanism described in Section~\ref{env-union-find-classes-approach} in $O(\log m)$, the cost of traversing up to the root of a class from a leaf without path compression.
    281 $combine$ on the basic union-find data structure works similarly to the data structures discussed above in Section~\ref{naive-incremental-analysis}, with a $O(nu(n))$ term for the $O(n)$ underlying $unify$ operations, and a $O(n\alpha(m))$ term to find the classes which need unification by checking the class representatives of each corresponding type variable in both environments for equality.
    282 Persistent union-find uses a different approach for $combine$, discussed in Section~\ref{env-persistent-union-find}.
    283 Discounting recursive $unify$ operations included in the $u(n)$ $unifyBound$ term, there may be at most $O(p)$ $unify$ operations performed, at cost $O(pu(n))$.
    284 Each of the $O(p)$ steps on the edit path can be processed in the $O(\log m)$ time it takes to find the current representative of the modified type class, for a total runtime of $O(p \log m + pu(n))$.
    285 
    286 In terms of backtracking operations, the basic union-find data structure only supports deep copies, for $O(nm)$ cost for both $save$ and $backtrack$.
    287 Persistent union-find, as the name suggests, is more optimized, with $O(1)$ cost to $save$ a backtrack-capable reference to the current environment state, and $O(p)$ cost to revert to that state (possibly destroying no-longer-used edit nodes along the path).
    288 
    289 \section{Conclusion \& Future Work}
    290 
    291 This chapter presents the type environment abstract data type, some type-environment data-structures optimized for workloads encountered in the expression resolution problem, and asymptotic analysis of each data structure.
    292 Chapter~\ref{expr-chap} provides experimental performance results for a representative set of these approaches.
    293 One contribution of this thesis is the union-find with classes data structure for efficient retrieval of union-find class members, along with a related algorithm for reversing the history of $union$ operations in this data structure.
    294 This reversible history contributes to the second novel contribution of this chapter, a type environment data structure based off the persistent union-find data structure of Conchon and Filli\^{a}tre~\cite{Conchon07}.
    295 This persistent union-find environment uses the $split$ operation introduced in union-find with classes and the edit history of the persistent data structure to support an environment-combining algorithm that only considers the edits between the environments to be merged.
    296 
    297 This persistent union-find data structure is efficient, but not thread-safe; as suggested in Section~\ref{resn-conclusion-sec}, it may be valuable to parallelize the \CFA{} expression resolver.
    298 However, allowing multiple threads concurrent access to the persistent data structure is likely to result in ``reroot thrashing'', as different threads reroot the data structure to their own versions of interest.
    299 This contention could be mitigated by partitioning the data structure into separate subtrees for each thread, with each subtree having its own root node, and the boundaries among them implemented with a lock-equipped !ThreadBoundary! edit node.
    300 Alternatively, the concurrent hash trie of Prokopec \etal{} \cite{Prokopec11,Prokopec12} may be a useful hash-table replacement.
     209% Future work: design multi-threaded version of C&F persistent map --- core idea is some sort of thread-boundary edit node
  • doc/user/user.tex

    r933f32f r6a9d4b4  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sun May  5 18:24:50 2019
    14 %% Update Count     : 3489
     13%% Last Modified On : Tue Dec 11 23:19:26 2018
     14%% Update Count     : 3400
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    193193\end{center}
    194194While the \CFA I/O looks similar to the \Index*[C++]{\CC{}} output style, there are important differences, such as automatic spacing between variables as in \Index*{Python} (see~\VRef{s:IOLibrary}).
    195 
    196195
    197196\subsection{Background}
     
    433432which conditionally includes the correct header file, if the program is compiled using \Indexc{gcc} or \Indexc{cfa}.
    434433
    435 The \CFA translator has multiple steps.
    436 The following flags control how the tranlator works, the stages run, and printing within a stage.
    437 The majority of these flags are used by \CFA developers, but some are occasionally useful to programmers.
    438 \begin{description}[topsep=5pt,itemsep=0pt,parsep=0pt]
    439 \item
    440 \Indexc{-h}\index{translator option!-h@{©-h©}}, \Indexc{--help}\index{translator option!--help@{©--help©}} \, print help message
    441 \item
    442 \Indexc{-l}\index{translator option!-l@{©-l©}}, \Indexc{--libcfa}\index{translator option!--libcfa@{©--libcfa©}} \, generate libcfa.c
    443 \item
    444 \Indexc{-L}\index{translator option!-L@{©-L©}}, \Indexc{--linemarks}\index{translator option!--linemarks@{©--linemarks©}} \, generate line marks
    445 \item
    446 \Indexc{-m}\index{translator option!-m@{©-m©}}, \Indexc{--no-main}\index{translator option!--no-main@{©--no-main©}} \, do not replace main
    447 \item
    448 \Indexc{-N}\index{translator option!-N@{©-N©}}, \Indexc{--no-linemarks}\index{translator option!--no-linemarks@{©--no-linemarks©}} \, do not generate line marks
    449 \item
    450 \Indexc{-n}\index{translator option!-n@{©-n©}}, \Indexc{--no-prelude}\index{translator option!--no-prelude@{©--no-prelude©}} \, do not read prelude
    451 \item
    452 \Indexc{-p}\index{translator option!-p@{©-p©}}, \Indexc{--prototypes}\index{translator option!--prototypes@{©--prototypes©}} \, generate prototypes for prelude functions
    453 \item
    454 \Indexc{-P}\index{translator option!-P@{©-P©}}, \Indexc{--print}\index{translator option!--print@{©--print©}} \, one of:
    455 \begin{description}[topsep=0pt,itemsep=0pt,parsep=0pt]
    456 \item
    457 \Indexc{altexpr}\index{translator option!-P@{©-P©}!©altexpr©}\index{translator option!--print@{©-print©}!©altexpr©} \, alternatives for expressions
    458 \item
    459 \Indexc{ascodegen}\index{translator option!-P@{©-P©}!©ascodegen©}\index{translator option!--print@{©-print©}!©ascodegen©} \, as codegen rather than AST
    460 \item
    461 \Indexc{ast}\index{translator option!-P@{©-P©}!©ast©}\index{translator option!--print@{©-print©}!©ast©} \, AST after parsing
    462 \item
    463 \Indexc{astdecl}\index{translator option!-P@{©-P©}!©astdecl©}\index{translator option!--print@{©-print©}!©astdecl©} \, AST after declaration validation pass
    464 \item
    465 \Indexc{asterr}\index{translator option!-P@{©-P©}!©asterr©}\index{translator option!--print@{©-print©}!©asterr©} \, AST on error
    466 \item
    467 \Indexc{astexpr}\index{translator option!-P@{©-P©}!©astexpr©}\index{translator option!--print@{©-print©}!©altexpr©} \, AST after expression analysis
    468 \item
    469 \Indexc{astgen}\index{translator option!-P@{©-P©}!©astgen©}\index{translator option!--print@{©-print©}!©astgen©} \, AST after instantiate generics
    470 \item
    471 \Indexc{box}\index{translator option!-P@{©-P©}!©box©}\index{translator option!--print@{©-print©}!©box©} \, before box step
    472 \item
    473 \Indexc{ctordtor}\index{translator option!-P@{©-P©}!©ctordtor©}\index{translator option!--print@{©-print©}!©ctordtor©} \, after ctor/dtor are replaced
    474 \item
    475 \Indexc{codegen}\index{translator option!-P@{©-P©}!©codegen©}\index{translator option!--print@{©-print©}!©codegen©} \, before code generation
    476 \item
    477 \Indexc{declstats}\index{translator option!-P@{©-P©}!©declstats©}\index{translator option!--print@{©-print©}!©declstats©} \, code property statistics
    478 \item
    479 \Indexc{parse}\index{translator option!-P@{©-P©}!©parse©}\index{translator option!--print@{©-print©}!©parse©} \, yacc (parsing) debug information
    480 \item
    481 \Indexc{pretty}\index{translator option!-P@{©-P©}!©pretty©}\index{translator option!--print@{©-print©}!©pretty©} \, prettyprint for ascodegen flag
    482 \item
    483 \Indexc{resolver}\index{translator option!-P@{©-P©}!©resolver©}\index{translator option!--print@{©-print©}!©resolver©} \, before resolver step
    484 \item
    485 \Indexc{rproto}\index{translator option!-P@{©-P©}!©rproto©}\index{translator option!--print@{©-print©}!©rproto©} \, resolver-proto instance
    486 \item
    487 \Indexc{rsteps}\index{translator option!-P@{©-P©}!©rsteps©}\index{translator option!--print@{©-print©}!©rsteps©} \, resolver steps
    488 \item
    489 \Indexc{symevt}\index{translator option!-P@{©-P©}!©symevt©}\index{translator option!--print@{©-print©}!©symevt©} \, symbol table events
    490 \item
    491 \Indexc{tree}\index{translator option!-P@{©-P©}!©tree©}\index{translator option!--print@{©-print©}!©tree©} \, parse tree
    492 \item
    493 \Indexc{tuple}\index{translator option!-P@{©-P©}!©tuple©}\index{translator option!--print@{©-print©}!©tuple©} \, after tuple expansion
    494 \end{description}
    495 \item
    496 \Indexc{--prelude-dir} <directory> \, prelude directory for debug/nodebug
    497 \item
    498 \Indexc{-S}\index{translator option!-S@{©-S©}!©counters,heap,time,all,none©}, \Indexc{--statistics}\index{translator option!--statistics@{©--statistics©}!©counters,heap,time,all,none©} <option-list> \, enable profiling information:
    499 \begin{description}[topsep=0pt,itemsep=0pt,parsep=0pt]
    500 \item
    501 \Indexc{counters,heap,time,all,none}
    502 \end{description}
    503 \item
    504 \Indexc{-t}\index{translator option!-t@{©-t©}}, \Indexc{--tree}\index{translator option!--tree@{©--tree©}} build in tree
    505 \end{description}
    506 
    507434
    508435\section{Backquote Identifiers}
     
    581508
    582509As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
    583 Integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the exponent is 2).
    584 Overflow from large exponents or negative exponents return zero.
    585 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
    586 \begin{cfa}
    587 sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\® 2.1
    588            | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
    589 1 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
    590 \end{cfa}
    591 Note, ©5 ®\® 32© and ©5L ®\® 64© overflow, and ©-4 ®\® -3© is a fraction but stored in an integer so all three computations generate an integral zero.
     510Unsigned integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the base is 2).
     511Signed integral exponentiation\index{exponentiation!signed integral} is performed with repeated multiplication (or shifting if the base is 2), but yields a floating result because $x^{-y}=1/x^y$.
     512Hence, it is important to designate exponent integral-constants as unsigned or signed: ©3 \ 3u© return an integral result, while ©3 \ 3© returns a floating result.
     513Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the base cannot be negative.
     514\begin{cfa}
     515sout | 2 ®\® 8u | 4 ®\® 3u | -4 ®\® 3u | 4 ®\® -3 | -4 ®\® -3 | 4.0 ®\® 2.1 | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
     516256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
     517\end{cfa}
    592518Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©.
    593 The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation version is available.
    594 \begin{cfa}
    595 forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } )
    596 OT ?®\®?( OT ep, unsigned int y );
    597 forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } )
    598 OT ?®\®?( OT ep, unsigned long int y );
    599 \end{cfa}
    600 The user type ©T© must define multiplication, one, ©1©, and, ©*©.
     519The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation versions are available.
     520For returning an integral value, the user type ©T© must define multiplication, ©*©, and one, ©1©;
     521for returning a floating value, an additional divide of type ©T© into a ©double© returning a ©double© (©double ?/?( double, T )©) is necessary for negative exponents.
    601522
    602523
     
    628549\subsection{Loop Control}
    629550
    630 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
    631 \begin{itemize}
    632 \item
     551The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges.
    633552An empty conditional implies ©1©.
    634 \item
    635 The up-to range ©~©\index{~@©~©} means exclusive range [M,N).
    636 \item
    637 The up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N].
    638 \item
    639 The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M).
    640 \item
    641 The down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M].
    642 \item
    643 ©@© means put nothing in this field.
    644 \item
     553The up-to range ©~©\index{~@©~©} means exclusive range [M,N);
     554the up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N].
     555The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M);
     556the down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M].
    645557©0© is the implicit start value;
    646 \item
    647558©1© is the implicit increment value.
    648 \item
    649559The up-to range uses ©+=© for increment;
    650 \item
    651 The down-to range uses ©-=© for decrement.
    652 \item
     560the down-to range uses ©-=© for decrement.
    653561The loop index is polymorphic in the type of the start value or comparison value when start is implicitly ©0©.
    654 \end{itemize}
    655 
    656 \begin{figure}
    657562\begin{cquote}
    658 \begin{tabular}{@{}l|l@{}}
    659 \multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\
     563\begin{tabular}{@{}ll|l@{}}
     564\multicolumn{2}{c|}{loop control} & \multicolumn{1}{c}{output} \\
    660565\hline
    661566\begin{cfa}
    662 sout | nlOff;
    663 while ®()® { sout | "empty"; break; } sout | nl;
    664 do { sout | "empty"; break; } while ®()®; sout | nl;
    665 for ®()® { sout | "empty"; break; } sout | nl;
    666 for ( ®0® ) { sout | "A"; } sout | "zero" | nl;
    667 for ( ®1® ) { sout | "A"; } sout | nl;
    668 for ( ®10® ) { sout | "A"; } sout | nl;
    669 for ( ®1 ~= 10 ~ 2® ) { sout | "B"; } sout | nl;
    670 for ( ®10 -~= 1 ~ 2® ) { sout | "C"; } sout | nl;
    671 for ( ®0.5 ~ 5.5® ) { sout | "D"; } sout | nl;
    672 for ( ®5.5 -~ 0.5® ) { sout | "E"; } sout | nl;
    673 for ( ®i; 10® ) { sout | i; } sout | nl;
    674 for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; } sout | nl;
    675 for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; } sout | nl;
    676 for ( ®i; 0.5 ~ 5.5® ) { sout | i; } sout | nl;
    677 for ( ®i; 5.5 -~ 0.5® ) { sout | i; } sout | nl;
    678 for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; } sout | nl;
    679 for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; } sout | nl;
     567while ®()® { sout | "empty"; break; }
     568do { sout | "empty"; break; } while ®()®;
     569for ®()® { sout | "empty"; break; }
     570for ( ®0® ) { sout | "A"; }
     571for ( ®1® ) { sout | "A"; }
     572for ( ®10® ) { sout | "A"; }
     573for ( ®1 ~= 10 ~ 2® ) { sout | "B"; }
     574for ( ®10 -~= 1 ~ 2® ) { sout | "C"; }
     575for ( ®0.5 ~ 5.5® ) { sout | "D"; }
     576for ( ®5.5 -~ 0.5® ) { sout | "E"; }
     577for ( ®i; 10® ) { sout | i; }
     578for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; }
     579for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; }
     580for ( ®i; 0.5 ~ 5.5® ) { sout | i; }
     581for ( ®i; 5.5 -~ 0.5® ) { sout | i; }
     582for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; }
     583for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; }
    680584enum { N = 10 };
    681 for ( ®N® ) { sout | "N"; } sout | nl;
    682 for ( ®i; N® ) { sout | i; } sout | nl;
    683 for ( ®i; N -~ 0® ) { sout | i; } sout | nl;
     585for ( ®N® ) { sout | "N"; }
     586for ( ®i; N® ) { sout | i; }
     587for ( ®i; N -~ 0® ) { sout | i; }
    684588const int start = 3, comp = 10, inc = 2;
    685 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } sout | nl;
    686 for ( ®i; 1 ~ @® ) { if ( i > 10 ) break;
    687         sout | i; } sout | nl;
    688 for ( ®i; 10 -~ @® ) { if ( i < 0 ) break;
    689         sout | i; } sout | nl;
    690 for ( ®i; 2 ~ @ ~ 2® ) { if ( i > 10 ) break;
    691         sout | i; } sout | nl;
    692 for ( ®i; 2.1 ~ @ ~ @® ) { if ( i > 10.5 ) break;
    693         sout | i; i += 1.7; } sout | nl;
    694 for ( ®i; 10 -~ @ ~ 2® ) { if ( i < 0 ) break;
    695         sout | i; } sout | nl;
    696 for ( ®i; 12.1 ~ @ ~ @® ) { if ( i < 2.5 ) break;
    697         sout | i; i -= 1.7; } sout | nl;
    698 for ( ®i; 5 : j; -5 ~ @® ) { sout | i | j; } sout | nl;
    699 for ( ®i; 5 : j; -5 -~ @® ) { sout | i | j; } sout | nl;
    700 for ( ®i; 5 : j; -5 ~ @ ~ 2® ) { sout | i | j; } sout | nl;
    701 for ( ®i; 5 : j; -5 -~ @ ~ 2® ) { sout | i | j; } sout | nl;
    702 for ( ®j; -5 ~ @ : i; 5® ) { sout | i | j; } sout | nl;
    703 for ( ®j; -5 -~ @ : i; 5® ) { sout | i | j; } sout | nl;
    704 for ( ®j; -5 ~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl;
    705 for ( ®j; -5 -~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl;
    706 for ( ®j; -5 -~ @ ~ 2 : i; 5 : k; 1.5 ~ @® ) {
    707         sout | i | j | k; } sout | nl;
    708 for ( ®j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 5® ) {
    709         sout | i | j | k; } sout | nl;
    710 for ( ®k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 5® ) {
    711         sout | i | j | k; } sout | nl;
     589for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; }
    712590\end{cfa}
    713591&
    714592\begin{cfa}
    715 
     593sout | nl;
     594sout | nl;
     595sout | nl;
     596sout | "zero" | nl;
     597sout | nl;
     598sout | nl;
     599sout | nl;
     600sout | nl;
     601sout | nl;
     602sout | nl;
     603sout | nl;
     604sout | nl;
     605sout | nl;
     606sout | nl;
     607sout | nl;
     608sout | nl;
     609sout | nl | nl;
     610
     611sout | nl;
     612sout | nl;
     613sout | nl | nl;
     614
     615sout | nl;
     616\end{cfa}
     617&
     618\begin{cfa}
    716619empty
    717620empty
     
    737640
    7386413 6 9
    739 
    740 1 2 3 4 5 6 7 8 9 10
    741 
    742 10 9 8 7 6 5 4 3 2 1 0
    743 
    744 2 4 6 8 10
    745 
    746 2.1 3.8 5.5 7.2 8.9
    747 
    748 10 8 6 4 2 0
    749 
    750 12.1 10.4 8.7 7 5.3 3.6
    751 0 -5 1 -4 2 -3 3 -2 4 -1
    752 0 -5 1 -6 2 -7 3 -8 4 -9
    753 0 -5 1 -3 2 -1 3 1 4 3
    754 0 -5 1 -7 2 -9 3 -11 4 -13
    755 0 -5 1 -4 2 -3 3 -2 4 -1
    756 0 -5 1 -6 2 -7 3 -8 4 -9
    757 0 -5 1 -3 2 -1 3 1 4 3
    758 0 -5 1 -7 2 -9 3 -11 4 -13
    759 
    760 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    761 
    762 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    763 
    764 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    765642\end{cfa}
    766643\end{tabular}
    767644\end{cquote}
    768 \caption{Loop Control Examples}
    769 \label{f:LoopControlExamples}
    770 \end{figure}
    771645
    772646
     
    14461320\end{cfa}
    14471321Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
    1448 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise:
    1449 \begin{quote}
    1450 In spite of its difficulties, I believe that the C's approach to declarations remains plausible, and am comfortable with it; it is a useful unifying principle.~\cite[p.~12]{Ritchie93}
    1451 \end{quote}
     1322While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice.
    14521323
    14531324\CFA provides its own type, variable and routine declarations, using a different syntax.
  • driver/Makefile.am

    r933f32f r6a9d4b4  
    1919
    2020# applies to both programs
    21 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src -I${abs_top_srcdir}/src/include
     21AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src
    2222
    2323# don't install cfa directly
  • driver/Makefile.in

    r933f32f r6a9d4b4  
    187187DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    188188ACLOCAL = @ACLOCAL@
     189ALLOCA = @ALLOCA@
    189190AMTAR = @AMTAR@
    190191AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    334335
    335336# applies to both programs
    336 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src -I${abs_top_srcdir}/src/include
     337AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src
    337338cfa_SOURCES = cfa.cc
    338339
  • driver/cfa.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 10 08:28:09 2019
    13 // Update Count     : 281
     12// Last Modified On : Tue Jan 15 20:56:03 2019
     13// Update Count     : 280
    1414//
    1515
     
    107107        bool link = true;                                                                       // linking as well as compiling
    108108        bool verbose = false;                                                           // -v flag
    109         bool quiet = false;                                                             // -quiet flag
    110         bool debug = true;                                                              // -debug flag
    111         bool nolib = false;                                                             // -nolib flag
    112         bool help = false;                                                              // -help flag
     109        bool quiet = false;                                                                     // -quiet flag
     110        bool debug = true;                                                                      // -debug flag
     111        bool help = false;                                                                      // -help flag
    113112        bool CFA_flag = false;                                                          // -CFA flag
    114113        bool cpp_flag = false;                                                          // -E or -M flag, preprocessor only
     
    163162                                debug = true;                                                   // strip the debug flag
    164163                        } else if ( arg == "-nodebug" ) {
    165                                 debug = false;                                                  // strip the debug flag
    166                         } else if ( arg == "-nolib" ) {
    167                                 nolib = true;                                                   // strip the nodebug flag
     164                                debug = false;                                                  // strip the nodebug flag
    168165                        } else if ( arg == "-quiet" ) {
    169166                                quiet = true;                                                   // strip the quiet flag
     
    369366                }  // if
    370367        } // if
    371         const char * config = nolib ? "nolib" : (debug ? "debug": "nodebug");
     368        const char * config = debug ? "debug": "nodebug";
    372369        string libdir = libbase + arch + "-" + config;
    373370
    374         if ( ! nolib && ! dirExists( libdir ) ) {
     371        if ( ! dirExists( libdir ) ) {
    375372                cerr << argv[0] << " internal error, configuration " << config << " not installed." << endl;
    376373                cerr << "Was looking for " << libdir << endl;
     
    498495                args[nargs] = "-Wno-deprecated";
    499496                nargs += 1;
    500 #ifdef HAVE_CAST_FUNCTION_TYPE
    501                 args[nargs] = "-Wno-cast-function-type";
    502                 nargs += 1;
    503 #endif // HAVE_CAST_FUNCTION_TYPE
    504497                if ( ! std_flag ) {                                                             // default c11, if none specified
    505498                        args[nargs] = "-std=gnu11";
  • libcfa/configure

    r933f32f r6a9d4b4  
    23822382
    23832383
    2384 # http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m4
    2385 
    23862384
    23872385am__api_version='1.15'
     
    29592957case $CONFIGURATION in
    29602958        "debug"   )
    2961                 CONFIG_CFLAGS="-Og -g"
     2959                CONFIG_CFLAGS="-O0 -g"
    29622960                CONFIG_CFAFLAGS="-debug"
    29632961                CONFIG_BUILDLIB="yes"
    29642962        ;;
    29652963        "nodebug" )
    2966                 CONFIG_CFLAGS="-O3 -s"
     2964                CONFIG_CFLAGS="-O2 -s"
    29672965                CONFIG_CFAFLAGS="-nodebug"
    29682966                CONFIG_BUILDLIB="yes"
    29692967        ;;
    29702968        "nolib"   )
    2971                 CONFIG_CFLAGS="-O3 -s"
    2972                 CONFIG_CFAFLAGS="-nolib"
     2969                CONFIG_CFLAGS="-O2 -s"
     2970                CONFIG_CFAFLAGS="-nodebug"
    29732971                CONFIG_BUILDLIB="no"
    2974         ;;
    2975         "profile" )
    2976                 CONFIG_CFLAGS="-O3 -g -fno-omit-frame-pointer"
    2977                 CONFIG_CFAFLAGS="-nodebug"
    2978                 CONFIG_BUILDLIB="yes"
    29792972        ;;
    29802973        *)
     
    29822975        ;;
    29832976esac
    2984 
    2985 CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}"
    29862977
    29872978
  • libcfa/configure.ac

    r933f32f r6a9d4b4  
    4545case $CONFIGURATION in
    4646        "debug"   )
    47                 CONFIG_CFLAGS="-Og -g"
     47                CONFIG_CFLAGS="-O0 -g"
    4848                CONFIG_CFAFLAGS="-debug"
    4949                CONFIG_BUILDLIB="yes"
    5050        ;;
    5151        "nodebug" )
    52                 CONFIG_CFLAGS="-O3 -s"
     52                CONFIG_CFLAGS="-O2 -s"
    5353                CONFIG_CFAFLAGS="-nodebug"
    5454                CONFIG_BUILDLIB="yes"
    5555        ;;
    5656        "nolib"   )
    57                 CONFIG_CFLAGS="-O3 -s"
    58                 CONFIG_CFAFLAGS="-nolib"
     57                CONFIG_CFLAGS="-O2 -s"
     58                CONFIG_CFAFLAGS="-nodebug"
    5959                CONFIG_BUILDLIB="no"
    60         ;;
    61         "profile" )
    62                 CONFIG_CFLAGS="-O3 -g -fno-omit-frame-pointer"
    63                 CONFIG_CFAFLAGS="-nodebug"
    64                 CONFIG_BUILDLIB="yes"
    6560        ;;
    6661        *)
     
    6863        ;;
    6964esac
    70 
    71 CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}"
    7265
    7366AC_SUBST(CONFIG_CFLAGS)
  • libcfa/prelude/builtins.c

    r933f32f r6a9d4b4  
    1010// Created On       : Fri Jul 21 16:21:03 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 26 23:10:36 2019
    13 // Update Count     : 95
     12// Last Modified On : Sun Aug  5 21:40:38 2018
     13// Update Count     : 20
    1414//
    1515
     
    4242typedef unsigned long long __cfaabi_abi_exception_type_t;
    4343
    44 #include <limits.h>                                                                             // CHAR_BIT
    4544#include "../src/virtual.h"
    4645#include "../src/exception.h"
     
    5150// increment/decrement unification
    5251
    53 static inline {
    54         forall( dtype DT | { DT & ?+=?( DT &, one_t ); } )
    55         DT & ++?( DT & x ) { return x += 1; }
     52static inline forall( dtype T | { T& ?+=?( T&, one_t ); } )
     53T& ++? ( T& x ) { return x += 1; }
    5654
    57         forall( dtype DT | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?+=?( DT &, one_t ); } )
    58         DT & ?++( DT & x ) { DT tmp = x; x += 1; return tmp; }
     55static inline forall( dtype T | sized(T) | { void ?{}( T&, T ); void ^?{}( T& ); T& ?+=?( T&, one_t ); } )
     56T& ?++ ( T& x ) { T tmp = x; x += 1; return tmp; }
    5957
    60         forall( dtype DT | { DT & ?-=?( DT &, one_t ); } )
    61         DT & --?( DT & x ) { return x -= 1; }
     58static inline forall( dtype T | { T& ?-=?( T&, one_t ); } )
     59T& --? ( T& x ) { return x -= 1; }
    6260
    63         forall( dtype DT | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?-=?( DT &, one_t ); } )
    64         DT & ?--( DT & x ) { DT tmp = x; x -= 1; return tmp; }
    65 } // distribution
    66 
    67 // universal typed pointer constant
    68 // Compiler issue: there is a problem with anonymous types that do not have a size.
    69 static inline forall( dtype DT | sized(DT) ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }
     61static inline forall( dtype T | sized(T) | { void ?{}( T&, T ); void ^?{}( T& ); T& ?-=?( T&, one_t ); } )
     62T& ?-- ( T& x ) { T tmp = x; x -= 1; return tmp; }
    7063
    7164// exponentiation operator implementation
     
    8073} // extern "C"
    8174
    82 static inline {
    83         float ?\?( float x, float y ) { return powf( x, y ); }
    84         double ?\?( double x, double y ) { return pow( x, y ); }
    85         long double ?\?( long double x, long double y ) { return powl( x, y ); }
    86         float _Complex ?\?( float _Complex x, _Complex float y ) { return cpowf(x, y ); }
    87         double _Complex ?\?( double _Complex x, _Complex double y ) { return cpow( x, y ); }
    88         long double _Complex ?\?( long double _Complex x, _Complex long double y ) { return cpowl( x, y ); }
    89 } // distribution
     75static inline float ?\?( float x, float y ) { return powf( x, y ); }
     76static inline double ?\?( double x, double y ) { return pow( x, y ); }
     77static inline long double ?\?( long double x, long double y ) { return powl( x, y ); }
     78static inline float _Complex ?\?( float _Complex x, _Complex float y ) { return cpowf(x, y ); }
     79static inline double _Complex ?\?( double _Complex x, _Complex double y ) { return cpow( x, y ); }
     80static inline long double _Complex ?\?( long double _Complex x, _Complex long double y ) { return cpowl( x, y ); }
    9081
    91 #define __CFA_BASE_COMP_1__() if ( ep == 1 ) return 1
    92 #define __CFA_BASE_COMP_2__() if ( ep == 2 ) return ep << (y - 1)
    93 #define __CFA_EXP_OVERFLOW__() if ( y >= sizeof(y) * CHAR_BIT ) return 0
     82static inline long int ?\?( long int ep, unsigned long int y ) { // disallow negative exponent
     83        if ( y == 0 ) return 1;                                                         // base case
     84        if ( ep == 2 ) return ep << (y - 1);                            // special case, positive shifting only
     85        typeof( ep ) op = 1;                                                            // accumulate odd product
     86        for ( ; y > 1; y >>= 1 ) {                                                      // squaring exponentiation, O(log2 y)
     87                if ( (y & 1) == 1 ) op *= ep;                                   // odd ?
     88                ep *= ep;
     89        } // for
     90        return ep * op;
     91} // ?\?
    9492
    95 #define __CFA_EXP__() \
    96         if ( y == 0 ) return 1;                                                         /* convention */ \
    97         __CFA_BASE_COMP_1__();                                                          /* base case */ \
    98         __CFA_BASE_COMP_2__();                                                          /* special case, positive shifting for integral types */ \
    99         __CFA_EXP_OVERFLOW__();                                                         /* immediate overflow, negative exponent > 2^size-1 */ \
    100         typeof(ep) op = 1;                                                                      /* accumulate odd product */ \
    101         for ( ; y > 1; y >>= 1 ) {                                                      /* squaring exponentiation, O(log2 y) */ \
    102                 if ( (y & 1) == 1 ) op = op * ep;                               /* odd ? */ \
    103                 ep = ep * ep; \
    104         } \
    105         return ep * op
     93static inline forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } )
     94T ?\?( T ep, unsigned long int y ) {
     95        if ( y == 0 ) return 1;
     96        T op = 1;
     97        for ( ; y > 1; y >>= 1 ) {                                                      // squaring exponentiation, O(log2 y)
     98                if ( (y & 1) == 1 ) op = op * ep;                               // odd ?
     99                ep = ep * ep;
     100        } // for
     101        return ep * op;
     102} // ?\?
    106103
    107 static inline {
    108         long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); }
    109         long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); }
    110         // unsigned computation may be faster and larger
    111         unsigned long int ?\?( unsigned int ep, unsigned int y ) { __CFA_EXP__(); }
    112         unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { __CFA_EXP__(); }
    113 } // distribution
     104// unsigned computation may be faster and larger
     105static inline unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { // disallow negative exponent
     106        if ( y == 0 ) return 1;                                                         // base case
     107        if ( ep == 2 ) return ep << (y - 1);                            // special case, positive shifting only
     108        typeof( ep ) op = 1;                                                            // accumulate odd product
     109        for ( ; y > 1; y >>= 1 ) {                                                      // squaring exponentiation, O(log2 y)
     110                if ( (y & 1) == 1 ) op *= ep;                                   // odd ?
     111                ep *= ep;
     112        } // for
     113        return ep * op;
     114} // ?\?
    114115
    115 #undef __CFA_BASE_COMP_1__
    116 #undef __CFA_BASE_COMP_2__
    117 #undef __CFA_EXP_OVERFLOW__
    118 #define __CFA_BASE_COMP_1__()
    119 #define __CFA_BASE_COMP_2__()
    120 #define __CFA_EXP_OVERFLOW__()
     116static inline double ?\?( long int x, signed long int y ) {     // allow negative exponent
     117        if ( y >=  0 ) return (double)(x \ (unsigned long int)y);
     118        else return 1.0 / x \ (unsigned int)(-y);
     119} // ?\?
    121120
    122 static inline forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) {
    123         OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); }
    124         OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); }
    125 } // distribution
     121// FIXME (x \ (unsigned long int)y) relies on X ?\?(T, unsigned long) a function that is neither
     122// defined, nor passed as an assertion parameter. Without user-defined conversions, cannot specify
     123// X as a type that casts to double, yet it doesn't make sense to write functions with that type
     124// signature where X is double.
    126125
    127 #undef __CFA_BASE_COMP_1__
    128 #undef __CFA_BASE_COMP_2__
    129 #undef __CFA_EXP_OVERFLOW__
     126// static inline forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); double ?/?( double, T ); } )
     127// double ?\?( T x, signed long int y ) {
     128//     if ( y >=  0 ) return (double)(x \ (unsigned long int)y);
     129//     else return 1.0 / x \ (unsigned long int)(-y);
     130// } // ?\?
    130131
    131 static inline {
    132         long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
    133         unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
    134         int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; }
    135         unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
    136 } // distribution
     132static inline long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
     133static inline unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
     134static inline int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; }
     135static inline unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
    137136
    138137// Local Variables: //
  • libcfa/prelude/extras.c

    r933f32f r6a9d4b4  
    1 #include <stddef.h>                                     // size_t, ptrdiff_t, intptr_t, uintptr_t
     1#include <stddef.h>                                     // size_t, ptrdiff_t
    22#include <stdint.h>                                     // intX_t, uintX_t, where X is 8, 16, 32, 64
    33#include <uchar.h>                                      // char16_t, char32_t
  • libcfa/prelude/extras.regx

    r933f32f r6a9d4b4  
    11typedef.* size_t;
    22typedef.* ptrdiff_t;
    3 typedef.* intptr_t;
    4 typedef.* uintptr_t;
    53typedef.* __int8_t;
    64typedef.* __int16_t;
  • libcfa/prelude/prelude-gen.cc

    r933f32f r6a9d4b4  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // prelude-gen.cc --
    8 //
    9 // Author           : Rob Schluntz and Thierry Delisle
    10 // Created On       : Sat Feb 16 08:44:58 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr  2 17:18:24 2019
    13 // Update Count     : 37
    14 //
    15 
    161#include <algorithm>
    172#include <array>
     
    2611        bool hasComparison;
    2712} basicTypes[] = {
    28         { "char"                  , false, true , },
    29         { "signed char"           , false, true , },
    30         { "unsigned char"         , false, true , },
     13        // { "char"                  , false, true , },
     14        // { "signed char"           , false, true , },
     15        // { "unsigned char"         , false, true , },
    3116        { "signed short"          , false, true , },
    3217        { "unsigned short"        , false, true , },
     
    4934#if defined(__i386__) || defined(__ia64__) || defined(__x86_64__)
    5035        { "__float80"             , true , true , },
    51         { "__float128"            , true , true , },
     36        { "_Float128"             , true , true , },
    5237#endif
    5338};
     
    118103        { "?!=?", false, "signed int", Normal, "" },
    119104        { "?=?", true, "", Normal, "" }, // void * LHS, zero_t RHS ???
    120 //      { "*?", false, "&", Normal, " | sized(DT)" }, // & ???
    121         { "*?", false, "&", Normal, "" }, // & ???
     105        { "*?", false, "&", Normal, " | sized(DT)" }, // & ???
    122106
    123107        { "?-?", false, "ptrdiff_t", Normal, " | sized(DT)" },
     
    166150        cout << endl;
    167151
    168         cout << "signed int ?==?( zero_t, zero_t ),     ?!=?( zero_t, zero_t );" << endl;
    169         cout << "signed int ?==?( one_t, one_t ),       ?!=?( one_t, one_t );" << endl;
    170         cout << "signed int ?==?( _Bool, _Bool ),       ?!=?( _Bool, _Bool );" << endl;
    171         cout << "signed int !?( _Bool );" << endl;
     152        cout << "signed int ?==?( zero_t, zero_t ),                                                     ?!=?( zero_t, zero_t );" << endl;
     153        cout << "signed int ?==?( one_t, one_t ),                                                       ?!=?( one_t, one_t );" << endl;
     154        cout << "signed int ?==?( _Bool, _Bool ),                                                       ?!=?( _Bool, _Bool );" << endl;
     155        cout << "signed int     !?( _Bool );" << endl;
    172156
    173157        for (auto op : arithmeticOperators) {
     
    204188        cout << "// Arithmetic Constructors //" << endl;
    205189        cout << "/////////////////////////////" << endl;
    206         cout << endl;
    207 
    208190        auto otype = [](const std::string & type, bool do_volatile = false) {
    209                 cout << "void ?{} (" << type << " &);" << endl;
    210                 cout << "void ?{} (" << type << " &, " << type << ");" << endl;
    211                 cout << type << " ?=? (" << type << " &, " << type << ")";
    212                 if ( do_volatile ) {
    213                         cout << ", ?=?(volatile " << type << " &, " << type << ")";
     191                cout << "void \t?{} ( " << type << " & );" << endl;
     192                cout << "void \t?{} ( " << type << " &, " << type << " );" << endl;
     193                cout << type << " \t?=? ( " << type << " &, " << type << " )";
     194                if( do_volatile ) {
     195                        cout << ", \t?=?( volatile " << type << " &, " << type << " )";
    214196                }
    215197                cout << ";" << endl;
    216                 cout << "void ^?{}( " << type << " & );" << endl;
     198                cout << "void \t^?{}( " << type << " & );" << endl;
    217199        };
    218200
    219201        otype("zero_t");
    220         cout << endl;
    221202        otype("one_t");
    222         cout << endl;
    223203        otype("_Bool", true);
    224         cout << endl;
     204        otype("char", true);
     205        otype("signed char", true);
     206        otype("unsigned char", true);
    225207
    226208        for (auto type : basicTypes) {
    227                 cout << "void ?{}(" << type.name << " &);" << endl;
    228                 cout << "void ?{}(" << type.name << " &, " << type.name << ");" << endl;
    229                 cout << "void ?{}(" << type.name << " &, zero_t);" << endl;
    230                 cout << "void ?{}(" << type.name << " &, one_t);" << endl;
     209                cout << "void  ?{}(" << type.name << " &);" << endl;
     210                cout << "void  ?{}(" << type.name << " &, " << type.name << ");" << endl;
    231211                cout << "void ^?{}(" << type.name << " &);" << endl;
    232212                cout << endl;
     
    237217        cout << "// Pointer Constructors //" << endl;
    238218        cout << "//////////////////////////" << endl;
    239         cout << endl;
    240 
    241         cout << "forall(ftype FT) void ?{}( FT *&, FT * );" << endl;
    242         cout << "forall(ftype FT) void ?{}( FT * volatile &, FT * );" << endl;
     219        cout << "forall(ftype FT) void  ?{}( FT *&, FT * );" << endl;
     220        cout << "forall(ftype FT) void  ?{}( FT * volatile &, FT * );" << endl;
    243221
    244222        // generate qualifiers
     
    264242                for (auto cvq : qualifiersPair) {
    265243                        for (auto is_vol : { "        ", "volatile" }) {
    266                                 cout << "forall(dtype DT) void ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl;
     244                                cout << "forall(dtype DT) void  ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl;
    267245                        }
    268246                }
    269247                for (auto cvq : qualifiersSingle) {
    270248                        for (auto is_vol : { "        ", "volatile" }) {
    271                                 cout << "forall(dtype DT) void ?{}(" << cvq << type << " * " << is_vol << " &);" << endl;
     249                                cout << "forall(dtype DT) void  ?{}(" << cvq << type << " * " << is_vol << " &);" << endl;
    272250                        }
    273251                        for (auto is_vol : { "        ", "volatile" }) {
     
    291269        cout << "forall(ftype FT) FT *                  ?=?( FT *          &, zero_t );" << endl;
    292270        cout << "forall(ftype FT) FT *                  ?=?( FT * volatile &, zero_t );" << endl;
    293         cout << "forall(ftype FT) void  ?{}( FT *          & );" << endl;
    294         cout << "forall(ftype FT) void  ^?{}( FT *         & );" << endl;
     271        cout << "forall( ftype FT ) void        ?{}( FT *          & );" << endl;
     272        cout << "forall( ftype FT ) void        ^?{}( FT *         & );" << endl;
    295273        cout << endl;
    296274
     
    299277        cout << "///////////////////////" << endl;
    300278
    301         cout << "forall(ftype FT) FT *                  ?=?( FT *&, FT * );" << endl;
    302         cout << "forall(ftype FT) FT *                  ?=?( FT * volatile &, FT * );" << endl;
    303         cout << "forall(ftype FT) int !?( FT * );" << endl;
    304         cout << "forall(ftype FT) signed int ?==?( FT *, FT * );" << endl;
    305         cout << "forall(ftype FT) signed int ?!=?( FT *, FT * );" << endl;
    306         cout << "forall(ftype FT) FT &           *?( FT * );" << endl;
     279        cout << "forall( ftype FT ) FT *                        ?=?( FT *&, FT * );" << endl;
     280        cout << "forall( ftype FT ) FT *                        ?=?( FT * volatile &, FT * );" << endl;
     281        cout << "forall( ftype FT ) int !?( FT * );" << endl;
     282        cout << "forall( ftype FT ) signed int ?==?( FT *, FT * );" << endl;
     283        cout << "forall( ftype FT ) signed int ?!=?( FT *, FT * );" << endl;
     284        cout << "forall( ftype FT ) FT &                 *?( FT * );" << endl;
     285
    307286
    308287        for (auto op : pointerOperators) {
     
    408387}
    409388
    410 // Local Variables: //
    411 // tab-width: 4 //
    412 // End: //
  • libcfa/prelude/sync-builtins.cf

    r933f32f r6a9d4b4  
    323323_Bool __sync_bool_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    324324#endif
    325 forall(dtype T) _Bool __sync_bool_compare_and_swap(T * volatile *, T *, T*, ...);
    326325
    327326char __sync_val_compare_and_swap(volatile char *, char, char,...);
     
    349348unsigned __int128 __sync_val_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    350349#endif
    351 forall(dtype T) T * __sync_val_compare_and_swap(T * volatile *, T *, T*,...);
    352350
    353351char __sync_lock_test_and_set(volatile char *, char,...);
     
    436434#endif
    437435
    438 char __atomic_exchange_n(volatile char *, char, int);
     436char __atomic_exchange_n(volatile char *, volatile char *, int);
    439437char __atomic_exchange_1(volatile char *, char, int);
    440438void __atomic_exchange(volatile char *, volatile char *, volatile char *, int);
    441 signed char __atomic_exchange_n(volatile signed char *, signed char, int);
     439signed char __atomic_exchange_n(volatile signed char *, volatile signed char *, int);
    442440signed char __atomic_exchange_1(volatile signed char *, signed char, int);
    443441void __atomic_exchange(volatile signed char *, volatile signed char *, volatile signed char *, int);
    444 unsigned char __atomic_exchange_n(volatile unsigned char *, unsigned char, int);
     442unsigned char __atomic_exchange_n(volatile unsigned char *, volatile unsigned char *, int);
    445443unsigned char __atomic_exchange_1(volatile unsigned char *, unsigned char, int);
    446444void __atomic_exchange(volatile unsigned char *, volatile unsigned char *, volatile unsigned char *, int);
    447 signed short __atomic_exchange_n(volatile signed short *, signed short, int);
     445signed short __atomic_exchange_n(volatile signed short *, volatile signed short *, int);
    448446signed short __atomic_exchange_2(volatile signed short *, signed short, int);
    449447void __atomic_exchange(volatile signed short *, volatile signed short *, volatile signed short *, int);
    450 unsigned short __atomic_exchange_n(volatile unsigned short *, unsigned short, int);
     448unsigned short __atomic_exchange_n(volatile unsigned short *, volatile unsigned short *, int);
    451449unsigned short __atomic_exchange_2(volatile unsigned short *, unsigned short, int);
    452450void __atomic_exchange(volatile unsigned short *, volatile unsigned short *, volatile unsigned short *, int);
    453 signed int __atomic_exchange_n(volatile signed int *, signed int, int);
     451signed int __atomic_exchange_n(volatile signed int *, volatile signed int *, int);
    454452signed int __atomic_exchange_4(volatile signed int *, signed int, int);
    455453void __atomic_exchange(volatile signed int *, volatile signed int *, volatile signed int *, int);
    456 unsigned int __atomic_exchange_n(volatile unsigned int *, unsigned int, int);
     454unsigned int __atomic_exchange_n(volatile unsigned int *, volatile unsigned int *, int);
    457455unsigned int __atomic_exchange_4(volatile unsigned int *, unsigned int, int);
    458456void __atomic_exchange(volatile unsigned int *, volatile unsigned int *, volatile unsigned int *, int);
    459 signed long long int __atomic_exchange_n(volatile signed long long int *, signed long long int, int);
     457signed long long int __atomic_exchange_n(volatile signed long long int *, volatile signed long long int *, int);
    460458signed long long int __atomic_exchange_8(volatile signed long long int *, signed long long int, int);
    461459void __atomic_exchange(volatile signed long long int *, volatile signed long long int *, volatile signed long long int *, int);
    462 unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, unsigned long long int, int);
     460unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, volatile unsigned long long int *, int);
    463461unsigned long long int __atomic_exchange_8(volatile unsigned long long int *, unsigned long long int, int);
    464462void __atomic_exchange(volatile unsigned long long int *, volatile unsigned long long int *, volatile unsigned long long int *, int);
    465463#if defined(__SIZEOF_INT128__)
    466 signed __int128 __atomic_exchange_n(volatile signed __int128 *, signed __int128, int);
     464signed __int128 __atomic_exchange_n(volatile signed __int128 *, volatile signed __int128 *, int);
    467465signed __int128 __atomic_exchange_16(volatile signed __int128 *, signed __int128, int);
    468466void __atomic_exchange(volatile signed __int128 *, volatile signed __int128 *, volatile signed __int128 *, int);
    469 unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, unsigned __int128, int);
     467unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    470468unsigned __int128 __atomic_exchange_16(volatile unsigned __int128 *, unsigned __int128, int);
    471469void __atomic_exchange(volatile unsigned __int128 *, volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    472470#endif
    473 forall(dtype T) T * __atomic_exchange_n(T * volatile *, T *, int);
    474 forall(dtype T) void __atomic_exchange(T * volatile *, T * volatile *, T * volatile *, int);
    475471
    476472_Bool __atomic_load_n(const volatile _Bool *, int);
     
    511507void __atomic_load(const volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    512508#endif
    513 forall(dtype T) T * __atomic_load_n(T * const volatile *, int);
    514 forall(dtype T) void __atomic_load(T * const volatile *, T **, int);
    515509
    516510_Bool __atomic_compare_exchange_n(volatile char *, char *, char, _Bool, int, int);
     
    549543_Bool __atomic_compare_exchange   (volatile unsigned __int128 *, unsigned __int128 *, unsigned __int128 *, _Bool, int, int);
    550544#endif
    551 forall(dtype T) _Bool __atomic_compare_exchange_n (T * volatile *, T **, T*, _Bool, int, int);
    552 forall(dtype T) _Bool __atomic_compare_exchange   (T * volatile *, T **, T**, _Bool, int, int);
    553545
    554546void __atomic_store_n(volatile _Bool *, _Bool, int);
     
    589581void __atomic_store(volatile unsigned __int128 *, unsigned __int128 *, int);
    590582#endif
    591 forall(dtype T) void __atomic_store_n(T * volatile *, T *, int);
    592 forall(dtype T) void __atomic_store(T * volatile *, T **, int);
    593583
    594584char __atomic_add_fetch  (volatile char *, char, int);
  • libcfa/src/Makefile.am

    r933f32f r6a9d4b4  
    7474
    7575prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    76         ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
     76        ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
    7777
    7878prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    7979        ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
    80         $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
     80        @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
    8181
    8282
  • libcfa/src/Makefile.in

    r933f32f r6a9d4b4  
    926926
    927927prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    928         ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
     928        ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
    929929
    930930prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    931931        ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
    932         $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
     932        @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
    933933
    934934#----------------------------------------------------------------------------------------------------------------
  • libcfa/src/bits/containers.hfa

    r933f32f r6a9d4b4  
    186186
    187187        forall(dtype T | is_node(T))
    188         static inline bool ?!=?( __queue(T) & this, __attribute__((unused)) zero_t zero ) {
     188        static inline bool ?!=?( __queue(T) & this, zero_t zero ) {
    189189                return this.head != 0;
    190190        }
     
    196196//-----------------------------------------------------------------------------
    197197#ifdef __cforall
    198         forall(dtype TYPE)
     198        forall(dtype TYPE | sized(TYPE))
    199199        #define T TYPE
    200200        #define __getter_t * [T * & next, T * & prev] ( T & )
     
    268268
    269269        forall(dtype T | sized(T))
    270         static inline bool ?!=?( __dllist(T) & this, __attribute__((unused)) zero_t zero ) {
     270        static inline bool ?!=?( __dllist(T) & this, zero_t zero ) {
    271271                return this.head != 0;
    272272        }
  • libcfa/src/concurrency/CtxSwitch-i386.S

    r933f32f r6a9d4b4  
    4141#define PC_OFFSET       ( 2 * PTR_BYTE )
    4242
    43         .text
     43.text
    4444        .align 2
    45         .globl CtxSwitch
    46         .type  CtxSwitch, @function
     45.globl  CtxSwitch
    4746CtxSwitch:
    4847
     
    5150
    5251        movl 4(%esp),%eax
     52
     53        // Save floating & SSE control words on the stack.
     54
     55        sub    $8,%esp
     56        stmxcsr 0(%esp)         // 4 bytes
     57        fnstcw  4(%esp)         // 2 bytes
    5358
    5459        // Save volatile registers on the stack.
     
    6267        movl %esp,SP_OFFSET(%eax)
    6368        movl %ebp,FP_OFFSET(%eax)
     69//      movl 4(%ebp),%ebx       // save previous eip for debugger
     70//      movl %ebx,PC_OFFSET(%eax)
    6471
    6572        // Copy the "to" context argument from the stack to register eax
     
    6774        // argument is now at 8 + 12 = 20(%esp)
    6875
    69         movl 20(%esp),%eax
     76        movl 28(%esp),%eax
    7077
    7178        // Load new context from the "to" area.
     
    8087        popl %ebx
    8188
     89        // Load floating & SSE control words from the stack.
     90
     91        fldcw   4(%esp)
     92        ldmxcsr 0(%esp)
     93        add    $8,%esp
     94
    8295        // Return to thread.
    8396
    8497        ret
    85         .size  CtxSwitch, .-CtxSwitch
    8698
    8799// Local Variables: //
  • libcfa/src/concurrency/CtxSwitch-x86_64.S

    r933f32f r6a9d4b4  
    3939#define SP_OFFSET       ( 0 * PTR_BYTE )
    4040#define FP_OFFSET       ( 1 * PTR_BYTE )
     41#define PC_OFFSET       ( 2 * PTR_BYTE )
    4142
    42 //-----------------------------------------------------------------------------
    43 // Regular context switch routine which enables switching from one context to anouther
    44         .text
     43.text
    4544        .align 2
    46         .globl CtxSwitch
    47         .type  CtxSwitch, @function
     45.globl  CtxSwitch
    4846CtxSwitch:
     47
     48        // Save floating & SSE control words on the stack.
     49
     50        subq   $8,%rsp
     51        stmxcsr 0(%rsp)         // 4 bytes
     52        fnstcw  4(%rsp)         // 2 bytes
    4953
    5054        // Save volatile registers on the stack.
     
    7478        popq %r15
    7579
     80        // Load floating & SSE control words from the stack.
     81
     82        fldcw   4(%rsp)
     83        ldmxcsr 0(%rsp)
     84        addq   $8,%rsp
     85
    7686        // Return to thread.
    7787
    7888        ret
    79         .size  CtxSwitch, .-CtxSwitch
    8089
    81 //-----------------------------------------------------------------------------
    82 // Stub used to create new stacks which are ready to be context switched to
    83         .text
     90.text
    8491        .align 2
    85         .globl CtxInvokeStub
    86         .type    CtxInvokeStub, @function
     92.globl  CtxInvokeStub
    8793CtxInvokeStub:
    8894        movq %rbx, %rdi
    8995        jmp *%r12
    90         .size  CtxInvokeStub, .-CtxInvokeStub
    9196
    9297// Local Variables: //
  • libcfa/src/concurrency/coroutine.cfa

    r933f32f r6a9d4b4  
    3535
    3636extern "C" {
    37         void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
    38         static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__));
    39         static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) {
    40                 abort();
    41         }
    42 
    43         extern void CtxRet( struct __stack_context_t * to ) asm ("CtxRet") __attribute__ ((__noreturn__));
     37      void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) __attribute__ ((__noreturn__));
     38      static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__));
     39      static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) {
     40            abort();
     41      }
    4442}
    4543
     
    4947// minimum feasible stack size in bytes
    5048#define MinStackSize 1000
    51 extern size_t __page_size;                              // architecture pagesize HACK, should go in proper runtime singleton
    52 
    53 void __stack_prepare( __stack_info_t * this, size_t create_size );
     49static size_t pageSize = 0;                             // architecture pagesize HACK, should go in proper runtime singleton
    5450
    5551//-----------------------------------------------------------------------------
    5652// Coroutine ctors and dtors
    57 void ?{}( __stack_info_t & this, void * storage, size_t storageSize ) {
    58         this.storage   = (__stack_t *)storage;
    59 
    60         // Did we get a piece of storage ?
    61         if (this.storage || storageSize != 0) {
    62                 // We either got a piece of storage or the user asked for a specific size
    63                 // Immediately create the stack
    64                 // (This is slightly unintuitive that non-default sized coroutines create are eagerly created
    65                 // but it avoids that all coroutines carry an unnecessary size)
    66                 verify( storageSize != 0 );
    67                 __stack_prepare( &this, storageSize );
    68         }
    69 }
    70 
    71 void ^?{}(__stack_info_t & this) {
    72         bool userStack = ((intptr_t)this.storage & 0x1) != 0;
    73         if ( ! userStack && this.storage ) {
    74                 __attribute__((may_alias)) intptr_t * istorage = (intptr_t *)&this.storage;
    75                 *istorage &= (intptr_t)-1;
    76 
    77                 void * storage = this.storage->limit;
    78                 __cfaabi_dbg_debug_do(
    79                         storage = (char*)(storage) - __page_size;
    80                         if ( mprotect( storage, __page_size, PROT_READ | PROT_WRITE ) == -1 ) {
    81                                 abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) );
    82                         }
    83                 );
    84                 __cfaabi_dbg_print_safe("Kernel : Deleting stack %p\n", storage);
    85                 free( storage );
    86         }
     53void ?{}( coStack_t & this, void * storage, size_t storageSize ) with( this ) {
     54      size               = storageSize == 0 ? 65000 : storageSize; // size of stack
     55      this.storage = storage;                                // pointer to stack
     56      limit              = NULL;                                   // stack grows towards stack limit
     57      base               = NULL;                                   // base of stack
     58      context    = NULL;                                   // address of cfa_context_t
     59      top                = NULL;                                   // address of top of storage
     60      userStack  = storage != NULL;
     61}
     62
     63void ^?{}(coStack_t & this) {
     64      if ( ! this.userStack && this.storage ) {
     65            __cfaabi_dbg_debug_do(
     66                  if ( mprotect( this.storage, pageSize, PROT_READ | PROT_WRITE ) == -1 ) {
     67                        abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) );
     68                  }
     69            );
     70            free( this.storage );
     71      }
    8772}
    8873
    8974void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) {
    90         (this.context){NULL, NULL};
    91         (this.stack){storage, storageSize};
    92         this.name = name;
    93         state = Start;
    94         starter = NULL;
    95         last = NULL;
    96         cancellation = NULL;
     75      (this.stack){storage, storageSize};
     76      this.name = name;
     77      errno_ = 0;
     78      state = Start;
     79      starter = NULL;
     80      last = NULL;
     81      cancellation = NULL;
    9782}
    9883
    9984void ^?{}(coroutine_desc& this) {
    100         if(this.state != Halted && this.state != Start) {
    101                 coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    102                 coroutine_desc * dst = &this;
    103 
    104                 struct _Unwind_Exception storage;
    105                 storage.exception_class = -1;
    106                 storage.exception_cleanup = _CtxCoroutine_UnwindCleanup;
    107                 this.cancellation = &storage;
    108                 this.last = src;
    109 
    110                 // not resuming self ?
    111                 if ( src == dst ) {
    112                         abort( "Attempt by coroutine %.256s (%p) to terminate itself.\n", src->name, src );
    113                 }
    114 
    115                 CoroutineCtxSwitch( src, dst );
    116         }
     85      if(this.state != Halted && this.state != Start) {
     86            coroutine_desc * src = TL_GET( this_coroutine );
     87            coroutine_desc * dst = &this;
     88
     89            struct _Unwind_Exception storage;
     90            storage.exception_class = -1;
     91            storage.exception_cleanup = _CtxCoroutine_UnwindCleanup;
     92            this.cancellation = &storage;
     93            this.last = src;
     94
     95              // not resuming self ?
     96              if ( src == dst ) {
     97                      abort( "Attempt by coroutine %.256s (%p) to terminate itself.\n", src->name, src );
     98            }
     99
     100              CoroutineCtxSwitch( src, dst );
     101      }
    117102}
    118103
     
    121106forall(dtype T | is_coroutine(T))
    122107void prime(T& cor) {
    123         coroutine_desc* this = get_coroutine(cor);
    124         assert(this->state == Start);
    125 
    126         this->state = Primed;
    127         resume(cor);
    128 }
    129 
    130 [void *, size_t] __stack_alloc( size_t storageSize ) {
    131         static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
    132         assert(__page_size != 0l);
    133         size_t size = libCeiling( storageSize, 16 ) + stack_data_size;
    134 
    135         // If we are running debug, we also need to allocate a guardpage to catch stack overflows.
    136         void * storage;
    137         __cfaabi_dbg_debug_do(
    138                 storage = memalign( __page_size, size + __page_size );
    139         );
    140         __cfaabi_dbg_no_debug_do(
    141                 storage = (void*)malloc(size);
    142         );
    143 
    144         __cfaabi_dbg_print_safe("Kernel : Created stack %p of size %zu\n", storage, size);
    145         __cfaabi_dbg_debug_do(
    146                 if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) {
    147                         abort( "__stack_alloc : internal error, mprotect failure, error(%d) %s.", (int)errno, strerror( (int)errno ) );
    148                 }
    149                 storage = (void *)(((intptr_t)storage) + __page_size);
    150         );
    151 
    152         verify( ((intptr_t)storage & (libAlign() - 1)) == 0ul );
    153         return [storage, size];
    154 }
    155 
    156 void __stack_prepare( __stack_info_t * this, size_t create_size ) {
    157         static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
    158         bool userStack;
    159         void * storage;
    160         size_t size;
    161         if ( !this->storage ) {
    162                 userStack = false;
    163                 [storage, size] = __stack_alloc( create_size );
    164         } else {
    165                 userStack = true;
    166                 __cfaabi_dbg_print_safe("Kernel : stack obj %p using user stack %p(%zd bytes)\n", this, this->storage, (intptr_t)this->storage->limit - (intptr_t)this->storage->base);
    167 
    168                 // The stack must be aligned, advance the pointer to the next align data
    169                 storage = (void*)libCeiling( (intptr_t)this->storage, libAlign());
    170 
    171                 // The size needs to be shrinked to fit all the extra data structure and be aligned
    172                 ptrdiff_t diff = (intptr_t)storage - (intptr_t)this->storage;
    173                 size = libFloor(create_size - stack_data_size - diff, libAlign());
    174         } // if
    175         assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize );
    176 
    177         this->storage = (__stack_t *)((intptr_t)storage + size);
    178         this->storage->limit = storage;
    179         this->storage->base  = (void*)((intptr_t)storage + size);
    180         __attribute__((may_alias)) intptr_t * istorage = (intptr_t*)&this->storage;
    181         *istorage |= userStack ? 0x1 : 0x0;
     108      coroutine_desc* this = get_coroutine(cor);
     109      assert(this->state == Start);
     110
     111      this->state = Primed;
     112      resume(cor);
     113}
     114
     115// Wrapper for co
     116void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
     117      // Safety note : This could cause some false positives due to preemption
     118      verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
     119      disable_interrupts();
     120
     121      // set state of current coroutine to inactive
     122      src->state = src->state == Halted ? Halted : Inactive;
     123
     124      // set new coroutine that task is executing
     125      kernelTLS.this_coroutine = dst;
     126
     127      // context switch to specified coroutine
     128      assert( src->stack.context );
     129      CtxSwitch( src->stack.context, dst->stack.context );
     130      // when CtxSwitch returns we are back in the src coroutine
     131
     132      // set state of new coroutine to active
     133      src->state = Active;
     134
     135      enable_interrupts( __cfaabi_dbg_ctx );
     136      // Safety note : This could cause some false positives due to preemption
     137      verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
     138
     139      if( unlikely(src->cancellation != NULL) ) {
     140            _CtxCoroutine_Unwind(src->cancellation);
     141      }
     142} //ctxSwitchDirect
     143
     144void create_stack( coStack_t* this, unsigned int storageSize ) with( *this ) {
     145      //TEMP HACK do this on proper kernel startup
     146      if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE );
     147
     148      size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment
     149
     150      if ( !storage ) {
     151            __cfaabi_dbg_print_safe("Kernel : Creating stack of size %zu for stack obj %p\n", cxtSize + size + 8, this);
     152
     153            userStack = false;
     154            size = libCeiling( storageSize, 16 );
     155            // use malloc/memalign because "new" raises an exception for out-of-memory
     156
     157            // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment
     158            __cfaabi_dbg_debug_do( storage = memalign( pageSize, cxtSize + size + pageSize ) );
     159            __cfaabi_dbg_no_debug_do( storage = malloc( cxtSize + size + 8 ) );
     160
     161            __cfaabi_dbg_debug_do(
     162                  if ( mprotect( storage, pageSize, PROT_NONE ) == -1 ) {
     163                        abort( "(uMachContext &)%p.createContext() : internal error, mprotect failure, error(%d) %s.", this, (int)errno, strerror( (int)errno ) );
     164                  } // if
     165            );
     166
     167            if ( (intptr_t)storage == 0 ) {
     168                  abort( "Attempt to allocate %zd bytes of storage for coroutine or task execution-state but insufficient memory available.", size );
     169            } // if
     170
     171            __cfaabi_dbg_debug_do( limit = (char *)storage + pageSize );
     172            __cfaabi_dbg_no_debug_do( limit = (char *)libCeiling( (unsigned long)storage, 16 ) ); // minimum alignment
     173
     174      } else {
     175            __cfaabi_dbg_print_safe("Kernel : stack obj %p using user stack %p(%u bytes)\n", this, storage, storageSize);
     176
     177            assertf( ((size_t)storage & (libAlign() - 1)) == 0ul, "Stack storage %p for task/coroutine must be aligned on %d byte boundary.", storage, (int)libAlign() );
     178            userStack = true;
     179            size = storageSize - cxtSize;
     180
     181            if ( size % 16 != 0u ) size -= 8;
     182
     183            limit = (char *)libCeiling( (unsigned long)storage, 16 ); // minimum alignment
     184      } // if
     185      assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize );
     186
     187      base = (char *)limit + size;
     188      context = base;
     189      top = (char *)context + cxtSize;
    182190}
    183191
     
    185193// is not inline (We can't inline Cforall in C)
    186194extern "C" {
    187         void __suspend_internal(void) {
    188                 suspend();
    189         }
    190 
    191         void __leave_coroutine( coroutine_desc * src ) {
    192                 coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter;
    193 
    194                 src->state = Halted;
    195 
    196                 assertf( starter != 0,
    197                         "Attempt to suspend/leave coroutine \"%.256s\" (%p) that has never been resumed.\n"
    198                         "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    199                         src->name, src );
    200                 assertf( starter->state != Halted,
    201                         "Attempt by coroutine \"%.256s\" (%p) to suspend/leave back to terminated coroutine \"%.256s\" (%p).\n"
    202                         "Possible cause is terminated coroutine's main routine has already returned.",
    203                         src->name, src, starter->name, starter );
    204 
    205                 CoroutineCtxSwitch( src, starter );
    206         }
     195      void __suspend_internal(void) {
     196            suspend();
     197      }
     198
     199      void __leave_coroutine() {
     200            coroutine_desc * src = TL_GET( this_coroutine ); // optimization
     201            coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter;
     202
     203            src->state = Halted;
     204
     205            assertf( starter != 0,
     206                  "Attempt to suspend/leave coroutine \"%.256s\" (%p) that has never been resumed.\n"
     207                  "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     208                  src->name, src );
     209            assertf( starter->state != Halted,
     210                  "Attempt by coroutine \"%.256s\" (%p) to suspend/leave back to terminated coroutine \"%.256s\" (%p).\n"
     211                  "Possible cause is terminated coroutine's main routine has already returned.",
     212                  src->name, src, starter->name, starter );
     213
     214            CoroutineCtxSwitch( src, starter );
     215      }
    207216}
    208217
  • libcfa/src/concurrency/coroutine.hfa

    r933f32f r6a9d4b4  
    4646//-----------------------------------------------------------------------------
    4747// Public coroutine API
    48 static inline void suspend(void);
     48static inline void suspend();
    4949
    5050forall(dtype T | is_coroutine(T))
    51 static inline T & resume(T & cor);
     51static inline void resume(T & cor);
    5252
    5353forall(dtype T | is_coroutine(T))
     
    6464      forall(dtype T | is_coroutine(T))
    6565      void CtxStart(T * this, void ( *invoke)(T *));
    66 
    67         extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
    68 
    69         extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
    7066}
    7167
    7268// Private wrappers for context switch and stack creation
    73 // Wrapper for co
    74 static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    75         // set state of current coroutine to inactive
    76         src->state = src->state == Halted ? Halted : Inactive;
    77 
    78         // set new coroutine that task is executing
    79         TL_GET( this_thread )->curr_cor = dst;
    80 
    81         // context switch to specified coroutine
    82         verify( dst->context.SP );
    83         CtxSwitch( &src->context, &dst->context );
    84         // when CtxSwitch returns we are back in the src coroutine
    85 
    86         // set state of new coroutine to active
    87         src->state = Active;
    88 
    89         if( unlikely(src->cancellation != NULL) ) {
    90                 _CtxCoroutine_Unwind(src->cancellation, src);
    91         }
    92 }
    93 
    94 extern void __stack_prepare   ( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
     69extern void CoroutineCtxSwitch(coroutine_desc * src, coroutine_desc * dst);
     70extern void create_stack( coStack_t * this, unsigned int storageSize );
    9571
    9672// Suspend implementation inlined for performance
    97 static inline void suspend(void) {
     73static inline void suspend() {
    9874        // optimization : read TLS once and reuse it
    9975        // Safety note: this is preemption safe since if
     
    10177        // will also migrate which means this value will
    10278        // stay in syn with the TLS
    103         coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     79        coroutine_desc * src = TL_GET( this_coroutine );
    10480
    10581        assertf( src->last != 0,
     
    11793// Resume implementation inlined for performance
    11894forall(dtype T | is_coroutine(T))
    119 static inline T & resume(T & cor) {
     95static inline void resume(T & cor) {
    12096        // optimization : read TLS once and reuse it
    12197        // Safety note: this is preemption safe since if
     
    12399        // will also migrate which means this value will
    124100        // stay in syn with the TLS
    125         coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     101        coroutine_desc * src = TL_GET( this_coroutine );
    126102        coroutine_desc * dst = get_coroutine(cor);
    127103
    128         if( unlikely(dst->context.SP == NULL) ) {
    129                 __stack_prepare(&dst->stack, 65000);
     104        if( unlikely(!dst->stack.base) ) {
     105                create_stack(&dst->stack, dst->stack.size);
    130106                CtxStart(&cor, CtxInvokeCoroutine);
    131107        }
     
    145121        // always done for performance testing
    146122        CoroutineCtxSwitch( src, dst );
    147 
    148         return cor;
    149123}
    150124
     
    155129        // will also migrate which means this value will
    156130        // stay in syn with the TLS
    157         coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     131        coroutine_desc * src = TL_GET( this_coroutine );
    158132
    159133        // not resuming self ?
  • libcfa/src/concurrency/invoke.c

    r933f32f r6a9d4b4  
    2828
    2929extern void __suspend_internal(void);
    30 extern void __leave_coroutine( struct coroutine_desc * );
    31 extern void __finish_creation( struct thread_desc * );
     30extern void __leave_coroutine(void);
     31extern void __finish_creation(void);
    3232extern void __leave_thread_monitor( struct thread_desc * this );
    3333extern void disable_interrupts();
     
    4747        cor->state = Active;
    4848
     49        enable_interrupts( __cfaabi_dbg_ctx );
     50
    4951        main( this );
    5052
    5153        //Final suspend, should never return
    52         __leave_coroutine( cor );
     54        __leave_coroutine();
    5355        __cabi_abort( "Resumed dead coroutine" );
    5456}
     
    6062        __attribute((__unused__)) struct _Unwind_Exception * unwind_exception,
    6163        __attribute((__unused__)) struct _Unwind_Context * context,
    62         void * param
     64        __attribute((__unused__)) void * param
    6365) {
    6466        if( actions & _UA_END_OF_STACK  ) {
    6567                // We finished unwinding the coroutine,
    6668                // leave it
    67                 __leave_coroutine( param );
     69                __leave_coroutine();
    6870                __cabi_abort( "Resumed dead coroutine" );
    6971        }
     
    7375}
    7476
    75 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) __attribute__ ((__noreturn__));
    76 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) {
    77         _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, cor );
     77void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) __attribute__ ((__noreturn__));
     78void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) {
     79        _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, NULL );
    7880        printf("UNWIND ERROR %d after force unwind\n", ret);
    7981        abort();
     
    8688        void *this
    8789) {
     90        // First suspend, once the thread arrives here,
     91        // the function pointer to main can be invalidated without risk
     92        __finish_creation();
     93
    8894        // Fetch the thread handle from the user defined thread structure
    8995        struct thread_desc* thrd = get_thread( this );
    90 
    91         // First suspend, once the thread arrives here,
    92         // the function pointer to main can be invalidated without risk
    93         __finish_creation( thrd );
     96        thrd->self_cor.last = NULL;
    9497
    9598        // Officially start the thread by enabling preemption
     
    117120        void (*invoke)(void *)
    118121) {
    119         struct coroutine_desc * cor = get_coroutine( this );
    120         struct __stack_t * stack = cor->stack.storage;
     122        struct coStack_t* stack = &get_coroutine( this )->stack;
    121123
    122124#if defined( __i386 )
    123125
    124126        struct FakeStack {
    125             void *fixedRegisters[3];              // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant)
     127            void *fixedRegisters[3];                    // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant)
     128            uint32_t mxcr;                        // SSE Status and Control bits (control bits are preserved across function calls)
     129            uint16_t fcw;                         // X97 FPU control word (preserved across function calls)
    126130            void *rturn;                          // where to go on return from uSwitch
    127             void *dummyReturn;                    // fake return compiler would have pushed on call to uInvoke
    128             void *argument[3];                    // for 16-byte ABI, 16-byte alignment starts here
    129             void *padding;                        // padding to force 16-byte alignment, as "base" is 16-byte aligned
     131            void *dummyReturn;                          // fake return compiler would have pushed on call to uInvoke
     132            void *argument[3];                          // for 16-byte ABI, 16-byte alignment starts here
     133            void *padding;                              // padding to force 16-byte alignment, as "base" is 16-byte aligned
    130134        };
    131135
    132         cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );
    133         cor->context.FP = NULL;         // terminate stack with NULL fp
     136        ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );
     137        ((struct machine_context_t *)stack->context)->FP = NULL;                // terminate stack with NULL fp
    134138
    135         struct FakeStack *fs = (struct FakeStack *)cor->context.SP;
    136 
    137         fs->dummyReturn = NULL;
    138         fs->argument[0] = this;     // argument to invoke
    139         fs->rturn = invoke;
     139        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL;
     140        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument[0] = this;     // argument to invoke
     141        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = invoke;
     142        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520
     143        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F;  //Vol. 1 8-7
    140144
    141145#elif defined( __x86_64 )
     
    143147        struct FakeStack {
    144148                void *fixedRegisters[5];            // fixed registers rbx, r12, r13, r14, r15
     149                uint32_t mxcr;                      // SSE Status and Control bits (control bits are preserved across function calls)
     150                uint16_t fcw;                       // X97 FPU control word (preserved across function calls)
    145151                void *rturn;                        // where to go on return from uSwitch
    146152                void *dummyReturn;                  // NULL return address to provide proper alignment
    147153        };
    148154
    149         cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );
    150         cor->context.FP = NULL;         // terminate stack with NULL fp
     155        ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );
     156        ((struct machine_context_t *)stack->context)->FP = NULL;                // terminate stack with NULL fp
    151157
    152         struct FakeStack *fs = (struct FakeStack *)cor->context.SP;
    153 
    154         fs->dummyReturn = NULL;
    155         fs->rturn = CtxInvokeStub;
    156         fs->fixedRegisters[0] = this;
    157         fs->fixedRegisters[1] = invoke;
     158        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL;
     159        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = CtxInvokeStub;
     160        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[0] = this;
     161        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = invoke;
     162        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520
     163        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F;  //Vol. 1 8-7
    158164
    159165#elif defined( __ARM_ARCH )
     
    165171        };
    166172
    167         cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );
    168         cor->context.FP = NULL;
     173        ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );
     174        ((struct machine_context_t *)stack->context)->FP = NULL;
    169175
    170         struct FakeStack *fs = (struct FakeStack *)cor->context.SP;
     176        struct FakeStack *fs = (struct FakeStack *)((struct machine_context_t *)stack->context)->SP;
    171177
    172178        fs->intRegs[8] = CtxInvokeStub;
  • libcfa/src/concurrency/invoke.h

    r933f32f r6a9d4b4  
    5050
    5151                extern thread_local struct KernelThreadData {
     52                        struct coroutine_desc * volatile this_coroutine;
    5253                        struct thread_desc    * volatile this_thread;
    5354                        struct processor      * volatile this_processor;
     
    6061                } kernelTLS __attribute__ ((tls_model ( "initial-exec" )));
    6162        }
     63
     64        static inline struct coroutine_desc * volatile active_coroutine() { return TL_GET( this_coroutine ); }
     65        static inline struct thread_desc    * volatile active_thread   () { return TL_GET( this_thread    ); }
     66        static inline struct processor      * volatile active_processor() { return TL_GET( this_processor ); } // UNSAFE
    6267        #endif
    6368
    64         struct __stack_context_t {
    65                 void * SP;
    66                 void * FP;
    67         };
    68 
    69         // low adresses  :           +----------------------+ <- start of allocation
    70         //                           |  optional guard page |
    71         //                           +----------------------+ <- __stack_t.limit
    72         //                           |                      |
    73         //                           |       /\ /\ /\       |
    74         //                           |       || || ||       |
    75         //                           |                      |
    76         //                           |    program  stack    |
    77         //                           |                      |
    78         // __stack_info_t.storage -> +----------------------+ <- __stack_t.base
    79         //                           |      __stack_t       |
    80         // high adresses :           +----------------------+ <- end of allocation
    81 
    82         struct __stack_t {
    83                 // stack grows towards stack limit
    84                 void * limit;
    85 
    86                 // base of stack
    87                 void * base;
    88         };
    89 
    90         struct __stack_info_t {
    91                 // pointer to stack
    92                 struct __stack_t * storage;
     69        struct coStack_t {
     70                size_t size;                                                                    // size of stack
     71                void * storage;                                                                 // pointer to stack
     72                void * limit;                                                                   // stack grows towards stack limit
     73                void * base;                                                                    // base of stack
     74                void * context;                                                                 // address of cfa_context_t
     75                void * top;                                                                             // address of top of storage
     76                bool userStack;                                                                 // whether or not the user allocated the stack
    9377        };
    9478
     
    9680
    9781        struct coroutine_desc {
    98                 // context that is switch during a CtxSwitch
    99                 struct __stack_context_t context;
    100 
    10182                // stack information of the coroutine
    102                 struct __stack_info_t stack;
    103 
    104                 // textual name for coroutine/task
     83                struct coStack_t stack;
     84
     85                // textual name for coroutine/task, initialized by uC++ generated code
    10586                const char * name;
     87
     88                // copy of global UNIX variable errno
     89                int errno_;
    10690
    10791                // current execution status for coroutine
    10892                enum coroutine_state state;
    109 
    11093                // first coroutine to resume this one
    11194                struct coroutine_desc * starter;
     
    161144        struct thread_desc {
    162145                // Core threading fields
    163                 // context that is switch during a CtxSwitch
    164                 struct __stack_context_t context;
    165 
    166                 // current execution status for coroutine
    167                 enum coroutine_state state;
    168 
    169                 //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it
    170 
    171146                // coroutine body used to store context
    172147                struct coroutine_desc  self_cor;
     
    195170                        struct thread_desc * prev;
    196171                } node;
    197         };
    198 
    199         #ifdef __cforall
    200         extern "Cforall" {
    201                 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
    202                 static inline struct thread_desc    * active_thread   () { return TL_GET( this_thread    ); }
    203                 static inline struct processor      * active_processor() { return TL_GET( this_processor ); } // UNSAFE
    204 
     172     };
     173
     174     #ifdef __cforall
     175     extern "Cforall" {
    205176                static inline thread_desc * & get_next( thread_desc & this ) {
    206177                        return this.next;
     
    260231        // assembler routines that performs the context switch
    261232        extern void CtxInvokeStub( void );
    262         extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
    263         // void CtxStore ( void * this ) asm ("CtxStore");
    264         // void CtxRet   ( void * dst  ) asm ("CtxRet");
     233        void CtxSwitch( void * from, void * to ) asm ("CtxSwitch");
     234
     235        #if   defined( __i386 )
     236        #define CtxGet( ctx ) __asm__ ( \
     237                        "movl %%esp,%0\n"   \
     238                        "movl %%ebp,%1\n"   \
     239                : "=rm" (ctx.SP), "=rm" (ctx.FP) )
     240        #elif defined( __x86_64 )
     241        #define CtxGet( ctx ) __asm__ ( \
     242                        "movq %%rsp,%0\n"   \
     243                        "movq %%rbp,%1\n"   \
     244                : "=rm" (ctx.SP), "=rm" (ctx.FP) )
     245        #elif defined( __ARM_ARCH )
     246        #define CtxGet( ctx ) __asm__ ( \
     247                        "mov %0,%%sp\n"   \
     248                        "mov %1,%%r11\n"   \
     249                : "=rm" (ctx.SP), "=rm" (ctx.FP) )
     250        #else
     251                #error unknown hardware architecture
     252        #endif
    265253
    266254#endif //_INVOKE_PRIVATE_H_
  • libcfa/src/concurrency/kernel.cfa

    r933f32f r6a9d4b4  
    3636#include "invoke.h"
    3737
    38 //-----------------------------------------------------------------------------
    39 // Some assembly required
    40 #if   defined( __i386 )
    41         #define CtxGet( ctx )        \
    42                 __asm__ volatile (     \
    43                         "movl %%esp,%0\n"\
    44                         "movl %%ebp,%1\n"\
    45                         : "=rm" (ctx.SP),\
    46                                 "=rm" (ctx.FP) \
    47                 )
    48 
    49         // mxcr : SSE Status and Control bits (control bits are preserved across function calls)
    50         // fcw  : X87 FPU control word (preserved across function calls)
    51         #define __x87_store         \
    52                 uint32_t __mxcr;      \
    53                 uint16_t __fcw;       \
    54                 __asm__ volatile (    \
    55                         "stmxcsr %0\n"  \
    56                         "fnstcw  %1\n"  \
    57                         : "=m" (__mxcr),\
    58                                 "=m" (__fcw)  \
    59                 )
    60 
    61         #define __x87_load         \
    62                 __asm__ volatile (   \
    63                         "fldcw  %1\n"  \
    64                         "ldmxcsr %0\n" \
    65                         ::"m" (__mxcr),\
    66                                 "m" (__fcw)  \
    67                 )
    68 
    69 #elif defined( __x86_64 )
    70         #define CtxGet( ctx )        \
    71                 __asm__ volatile (     \
    72                         "movq %%rsp,%0\n"\
    73                         "movq %%rbp,%1\n"\
    74                         : "=rm" (ctx.SP),\
    75                                 "=rm" (ctx.FP) \
    76                 )
    77 
    78         #define __x87_store         \
    79                 uint32_t __mxcr;      \
    80                 uint16_t __fcw;       \
    81                 __asm__ volatile (    \
    82                         "stmxcsr %0\n"  \
    83                         "fnstcw  %1\n"  \
    84                         : "=m" (__mxcr),\
    85                                 "=m" (__fcw)  \
    86                 )
    87 
    88         #define __x87_load          \
    89                 __asm__ volatile (    \
    90                         "fldcw  %1\n"   \
    91                         "ldmxcsr %0\n"  \
    92                         :: "m" (__mxcr),\
    93                                 "m" (__fcw)  \
    94                 )
    95 
    96 
    97 #elif defined( __ARM_ARCH )
    98 #define CtxGet( ctx ) __asm__ ( \
    99                 "mov %0,%%sp\n"   \
    100                 "mov %1,%%r11\n"   \
    101         : "=rm" (ctx.SP), "=rm" (ctx.FP) )
    102 #else
    103         #error unknown hardware architecture
    104 #endif
    105 
    106 //-----------------------------------------------------------------------------
    10738//Start and stop routine for the kernel, declared first to make sure they run first
    10839static void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
     
    11142//-----------------------------------------------------------------------------
    11243// Kernel storage
    113 KERNEL_STORAGE(cluster,         mainCluster);
    114 KERNEL_STORAGE(processor,       mainProcessor);
    115 KERNEL_STORAGE(thread_desc,     mainThread);
    116 KERNEL_STORAGE(__stack_t,       mainThreadCtx);
     44KERNEL_STORAGE(cluster,           mainCluster);
     45KERNEL_STORAGE(processor,         mainProcessor);
     46KERNEL_STORAGE(thread_desc,       mainThread);
     47KERNEL_STORAGE(machine_context_t, mainThreadCtx);
    11748
    11849cluster     * mainCluster;
     
    12354struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
    12455}
    125 
    126 size_t __page_size = 0;
    12756
    12857//-----------------------------------------------------------------------------
     
    13160        NULL,
    13261        NULL,
     62        NULL,
    13363        { 1, false, false }
    13464};
     
    13767// Struct to steal stack
    13868struct current_stack_info_t {
    139         __stack_t * storage;            // pointer to stack object
     69        machine_context_t ctx;
     70        unsigned int size;              // size of stack
    14071        void *base;                             // base of stack
     72        void *storage;                  // pointer to stack
    14173        void *limit;                    // stack grows towards stack limit
    14274        void *context;                  // address of cfa_context_t
     75        void *top;                              // address of top of storage
    14376};
    14477
    14578void ?{}( current_stack_info_t & this ) {
    146         __stack_context_t ctx;
    147         CtxGet( ctx );
    148         this.base = ctx.FP;
     79        CtxGet( this.ctx );
     80        this.base = this.ctx.FP;
     81        this.storage = this.ctx.SP;
    14982
    15083        rlimit r;
    15184        getrlimit( RLIMIT_STACK, &r);
    152         size_t size = r.rlim_cur;
    153 
    154         this.limit = (void *)(((intptr_t)this.base) - size);
     85        this.size = r.rlim_cur;
     86
     87        this.limit = (void *)(((intptr_t)this.base) - this.size);
    15588        this.context = &storage_mainThreadCtx;
     89        this.top = this.base;
    15690}
    15791
    15892//-----------------------------------------------------------------------------
    15993// Main thread construction
     94void ?{}( coStack_t & this, current_stack_info_t * info) with( this ) {
     95        size      = info->size;
     96        storage   = info->storage;
     97        limit     = info->limit;
     98        base      = info->base;
     99        context   = info->context;
     100        top       = info->top;
     101        userStack = true;
     102}
    160103
    161104void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) {
    162         stack.storage = info->storage;
    163         with(*stack.storage) {
    164                 limit     = info->limit;
    165                 base      = info->base;
    166         }
    167         __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage;
    168         *istorage |= 0x1;
     105        stack{ info };
    169106        name = "Main Thread";
     107        errno_ = 0;
    170108        state = Start;
    171109        starter = NULL;
    172         last = NULL;
    173         cancellation = NULL;
    174110}
    175111
    176112void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) {
    177         state = Start;
    178113        self_cor{ info };
    179114        curr_cor = &self_cor;
     
    306241}
    307242
    308 static int * __volatile_errno() __attribute__((noinline));
    309 static int * __volatile_errno() { asm(""); return &errno; }
    310 
    311243// KERNEL ONLY
    312244// runThread runs a thread by context switching
    313245// from the processor coroutine to the target thread
    314 static void runThread(processor * this, thread_desc * thrd_dst) {
     246static void runThread(processor * this, thread_desc * dst) {
     247        assert(dst->curr_cor);
    315248        coroutine_desc * proc_cor = get_coroutine(this->runner);
     249        coroutine_desc * thrd_cor = dst->curr_cor;
    316250
    317251        // Reset the terminating actions here
     
    319253
    320254        // Update global state
    321         kernelTLS.this_thread = thrd_dst;
    322 
    323         // set state of processor coroutine to inactive and the thread to active
    324         proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
    325         thrd_dst->state = Active;
    326 
    327         // set context switch to the thread that the processor is executing
    328         verify( thrd_dst->context.SP );
    329         CtxSwitch( &proc_cor->context, &thrd_dst->context );
    330         // when CtxSwitch returns we are back in the processor coroutine
    331 
    332         // set state of processor coroutine to active and the thread to inactive
    333         thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive;
    334         proc_cor->state = Active;
     255        kernelTLS.this_thread = dst;
     256
     257        // Context Switch to the thread
     258        ThreadCtxSwitch(proc_cor, thrd_cor);
     259        // when ThreadCtxSwitch returns we are back in the processor coroutine
    335260}
    336261
     
    338263static void returnToKernel() {
    339264        coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
    340         thread_desc * thrd_src = kernelTLS.this_thread;
    341 
    342         // set state of current coroutine to inactive
    343         thrd_src->state = thrd_src->state == Halted ? Halted : Inactive;
    344         proc_cor->state = Active;
    345         int local_errno = *__volatile_errno();
    346         #if defined( __i386 ) || defined( __x86_64 )
    347                 __x87_store;
    348         #endif
    349 
    350         // set new coroutine that the processor is executing
    351         // and context switch to it
    352         verify( proc_cor->context.SP );
    353         CtxSwitch( &thrd_src->context, &proc_cor->context );
    354 
    355         // set state of new coroutine to active
    356         proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
    357         thrd_src->state = Active;
    358 
    359         #if defined( __i386 ) || defined( __x86_64 )
    360                 __x87_load;
    361         #endif
    362         *__volatile_errno() = local_errno;
     265        coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine;
     266        ThreadCtxSwitch(thrd_cor, proc_cor);
    363267}
    364268
     
    403307        processor * proc = (processor *) arg;
    404308        kernelTLS.this_processor = proc;
     309        kernelTLS.this_coroutine = NULL;
    405310        kernelTLS.this_thread    = NULL;
    406311        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
     
    409314        // to waste the perfectly valid stack create by pthread.
    410315        current_stack_info_t info;
    411         __stack_t ctx;
    412         info.storage = &ctx;
     316        machine_context_t ctx;
     317        info.context = &ctx;
    413318        (proc->runner){ proc, &info };
    414319
    415         __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
     320        __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.base);
    416321
    417322        //Set global state
     323        kernelTLS.this_coroutine = get_coroutine(proc->runner);
    418324        kernelTLS.this_thread    = NULL;
    419325
     
    444350
    445351// KERNEL_ONLY
    446 void kernel_first_resume( processor * this ) {
    447         thread_desc * src = mainThread;
     352void kernel_first_resume(processor * this) {
     353        coroutine_desc * src = kernelTLS.this_coroutine;
    448354        coroutine_desc * dst = get_coroutine(this->runner);
    449355
    450356        verify( ! kernelTLS.preemption_state.enabled );
    451357
    452         __stack_prepare( &dst->stack, 65000 );
     358        create_stack(&dst->stack, dst->stack.size);
    453359        CtxStart(&this->runner, CtxInvokeCoroutine);
    454360
    455361        verify( ! kernelTLS.preemption_state.enabled );
    456362
    457         dst->last = &src->self_cor;
    458         dst->starter = dst->starter ? dst->starter : &src->self_cor;
     363        dst->last = src;
     364        dst->starter = dst->starter ? dst->starter : src;
    459365
    460366        // set state of current coroutine to inactive
    461367        src->state = src->state == Halted ? Halted : Inactive;
    462368
     369        // set new coroutine that task is executing
     370        kernelTLS.this_coroutine = dst;
     371
     372        // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch.
     373        // Therefore, when first creating a coroutine, interrupts are enable before calling the main.
     374        // This is consistent with thread creation. However, when creating the main processor coroutine,
     375        // we wan't interrupts to be disabled. Therefore, we double-disable interrupts here so they will
     376        // stay disabled.
     377        disable_interrupts();
     378
    463379        // context switch to specified coroutine
    464         verify( dst->context.SP );
    465         CtxSwitch( &src->context, &dst->context );
     380        assert( src->stack.context );
     381        CtxSwitch( src->stack.context, dst->stack.context );
    466382        // when CtxSwitch returns we are back in the src coroutine
    467383
     
    470386
    471387        verify( ! kernelTLS.preemption_state.enabled );
    472 }
    473 
    474 // KERNEL_ONLY
    475 void kernel_last_resume( processor * this ) {
    476         coroutine_desc * src = &mainThread->self_cor;
    477         coroutine_desc * dst = get_coroutine(this->runner);
    478 
    479         verify( ! kernelTLS.preemption_state.enabled );
    480         verify( dst->starter == src );
    481         verify( dst->context.SP );
    482 
    483         // context switch to the processor
    484         CtxSwitch( &src->context, &dst->context );
    485388}
    486389
     
    491394void ScheduleThread( thread_desc * thrd ) {
    492395        verify( thrd );
    493         verify( thrd->state != Halted );
     396        verify( thrd->self_cor.state != Halted );
    494397
    495398        verify( ! kernelTLS.preemption_state.enabled );
     
    648551        __cfaabi_dbg_print_safe("Kernel : Starting\n");
    649552
    650         __page_size = sysconf( _SC_PAGESIZE );
    651 
    652553        __cfa_dbg_global_clusters.list{ __get };
    653554        __cfa_dbg_global_clusters.lock{};
     
    664565        mainThread = (thread_desc *)&storage_mainThread;
    665566        current_stack_info_t info;
    666         info.storage = (__stack_t*)&storage_mainThreadCtx;
    667567        (*mainThread){ &info };
    668568
     
    699599        kernelTLS.this_processor = mainProcessor;
    700600        kernelTLS.this_thread    = mainThread;
     601        kernelTLS.this_coroutine = &mainThread->self_cor;
    701602
    702603        // Enable preemption
     
    733634        // which is currently here
    734635        __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);
    735         kernel_last_resume( kernelTLS.this_processor );
     636        returnToKernel();
    736637        mainThread->self_cor.state = Halted;
    737638
     
    819720                __cfaabi_dbg_bits_write( abort_text, len );
    820721
    821                 if ( &thrd->self_cor != thrd->curr_cor ) {
    822                         len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor );
     722                if ( get_coroutine(thrd) != kernelTLS.this_coroutine ) {
     723                        len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", kernelTLS.this_coroutine->name, kernelTLS.this_coroutine );
    823724                        __cfaabi_dbg_bits_write( abort_text, len );
    824725                }
  • libcfa/src/concurrency/thread.cfa

    r933f32f r6a9d4b4  
    3131// Thread ctors and dtors
    3232void ?{}(thread_desc & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {
    33         context{ NULL, NULL };
    3433        self_cor{ name, storage, storageSize };
    35         state = Start;
     34        verify(&self_cor);
    3635        curr_cor = &self_cor;
    3736        self_mon.owner = &this;
     
    7473forall( dtype T | is_thread(T) )
    7574void __thrd_start( T& this ) {
    76         thread_desc * this_thrd = get_thread(this);
    77         thread_desc * curr_thrd = TL_GET( this_thread );
     75        coroutine_desc* thrd_c = get_coroutine(this);
     76        thread_desc   * thrd_h = get_thread   (this);
     77        thrd_c->last = TL_GET( this_coroutine );
     78
     79        // __cfaabi_dbg_print_safe("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h);
    7880
    7981        disable_interrupts();
     82        create_stack(&thrd_c->stack, thrd_c->stack.size);
     83        kernelTLS.this_coroutine = thrd_c;
    8084        CtxStart(&this, CtxInvokeThread);
    81         this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];
    82         verify( this_thrd->context.SP );
    83         CtxSwitch( &curr_thrd->context, &this_thrd->context );
     85        assert( thrd_c->last->stack.context );
     86        CtxSwitch( thrd_c->last->stack.context, thrd_c->stack.context );
    8487
    85         ScheduleThread(this_thrd);
     88        ScheduleThread(thrd_h);
    8689        enable_interrupts( __cfaabi_dbg_ctx );
    8790}
     
    8992extern "C" {
    9093        // KERNEL ONLY
    91         void __finish_creation(thread_desc * this) {
    92                 // set new coroutine that the processor is executing
    93                 // and context switch to it
    94                 verify( kernelTLS.this_thread != this );
    95                 verify( kernelTLS.this_thread->context.SP );
    96                 CtxSwitch( &this->context, &kernelTLS.this_thread->context );
     94        void __finish_creation(void) {
     95                coroutine_desc* thrd_c = kernelTLS.this_coroutine;
     96                ThreadCtxSwitch( thrd_c, thrd_c->last );
    9797        }
    9898}
     
    112112}
    113113
     114// KERNEL ONLY
     115void ThreadCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
     116        // set state of current coroutine to inactive
     117        src->state = src->state == Halted ? Halted : Inactive;
     118        dst->state = Active;
     119
     120        // set new coroutine that the processor is executing
     121        // and context switch to it
     122        kernelTLS.this_coroutine = dst;
     123        assert( src->stack.context );
     124        CtxSwitch( src->stack.context, dst->stack.context );
     125        kernelTLS.this_coroutine = src;
     126
     127        // set state of new coroutine to active
     128        dst->state = dst->state == Halted ? Halted : Inactive;
     129        src->state = Active;
     130}
     131
    114132// Local Variables: //
    115133// mode: c //
  • libcfa/src/concurrency/thread.hfa

    r933f32f r6a9d4b4  
    6161void ^?{}(thread_desc & this);
    6262
    63 static inline void ?{}(thread_desc & this)                                                                  { this{ "Anonymous Thread", *mainCluster, NULL, 65000 }; }
     63static inline void ?{}(thread_desc & this)                                                                  { this{ "Anonymous Thread", *mainCluster, NULL, 0 }; }
    6464static inline void ?{}(thread_desc & this, size_t stackSize )                                               { this{ "Anonymous Thread", *mainCluster, NULL, stackSize }; }
    6565static inline void ?{}(thread_desc & this, void * storage, size_t storageSize )                             { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; }
    66 static inline void ?{}(thread_desc & this, struct cluster & cl )                                            { this{ "Anonymous Thread", cl, NULL, 65000 }; }
    67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, NULL, stackSize }; }
     66static inline void ?{}(thread_desc & this, struct cluster & cl )                                            { this{ "Anonymous Thread", cl, NULL, 0 }; }
     67static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, 0, stackSize }; }
    6868static inline void ?{}(thread_desc & this, struct cluster & cl, void * storage, size_t storageSize )        { this{ "Anonymous Thread", cl, storage, storageSize }; }
    69 static inline void ?{}(thread_desc & this, const char * const name)                                         { this{ name, *mainCluster, NULL, 65000 }; }
    70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl )                   { this{ name, cl, NULL, 65000 }; }
     69static inline void ?{}(thread_desc & this, const char * const name)                                         { this{ name, *mainCluster, NULL, 0 }; }
     70static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl )                   { this{ name, cl, NULL, 0 }; }
    7171static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, NULL, stackSize }; }
    7272
  • libcfa/src/containers/maybe.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed May 24 15:40:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 17 11:22:03 2019
    13 // Update Count     : 3
     12// Last Modified On : Thu Jul 20 15:23:50 2017
     13// Update Count     : 2
    1414//
    1515
     
    3939forall(otype T)
    4040maybe(T) ?=?(maybe(T) & this, maybe(T) that) {
    41         if (this.has_value && that.has_value) {
     41        if (this.has_value & that.has_value) {
    4242                this.value = that.value;
    4343        } else if (this.has_value) {
  • libcfa/src/containers/result.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed May 24 15:40:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 17 11:24:04 2019
    13 // Update Count     : 3
     12// Last Modified On : Thu Jul 20 15:23:58 2017
     13// Update Count     : 2
    1414//
    1515
     
    4848forall(otype T, otype E)
    4949result(T, E) ?=?(result(T, E) & this, result(T, E) that) {
    50         if (this.has_value && that.has_value) {
     50        if (this.has_value & that.has_value) {
    5151                this.value = that.value;
    5252        } else if (this.has_value) {
  • libcfa/src/fstream.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu May 16 08:33:28 2019
    13 // Update Count     : 328
     12// Last Modified On : Mon Dec 24 18:33:38 2018
     13// Update Count     : 304
    1414//
    1515
     
    2323#include <complex.h>                                                                    // creal, cimag
    2424#include <assert.h>
    25 #include <errno.h>                                                                              // errno
    2625
    2726#define IO_MSG "I/O error: "
    2827
    29 void ?{}( ofstream & os, void * file ) {
     28void ?{}( ofstream & os, void * file, bool sepDefault, bool sepOnOff, bool nlOnOff, bool prt, const char * separator, const char * tupleSeparator ) {
    3029        os.file = file;
    31         os.sepDefault = true;
    32         os.sepOnOff = false;
    33         os.nlOnOff = true;
    34         os.prt = false;
    35         os.sawNL = false;
    36         sepSet( os, " " );
     30        os.sepDefault = sepDefault;
     31        os.sepOnOff = sepOnOff;
     32        os.nlOnOff = nlOnOff;
     33        os.prt = prt;
     34        sepSet( os, separator );
    3735        sepSetCur( os, sepGet( os ) );
    38         sepSetTuple( os, ", " );
     36        sepSetTuple( os, tupleSeparator );
    3937}
    4038
     
    104102
    105103void open( ofstream & os, const char * name, const char * mode ) {
    106         FILE * file = fopen( name, mode );
     104        FILE *file = fopen( name, mode );
    107105        #ifdef __CFA_DEBUG__
    108106        if ( file == 0 ) {
    109                 abort( IO_MSG "open output file \"%s\", %s", name, strerror( errno ) );
     107                fprintf( stderr, IO_MSG "open output file \"%s\", ", name );
     108                perror( 0 );
     109                exit( EXIT_FAILURE );
    110110        } // if
    111111        #endif // __CFA_DEBUG__
    112         (os){ file };
     112        (os){ file, true, false, true, false, " ", ", " };
    113113} // open
    114114
     
    121121
    122122        if ( fclose( (FILE *)(os.file) ) == EOF ) {
    123                 abort( IO_MSG "close output %s", strerror( errno ) );
     123                perror( IO_MSG "close output" );
    124124        } // if
    125125} // close
     
    127127ofstream & write( ofstream & os, const char * data, size_t size ) {
    128128        if ( fail( os ) ) {
    129                 abort( "attempt write I/O on failed stream\n" );
     129                fprintf( stderr, "attempt write I/O on failed stream\n" );
     130                exit( EXIT_FAILURE );
    130131        } // if
    131132
    132133        if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) {
    133                 abort( IO_MSG "write %s", strerror( errno ) );
     134                perror( IO_MSG "write" );
     135                exit( EXIT_FAILURE );
    134136        } // if
    135137        return os;
     
    142144        if ( len == EOF ) {
    143145                if ( ferror( (FILE *)(os.file) ) ) {
    144                         abort( "invalid write\n" );
     146                        fprintf( stderr, "invalid write\n" );
     147                        exit( EXIT_FAILURE );
    145148                } // if
    146149        } // if
     
    152155} // fmt
    153156
    154 static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_) };
     157static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_), true, false, true, false, " ", ", " };
    155158ofstream & sout = soutFile;
    156 static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_) };
     159static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_), true, false, true, false, " ", ", " };
    157160ofstream & serr = serrFile;
    158161
    159 // static ofstream sexitFile = { (FILE *)(&_IO_2_1_stdout_) };
    160 // ofstream & sexit = sexitFile;
    161 // static ofstream sabortFile = { (FILE *)(&_IO_2_1_stderr_) };
    162 // ofstream & sabort = sabortFile;
    163 
    164 void nl( ofstream & os ) {
    165         if ( getANL( os ) ) (ofstream &)(nl( os ));                     // implementation only
    166         else setPrt( os, false );                                                       // turn off
    167 }
    168162
    169163//---------------------------------------
     
    172166void ?{}( ifstream & is, void * file ) {
    173167        is.file = file;
    174         is.nlOnOff = false;
    175168}
    176169
     
    184177        open( is, name, "r" );
    185178}
    186 
    187 void nlOn( ifstream & os ) { os.nlOnOff = true; }
    188 void nlOff( ifstream & os ) { os.nlOnOff = false; }
    189 bool getANL( ifstream & os ) { return os.nlOnOff; }
    190179
    191180int fail( ifstream & is ) {
     
    198187
    199188void open( ifstream & is, const char * name, const char * mode ) {
    200         FILE * file = fopen( name, mode );
     189        FILE *file = fopen( name, mode );
    201190        #ifdef __CFA_DEBUG__
    202191        if ( file == 0 ) {
    203                 abort( IO_MSG "open input file \"%s\", %s\n", name, strerror( errno ) );
     192                fprintf( stderr, IO_MSG "open input file \"%s\", ", name );
     193                perror( 0 );
     194                exit( EXIT_FAILURE );
    204195        } // if
    205196        #endif // __CFA_DEBUG__
     
    215206
    216207        if ( fclose( (FILE *)(is.file) ) == EOF ) {
    217                 abort( IO_MSG "close input %s", strerror( errno ) );
     208                perror( IO_MSG "close input" );
    218209        } // if
    219210} // close
     
    221212ifstream & read( ifstream & is, char * data, size_t size ) {
    222213        if ( fail( is ) ) {
    223                 abort( "attempt read I/O on failed stream\n" );
     214                fprintf( stderr, "attempt read I/O on failed stream\n" );
     215                exit( EXIT_FAILURE );
    224216        } // if
    225217
    226218        if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) {
    227                 abort( IO_MSG "read %s", strerror( errno ) );
     219                perror( IO_MSG "read" );
     220                exit( EXIT_FAILURE );
    228221        } // if
    229222        return is;
     
    232225ifstream &ungetc( ifstream & is, char c ) {
    233226        if ( fail( is ) ) {
    234                 abort( "attempt ungetc I/O on failed stream\n" );
     227                fprintf( stderr, "attempt ungetc I/O on failed stream\n" );
     228                exit( EXIT_FAILURE );
    235229        } // if
    236230
    237231        if ( ungetc( c, (FILE *)(is.file) ) == EOF ) {
    238                 abort( IO_MSG "ungetc %s", strerror( errno ) );
     232                perror( IO_MSG "ungetc" );
     233                exit( EXIT_FAILURE );
    239234        } // if
    240235        return is;
     
    248243        if ( len == EOF ) {
    249244                if ( ferror( (FILE *)(is.file) ) ) {
    250                         abort( "invalid read\n" );
     245                        fprintf( stderr, "invalid read\n" );
     246                        exit( EXIT_FAILURE );
    251247                } // if
    252248        } // if
  • libcfa/src/fstream.hfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu May 16 08:34:10 2019
    13 // Update Count     : 157
     12// Last Modified On : Mon Dec 24 18:33:41 2018
     13// Update Count     : 149
    1414//
    1515
     
    7070extern ofstream & sout, & serr;
    7171
    72 // extern ofstream & sout, & serr, & sexit, & sabort;
    73 // void nl( ofstream & os );
    74 
    7572
    7673struct ifstream {
    7774        void * file;
    78         bool nlOnOff;
    7975}; // ifstream
    8076
    8177// public
    82 void nlOn( ifstream & );
    83 void nlOff( ifstream & );
    84 bool getANL( ifstream & );
    8578int fail( ifstream & is );
    8679int eof( ifstream & is );
  • libcfa/src/gmp.hfa

    r933f32f r6a9d4b4  
    1010// Created On       : Tue Apr 19 08:43:43 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Apr 20 09:01:52 2019
    13 // Update Count     : 24
     12// Last Modified On : Tue Dec  4 23:25:51 2018
     13// Update Count     : 22
    1414//
    1515
     
    271271
    272272        void ?|?( ostype & os, Int mp ) {
    273                 (ostype)(os | mp); nl( os );
     273                (ostype)(os | mp); if ( getANL( os ) ) nl( os );
    274274        } // ?|?
    275275} // distribution
  • libcfa/src/heap.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu May  9 16:29:12 2019
    13 // Update Count     : 516
     12// Last Modified On : Thu Sep  6 09:01:30 2018
     13// Update Count     : 513
    1414//
    1515
     
    220220                StackLF<Storage> freeList;
    221221                #else
    222                         #error undefined lock type for bucket lock
     222                #error undefined lock type for bucket lock
    223223                #endif // SPINLOCK
    224224                size_t blockSize;                                                               // size of allocations on this list
     
    234234}; // HeapManager
    235235
    236 
    237236static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; }
    238 
    239237// statically allocated variables => zero filled.
     238
     239
    240240static size_t pageSize;                                                                 // architecture pagesize
    241241static size_t heapExpand;                                                               // sbrk advance
     
    306306        sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment
    307307        heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
    308 } // HeapManager
     308                           } // HeapManager
    309309
    310310
     
    316316        // } // if
    317317        #endif // __STATISTICS__
    318 } // ~HeapManager
     318                                } // ~HeapManager
    319319
    320320
     
    533533
    534534static inline void * doMalloc( size_t size ) with ( heapManager ) {
    535         HeapManager.Storage * block;                                            // pointer to new block of storage
     535        HeapManager.Storage * block;
    536536
    537537        // Look up size in the size list.  Make sure the user request includes space for the header that must be allocated
     
    656656        __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST );
    657657        if ( traceHeap() ) {
    658                 enum { BufferSize = 64 };
    659                 char helpText[BufferSize];
     658                char helpText[64];
    660659                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    661660                __cfaabi_dbg_bits_write( helpText, len );
     
    854853                        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    855854                        if ( ! mapped )
    856                         #endif // __CFA_DEBUG__
     855                                #endif // __CFA_DEBUG__
    857856                                memset( (char *)area + usize, '\0', asize - ( (char *)area - (char *)header ) - usize ); // zero-fill back part
    858857                        header->kind.real.blockSize |= 2;                       // mark new request as zero fill
     
    10351034// Local Variables: //
    10361035// tab-width: 4 //
    1037 // compile-command: "cfa -nodebug -O2 heap.cfa" //
     1036// compile-command: "cfa -nodebug -O2 heap.c" //
    10381037// End: //
  • libcfa/src/iostream.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun May 19 10:48:27 2019
    13 // Update Count     : 654
     12// Last Modified On : Mon Dec 24 18:33:40 2018
     13// Update Count     : 589
    1414//
    1515
     
    2323extern size_t strlen (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1)));
    2424#include <float.h>                                                                              // DBL_DIG, LDBL_DIG
    25 #include <math.h>                                                                               // isfinite
    2625#include <complex.h>                                                                    // creal, cimag
    2726}
    2827
    2928forall( dtype ostype | ostream( ostype ) ) {
    30         ostype & ?|?( ostype & os, zero_t ) {
    31                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    32                 fmt( os, "%d", 0n );
    33                 return os;
    34         } // ?|?
    35         void ?|?( ostype & os, zero_t z ) {
    36                 (ostype &)(os | z); nl( os );
    37         } // ?|?
    38 
    39         ostype & ?|?( ostype & os, one_t ) {
    40                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    41                 fmt( os, "%d", 1n );
    42                 return os;
    43         } // ?|?
    44         void ?|?( ostype & os, one_t o ) {
    45                 (ostype &)(os | o); nl( os );
    46         } // ?|?
    47 
    4829        ostype & ?|?( ostype & os, bool b ) {
    4930                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     
    154135        } // ?|?
    155136
    156         static void checkDecPt( ostype & os, const char * buf, int len ) {
    157                 for ( int i = 0;; i += 1 ) {
    158                         if ( i == len ) { fmt( os, "." ); break; }
    159                         if ( buf[i] == '.' ) break;
    160                 } // for
    161         } // checkDecPt
    162 
    163137        ostype & ?|?( ostype & os, float f ) {
    164138                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    165                 char buf[48];
    166                 int len = snprintf( buf, 48, "%g", f );
    167                 fmt( os, "%s", buf );
    168                 if ( isfinite( f ) ) checkDecPt( os, buf, len ); // always print decimal point
     139                fmt( os, "%g", f );
    169140                return os;
    170141        } // ?|?
     
    175146        ostype & ?|?( ostype & os, double d ) {
    176147                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    177                 char buf[48];
    178                 int len = snprintf( buf, 48, "%.*lg", DBL_DIG, d );
    179                 fmt( os, "%s", buf );
    180                 if ( isfinite( d ) ) checkDecPt( os, buf, len ); // always print decimal point
     148                fmt( os, "%.*lg", DBL_DIG, d );
    181149                return os;
    182150        } // ?|?
     
    187155        ostype & ?|?( ostype & os, long double ld ) {
    188156                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    189                 char buf[48];
    190                 int len = snprintf( buf, 48, "%.*Lg", LDBL_DIG, ld );
    191                 fmt( os, "%s", buf );
    192                 if ( isfinite( ld ) ) checkDecPt( os, buf, len ); // always print decimal point
     157                fmt( os, "%.*Lg", LDBL_DIG, ld );
    193158                return os;
    194159        } // ?|?
     
    199164        ostype & ?|?( ostype & os, float _Complex fc ) {
    200165                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    201 //              os | crealf( fc ) | nonl;
    202                 float f = crealf( fc );
    203                 char buf[48];
    204                 int len = snprintf( buf, 48, "%g", f );
    205                 fmt( os, "%s", buf );
    206                 if ( isfinite( f ) ) checkDecPt( os, buf, len ); // always print decimal point
    207                 f = cimagf( fc );
    208                 len = snprintf( buf, 48, "%+g", f );
    209                 fmt( os, "%s", buf );
    210                 if ( isfinite( f ) ) checkDecPt( os, buf, len ); // always print decimal point
    211                 fmt( os, "i" );
     166                fmt( os, "%g%+gi", crealf( fc ), cimagf( fc ) );
    212167                return os;
    213168        } // ?|?
     
    218173        ostype & ?|?( ostype & os, double _Complex dc ) {
    219174                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    220 //              os | creal( dc ) | nonl;
    221                 double d = creal( dc );
    222                 char buf[48];
    223                 int len = snprintf( buf, 48, "%.*lg", DBL_DIG, d );
    224                 fmt( os, "%s", buf );
    225                 if ( isfinite( d ) ) checkDecPt( os, buf, len ); // always print decimal point
    226                 d = cimag( dc );
    227                 len = snprintf( buf, 48, "%+.*lg", DBL_DIG, d );
    228                 fmt( os, "%s", buf );
    229                 if ( isfinite( d ) ) checkDecPt( os, buf, len ); // always print decimal point
    230                 fmt( os, "i" );
     175                fmt( os, "%.*lg%+.*lgi", DBL_DIG, creal( dc ), DBL_DIG, cimag( dc ) );
    231176                return os;
    232177        } // ?|?
     
    237182        ostype & ?|?( ostype & os, long double _Complex ldc ) {
    238183                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    239 //              os | creall( ldc ) || nonl;
    240                 long double ld = creall( ldc );
    241                 char buf[48];
    242                 int len = snprintf( buf, 48, "%.*Lg", LDBL_DIG, ld );
    243                 fmt( os, "%s", buf );
    244                 if ( isfinite( ld ) ) checkDecPt( os, buf, len ); // always print decimal point
    245                 ld = cimagl( ldc );
    246                 len = snprintf( buf, 48, "%+.*Lg", LDBL_DIG, ld );
    247                 fmt( os, "%s", buf );
    248                 if ( isfinite( ld ) ) checkDecPt( os, buf, len ); // always print decimal point
    249                 fmt( os, "i" );
     184                fmt( os, "%.*Lg%+.*Lgi", LDBL_DIG, creall( ldc ), LDBL_DIG, cimagl( ldc ) );
    250185                return os;
    251186        } // ?|?
     
    443378
    444379        istype & ?|?( istype & is, char & c ) {
    445                 char temp;
    446                 for () {
    447                         fmt( is, "%c", &temp );                                                 // must pass pointer through varg to fmt
    448                         // do not overwrite parameter with newline unless appropriate
    449                         if ( temp != '\n' || getANL( is ) ) { c = temp; break; }
    450                         if ( eof( is ) ) break;
    451                 } // for
     380                fmt( is, "%c", &c );                                                    // must pass pointer through varg to fmt
    452381                return is;
    453382        } // ?|?
     
    541470        } // ?|?
    542471
     472
    543473        // manipulators
    544474        istype & ?|?( istype & is, istype & (* manip)( istype & ) ) {
     
    547477
    548478        istype & nl( istype & is ) {
    549                 fmt( is, "%*[^\n]" );                                                   // ignore characters to newline
     479                fmt( is, "%*[ \t\f\n\r\v]" );                                   // ignore whitespace
    550480                return is;
    551481        } // nl
    552 
    553         istype & nlOn( istype & is ) {
    554                 nlOn( is );                                                                             // call void returning
    555                 return is;
    556         } // nlOn
    557 
    558         istype & nlOff( istype & is ) {
    559                 nlOff( is );                                                                    // call void returning
    560                 return is;
    561         } // nlOff
    562482} // distribution
    563483
  • libcfa/src/iostream.hfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 11 10:31:27 2019
    13 // Update Count     : 232
     12// Last Modified On : Mon Dec 24 18:33:40 2018
     13// Update Count     : 220
    1414//
    1515
     
    4848        void close( ostype & os );
    4949        ostype & write( ostype &, const char *, size_t );
    50         int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
     50        int fmt( ostype &, const char format[], ... );
    5151}; // ostream
    5252
     
    6262
    6363forall( dtype ostype | ostream( ostype ) ) {
    64         ostype & ?|?( ostype &, zero_t );
    65         void ?|?( ostype &, zero_t );
    66         ostype & ?|?( ostype &, one_t );
    67         void ?|?( ostype &, one_t );
    68 
    6964        ostype & ?|?( ostype &, bool );
    7065        void ?|?( ostype &, bool );
     
    149144
    150145trait istream( dtype istype ) {
    151         void nlOn( istype & );                                                          // read newline
    152         void nlOff( istype & );                                                         // scan newline
    153         bool getANL( istype & );                                                        // get scan newline (on/off)
    154146        int fail( istype & );
    155147        int eof( istype & );
     
    158150        istype & read( istype &, char *, size_t );
    159151        istype & ungetc( istype &, char );
    160         int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     152        int fmt( istype &, const char format[], ... );
    161153}; // istream
    162154
     
    192184        istype & ?|?( istype &, istype & (*)( istype & ) );
    193185        istype & nl( istype & is );
    194         istype & nlOn( istype & );
    195         istype & nlOff( istype & );
    196186} // distribution
    197187
     
    215205
    216206// Local Variables: //
     207// mode: c //
    217208// tab-width: 4 //
    218209// End: //
  • libcfa/src/rational.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed Apr  6 17:54:28 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar 28 17:33:03 2019
    13 // Update Count     : 181
     12// Last Modified On : Sun Dec 23 22:56:49 2018
     13// Update Count     : 170
    1414//
    1515
     
    3535        static RationalImpl simplify( RationalImpl & n, RationalImpl & d ) {
    3636                if ( d == (RationalImpl){0} ) {
    37                         abort( "Invalid rational number construction: denominator cannot be equal to 0.\n" );
     37                        serr | "Invalid rational number construction: denominator cannot be equal to 0.";
     38                        exit( EXIT_FAILURE );
    3839                } // exit
    3940                if ( d < (RationalImpl){0} ) { d = -d; n = -n; } // move sign to numerator
     
    5354        void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ) {
    5455                RationalImpl t = simplify( n, d );                              // simplify
    55                 r.[numerator, denominator] = [n / t, d / t];
     56                r.numerator = n / t;
     57                r.denominator = d / t;
    5658        } // rational
    5759
     
    7678                RationalImpl prev = r.numerator;
    7779                RationalImpl t = gcd( abs( n ), r.denominator ); // simplify
    78                 r.[numerator, denominator] = [n / t, r.denominator / t];
     80                r.numerator = n / t;
     81                r.denominator = r.denominator / t;
    7982                return prev;
    8083        } // numerator
     
    8386                RationalImpl prev = r.denominator;
    8487                RationalImpl t = simplify( r.numerator, d );    // simplify
    85                 r.[numerator, denominator] = [r.numerator / t, d / t];
     88                r.numerator = r.numerator / t;
     89                r.denominator = d / t;
    8690                return prev;
    8791        } // denominator
     
    116120
    117121        Rational(RationalImpl) +?( Rational(RationalImpl) r ) {
    118                 return (Rational(RationalImpl)){ r.numerator, r.denominator };
     122                Rational(RationalImpl) t = { r.numerator, r.denominator };
     123                return t;
    119124        } // +?
    120125
    121126        Rational(RationalImpl) -?( Rational(RationalImpl) r ) {
    122                 return (Rational(RationalImpl)){ -r.numerator, r.denominator };
     127                Rational(RationalImpl) t = { -r.numerator, r.denominator };
     128                return t;
    123129        } // -?
    124130
    125131        Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    126132                if ( l.denominator == r.denominator ) {                 // special case
    127                         return (Rational(RationalImpl)){ l.numerator + r.numerator, l.denominator };
     133                        Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator };
     134                        return t;
    128135                } else {
    129                         return (Rational(RationalImpl)){ l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
     136                        Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
     137                        return t;
    130138                } // if
    131139        } // ?+?
     
    133141        Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    134142                if ( l.denominator == r.denominator ) {                 // special case
    135                         return (Rational(RationalImpl)){ l.numerator - r.numerator, l.denominator };
     143                        Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator };
     144                        return t;
    136145                } else {
    137                         return (Rational(RationalImpl)){ l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
     146                        Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
     147                        return t;
    138148                } // if
    139149        } // ?-?
    140150
    141151        Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    142                 return (Rational(RationalImpl)){ l.numerator * r.numerator, l.denominator * r.denominator };
     152                Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator };
     153                return t;
    143154        } // ?*?
    144155
    145156        Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    146157                if ( r.numerator < (RationalImpl){0} ) {
    147                         r.[numerator, denominator] = [-r.numerator, -r.denominator];
     158                        r.numerator = -r.numerator;
     159                        r.denominator = -r.denominator;
    148160                } // if
    149                 return (Rational(RationalImpl)){ l.numerator * r.denominator, l.denominator * r.numerator };
     161                Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator };
     162                return t;
    150163        } // ?/?
    151164
     
    154167        forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )
    155168        istype & ?|?( istype & is, Rational(RationalImpl) & r ) {
     169                RationalImpl t;
    156170                is | r.numerator | r.denominator;
    157                 RationalImpl t = simplify( r.numerator, r.denominator );
     171                t = simplify( r.numerator, r.denominator );
    158172                r.numerator /= t;
    159173                r.denominator /= t;
     
    171185        } // distribution
    172186} // distribution
    173 
    174 forall( otype RationalImpl | arithmetic( RationalImpl ) | { RationalImpl ?\?( RationalImpl, unsigned long ); } )
    175 Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y ) {
    176         if ( y < 0 ) {
    177                 return (Rational(RationalImpl)){ x.denominator \ -y, x.numerator \ -y };
    178         } else {
    179                 return (Rational(RationalImpl)){ x.numerator \ y, x.denominator \ y };
    180         } // if
    181 }
    182187
    183188// conversion
  • libcfa/src/rational.hfa

    r933f32f r6a9d4b4  
    1212// Created On       : Wed Apr  6 17:56:25 2016
    1313// Last Modified By : Peter A. Buhr
    14 // Last Modified On : Tue Mar 26 23:16:10 2019
    15 // Update Count     : 109
     14// Last Modified On : Tue Dec  4 23:07:46 2018
     15// Update Count     : 106
    1616//
    1717
     
    9898} // distribution
    9999
    100 forall( otype RationalImpl | arithmetic( RationalImpl ) |{RationalImpl ?\?( RationalImpl, unsigned long );} )
    101 Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y );
    102 
    103100// conversion
    104101forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); } )
  • libcfa/src/stdhdr/stdbool.h

    r933f32f r6a9d4b4  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 25 08:00:08 2019
    13 // Update Count     : 15
     12// Last Modified On : Tue Jul  5 20:39:51 2016
     13// Update Count     : 12
    1414//
    1515
    1616extern "C" {
    1717#include_next <stdbool.h>                                                               // has internal check for multiple expansion
    18 
    19 // allows printing as true/false
    20 #if defined( true )
    21 #undef true
    22 #define true ((_Bool)1)
    23 #endif // true
    24 
    25 #if defined( false )
    26 #undef false
    27 #define false ((_Bool)0)
    28 #endif // false
    2918} // extern "C"
    3019
  • libcfa/src/stdlib.hfa

    r933f32f r6a9d4b4  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 24 17:35:43 2019
    13 // Update Count     : 352
     12// Last Modified On : Mon Dec 17 15:37:45 2018
     13// Update Count     : 346
    1414//
    1515
     
    4040        } // malloc
    4141
     42        // T & malloc( void ) {
     43        //      int & p = *(T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc
     44        //      printf( "& malloc %p\n", &p );
     45        //      return p;
     46        //      //      return (T &)*(T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc
     47        // } // malloc
     48
    4249        T * calloc( size_t dim ) {
    4350                return (T *)(void *)calloc( dim, sizeof(T) );   // C calloc
     
    6976        T * alloc( char fill ) {
    7077                T * ptr = (T *)(void *)malloc( (size_t)sizeof(T) );     // C malloc
    71                 return (T *)memset( ptr, (int)fill, sizeof(T) ); // initialize with fill value
     78                return (T *)memset( ptr, (int)fill, sizeof(T) );        // initial with fill value
    7279        } // alloc
    7380
     
    7784
    7885        T * alloc( size_t dim, char fill ) {
    79                 T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C calloc
    80                 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); // initialize with fill value
     86                T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C malloc
     87                return (T *)memset( ptr, (int)fill, dim * sizeof(T) );    // initial with fill value
    8188        } // alloc
    8289
  • libcfa/src/time.hfa

    r933f32f r6a9d4b4  
    3030
    3131static inline {
    32         Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; }
     32        Duration ?=?( Duration & dur, zero_t ) { return dur{ 0 }; }
    3333
    3434        Duration +?( Duration rhs ) with( rhs ) {       return (Duration)@{ +tv }; }
     
    5959        bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tv >= rhs.tv; }
    6060
    61         bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv == 0; }
    62         bool ?!=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv != 0; }
    63         bool ?<? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv <  0; }
    64         bool ?<=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv <= 0; }
    65         bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv >  0; }
    66         bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv >= 0; }
     61        bool ?==?( Duration lhs, zero_t ) { return lhs.tv == 0; }
     62        bool ?!=?( Duration lhs, zero_t ) { return lhs.tv != 0; }
     63        bool ?<? ( Duration lhs, zero_t ) { return lhs.tv <  0; }
     64        bool ?<=?( Duration lhs, zero_t ) { return lhs.tv <= 0; }
     65        bool ?>? ( Duration lhs, zero_t ) { return lhs.tv >  0; }
     66        bool ?>=?( Duration lhs, zero_t ) { return lhs.tv >= 0; }
    6767
    6868        Duration abs( Duration rhs ) { return rhs.tv >= 0 ? rhs : -rhs; }
     
    101101        void ?{}( timeval & t, time_t sec, suseconds_t usec ) { t.tv_sec = sec; t.tv_usec = usec; }
    102102        void ?{}( timeval & t, time_t sec ) { t{ sec, 0 }; }
    103         void ?{}( timeval & t, __attribute__((unused)) zero_t ) { t{ 0, 0 }; }
    104 
    105         timeval ?=?( timeval & t, __attribute__((unused)) zero_t ) { return t{ 0 }; }
     103        void ?{}( timeval & t, zero_t ) { t{ 0, 0 }; }
     104
     105        timeval ?=?( timeval & t, zero_t ) { return t{ 0 }; }
    106106        timeval ?+?( timeval lhs, timeval rhs ) { return (timeval)@{ lhs.tv_sec + rhs.tv_sec, lhs.tv_usec + rhs.tv_usec }; }
    107107        timeval ?-?( timeval lhs, timeval rhs ) { return (timeval)@{ lhs.tv_sec - rhs.tv_sec, lhs.tv_usec - rhs.tv_usec }; }
     
    116116        void ?{}( timespec & t, time_t sec, __syscall_slong_t nsec ) { t.tv_sec = sec; t.tv_nsec = nsec; }
    117117        void ?{}( timespec & t, time_t sec ) { t{ sec, 0}; }
    118         void ?{}( timespec & t, __attribute__((unused)) zero_t ) { t{ 0, 0 }; }
    119 
    120         timespec ?=?( timespec & t, __attribute__((unused)) zero_t ) { return t{ 0 }; }
     118        void ?{}( timespec & t, zero_t ) { t{ 0, 0 }; }
     119
     120        timespec ?=?( timespec & t, zero_t ) { return t{ 0 }; }
    121121        timespec ?+?( timespec lhs, timespec rhs ) { return (timespec)@{ lhs.tv_sec + rhs.tv_sec, lhs.tv_nsec + rhs.tv_nsec }; }
    122122        timespec ?-?( timespec lhs, timespec rhs ) { return (timespec)@{ lhs.tv_sec - rhs.tv_sec, lhs.tv_nsec - rhs.tv_nsec }; }
     
    145145void ?{}( Time & time, int year, int month = 0, int day = 0, int hour = 0, int min = 0, int sec = 0, int nsec = 0 );
    146146static inline {
    147         Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; }
     147        Time ?=?( Time & time, zero_t ) { return time{ 0 }; }
    148148
    149149        void ?{}( Time & time, timeval t ) with( time ) { tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
  • libcfa/src/time_t.hfa

    r933f32f r6a9d4b4  
    2424
    2525static inline void ?{}( Duration & dur ) with( dur ) { tv = 0; }
    26 static inline void ?{}( Duration & dur, __attribute__((unused)) zero_t ) with( dur ) { tv = 0; }
     26static inline void ?{}( Duration & dur, zero_t ) with( dur ) { tv = 0; }
    2727
    2828
     
    3434
    3535static inline void ?{}( Time & time ) with( time ) { tv = 0; }
    36 static inline void ?{}( Time & time, __attribute__((unused)) zero_t ) with( time ) { tv = 0; }
     36static inline void ?{}( Time & time, zero_t ) with( time ) { tv = 0; }
    3737
    3838// Local Variables: //
  • src/CodeGen/CodeGenerator.cc

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr May  2 10:47:00 2019
    13 // Update Count     : 497
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat May  5 09:08:32 2018
     13// Update Count     : 494
    1414//
    1515#include "CodeGenerator.h"
     
    8383        void CodeGenerator::updateLocation( CodeLocation const & to ) {
    8484                // skip if linemarks shouldn't appear or if codelocation is unset
    85                 if ( !options.lineMarks || to.isUnset() ) return;
     85                if ( !lineMarks || to.isUnset() ) return;
    8686
    8787                if ( currentLocation.followedBy( to, 0 ) ) {
     
    116116        }
    117117
    118         CodeGenerator::CodeGenerator( std::ostream & os, bool pretty, bool genC, bool lineMarks, bool printExprTypes ) : indent( CodeGenerator::tabsize ), output( os ), printLabels( *this ), options( pretty, genC, lineMarks, printExprTypes ), endl( *this ) {}
    119         CodeGenerator::CodeGenerator( std::ostream & os, const Options &options ) : indent( CodeGenerator::tabsize ), output( os ), printLabels( *this ), options(options), endl( *this ) {}
     118        CodeGenerator::CodeGenerator( std::ostream & os, bool pretty, bool genC, bool lineMarks, bool printExprTypes ) : indent( CodeGenerator::tabsize ), output( os ), printLabels( *this ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ), printExprTypes( printExprTypes ), endl( *this ) {}
    120119
    121120        string CodeGenerator::mangleName( DeclarationWithType * decl ) {
    122121                // GCC builtins should always be printed unmangled
    123                 if ( options.pretty || decl->linkage.is_gcc_builtin ) return decl->name;
     122                if ( pretty || decl->linkage.is_gcc_builtin ) return decl->name;
    124123                if ( decl->mangleName != "" ) {
    125124                        // need to incorporate scope level in order to differentiate names for destructors
     
    165164                previsit( (BaseSyntaxNode *)node );
    166165                GuardAction( [this, node](){
    167                         if ( options.printExprTypes && node->result ) {
    168                                 output << " /* " << genType( node->result, "", options ) << " */ ";
     166                        if ( printExprTypes && node->result ) {
     167                                output << " /* " << genType( node->result, "", pretty, genC ) << " */ ";
    169168                        }
    170169                } );
     
    174173        void CodeGenerator::postvisit( FunctionDecl * functionDecl ) {
    175174                // deleted decls should never be used, so don't print them
    176                 if ( functionDecl->isDeleted && options.genC ) return;
     175                if ( functionDecl->isDeleted && genC ) return;
    177176                extension( functionDecl );
    178177                genAttributes( functionDecl->get_attributes() );
     
    181180                functionDecl->get_funcSpec().print( output );
    182181
    183                 Options subOptions = options;
    184                 subOptions.anonymousUnused = functionDecl->has_body();
    185                 output << genType( functionDecl->get_functionType(), mangleName( functionDecl ), subOptions );
     182                output << genType( functionDecl->get_functionType(), mangleName( functionDecl ), pretty, genC );
    186183
    187184                asmName( functionDecl );
     
    197194        void CodeGenerator::postvisit( ObjectDecl * objectDecl ) {
    198195                // deleted decls should never be used, so don't print them
    199                 if ( objectDecl->isDeleted && options.genC ) return;
    200                 if (objectDecl->get_name().empty() && options.genC ) {
     196                if ( objectDecl->isDeleted && genC ) return;
     197                if (objectDecl->get_name().empty() && genC ) {
    201198                        // only generate an anonymous name when generating C code, otherwise it clutters the output too much
    202199                        static UniqueName name = { "__anonymous_object" };
    203200                        objectDecl->set_name( name.newName() );
    204             // Stops unused parameter warnings.
    205             if ( options.anonymousUnused ) {
    206                 objectDecl->attributes.push_back( new Attribute( "unused" ) );
    207             }
    208201                }
    209202
     
    212205
    213206                handleStorageClass( objectDecl );
    214                 output << genType( objectDecl->get_type(), mangleName( objectDecl ), options.pretty, options.genC );
     207                output << genType( objectDecl->get_type(), mangleName( objectDecl ), pretty, genC );
    215208
    216209                asmName( objectDecl );
     
    231224
    232225        void CodeGenerator::handleAggregate( AggregateDecl * aggDecl, const std::string & kind ) {
    233                 if( ! aggDecl->parameters.empty() && ! options.genC ) {
     226                if( ! aggDecl->parameters.empty() && ! genC ) {
    234227                        // assertf( ! genC, "Aggregate type parameters should not reach code generation." );
    235228                        output << "forall(";
     
    301294
    302295        void CodeGenerator::postvisit( TraitDecl * traitDecl ) {
    303                 assertf( ! options.genC, "TraitDecls should not reach code generation." );
     296                assertf( ! genC, "TraitDecls should not reach code generation." );
    304297                extension( traitDecl );
    305298                handleAggregate( traitDecl, "trait " );
     
    307300
    308301        void CodeGenerator::postvisit( TypedefDecl * typeDecl ) {
    309                 assertf( ! options.genC, "Typedefs are removed and substituted in earlier passes." );
     302                assertf( ! genC, "Typedefs are removed and substituted in earlier passes." );
    310303                output << "typedef ";
    311                 output << genType( typeDecl->get_base(), typeDecl->get_name(), options ) << endl;
     304                output << genType( typeDecl->get_base(), typeDecl->get_name(), pretty, genC ) << endl;
    312305        }
    313306
    314307        void CodeGenerator::postvisit( TypeDecl * typeDecl ) {
    315                 assertf( ! options.genC, "TypeDecls should not reach code generation." );
     308                assertf( ! genC, "TypeDecls should not reach code generation." );
    316309                output << typeDecl->genTypeString() << " " << typeDecl->name;
    317310                if ( typeDecl->sized ) {
     
    378371
    379372        void CodeGenerator::postvisit( ConstructorInit * init ){
    380                 assertf( ! options.genC, "ConstructorInit nodes should not reach code generation." );
     373                assertf( ! genC, "ConstructorInit nodes should not reach code generation." );
    381374                // pseudo-output for constructor/destructor pairs
    382375                output << "<ctorinit>{" << endl << ++indent << "ctor: ";
     
    514507                                        } else {
    515508                                                // no constructors with 0 or more than 2 parameters
    516                                                 assertf( ! options.genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );
     509                                                assertf( ! genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );
    517510                                                output << "(";
    518511                                                (*arg++)->accept( *visitor );
     
    611604                        // an lvalue cast, this has been taken out.
    612605                        output << "(";
    613                         output << genType( castExpr->get_result(), "", options );
     606                        output << genType( castExpr->get_result(), "", pretty, genC );
    614607                        output << ")";
    615608                } // if
     
    619612
    620613        void CodeGenerator::postvisit( KeywordCastExpr * castExpr ) {
    621                 assertf( ! options.genC, "KeywordCast should not reach code generation." );
     614                assertf( ! genC, "KeywordCast should not reach code generation." );
    622615                extension( castExpr );
    623616                output << "((" << castExpr->targetString() << " &)";
     
    627620
    628621        void CodeGenerator::postvisit( VirtualCastExpr * castExpr ) {
    629                 assertf( ! options.genC, "VirtualCastExpr should not reach code generation." );
     622                assertf( ! genC, "VirtualCastExpr should not reach code generation." );
    630623                extension( castExpr );
    631624                output << "(virtual ";
     
    635628
    636629        void CodeGenerator::postvisit( UntypedMemberExpr * memberExpr ) {
    637                 assertf( ! options.genC, "UntypedMemberExpr should not reach code generation." );
     630                assertf( ! genC, "UntypedMemberExpr should not reach code generation." );
    638631                extension( memberExpr );
    639632                memberExpr->get_aggregate()->accept( *visitor );
     
    668661                output << "sizeof(";
    669662                if ( sizeofExpr->get_isType() ) {
    670                         output << genType( sizeofExpr->get_type(), "", options );
     663                        output << genType( sizeofExpr->get_type(), "", pretty, genC );
    671664                } else {
    672665                        sizeofExpr->get_expr()->accept( *visitor );
     
    680673                output << "__alignof__(";
    681674                if ( alignofExpr->get_isType() ) {
    682                         output << genType( alignofExpr->get_type(), "", options );
     675                        output << genType( alignofExpr->get_type(), "", pretty, genC );
    683676                } else {
    684677                        alignofExpr->get_expr()->accept( *visitor );
     
    688681
    689682        void CodeGenerator::postvisit( UntypedOffsetofExpr * offsetofExpr ) {
    690                 assertf( ! options.genC, "UntypedOffsetofExpr should not reach code generation." );
     683                assertf( ! genC, "UntypedOffsetofExpr should not reach code generation." );
    691684                output << "offsetof(";
    692                 output << genType( offsetofExpr->get_type(), "", options );
     685                output << genType( offsetofExpr->get_type(), "", pretty, genC );
    693686                output << ", " << offsetofExpr->get_member();
    694687                output << ")";
     
    698691                // use GCC builtin
    699692                output << "__builtin_offsetof(";
    700                 output << genType( offsetofExpr->get_type(), "", options );
     693                output << genType( offsetofExpr->get_type(), "", pretty, genC );
    701694                output << ", " << mangleName( offsetofExpr->get_member() );
    702695                output << ")";
     
    704697
    705698        void CodeGenerator::postvisit( OffsetPackExpr * offsetPackExpr ) {
    706                 assertf( ! options.genC, "OffsetPackExpr should not reach code generation." );
    707                 output << "__CFA_offsetpack(" << genType( offsetPackExpr->get_type(), "", options ) << ")";
     699                assertf( ! genC, "OffsetPackExpr should not reach code generation." );
     700                output << "__CFA_offsetpack(" << genType( offsetPackExpr->get_type(), "", pretty, genC ) << ")";
    708701        }
    709702
     
    735728                extension( commaExpr );
    736729                output << "(";
    737                 if ( options.genC ) {
     730                if ( genC ) {
    738731                        // arg1 of a CommaExpr is never used, so it can be safely cast to void to reduce gcc warnings.
    739732                        commaExpr->set_arg1( new CastExpr( commaExpr->get_arg1() ) );
     
    746739
    747740        void CodeGenerator::postvisit( TupleAssignExpr * tupleExpr ) {
    748                 assertf( ! options.genC, "TupleAssignExpr should not reach code generation." );
     741                assertf( ! genC, "TupleAssignExpr should not reach code generation." );
    749742                tupleExpr->stmtExpr->accept( *visitor );
    750743        }
    751744
    752745        void CodeGenerator::postvisit( UntypedTupleExpr * tupleExpr ) {
    753                 assertf( ! options.genC, "UntypedTupleExpr should not reach code generation." );
     746                assertf( ! genC, "UntypedTupleExpr should not reach code generation." );
    754747                extension( tupleExpr );
    755748                output << "[";
     
    759752
    760753        void CodeGenerator::postvisit( TupleExpr * tupleExpr ) {
    761                 assertf( ! options.genC, "TupleExpr should not reach code generation." );
     754                assertf( ! genC, "TupleExpr should not reach code generation." );
    762755                extension( tupleExpr );
    763756                output << "[";
     
    767760
    768761        void CodeGenerator::postvisit( TupleIndexExpr * tupleExpr ) {
    769                 assertf( ! options.genC, "TupleIndexExpr should not reach code generation." );
     762                assertf( ! genC, "TupleIndexExpr should not reach code generation." );
    770763                extension( tupleExpr );
    771764                tupleExpr->get_tuple()->accept( *visitor );
     
    774767
    775768        void CodeGenerator::postvisit( TypeExpr * typeExpr ) {
    776                 // if ( options.genC ) std::cerr << "typeexpr still exists: " << typeExpr << std::endl;
    777                 // assertf( ! options.genC, "TypeExpr should not reach code generation." );
    778                 if ( ! options.genC ) {
    779                         output << genType( typeExpr->get_type(), "", options );
     769                // if ( genC ) std::cerr << "typeexpr still exists: " << typeExpr << std::endl;
     770                // assertf( ! genC, "TypeExpr should not reach code generation." );
     771                if ( ! genC ) {
     772                        output<< genType( typeExpr->get_type(), "", pretty, genC );
    780773                }
    781774        }
     
    795788        void CodeGenerator::postvisit( CompoundLiteralExpr *compLitExpr ) {
    796789                assert( compLitExpr->get_result() && dynamic_cast< ListInit * > ( compLitExpr->get_initializer() ) );
    797                 output << "(" << genType( compLitExpr->get_result(), "", options ) << ")";
     790                output << "(" << genType( compLitExpr->get_result(), "", pretty, genC ) << ")";
    798791                compLitExpr->get_initializer()->accept( *visitor );
    799792        }
    800793
    801794        void CodeGenerator::postvisit( UniqueExpr * unqExpr ) {
    802                 assertf( ! options.genC, "Unique expressions should not reach code generation." );
     795                assertf( ! genC, "Unique expressions should not reach code generation." );
    803796                output << "unq<" << unqExpr->get_id() << ">{ ";
    804797                unqExpr->get_expr()->accept( *visitor );
     
    836829
    837830        void CodeGenerator::postvisit( ConstructorExpr * expr ) {
    838                 assertf( ! options.genC, "Unique expressions should not reach code generation." );
     831                assertf( ! genC, "Unique expressions should not reach code generation." );
    839832                expr->callExpr->accept( *visitor );
    840833        }
    841834
    842835        void CodeGenerator::postvisit( DeletedExpr * expr ) {
    843                 assertf( ! options.genC, "Deleted expressions should not reach code generation." );
     836                assertf( ! genC, "Deleted expressions should not reach code generation." );
    844837                expr->expr->accept( *visitor );
    845838        }
    846839
    847840        void CodeGenerator::postvisit( DefaultArgExpr * arg ) {
    848                 assertf( ! options.genC, "Default argument expressions should not reach code generation." );
     841                assertf( ! genC, "Default argument expressions should not reach code generation." );
    849842                arg->expr->accept( *visitor );
    850843        }
    851844
    852845        void CodeGenerator::postvisit( GenericExpr * expr ) {
    853                 assertf( ! options.genC, "C11 _Generic expressions should not reach code generation." );
     846                assertf( ! genC, "C11 _Generic expressions should not reach code generation." );
    854847                output << "_Generic(";
    855848                expr->control->accept( *visitor );
     
    861854                                output << "default: ";
    862855                        } else {
    863                                 output << genType( assoc.type, "", options ) << ": ";
     856                                output << genType( assoc.type, "", pretty, genC ) << ": ";
    864857                        }
    865858                        assoc.expr->accept( *visitor );
     
    896889        void CodeGenerator::postvisit( ExprStmt * exprStmt ) {
    897890                assert( exprStmt );
    898                 if ( options.genC ) {
     891                if ( genC ) {
    899892                        // cast the top-level expression to void to reduce gcc warnings.
    900893                        exprStmt->set_expr( new CastExpr( exprStmt->get_expr() ) );
     
    1006999                  case BranchStmt::FallThrough:
    10071000                  case BranchStmt::FallThroughDefault:
    1008                         assertf( ! options.genC, "fallthru should not reach code generation." );
     1001                        assertf( ! genC, "fallthru should not reach code generation." );
    10091002                  output << "fallthru";
    10101003                        break;
    10111004                } // switch
    10121005                // print branch target for labelled break/continue/fallthru in debug mode
    1013                 if ( ! options.genC && branchStmt->get_type() != BranchStmt::Goto ) {
     1006                if ( ! genC && branchStmt->get_type() != BranchStmt::Goto ) {
    10141007                        if ( ! branchStmt->get_target().empty() ) {
    10151008                                output << " " << branchStmt->get_target();
     
    10281021
    10291022        void CodeGenerator::postvisit( ThrowStmt * throwStmt ) {
    1030                 assertf( ! options.genC, "Throw statements should not reach code generation." );
     1023                assertf( ! genC, "Throw statements should not reach code generation." );
    10311024
    10321025                output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ?
     
    10431036        }
    10441037        void CodeGenerator::postvisit( CatchStmt * stmt ) {
    1045                 assertf( ! options.genC, "Catch statements should not reach code generation." );
     1038                assertf( ! genC, "Catch statements should not reach code generation." );
    10461039
    10471040                output << ((stmt->get_kind() == CatchStmt::Terminate) ?
     
    10601053
    10611054        void CodeGenerator::postvisit( WaitForStmt * stmt ) {
    1062                 assertf( ! options.genC, "Waitfor statements should not reach code generation." );
     1055                assertf( ! genC, "Waitfor statements should not reach code generation." );
    10631056
    10641057                bool first = true;
     
    11061099
    11071100        void CodeGenerator::postvisit( WithStmt * with ) {
    1108                 if ( ! options.genC ) {
     1101                if ( ! genC ) {
    11091102                        output << "with ( ";
    11101103                        genCommaList( with->exprs.begin(), with->exprs.end() );
     
    11721165
    11731166        void CodeGenerator::postvisit( ImplicitCtorDtorStmt * stmt ) {
    1174                 assertf( ! options.genC, "ImplicitCtorDtorStmts should not reach code generation." );
     1167                assertf( ! genC, "ImplicitCtorDtorStmts should not reach code generation." );
    11751168                stmt->callStmt->accept( *visitor );
    11761169        }
  • src/CodeGen/CodeGenerator.h

    r933f32f r6a9d4b4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr 30 12:01:00 2019
    13 // Update Count     : 57
     12// Last Modified On : Fri Aug 18 15:40:00 2017
     13// Update Count     : 56
    1414//
    1515
     
    2020#include <string>                 // for string
    2121
    22 #include "CodeGen/Options.h"      // for Options
    2322#include "Common/Indenter.h"      // for Indenter
    2423#include "Common/PassVisitor.h"   // for PassVisitor
     
    3231
    3332                CodeGenerator( std::ostream &os, bool pretty = false, bool genC = false, bool lineMarks = false, bool printExprTypes = false );
    34                 CodeGenerator( std::ostream &os, const Options &options );
    3533
    3634                //*** Turn off visit_children for all nodes
     
    146144                std::ostream & output;
    147145                LabelPrinter printLabels;
    148                 Options options;
     146                bool pretty = false;  // pretty print
     147                bool genC = false;    // true if output has to be C code
     148                bool lineMarks = false;
     149                bool printExprTypes = false;
    149150        public:
    150151                LineEnder endl;
  • src/CodeGen/GenType.cc

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed May  1 15:24:00 2019
    13 // Update Count     : 23
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Mar 17 09:02:28 2017
     13// Update Count     : 22
    1414//
    1515#include "GenType.h"
     
    2828        struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
    2929                std::string typeString;
    30                 GenType( const std::string &typeString, const Options &options );
     30                GenType( const std::string &typeString, bool pretty, bool genC, bool lineMarks );
    3131
    3232                void previsit( BaseSyntaxNode * );
     
    5757                void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
    5858
    59                 Options options;
     59                bool pretty = false;    // pretty print
     60                bool genC = false;      // generating C code?
     61                bool lineMarks = false; // lineMarks on for CodeGenerator?
    6062        };
    6163
    62         std::string genType( Type *type, const std::string &baseString, const Options &options ) {
    63                 PassVisitor<GenType> gt( baseString, options );
     64        std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {
     65                PassVisitor<GenType> gt( baseString, pretty, genC, lineMarks );
    6466                std::ostringstream os;
    6567
    6668                if ( ! type->get_attributes().empty() ) {
    67                         PassVisitor<CodeGenerator> cg( os, options );
     69                        PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    6870                        cg.pass.genAttributes( type->get_attributes() );
    6971                } // if
     
    7375        }
    7476
    75         std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {
    76                 return genType( type, baseString, Options(pretty, genC, lineMarks, false ) );
    77         }
    78 
    79         std::string genPrettyType( Type * type, const std::string & baseString ) {
    80                 return genType( type, baseString, true, false );
    81         }
    82 
    83         GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {}
     77  std::string genPrettyType( Type * type, const std::string & baseString ) {
     78        return genType( type, baseString, true, false );
     79  }
     80
     81        GenType::GenType( const std::string &typeString, bool pretty, bool genC, bool lineMarks ) : typeString( typeString ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ) {}
    8482
    8583        // *** BaseSyntaxNode
     
    135133                } // if
    136134                if ( dimension != 0 ) {
    137                         PassVisitor<CodeGenerator> cg( os, options );
     135                        PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    138136                        dimension->accept( cg );
    139137                } else if ( isVarLen ) {
     
    169167        void GenType::postvisit( ReferenceType * refType ) {
    170168                assert( refType->base != 0);
    171                 assertf( ! options.genC, "Reference types should not reach code generation." );
     169                assertf( ! genC, "Reference types should not reach code generation." );
    172170                handleQualifiers( refType );
    173171                typeString = "&" + typeString;
     
    197195                        } // if
    198196                } else {
    199                         PassVisitor<CodeGenerator> cg( os, options );
     197                        PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    200198                        os << "(" ;
    201199
     
    217215
    218216                // add forall
    219                 if( ! funcType->forall.empty() && ! options.genC ) {
     217                if( ! funcType->forall.empty() && ! genC ) {
    220218                        // assertf( ! genC, "Aggregate type parameters should not reach code generation." );
    221219                        std::ostringstream os;
    222                         PassVisitor<CodeGenerator> cg( os, options );
     220                        PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    223221                        os << "forall(";
    224222                        cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );
     
    231229                if ( ! refType->parameters.empty() ) {
    232230                        std::ostringstream os;
    233                         PassVisitor<CodeGenerator> cg( os, options );
     231                        PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    234232                        os << "(";
    235233                        cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
     
    242240        void GenType::postvisit( StructInstType * structInst )  {
    243241                typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;
    244                 if ( options.genC ) typeString = "struct " + typeString;
     242                if ( genC ) typeString = "struct " + typeString;
    245243                handleQualifiers( structInst );
    246244        }
     
    248246        void GenType::postvisit( UnionInstType * unionInst ) {
    249247                typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;
    250                 if ( options.genC ) typeString = "union " + typeString;
     248                if ( genC ) typeString = "union " + typeString;
    251249                handleQualifiers( unionInst );
    252250        }
     
    254252        void GenType::postvisit( EnumInstType * enumInst ) {
    255253                typeString = enumInst->name + " " + typeString;
    256                 if ( options.genC ) typeString = "enum " + typeString;
     254                if ( genC ) typeString = "enum " + typeString;
    257255                handleQualifiers( enumInst );
    258256        }
     
    264262
    265263        void GenType::postvisit( TupleType * tupleType ) {
    266                 assertf( ! options.genC, "Tuple types should not reach code generation." );
     264                assertf( ! genC, "Tuple types should not reach code generation." );
    267265                unsigned int i = 0;
    268266                std::ostringstream os;
     
    270268                for ( Type * t : *tupleType ) {
    271269                        i++;
    272                         os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", ");
     270                        os << genType( t, "", pretty, genC, lineMarks ) << (i == tupleType->size() ? "" : ", ");
    273271                }
    274272                os << "] ";
     
    283281        void GenType::postvisit( ZeroType * zeroType ) {
    284282                // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    285                 typeString = (options.pretty ? "zero_t " : "long int ") + typeString;
     283                typeString = (pretty ? "zero_t " : "long int ") + typeString;
    286284                handleQualifiers( zeroType );
    287285        }
     
    289287        void GenType::postvisit( OneType * oneType ) {
    290288                // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    291                 typeString = (options.pretty ? "one_t " : "long int ") + typeString;
     289                typeString = (pretty ? "one_t " : "long int ") + typeString;
    292290                handleQualifiers( oneType );
    293291        }
    294292
    295293        void GenType::postvisit( GlobalScopeType * globalType ) {
    296                 assertf( ! options.genC, "Global scope type should not reach code generation." );
     294                assertf( ! genC, "Global scope type should not reach code generation." );
    297295                handleQualifiers( globalType );
    298296        }
    299297
    300298        void GenType::postvisit( TraitInstType * inst ) {
    301                 assertf( ! options.genC, "Trait types should not reach code generation." );
     299                assertf( ! genC, "Trait types should not reach code generation." );
    302300                typeString = inst->name + " " + typeString;
    303301                handleQualifiers( inst );
     
    306304        void GenType::postvisit( TypeofType * typeof ) {
    307305                std::ostringstream os;
    308                 PassVisitor<CodeGenerator> cg( os, options );
     306                PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    309307                os << "typeof(";
    310308                typeof->expr->accept( cg );
     
    315313
    316314        void GenType::postvisit( QualifiedType * qualType ) {
    317                 assertf( ! options.genC, "Qualified types should not reach code generation." );
    318                 std::ostringstream os;
    319                 os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString;
     315                assertf( ! genC, "Qualified types should not reach code generation." );
     316                std::ostringstream os;
     317                os << genType( qualType->parent, "", pretty, genC, lineMarks ) << "." << genType( qualType->child, "", pretty, genC, lineMarks ) << typeString;
    320318                typeString = os.str();
    321319                handleQualifiers( qualType );
     
    335333                        typeString = "_Atomic " + typeString;
    336334                } // if
    337                 if ( type->get_lvalue() && ! options.genC ) {
     335                if ( type->get_lvalue() && ! genC ) {
    338336                        // when not generating C code, print lvalue for debugging.
    339337                        typeString = "lvalue " + typeString;
  • src/CodeGen/GenType.h

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr 30 11:47:00 2019
    13 // Update Count     : 3
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Jul 21 22:17:23 2017
     13// Update Count     : 2
    1414//
    1515
     
    1818#include <string>  // for string
    1919
    20 #include "CodeGen/Options.h" // for Options
    21 
    2220class Type;
    2321
    2422namespace CodeGen {
    25         std::string genType( Type *type, const std::string &baseString, const Options &options );
    2623        std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false );
    2724  std::string genPrettyType( Type * type, const std::string & baseString );
  • src/CodeGen/module.mk

    r933f32f r6a9d4b4  
    1818#       ArgTweak/Mutate.cc
    1919
    20 SRC_CODEGEN = \
     20SRC +=  CodeGen/Generate.cc \
    2121        CodeGen/CodeGenerator.cc \
     22        CodeGen/GenType.cc \
     23        CodeGen/FixNames.cc \
    2224        CodeGen/FixMain.cc \
    23         CodeGen/GenType.cc \
    2425        CodeGen/OperatorTable.cc
    25 
    26 
    27 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/FixNames.cc
    28 SRCDEMANGLE += $(SRC_CODEGEN)
  • src/Common/Assert.cc

    r933f32f r6a9d4b4  
    3939}
    4040
    41 void abort(const char *fmt, ... ) noexcept __attribute__((noreturn, format(printf, 1, 2)));
    42 void abort(const char *fmt, ... ) noexcept {
    43         va_list args;
    44         va_start( args, fmt );
    45         vfprintf( stderr, fmt, args );
    46         va_end( args );
    47         fprintf( stderr, "\n" );
    48         abort();
    49 }
    50 
    5141// Local Variables: //
    5242// tab-width: 4 //
  • src/Common/PassVisitor.h

    r933f32f r6a9d4b4  
    44
    55#include <stack>
    6 #include <type_traits>
    7 
    8 #include "Common/Stats.h"
     6
    97#include "Common/utility.h"
    108
     
    155153        virtual void visit( ConstructorInit * ctorInit ) override final;
    156154
     155        virtual void visit( Subrange * subrange ) override final;
     156
    157157        virtual void visit( Constant * constant ) override final;
    158158
     
    255255        virtual Initializer * mutate( ConstructorInit * ctorInit ) override final;
    256256
     257        virtual Subrange * mutate( Subrange * subrange ) override final;
     258
    257259        virtual Constant * mutate( Constant * constant ) override final;
    258260
     
    298300
    299301
    300         auto                                    get_env_ptr    () -> decltype(env_impl( pass, 0)) { return env_impl( pass, 0); }
     302        TypeSubstitution **             get_env_ptr    () { return env_impl             ( pass, 0); }
    301303        std::list< Statement* > *       get_beforeStmts() { return stmtsToAddBefore_impl( pass, 0); }
    302304        std::list< Statement* > *       get_afterStmts () { return stmtsToAddAfter_impl ( pass, 0); }
     
    345347};
    346348
    347 class WithConstTypeSubstitution {
    348 protected:
    349         WithConstTypeSubstitution() = default;
    350         ~WithConstTypeSubstitution() = default;
    351 
    352 public:
    353         const TypeSubstitution * env = nullptr;
    354 };
    355 
    356349class WithStmtsToAdd {
    357350protected:
     
    433426};
    434427
    435 #include "Common/Stats.h"
    436 
    437 extern struct PassVisitorStats {
    438         size_t depth = 0;
    439         Stats::Counters::MaxCounter<double> * max = nullptr;
    440         Stats::Counters::AverageCounter<double> * avg = nullptr;
    441 } pass_visitor_stats;
    442 
    443428#include "SynTree/TypeSubstitution.h"
    444429#include "PassVisitor.impl.h"
  • src/Common/PassVisitor.impl.h

    r933f32f r6a9d4b4  
    2020
    2121#define MUTATE_END( type, node )                \
    22         auto __return = call_postmutate< type * >( node ); \
    23         assert( __return ); \
    24         return __return;
     22        return call_postmutate< type * >( node ); \
    2523
    2624
     
    6967        SemanticErrorException errors;
    7068
    71         pass_visitor_stats.depth++;
    72         pass_visitor_stats.max->push(pass_visitor_stats.depth);
    73         pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    7469        for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) {
    75 
    76 
    7770                // splice in new declarations after previous decl
    7871                if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); }
     
    9083                if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); }
    9184        }
    92         pass_visitor_stats.depth--;
    9385        if ( ! errors.isEmpty() ) {
    9486                throw errors;
     
    10294        SemanticErrorException errors;
    10395
    104         pass_visitor_stats.depth++;
    105         pass_visitor_stats.max->push(pass_visitor_stats.depth);
    106         pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    10796        for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) {
    10897                // splice in new declarations after previous decl
     
    120109                if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); }
    121110        }
    122         pass_visitor_stats.depth--;
    123111        if ( ! errors.isEmpty() ) {
    124112                throw errors;
     
    138126        if ( ! visitor.get_visit_children() ) return;
    139127        SemanticErrorException errors;
    140 
    141         pass_visitor_stats.depth++;
    142         pass_visitor_stats.max->push(pass_visitor_stats.depth);
    143         pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    144128        for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) {
    145129                try {
     
    151135                }
    152136        }
    153         pass_visitor_stats.depth--;
    154137        if ( ! errors.isEmpty() ) {
    155138                throw errors;
     
    168151template< typename Container, typename pass_type >
    169152inline void maybeMutate_impl( Container & container, PassVisitor< pass_type > & mutator ) {
    170 
    171153        if ( ! mutator.get_visit_children() ) return;
    172154        SemanticErrorException errors;
    173 
    174         pass_visitor_stats.depth++;
    175         pass_visitor_stats.max->push(pass_visitor_stats.depth);
    176         pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    177155        for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) {
    178156                try {
     
    185163                } // try
    186164        } // for
    187         pass_visitor_stats.depth--;
    188165        if ( ! errors.isEmpty() ) {
    189166                throw errors;
     
    208185        DeclList_t* afterDecls  = get_afterDecls();
    209186
    210         pass_visitor_stats.depth++;
    211         pass_visitor_stats.max->push(pass_visitor_stats.depth);
    212         pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    213187        for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) {
    214188
     
    218192                try {
    219193                        func( *i );
    220                         assert( *i );
    221194                        assert(( empty( beforeStmts ) && empty( afterStmts ))
    222195                            || ( empty( beforeDecls ) && empty( afterDecls )) );
     
    229202                if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); }
    230203        }
    231         pass_visitor_stats.depth--;
    232204
    233205        if ( !empty( afterDecls ) ) { splice( std::back_inserter( statements ), afterDecls); }
     
    257229
    258230        // don't want statements from outer CompoundStmts to be added to this CompoundStmt
    259         ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type >  oldEnv( get_env_ptr() );
     231        ValueGuardPtr< TypeSubstitution * >  oldEnv        ( get_env_ptr    () );
    260232        ValueGuardPtr< DeclList_t >          oldBeforeDecls( get_beforeDecls() );
    261233        ValueGuardPtr< DeclList_t >          oldAfterDecls ( get_afterDecls () );
     
    19931965
    19941966        // don't want statements from outer CompoundStmts to be added to this StmtExpr
    1995         ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type >  oldEnv( get_env_ptr() );
     1967        ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
    19961968        ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
    19971969        ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );
     
    20101982
    20111983        // don't want statements from outer CompoundStmts to be added to this StmtExpr
    2012         ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type >  oldEnv( get_env_ptr() );
     1984        ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
    20131985        ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
    20141986        ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );
     
    27062678
    27072679//--------------------------------------------------------------------------
     2680// Subrange
     2681template< typename pass_type >
     2682void PassVisitor< pass_type >::visit( Subrange * node ) {
     2683        VISIT_START( node );
     2684
     2685        VISIT_END( node );
     2686}
     2687
     2688template< typename pass_type >
     2689Subrange * PassVisitor< pass_type >::mutate( Subrange * node  )  {
     2690        MUTATE_START( node );
     2691
     2692        MUTATE_END( Subrange, node );
     2693}
     2694
     2695//--------------------------------------------------------------------------
    27082696// Attribute
    27092697template< typename pass_type >
  • src/Common/PassVisitor.proto.h

    r933f32f r6a9d4b4  
    165165static inline type * name##_impl( __attribute__((unused)) pass_type& pass, __attribute__((unused)) long unused ) { return nullptr;}    \
    166166
    167 FIELD_PTR( const TypeSubstitution *, env )
     167FIELD_PTR( TypeSubstitution *, env )
    168168FIELD_PTR( std::list< Statement* >, stmtsToAddBefore )
    169169FIELD_PTR( std::list< Statement* >, stmtsToAddAfter  )
     
    174174FIELD_PTR( PassVisitor<pass_type> * const, visitor )
    175175
    176 #undef FIELD_PTR
    177 
    178176//---------------------------------------------------------
    179177// Indexer
     
    222220INDEXER_FUNC2( addWith   , std::list< Expression * > &, BaseSyntaxNode * );
    223221
    224 #undef INDEXER_FUNC1
    225 #undef INDEXER_FUNC2
    226222
    227223template<typename pass_type>
  • src/Common/SemanticError.h

    r933f32f r6a9d4b4  
    1717
    1818#include "ErrorObjects.h"
    19 #include "AST/Node.hpp"
    2019#include <cstring>
    2120
  • src/Common/module.mk

    r933f32f r6a9d4b4  
    1515###############################################################################
    1616
    17 SRC_COMMON = \
    18       Common/Assert.cc \
    19       Common/Eval.cc \
    20       Common/PassVisitor.cc \
    21       Common/SemanticError.cc \
    22       Common/Stats/Counter.cc \
    23       Common/Stats/Heap.cc \
    24       Common/Stats/Stats.cc \
    25       Common/Stats/Time.cc \
    26       Common/UniqueName.cc
    27 
    28 SRC += $(SRC_COMMON) Common/DebugMalloc.cc
    29 SRCDEMANGLE += $(SRC_COMMON)
     17SRC += Common/SemanticError.cc \
     18       Common/UniqueName.cc \
     19       Common/DebugMalloc.cc \
     20       Common/Assert.cc \
     21       Common/Heap.cc \
     22       Common/Eval.cc
  • src/Common/utility.h

    r933f32f r6a9d4b4  
    463463std::pair<long long int, bool> eval(Expression * expr);
    464464
    465 namespace ast {
    466         class Expr;
    467 }
    468 
    469 std::pair<long long int, bool> eval(const ast::Expr * expr);
    470 
    471 // -----------------------------------------------------------------------------
    472 /// Reorders the input range in-place so that the minimal-value elements according to the
    473 /// comparator are in front;
     465// -----------------------------------------------------------------------------
     466/// Reorders the input range in-place so that the minimal-value elements according to the
     467/// comparator are in front;
    474468/// returns the iterator after the last minimal-value element.
    475469template<typename Iter, typename Compare>
    476470Iter sort_mins( Iter begin, Iter end, Compare& lt ) {
    477471        if ( begin == end ) return end;
    478 
     472       
    479473        Iter min_pos = begin;
    480474        for ( Iter i = begin + 1; i != end; ++i ) {
  • src/CompilationState.cc

    r933f32f r6a9d4b4  
    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 : Fri May  3 13:45:23 2019
    13 // Update Count     : 4
     11// Last Modified By : Rob Schluntz
     12// Last Modified On : Mon Ju1 30 10:46:25 2018
     13// Update Count     : 2
    1414//
    1515
    16 int
     16bool
    1717        astp = false,
    1818        bresolvep = false,
     
    2626        libcfap = false,
    2727        nopreludep = false,
    28         genproto = false,
     28        noprotop = false,
    2929        nomainp = false,
    3030        parsep = false,
  • src/CompilationState.h

    r933f32f r6a9d4b4  
    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 : Fri May  3 13:43:21 2019
    13 // Update Count     : 4
     11// Last Modified By : Rob Schluntz
     12// Last Modified On : Mon Ju1 30 10:46:25 2018
     13// Update Count     : 2
    1414//
    1515
    1616extern int yydebug;                   // set for -g flag (Grammar)
    17 extern int
     17extern bool
    1818        astp,
    1919        bresolvep,
     
    2727        libcfap,
    2828        nopreludep,
    29         genproto,
     29        noprotop,
    3030        nomainp,
    3131        parsep,
  • src/Concurrency/Waitfor.cc

    r933f32f r6a9d4b4  
    1111// Last Modified By :
    1212// Last Modified On :
    13 // Update Count     : 7
     13// Update Count     : 5
    1414//
    1515
  • src/Concurrency/module.mk

    r933f32f r6a9d4b4  
    1515###############################################################################
    1616
    17 SRC += Concurrency/Keywords.cc Concurrency/Waitfor.cc
    18 SRCDEMANGLE += Concurrency/Keywords.cc
     17SRC += Concurrency/Keywords.cc \
     18       Concurrency/Waitfor.cc
    1919
  • src/ControlStruct/ExceptTranslate.cc

    r933f32f r6a9d4b4  
    99// Author           : Andrew Beach
    1010// Created On       : Wed Jun 14 16:49:00 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 13 18:15:29 2019
    13 // Update Count     : 11
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Aug 17 17:19:00 2017
     13// Update Count     : 9
    1414//
    1515
     
    617617                                return create_terminate_rethrow( throwStmt );
    618618                        } else {
    619                                 abort("Invalid throw in %s at %i\n",
     619                                assertf(false, "Invalid throw in %s at %i\n",
    620620                                        throwStmt->location.filename.c_str(),
    621621                                        throwStmt->location.first_line);
     622                                return nullptr;
    622623                        }
    623624                } else {
     
    627628                                return create_resume_rethrow( throwStmt );
    628629                        } else {
    629                                 abort("Invalid throwResume in %s at %i\n",
     630                                assertf(false, "Invalid throwResume in %s at %i\n",
    630631                                        throwStmt->location.filename.c_str(),
    631632                                        throwStmt->location.first_line);
     633                                return nullptr;
    632634                        }
    633635                }
  • src/ControlStruct/ForExprMutator.cc

    r933f32f r6a9d4b4  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 11 22:26:52 2019
    13 // Update Count     : 14
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Aug 18 10:22:00 2017
     13// Update Count     : 12
    1414//
    1515
     
    2121
    2222namespace ControlStruct {
    23         Statement * hoist( Statement * originalStmt, std::list<Statement *> & init ) {
     23        Statement *hoist( Statement *originalStmt, std::list<Statement *> &init ) {
    2424                // If no hoisting is needed, skip:
    2525                if ( 0 == init.size() ) {
     
    2929                // Create compound statement, move initializers outside,
    3030                // the resut of the original stays as is.
    31                 CompoundStmt * block = new CompoundStmt();
    32                 std::list<Statement *> & stmts = block->get_kids();
     31                CompoundStmt *block = new CompoundStmt();
     32                std::list<Statement *> &stmts = block->get_kids();
    3333                stmts.splice( stmts.end(), init );
    3434
     
    3838        }
    3939
    40         Statement * ForExprMutator::postmutate( IfStmt * ifStmt ) {
     40        Statement *ForExprMutator::postmutate( IfStmt *ifStmt ) {
    4141                return hoist( ifStmt, ifStmt->initialization );
    4242        }
    43         Statement * ForExprMutator::postmutate( ForStmt * forStmt ) {
     43        Statement *ForExprMutator::postmutate( ForStmt *forStmt ) {
    4444                // hoist any initializer declarations to make them C89 (rather than C99)
    4545                return hoist( forStmt, forStmt->initialization );
    4646        }
    47         Statement * ForExprMutator::postmutate( WhileStmt * whileStmt ) {
     47        Statement *ForExprMutator::postmutate( WhileStmt *whileStmt ) {
    4848                return hoist( whileStmt, whileStmt->initialization );
    4949        }
  • src/ControlStruct/LabelFixer.cc

    r933f32f r6a9d4b4  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 11 22:26:02 2019
    13 // Update Count     : 159
     11// Last Modified By : Rob Schluntz
     12// Last Modified On : Tue Jul 28 13:32:43 2015
     13// Update Count     : 156
    1414//
    1515
     
    3232        }
    3333
    34         LabelFixer::LabelFixer( LabelGenerator * gen ) : generator ( gen ) {
     34        LabelFixer::LabelFixer( LabelGenerator *gen ) : generator ( gen ) {
    3535                if ( generator == 0 )
    3636                        generator = LabelGenerator::getGenerator();
     
    4949
    5050        // prune to at most one label definition for each statement
    51         void LabelFixer::previsit( Statement * stmt ) {
     51        void LabelFixer::previsit( Statement *stmt ) {
    5252                std::list< Label > &labels = stmt->get_labels();
    5353
     
    5858        }
    5959
    60         void LabelFixer::previsit( BranchStmt * branchStmt ) {
     60        void LabelFixer::previsit( BranchStmt *branchStmt ) {
    6161                previsit( ( Statement *)branchStmt );
    6262
     
    7575
    7676
    77         // sets the definition of the labelTable entry to be the provided statement for every label in the list
    78         // parameter. Happens for every kind of statement
    79         Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement * definition ) {
     77        // sets the definition of the labelTable entry to be the provided
     78        // statement for every label in the list parameter. Happens for every kind of statement
     79        Label LabelFixer::setLabelsDef( std::list< Label > &llabel, Statement *definition ) {
    8080                assert( definition != 0 );
    8181                assert( llabel.size() > 0 );
     
    100100                } // for
    101101
    102                 // produce one of the labels attached to this statement to be temporarily used as the canonical label
     102                // produce one of the labels attached to this statement to be
     103                // temporarily used as the canonical label
    103104                return labelTable[ llabel.front() ]->get_label();
    104105        }
     
    116117
    117118        // Builds a table that maps a label to its defining statement.
    118         std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
     119        std::map<Label, Statement * > *LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
    119120                std::map< Label, Statement * > *ret = new std::map< Label, Statement * >();
    120121                for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) {
  • src/ControlStruct/LabelGenerator.cc

    r933f32f r6a9d4b4  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 11 22:23:20 2019
    13 // Update Count     : 15
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Aug 14 14:14:00 2015
     13// Update Count     : 14
    1414//
    1515
     
    2424
    2525namespace ControlStruct {
    26         LabelGenerator * LabelGenerator::labelGenerator = 0;
     26        LabelGenerator *LabelGenerator::labelGenerator = 0;
    2727
    28         LabelGenerator * LabelGenerator::getGenerator() {
     28        LabelGenerator *LabelGenerator::getGenerator() {
    2929                if ( LabelGenerator::labelGenerator == 0 )
    3030                        LabelGenerator::labelGenerator = new LabelGenerator();
     31
    3132                return labelGenerator;
    3233        }
     
    3738                if ( stmt && ! stmt->get_labels().empty() ) {
    3839                        os << "_" << stmt->get_labels().front() << "__";
    39                 } // if
     40                }
    4041                std::string ret = os.str();
    4142                Label l( ret );
  • src/ControlStruct/module.mk

    r933f32f r6a9d4b4  
    1515###############################################################################
    1616
    17 SRC_CONTROLSTRUCT = \
     17SRC +=  ControlStruct/LabelGenerator.cc \
     18        ControlStruct/LabelFixer.cc \
     19        ControlStruct/MLEMutator.cc \
     20        ControlStruct/Mutate.cc \
    1821        ControlStruct/ForExprMutator.cc \
    19         ControlStruct/LabelFixer.cc \
    20         ControlStruct/LabelGenerator.cc \
    21         ControlStruct/MLEMutator.cc \
    22         ControlStruct/Mutate.cc
    23 
    24 SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc
    25 SRCDEMANGLE += $(SRC_CONTROLSTRUCT)
    26 
     22        ControlStruct/ExceptTranslate.cc
  • src/GenPoly/Box.cc

    r933f32f r6a9d4b4  
    7676
    7777                /// Replaces polymorphic return types with out-parameters, replaces calls to polymorphic functions with adapter calls as needed, and adds appropriate type variables to the function call
    78                 class Pass1 final : public BoxPass, public WithConstTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting {
     78                class Pass1 final : public BoxPass, public WithTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting {
    7979                  public:
    8080                        Pass1();
     
    150150                /// * Calculates polymorphic offsetof expressions from offset array
    151151                /// * Inserts dynamic calculation of polymorphic type layouts where needed
    152                 class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithConstTypeSubstitution {
     152                class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithTypeSubstitution {
    153153                public:
    154154                        PolyGenericCalculator();
  • src/GenPoly/GenPoly.cc

    r933f32f r6a9d4b4  
    440440        }
    441441
    442         bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
     442        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, TypeSubstitution * env ) {
    443443                // is parameter is not polymorphic, don't need to box
    444444                if ( ! isPolyType( param, exprTyVars ) ) return false;
     
    450450        }
    451451
    452         bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
     452        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, TypeSubstitution * env ) {
    453453                FunctionType * function = getFunctionType( appExpr->function->result );
    454454                assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() );
  • src/GenPoly/GenPoly.h

    r933f32f r6a9d4b4  
    8181
    8282        /// true if arg requires boxing given exprTyVars
    83         bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );
     83        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, TypeSubstitution * env );
    8484
    8585        /// true if arg requires boxing in the call to appExpr
    86         bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );
     86        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, TypeSubstitution * env );
    8787
    8888        /// Adds the type variable `tyVar` to `tyVarMap`
  • src/GenPoly/InstantiateGeneric.cc

    r933f32f r6a9d4b4  
    168168
    169169        /// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately
    170         struct GenericInstantiator final : public WithConstTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards {
     170        struct GenericInstantiator final : public WithTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards {
    171171                /// Map of (generic type, parameter list) pairs to concrete type instantiations
    172172                InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
  • src/GenPoly/Specialize.cc

    r933f32f r6a9d4b4  
    4242
    4343namespace GenPoly {
    44         struct Specialize final : public WithConstTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {
     44        struct Specialize final : public WithTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {
    4545                Expression * postmutate( ApplicationExpr *applicationExpr );
    4646                Expression * postmutate( CastExpr *castExpr );
     
    5454
    5555        /// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type.
    56         bool needsPolySpecialization( Type *formalType, Type *actualType, const TypeSubstitution *env ) {
     56        bool needsPolySpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    5757                if ( env ) {
    5858                        using namespace ResolvExpr;
     
    145145        }
    146146
    147         bool needsSpecialization( Type *formalType, Type *actualType, const TypeSubstitution *env ) {
     147        bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    148148                return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType );
    149149        }
  • src/GenPoly/module.mk

    r933f32f r6a9d4b4  
    2222       GenPoly/FindFunction.cc \
    2323       GenPoly/InstantiateGeneric.cc
    24 
    25 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/Lvalue.cc
    26 
  • src/InitTweak/FixInit.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 13 18:15:56 2019
    13 // Update Count     : 76
     12// Last Modified On : Wed Jun 21 17:35:05 2017
     13// Update Count     : 74
    1414//
    1515#include "FixInit.h"
     
    7272                };
    7373
    74                 struct InsertImplicitCalls : public WithConstTypeSubstitution {
     74                struct InsertImplicitCalls : public WithTypeSubstitution {
    7575                        /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
    7676                        /// function calls need their parameters to be copy constructed
  • src/InitTweak/InitTweak.cc

    r933f32f r6a9d4b4  
    55#include <memory>                  // for __shared_ptr
    66
    7 #include "AST/Expr.hpp"
    8 #include "AST/Stmt.hpp"
    9 #include "AST/Type.hpp"
    107#include "Common/PassVisitor.h"
    118#include "Common/SemanticError.h"  // for SemanticError
     
    2926#include "Tuples/Tuples.h"         // for Tuples::isTtype
    3027
     28class UntypedValofExpr;
     29
    3130namespace InitTweak {
    3231        namespace {
     
    433432                        assert( false );
    434433                }
    435 
    436                 // template<typename CallExpr>
    437                 // const ast::Expr * callArg( const CallExpr * call, unsigned int pos ) {
    438                 //      if( pos >= call->args.size() ) {
    439                 //              assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.",
    440                 //                      pos, toString( call ).c_str() );
    441                 //      }
    442                 //      for ( const ast::Expr * arg : call->args ) {
    443                 //              if ( pos == 0 ) return arg;
    444                 //              --pos;
    445                 //      }
    446                 //      assert( false );
    447                 // }
    448434        }
    449435
     
    465451                        assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );
    466452                }
    467         }
    468         const ast::Expr * getCallArg( const ast::Expr * call, unsigned pos ) {
    469                 (void)call;
    470                 (void)pos;
    471                 #warning unimplemented; needs to build AST/Expr.cpp
    472                 assertf(false, "unimplemented; needs to build AST/Expr.cpp");
    473                 // if ( auto app = dynamic_cast< const ast::ApplicationExpr * >( call ) ) {
    474                 //      return callArg( app, pos );
    475                 // } else if ( auto untyped = dynamic_cast< const ast::UntypedExpr * >( call ) ) {
    476                 //      return callArg( untyped, pos );
    477                 // } else if ( auto tupleAssn = dynamic_cast< const ast::TupleAssignExpr * >( call ) ) {
    478                 //      const std::list<ast::ptr<ast::Stmt>>& stmts = tupleAssn->stmtExpr->stmts->kids;
    479                 //      assertf( ! stmts.empty(), "TupleAssignExpr missing statements." );
    480                 //      const ExprStmt * stmt = strict_dynamic_cast< const ast::ExprStmt * >( stmts.back() );
    481                 //      const TupleExpr * tuple = strict_dynamic_cast< const ast::TupleExpr * >( stmt->expr );
    482                 //      assertf( ! tuple->exprs.empty(), "TupleAssignExpr has empty tuple expr.");
    483                 //      return getCallArg( tuple->exprs.front(), pos );
    484                 // } else if ( auto ctor = dynamic_cast< const ast::ImplicitCopyCtorExpr * >( call ) ) {
    485                 //      return getCallArg( ctor->callExpr, pos );
    486                 // } else {
    487                 //      assertf( false, "Unexpected expression type passed to getCallArg: %s",
    488                 //              toString( call ).c_str() );
    489                 // }
    490453        }
    491454
     
    550513                }
    551514        }
    552         const ast::Type* getPointerBase( const ast::Type* t ) {
    553                 (void)t;
    554                 #warning needs to build Type.cpp before inclusion
    555                 assertf(false, "needs to build Type.cpp before inclusion");
    556                 // if ( const auto * p = dynamic_cast< const ast::PointerType * >( t ) ) {
    557                 //      return p->base;
    558                 // } else if ( const auto * a = dynamic_cast< const ast::ArrayType * >( t ) ) {
    559                 //      return a->base;
    560                 // } else if ( const auto * r = dynamic_cast< const ast::ReferenceType * >( t ) ) {
    561                 //      return r->base;
    562                 // } else return nullptr;
    563         }
    564515
    565516        Type * isPointerType( Type * type ) {
  • src/InitTweak/InitTweak.h

    r933f32f r6a9d4b4  
    2020#include <string>             // for string, allocator
    2121
    22 #include "AST/Fwd.hpp"        // for AST nodes
    2322#include "SynTree/SynTree.h"  // for Visitor Nodes
    2423
     
    8180        /// returns the argument to a call expression in position N indexed from 0
    8281        Expression *& getCallArg( Expression * callExpr, unsigned int pos );
    83         const ast::Expr * getCallArg( const ast::Expr * call, unsigned pos );
    8482
    8583        /// returns the base type of a PointerType or ArrayType, else returns NULL
    8684        Type * getPointerBase( Type * );
    87         const ast::Type* getPointerBase( const ast::Type* );
    8885
    8986        /// returns the argument if it is a PointerType or ArrayType, else returns NULL
  • src/InitTweak/module.mk

    r933f32f r6a9d4b4  
    2020        InitTweak/InitTweak.cc
    2121
    22 SRCDEMANGLE += InitTweak/GenInit.cc \
    23         InitTweak/InitTweak.cc
    24 
  • src/MakeLibCfa.cc

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sat May 16 10:33:33 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 17 21:08:09 2019
    13 // Update Count     : 41
     11// Last Modified By : Rob Schluntz
     12// Last Modified On : Fri Apr 22 13:54:15 2016
     13// Update Count     : 40
    1414//
    1515
     
    146146        } // namespace
    147147} // namespace LibCfa
    148 
    149 // Local Variables: //
    150 // tab-width: 4 //
    151 // End: //
  • src/Makefile.am

    r933f32f r6a9d4b4  
    1010## Author           : Peter A. Buhr
    1111## Created On       : Sun May 31 08:51:46 2015
    12 ## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Fri Feb 15 09:44:09 2019
    14 ## Update Count     : 97
     12## Last Modified By : Andrew Beach
     13## Last Modified On : Tus Jul 25 10:34:00 2017
     14## Update Count     : 76
    1515###############################################################################
    1616
     
    2020
    2121SRC = main.cc \
    22       MakeLibCfa.cc \
    23       CompilationState.cc
    24 
    25 SRCDEMANGLE = CompilationState.cc
     22                        MakeLibCfa.cc \
     23                        CompilationState.cc
    2624
    2725MAINTAINERCLEANFILES =
    28 MOSTLYCLEANFILES =
     26MOSTLYCLEANFILES = Parser/gcc-flags.h
    2927
    30 if WITH_LIBPROFILER
    31 LIBPROFILER = -lprofiler
    32 endif
     28Parser/gcc-flags.h :
     29        ${AM_V_GEN}$(CC) -dM -E - < /dev/null | sed 's/define /define __GCC__/' > $(@)
    3330
    34 if WITH_LIBTCMALLOC
    35 LIBTCMALLOC = -ltcmalloc
    36 TCMALLOCFLAG = -DTCMALLOC
    37 endif
     31Parser/lex.ll : Parser/gcc-flags.h
    3832
    3933include CodeGen/module.mk
     
    5246include Virtual/module.mk
    5347
    54 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h
    55 
    56 $(srcdir)/SynTree/Type.h : BasicTypes-gen.cc
    57         ${AM_V_GEN}${CXXCOMPILE} $< -o BasicTypes-gen -Wall -Wextra
    58         @./BasicTypes-gen
    59         @rm BasicTypes-gen
    60 
    6148# put into lib for now
    6249cfa_cpplibdir = $(CFA_LIBDIR)
    6350cfa_cpplib_PROGRAMS = ../driver/cfa-cpp demangler
    6451___driver_cfa_cpp_SOURCES = $(SRC)
    65 ___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC)
     52___driver_cfa_cpp_LDADD = -ldl                  # yywrap
    6653
    67 AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O3 -g -std=c++14 $(TCMALLOCFLAG)
     54AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O2 -g -std=c++14
    6855AM_LDFLAGS  = @HOST_FLAGS@ -Xlinker -export-dynamic
    6956ARFLAGS     = cr
     
    7158demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete
    7259
    73 demangler_LDADD = libdemangle.a -ldl                    # yywrap
     60demangler_LDADD = libdemangle.a     # yywrap
    7461
    7562noinst_LIBRARIES = libdemangle.a
    76 libdemangle_a_SOURCES = $(SRCDEMANGLE)
     63libdemangle_a_SOURCES = \
     64        SymTab/Demangle.cc \
     65        SymTab/ManglerCommon.cc \
     66        SynTree/Type.cc \
     67        SynTree/VoidType.cc \
     68        SynTree/BasicType.cc \
     69        SynTree/PointerType.cc \
     70        SynTree/ArrayType.cc \
     71        SynTree/ReferenceType.cc \
     72        SynTree/FunctionType.cc \
     73        SynTree/ReferenceToType.cc \
     74        SynTree/TupleType.cc \
     75        SynTree/TypeofType.cc \
     76        SynTree/AttrType.cc \
     77        SynTree/VarArgsType.cc \
     78        SynTree/ZeroOneType.cc \
     79        SynTree/Constant.cc \
     80        SynTree/Expression.cc \
     81        SynTree/TupleExpr.cc \
     82        SynTree/CommaExpr.cc \
     83        SynTree/TypeExpr.cc \
     84        SynTree/ApplicationExpr.cc \
     85        SynTree/AddressExpr.cc \
     86        SynTree/Statement.cc \
     87        SynTree/CompoundStmt.cc \
     88        SynTree/DeclStmt.cc \
     89        SynTree/Declaration.cc \
     90        SynTree/DeclarationWithType.cc \
     91        SynTree/ObjectDecl.cc \
     92        SynTree/FunctionDecl.cc \
     93        SynTree/AggregateDecl.cc \
     94        SynTree/NamedTypeDecl.cc \
     95        SynTree/TypeDecl.cc \
     96        SynTree/Initializer.cc \
     97        SynTree/TypeSubstitution.cc \
     98        SynTree/Attribute.cc \
     99        SynTree/DeclReplacer.cc \
     100        CompilationState.cc \
     101        CodeGen/CodeGenerator.cc \
     102        CodeGen/FixMain.cc \
     103        CodeGen/Generate.cc \
     104        CodeGen/GenType.cc \
     105        CodeGen/OperatorTable.cc \
     106        Common/Assert.cc \
     107        Common/Eval.cc \
     108        Common/SemanticError.cc \
     109        Common/UniqueName.cc \
     110        Concurrency/Keywords.cc \
     111        ControlStruct/ForExprMutator.cc \
     112        ControlStruct/LabelFixer.cc \
     113        ControlStruct/LabelGenerator.cc \
     114        ControlStruct/MLEMutator.cc \
     115        ControlStruct/Mutate.cc \
     116        GenPoly/GenPoly.cc \
     117        GenPoly/Lvalue.cc \
     118        InitTweak/GenInit.cc \
     119        InitTweak/InitTweak.cc \
     120        Parser/LinkageSpec.cc \
     121        ResolvExpr/AdjustExprType.cc \
     122        ResolvExpr/Alternative.cc \
     123        ResolvExpr/AlternativeFinder.cc \
     124        ResolvExpr/ExplodedActual.cc \
     125        ResolvExpr/CastCost.cc \
     126        ResolvExpr/CommonType.cc \
     127        ResolvExpr/ConversionCost.cc \
     128        ResolvExpr/CurrentObject.cc \
     129        ResolvExpr/FindOpenVars.cc \
     130        ResolvExpr/Occurs.cc \
     131        ResolvExpr/PolyCost.cc \
     132        ResolvExpr/PtrsAssignable.cc \
     133        ResolvExpr/PtrsCastable.cc \
     134        ResolvExpr/RenameVars.cc \
     135        ResolvExpr/ResolveAssertions.cc \
     136        ResolvExpr/Resolver.cc \
     137        ResolvExpr/ResolveTypeof.cc \
     138        ResolvExpr/SpecCost.cc \
     139        ResolvExpr/TypeEnvironment.cc \
     140        ResolvExpr/Unify.cc \
     141        SymTab/Autogen.cc \
     142        SymTab/FixFunction.cc \
     143        SymTab/Indexer.cc \
     144        SymTab/Mangler.cc \
     145        SymTab/Validate.cc \
     146        Tuples/Explode.cc \
     147        Tuples/TupleAssignment.cc \
     148        Tuples/TupleExpansion.cc \
     149        Validate/HandleAttributes.cc \
     150        Validate/FindSpecialDecls.cc
     151
    77152
    78153MAINTAINERCLEANFILES += ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}}
  • src/Makefile.in

    r933f32f r6a9d4b4  
    162162libdemangle_a_LIBADD =
    163163am__dirstamp = $(am__leading_dot)dirstamp
    164 am__objects_1 = CodeGen/CodeGenerator.$(OBJEXT) \
    165         CodeGen/FixMain.$(OBJEXT) CodeGen/GenType.$(OBJEXT) \
    166         CodeGen/OperatorTable.$(OBJEXT)
    167 am__objects_2 = Common/Assert.$(OBJEXT) Common/Eval.$(OBJEXT) \
    168         Common/PassVisitor.$(OBJEXT) Common/SemanticError.$(OBJEXT) \
    169         Common/Stats/Counter.$(OBJEXT) Common/Stats/Heap.$(OBJEXT) \
    170         Common/Stats/Stats.$(OBJEXT) Common/Stats/Time.$(OBJEXT) \
    171         Common/UniqueName.$(OBJEXT)
    172 am__objects_3 = ControlStruct/ForExprMutator.$(OBJEXT) \
     164am_libdemangle_a_OBJECTS = SymTab/Demangle.$(OBJEXT) \
     165        SymTab/ManglerCommon.$(OBJEXT) SynTree/Type.$(OBJEXT) \
     166        SynTree/VoidType.$(OBJEXT) SynTree/BasicType.$(OBJEXT) \
     167        SynTree/PointerType.$(OBJEXT) SynTree/ArrayType.$(OBJEXT) \
     168        SynTree/ReferenceType.$(OBJEXT) SynTree/FunctionType.$(OBJEXT) \
     169        SynTree/ReferenceToType.$(OBJEXT) SynTree/TupleType.$(OBJEXT) \
     170        SynTree/TypeofType.$(OBJEXT) SynTree/AttrType.$(OBJEXT) \
     171        SynTree/VarArgsType.$(OBJEXT) SynTree/ZeroOneType.$(OBJEXT) \
     172        SynTree/Constant.$(OBJEXT) SynTree/Expression.$(OBJEXT) \
     173        SynTree/TupleExpr.$(OBJEXT) SynTree/CommaExpr.$(OBJEXT) \
     174        SynTree/TypeExpr.$(OBJEXT) SynTree/ApplicationExpr.$(OBJEXT) \
     175        SynTree/AddressExpr.$(OBJEXT) SynTree/Statement.$(OBJEXT) \
     176        SynTree/CompoundStmt.$(OBJEXT) SynTree/DeclStmt.$(OBJEXT) \
     177        SynTree/Declaration.$(OBJEXT) \
     178        SynTree/DeclarationWithType.$(OBJEXT) \
     179        SynTree/ObjectDecl.$(OBJEXT) SynTree/FunctionDecl.$(OBJEXT) \
     180        SynTree/AggregateDecl.$(OBJEXT) \
     181        SynTree/NamedTypeDecl.$(OBJEXT) SynTree/TypeDecl.$(OBJEXT) \
     182        SynTree/Initializer.$(OBJEXT) \
     183        SynTree/TypeSubstitution.$(OBJEXT) SynTree/Attribute.$(OBJEXT) \
     184        SynTree/DeclReplacer.$(OBJEXT) CompilationState.$(OBJEXT) \
     185        CodeGen/CodeGenerator.$(OBJEXT) CodeGen/FixMain.$(OBJEXT) \
     186        CodeGen/Generate.$(OBJEXT) CodeGen/GenType.$(OBJEXT) \
     187        CodeGen/OperatorTable.$(OBJEXT) Common/Assert.$(OBJEXT) \
     188        Common/Eval.$(OBJEXT) Common/SemanticError.$(OBJEXT) \
     189        Common/UniqueName.$(OBJEXT) Concurrency/Keywords.$(OBJEXT) \
     190        ControlStruct/ForExprMutator.$(OBJEXT) \
    173191        ControlStruct/LabelFixer.$(OBJEXT) \
    174192        ControlStruct/LabelGenerator.$(OBJEXT) \
    175193        ControlStruct/MLEMutator.$(OBJEXT) \
    176         ControlStruct/Mutate.$(OBJEXT)
    177 am__objects_4 = ResolvExpr/AdjustExprType.$(OBJEXT) \
     194        ControlStruct/Mutate.$(OBJEXT) GenPoly/GenPoly.$(OBJEXT) \
     195        GenPoly/Lvalue.$(OBJEXT) InitTweak/GenInit.$(OBJEXT) \
     196        InitTweak/InitTweak.$(OBJEXT) Parser/LinkageSpec.$(OBJEXT) \
     197        ResolvExpr/AdjustExprType.$(OBJEXT) \
    178198        ResolvExpr/Alternative.$(OBJEXT) \
    179199        ResolvExpr/AlternativeFinder.$(OBJEXT) \
     200        ResolvExpr/ExplodedActual.$(OBJEXT) \
    180201        ResolvExpr/CastCost.$(OBJEXT) ResolvExpr/CommonType.$(OBJEXT) \
    181202        ResolvExpr/ConversionCost.$(OBJEXT) \
    182203        ResolvExpr/CurrentObject.$(OBJEXT) \
    183         ResolvExpr/ExplodedActual.$(OBJEXT) \
    184204        ResolvExpr/FindOpenVars.$(OBJEXT) ResolvExpr/Occurs.$(OBJEXT) \
    185205        ResolvExpr/PolyCost.$(OBJEXT) \
     
    192212        ResolvExpr/SpecCost.$(OBJEXT) \
    193213        ResolvExpr/TypeEnvironment.$(OBJEXT) \
    194         ResolvExpr/Unify.$(OBJEXT)
    195 am__objects_5 = SymTab/Autogen.$(OBJEXT) SymTab/FixFunction.$(OBJEXT) \
     214        ResolvExpr/Unify.$(OBJEXT) SymTab/Autogen.$(OBJEXT) \
     215        SymTab/FixFunction.$(OBJEXT) SymTab/Indexer.$(OBJEXT) \
     216        SymTab/Mangler.$(OBJEXT) SymTab/Validate.$(OBJEXT) \
     217        Tuples/Explode.$(OBJEXT) Tuples/TupleAssignment.$(OBJEXT) \
     218        Tuples/TupleExpansion.$(OBJEXT) \
     219        Validate/HandleAttributes.$(OBJEXT) \
     220        Validate/FindSpecialDecls.$(OBJEXT)
     221libdemangle_a_OBJECTS = $(am_libdemangle_a_OBJECTS)
     222am__installdirs = "$(DESTDIR)$(cfa_cpplibdir)"
     223PROGRAMS = $(cfa_cpplib_PROGRAMS)
     224am__objects_1 = main.$(OBJEXT) MakeLibCfa.$(OBJEXT) \
     225        CompilationState.$(OBJEXT) CodeGen/Generate.$(OBJEXT) \
     226        CodeGen/CodeGenerator.$(OBJEXT) CodeGen/GenType.$(OBJEXT) \
     227        CodeGen/FixNames.$(OBJEXT) CodeGen/FixMain.$(OBJEXT) \
     228        CodeGen/OperatorTable.$(OBJEXT) CodeTools/DeclStats.$(OBJEXT) \
     229        CodeTools/ResolvProtoDump.$(OBJEXT) \
     230        CodeTools/TrackLoc.$(OBJEXT) Concurrency/Keywords.$(OBJEXT) \
     231        Concurrency/Waitfor.$(OBJEXT) Common/SemanticError.$(OBJEXT) \
     232        Common/UniqueName.$(OBJEXT) Common/DebugMalloc.$(OBJEXT) \
     233        Common/Assert.$(OBJEXT) Common/Heap.$(OBJEXT) \
     234        Common/Eval.$(OBJEXT) ControlStruct/LabelGenerator.$(OBJEXT) \
     235        ControlStruct/LabelFixer.$(OBJEXT) \
     236        ControlStruct/MLEMutator.$(OBJEXT) \
     237        ControlStruct/Mutate.$(OBJEXT) \
     238        ControlStruct/ForExprMutator.$(OBJEXT) \
     239        ControlStruct/ExceptTranslate.$(OBJEXT) GenPoly/Box.$(OBJEXT) \
     240        GenPoly/GenPoly.$(OBJEXT) GenPoly/ScrubTyVars.$(OBJEXT) \
     241        GenPoly/Lvalue.$(OBJEXT) GenPoly/Specialize.$(OBJEXT) \
     242        GenPoly/FindFunction.$(OBJEXT) \
     243        GenPoly/InstantiateGeneric.$(OBJEXT) \
     244        InitTweak/GenInit.$(OBJEXT) InitTweak/FixInit.$(OBJEXT) \
     245        InitTweak/FixGlobalInit.$(OBJEXT) \
     246        InitTweak/InitTweak.$(OBJEXT) Parser/parser.$(OBJEXT) \
     247        Parser/lex.$(OBJEXT) Parser/TypedefTable.$(OBJEXT) \
     248        Parser/ParseNode.$(OBJEXT) Parser/DeclarationNode.$(OBJEXT) \
     249        Parser/ExpressionNode.$(OBJEXT) Parser/StatementNode.$(OBJEXT) \
     250        Parser/InitializerNode.$(OBJEXT) Parser/TypeData.$(OBJEXT) \
     251        Parser/LinkageSpec.$(OBJEXT) Parser/parserutility.$(OBJEXT) \
     252        ResolvExpr/AlternativeFinder.$(OBJEXT) \
     253        ResolvExpr/Alternative.$(OBJEXT) ResolvExpr/Unify.$(OBJEXT) \
     254        ResolvExpr/PtrsAssignable.$(OBJEXT) \
     255        ResolvExpr/CommonType.$(OBJEXT) \
     256        ResolvExpr/ConversionCost.$(OBJEXT) \
     257        ResolvExpr/CastCost.$(OBJEXT) \
     258        ResolvExpr/PtrsCastable.$(OBJEXT) \
     259        ResolvExpr/AdjustExprType.$(OBJEXT) \
     260        ResolvExpr/AlternativePrinter.$(OBJEXT) \
     261        ResolvExpr/Resolver.$(OBJEXT) \
     262        ResolvExpr/ResolveTypeof.$(OBJEXT) \
     263        ResolvExpr/RenameVars.$(OBJEXT) \
     264        ResolvExpr/FindOpenVars.$(OBJEXT) \
     265        ResolvExpr/PolyCost.$(OBJEXT) ResolvExpr/Occurs.$(OBJEXT) \
     266        ResolvExpr/TypeEnvironment.$(OBJEXT) \
     267        ResolvExpr/CurrentObject.$(OBJEXT) \
     268        ResolvExpr/ExplodedActual.$(OBJEXT) \
     269        ResolvExpr/SpecCost.$(OBJEXT) \
     270        ResolvExpr/ResolveAssertions.$(OBJEXT) \
    196271        SymTab/Indexer.$(OBJEXT) SymTab/Mangler.$(OBJEXT) \
    197         SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT)
    198 am__objects_6 = SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \
     272        SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT) \
     273        SymTab/FixFunction.$(OBJEXT) SymTab/Autogen.$(OBJEXT) \
     274        SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \
    199275        SynTree/BasicType.$(OBJEXT) SynTree/PointerType.$(OBJEXT) \
    200276        SynTree/ArrayType.$(OBJEXT) SynTree/ReferenceType.$(OBJEXT) \
     
    215291        SynTree/Initializer.$(OBJEXT) \
    216292        SynTree/TypeSubstitution.$(OBJEXT) SynTree/Attribute.$(OBJEXT) \
    217         SynTree/DeclReplacer.$(OBJEXT)
    218 am__objects_7 = CompilationState.$(OBJEXT) $(am__objects_1) \
    219         Concurrency/Keywords.$(OBJEXT) $(am__objects_2) \
    220         $(am__objects_3) GenPoly/GenPoly.$(OBJEXT) \
    221         GenPoly/Lvalue.$(OBJEXT) InitTweak/GenInit.$(OBJEXT) \
    222         InitTweak/InitTweak.$(OBJEXT) Parser/LinkageSpec.$(OBJEXT) \
    223         $(am__objects_4) $(am__objects_5) SymTab/Demangle.$(OBJEXT) \
    224         $(am__objects_6) Tuples/TupleAssignment.$(OBJEXT) \
    225         Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
    226         Validate/HandleAttributes.$(OBJEXT) \
    227         Validate/FindSpecialDecls.$(OBJEXT)
    228 am_libdemangle_a_OBJECTS = $(am__objects_7)
    229 libdemangle_a_OBJECTS = $(am_libdemangle_a_OBJECTS)
    230 am__installdirs = "$(DESTDIR)$(cfa_cpplibdir)"
    231 PROGRAMS = $(cfa_cpplib_PROGRAMS)
    232 am__objects_8 = main.$(OBJEXT) MakeLibCfa.$(OBJEXT) \
    233         CompilationState.$(OBJEXT) $(am__objects_1) \
    234         CodeGen/Generate.$(OBJEXT) CodeGen/FixNames.$(OBJEXT) \
    235         CodeTools/DeclStats.$(OBJEXT) \
    236         CodeTools/ResolvProtoDump.$(OBJEXT) \
    237         CodeTools/TrackLoc.$(OBJEXT) Concurrency/Keywords.$(OBJEXT) \
    238         Concurrency/Waitfor.$(OBJEXT) $(am__objects_2) \
    239         Common/DebugMalloc.$(OBJEXT) $(am__objects_3) \
    240         ControlStruct/ExceptTranslate.$(OBJEXT) GenPoly/Box.$(OBJEXT) \
    241         GenPoly/GenPoly.$(OBJEXT) GenPoly/ScrubTyVars.$(OBJEXT) \
    242         GenPoly/Lvalue.$(OBJEXT) GenPoly/Specialize.$(OBJEXT) \
    243         GenPoly/FindFunction.$(OBJEXT) \
    244         GenPoly/InstantiateGeneric.$(OBJEXT) \
    245         InitTweak/GenInit.$(OBJEXT) InitTweak/FixInit.$(OBJEXT) \
    246         InitTweak/FixGlobalInit.$(OBJEXT) \
    247         InitTweak/InitTweak.$(OBJEXT) Parser/parser.$(OBJEXT) \
    248         Parser/lex.$(OBJEXT) Parser/TypedefTable.$(OBJEXT) \
    249         Parser/ParseNode.$(OBJEXT) Parser/DeclarationNode.$(OBJEXT) \
    250         Parser/ExpressionNode.$(OBJEXT) Parser/StatementNode.$(OBJEXT) \
    251         Parser/InitializerNode.$(OBJEXT) Parser/TypeData.$(OBJEXT) \
    252         Parser/LinkageSpec.$(OBJEXT) Parser/parserutility.$(OBJEXT) \
    253         $(am__objects_4) ResolvExpr/AlternativePrinter.$(OBJEXT) \
    254         $(am__objects_5) $(am__objects_6) \
     293        SynTree/DeclReplacer.$(OBJEXT) \
    255294        Tuples/TupleAssignment.$(OBJEXT) \
    256295        Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
     
    258297        Validate/FindSpecialDecls.$(OBJEXT) \
    259298        Virtual/ExpandCasts.$(OBJEXT)
    260 am____driver_cfa_cpp_OBJECTS = $(am__objects_8)
     299am____driver_cfa_cpp_OBJECTS = $(am__objects_1)
    261300___driver_cfa_cpp_OBJECTS = $(am____driver_cfa_cpp_OBJECTS)
    262 am__DEPENDENCIES_1 =
    263 ___driver_cfa_cpp_DEPENDENCIES = $(am__DEPENDENCIES_1) \
    264         $(am__DEPENDENCIES_1)
     301___driver_cfa_cpp_DEPENDENCIES =
    265302AM_V_lt = $(am__v_lt_@AM_V@)
    266303am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
     
    381418DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    382419ACLOCAL = @ACLOCAL@
     420ALLOCA = @ALLOCA@
    383421AMTAR = @AMTAR@
    384422AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    528566AUTOMAKE_OPTIONS = foreign subdir-objects
    529567ACLOCAL_AMFLAGS = -I automake
    530 SRC = main.cc MakeLibCfa.cc CompilationState.cc $(SRC_CODEGEN) \
    531         CodeGen/Generate.cc CodeGen/FixNames.cc CodeTools/DeclStats.cc \
     568SRC = main.cc MakeLibCfa.cc CompilationState.cc CodeGen/Generate.cc \
     569        CodeGen/CodeGenerator.cc CodeGen/GenType.cc \
     570        CodeGen/FixNames.cc CodeGen/FixMain.cc \
     571        CodeGen/OperatorTable.cc CodeTools/DeclStats.cc \
    532572        CodeTools/ResolvProtoDump.cc CodeTools/TrackLoc.cc \
    533         Concurrency/Keywords.cc Concurrency/Waitfor.cc $(SRC_COMMON) \
    534         Common/DebugMalloc.cc $(SRC_CONTROLSTRUCT) \
     573        Concurrency/Keywords.cc Concurrency/Waitfor.cc \
     574        Common/SemanticError.cc Common/UniqueName.cc \
     575        Common/DebugMalloc.cc Common/Assert.cc Common/Heap.cc \
     576        Common/Eval.cc ControlStruct/LabelGenerator.cc \
     577        ControlStruct/LabelFixer.cc ControlStruct/MLEMutator.cc \
     578        ControlStruct/Mutate.cc ControlStruct/ForExprMutator.cc \
    535579        ControlStruct/ExceptTranslate.cc GenPoly/Box.cc \
    536580        GenPoly/GenPoly.cc GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc \
     
    543587        Parser/StatementNode.cc Parser/InitializerNode.cc \
    544588        Parser/TypeData.cc Parser/LinkageSpec.cc \
    545         Parser/parserutility.cc $(SRC_RESOLVEXPR) \
    546         ResolvExpr/AlternativePrinter.cc $(SRC_SYMTAB) $(SRC_SYNTREE) \
     589        Parser/parserutility.cc ResolvExpr/AlternativeFinder.cc \
     590        ResolvExpr/Alternative.cc ResolvExpr/Unify.cc \
     591        ResolvExpr/PtrsAssignable.cc ResolvExpr/CommonType.cc \
     592        ResolvExpr/ConversionCost.cc ResolvExpr/CastCost.cc \
     593        ResolvExpr/PtrsCastable.cc ResolvExpr/AdjustExprType.cc \
     594        ResolvExpr/AlternativePrinter.cc ResolvExpr/Resolver.cc \
     595        ResolvExpr/ResolveTypeof.cc ResolvExpr/RenameVars.cc \
     596        ResolvExpr/FindOpenVars.cc ResolvExpr/PolyCost.cc \
     597        ResolvExpr/Occurs.cc ResolvExpr/TypeEnvironment.cc \
     598        ResolvExpr/CurrentObject.cc ResolvExpr/ExplodedActual.cc \
     599        ResolvExpr/SpecCost.cc ResolvExpr/ResolveAssertions.cc \
     600        SymTab/Indexer.cc SymTab/Mangler.cc SymTab/ManglerCommon.cc \
     601        SymTab/Validate.cc SymTab/FixFunction.cc SymTab/Autogen.cc \
     602        SynTree/Type.cc SynTree/VoidType.cc SynTree/BasicType.cc \
     603        SynTree/PointerType.cc SynTree/ArrayType.cc \
     604        SynTree/ReferenceType.cc SynTree/FunctionType.cc \
     605        SynTree/ReferenceToType.cc SynTree/TupleType.cc \
     606        SynTree/TypeofType.cc SynTree/AttrType.cc \
     607        SynTree/VarArgsType.cc SynTree/ZeroOneType.cc \
     608        SynTree/Constant.cc SynTree/Expression.cc SynTree/TupleExpr.cc \
     609        SynTree/CommaExpr.cc SynTree/TypeExpr.cc \
     610        SynTree/ApplicationExpr.cc SynTree/AddressExpr.cc \
     611        SynTree/Statement.cc SynTree/CompoundStmt.cc \
     612        SynTree/DeclStmt.cc SynTree/Declaration.cc \
     613        SynTree/DeclarationWithType.cc SynTree/ObjectDecl.cc \
     614        SynTree/FunctionDecl.cc SynTree/AggregateDecl.cc \
     615        SynTree/NamedTypeDecl.cc SynTree/TypeDecl.cc \
     616        SynTree/Initializer.cc SynTree/TypeSubstitution.cc \
     617        SynTree/Attribute.cc SynTree/DeclReplacer.cc \
    547618        Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
    548619        Tuples/Explode.cc Validate/HandleAttributes.cc \
    549620        Validate/FindSpecialDecls.cc Virtual/ExpandCasts.cc
    550 SRCDEMANGLE = CompilationState.cc $(SRC_CODEGEN) \
    551         Concurrency/Keywords.cc $(SRC_COMMON) $(SRC_CONTROLSTRUCT) \
    552         GenPoly/GenPoly.cc GenPoly/Lvalue.cc InitTweak/GenInit.cc \
    553         InitTweak/InitTweak.cc Parser/LinkageSpec.cc $(SRC_RESOLVEXPR) \
    554         $(SRC_SYMTAB) SymTab/Demangle.cc $(SRC_SYNTREE) \
    555         Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
    556         Tuples/Explode.cc Validate/HandleAttributes.cc \
    557         Validate/FindSpecialDecls.cc
    558621MAINTAINERCLEANFILES = ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}}
    559 MOSTLYCLEANFILES = Parser/lex.cc Parser/parser.cc Parser/parser.hh \
    560         Parser/parser.output
    561 @WITH_LIBPROFILER_TRUE@LIBPROFILER = -lprofiler
    562 @WITH_LIBTCMALLOC_TRUE@LIBTCMALLOC = -ltcmalloc
    563 @WITH_LIBTCMALLOC_TRUE@TCMALLOCFLAG = -DTCMALLOC
    564 SRC_CODEGEN = \
     622MOSTLYCLEANFILES = Parser/gcc-flags.h Parser/lex.cc Parser/parser.cc \
     623        Parser/parser.hh Parser/parser.output
     624BUILT_SOURCES = Parser/parser.hh
     625AM_YFLAGS = -d -t -v
     626
     627# put into lib for now
     628cfa_cpplibdir = $(CFA_LIBDIR)
     629___driver_cfa_cpp_SOURCES = $(SRC)
     630___driver_cfa_cpp_LDADD = -ldl                  # yywrap
     631AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O2 -g -std=c++14
     632AM_LDFLAGS = @HOST_FLAGS@ -Xlinker -export-dynamic
     633ARFLAGS = cr
     634demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete
     635demangler_LDADD = libdemangle.a     # yywrap
     636noinst_LIBRARIES = libdemangle.a
     637libdemangle_a_SOURCES = \
     638        SymTab/Demangle.cc \
     639        SymTab/ManglerCommon.cc \
     640        SynTree/Type.cc \
     641        SynTree/VoidType.cc \
     642        SynTree/BasicType.cc \
     643        SynTree/PointerType.cc \
     644        SynTree/ArrayType.cc \
     645        SynTree/ReferenceType.cc \
     646        SynTree/FunctionType.cc \
     647        SynTree/ReferenceToType.cc \
     648        SynTree/TupleType.cc \
     649        SynTree/TypeofType.cc \
     650        SynTree/AttrType.cc \
     651        SynTree/VarArgsType.cc \
     652        SynTree/ZeroOneType.cc \
     653        SynTree/Constant.cc \
     654        SynTree/Expression.cc \
     655        SynTree/TupleExpr.cc \
     656        SynTree/CommaExpr.cc \
     657        SynTree/TypeExpr.cc \
     658        SynTree/ApplicationExpr.cc \
     659        SynTree/AddressExpr.cc \
     660        SynTree/Statement.cc \
     661        SynTree/CompoundStmt.cc \
     662        SynTree/DeclStmt.cc \
     663        SynTree/Declaration.cc \
     664        SynTree/DeclarationWithType.cc \
     665        SynTree/ObjectDecl.cc \
     666        SynTree/FunctionDecl.cc \
     667        SynTree/AggregateDecl.cc \
     668        SynTree/NamedTypeDecl.cc \
     669        SynTree/TypeDecl.cc \
     670        SynTree/Initializer.cc \
     671        SynTree/TypeSubstitution.cc \
     672        SynTree/Attribute.cc \
     673        SynTree/DeclReplacer.cc \
     674        CompilationState.cc \
    565675        CodeGen/CodeGenerator.cc \
    566676        CodeGen/FixMain.cc \
     677        CodeGen/Generate.cc \
    567678        CodeGen/GenType.cc \
    568         CodeGen/OperatorTable.cc
    569 
    570 SRC_COMMON = \
    571       Common/Assert.cc \
    572       Common/Eval.cc \
    573       Common/PassVisitor.cc \
    574       Common/SemanticError.cc \
    575       Common/Stats/Counter.cc \
    576       Common/Stats/Heap.cc \
    577       Common/Stats/Stats.cc \
    578       Common/Stats/Time.cc \
    579       Common/UniqueName.cc
    580 
    581 SRC_CONTROLSTRUCT = \
     679        CodeGen/OperatorTable.cc \
     680        Common/Assert.cc \
     681        Common/Eval.cc \
     682        Common/SemanticError.cc \
     683        Common/UniqueName.cc \
     684        Concurrency/Keywords.cc \
    582685        ControlStruct/ForExprMutator.cc \
    583686        ControlStruct/LabelFixer.cc \
    584687        ControlStruct/LabelGenerator.cc \
    585688        ControlStruct/MLEMutator.cc \
    586         ControlStruct/Mutate.cc
    587 
    588 BUILT_SOURCES = Parser/parser.hh
    589 AM_YFLAGS = -d -t -v
    590 SRC_RESOLVEXPR = \
    591       ResolvExpr/AdjustExprType.cc \
    592       ResolvExpr/Alternative.cc \
    593       ResolvExpr/AlternativeFinder.cc \
    594       ResolvExpr/CastCost.cc \
    595       ResolvExpr/CommonType.cc \
    596       ResolvExpr/ConversionCost.cc \
    597       ResolvExpr/CurrentObject.cc \
    598       ResolvExpr/ExplodedActual.cc \
    599       ResolvExpr/FindOpenVars.cc \
    600       ResolvExpr/Occurs.cc \
    601       ResolvExpr/PolyCost.cc \
    602       ResolvExpr/PtrsAssignable.cc \
    603       ResolvExpr/PtrsCastable.cc \
    604       ResolvExpr/RenameVars.cc \
    605       ResolvExpr/ResolveAssertions.cc \
    606       ResolvExpr/Resolver.cc \
    607       ResolvExpr/ResolveTypeof.cc \
    608       ResolvExpr/SpecCost.cc \
    609       ResolvExpr/TypeEnvironment.cc \
    610       ResolvExpr/Unify.cc
    611 
    612 SRC_SYMTAB = \
    613       SymTab/Autogen.cc \
    614       SymTab/FixFunction.cc \
    615       SymTab/Indexer.cc \
    616       SymTab/Mangler.cc \
    617       SymTab/ManglerCommon.cc \
    618       SymTab/Validate.cc
    619 
    620 SRC_SYNTREE = \
    621       SynTree/Type.cc \
    622       SynTree/VoidType.cc \
    623       SynTree/BasicType.cc \
    624       SynTree/PointerType.cc \
    625       SynTree/ArrayType.cc \
    626       SynTree/ReferenceType.cc \
    627       SynTree/FunctionType.cc \
    628       SynTree/ReferenceToType.cc \
    629       SynTree/TupleType.cc \
    630       SynTree/TypeofType.cc \
    631       SynTree/AttrType.cc \
    632       SynTree/VarArgsType.cc \
    633       SynTree/ZeroOneType.cc \
    634       SynTree/Constant.cc \
    635       SynTree/Expression.cc \
    636       SynTree/TupleExpr.cc \
    637       SynTree/CommaExpr.cc \
    638       SynTree/TypeExpr.cc \
    639       SynTree/ApplicationExpr.cc \
    640       SynTree/AddressExpr.cc \
    641       SynTree/Statement.cc \
    642       SynTree/CompoundStmt.cc \
    643       SynTree/DeclStmt.cc \
    644       SynTree/Declaration.cc \
    645       SynTree/DeclarationWithType.cc \
    646       SynTree/ObjectDecl.cc \
    647       SynTree/FunctionDecl.cc \
    648       SynTree/AggregateDecl.cc \
    649       SynTree/NamedTypeDecl.cc \
    650       SynTree/TypeDecl.cc \
    651       SynTree/Initializer.cc \
    652       SynTree/TypeSubstitution.cc \
    653       SynTree/Attribute.cc \
    654       SynTree/DeclReplacer.cc
    655 
    656 
    657 # put into lib for now
    658 cfa_cpplibdir = $(CFA_LIBDIR)
    659 ___driver_cfa_cpp_SOURCES = $(SRC)
    660 ___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC)
    661 AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O3 -g -std=c++14 $(TCMALLOCFLAG)
    662 AM_LDFLAGS = @HOST_FLAGS@ -Xlinker -export-dynamic
    663 ARFLAGS = cr
    664 demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete
    665 demangler_LDADD = libdemangle.a -ldl                    # yywrap
    666 noinst_LIBRARIES = libdemangle.a
    667 libdemangle_a_SOURCES = $(SRCDEMANGLE)
     689        ControlStruct/Mutate.cc \
     690        GenPoly/GenPoly.cc \
     691        GenPoly/Lvalue.cc \
     692        InitTweak/GenInit.cc \
     693        InitTweak/InitTweak.cc \
     694        Parser/LinkageSpec.cc \
     695        ResolvExpr/AdjustExprType.cc \
     696        ResolvExpr/Alternative.cc \
     697        ResolvExpr/AlternativeFinder.cc \
     698        ResolvExpr/ExplodedActual.cc \
     699        ResolvExpr/CastCost.cc \
     700        ResolvExpr/CommonType.cc \
     701        ResolvExpr/ConversionCost.cc \
     702        ResolvExpr/CurrentObject.cc \
     703        ResolvExpr/FindOpenVars.cc \
     704        ResolvExpr/Occurs.cc \
     705        ResolvExpr/PolyCost.cc \
     706        ResolvExpr/PtrsAssignable.cc \
     707        ResolvExpr/PtrsCastable.cc \
     708        ResolvExpr/RenameVars.cc \
     709        ResolvExpr/ResolveAssertions.cc \
     710        ResolvExpr/Resolver.cc \
     711        ResolvExpr/ResolveTypeof.cc \
     712        ResolvExpr/SpecCost.cc \
     713        ResolvExpr/TypeEnvironment.cc \
     714        ResolvExpr/Unify.cc \
     715        SymTab/Autogen.cc \
     716        SymTab/FixFunction.cc \
     717        SymTab/Indexer.cc \
     718        SymTab/Mangler.cc \
     719        SymTab/Validate.cc \
     720        Tuples/Explode.cc \
     721        Tuples/TupleAssignment.cc \
     722        Tuples/TupleExpansion.cc \
     723        Validate/HandleAttributes.cc \
     724        Validate/FindSpecialDecls.cc
     725
    668726all: $(BUILT_SOURCES)
    669727        $(MAKE) $(AM_MAKEFLAGS) all-am
     
    704762clean-noinstLIBRARIES:
    705763        -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
     764SymTab/$(am__dirstamp):
     765        @$(MKDIR_P) SymTab
     766        @: > SymTab/$(am__dirstamp)
     767SymTab/$(DEPDIR)/$(am__dirstamp):
     768        @$(MKDIR_P) SymTab/$(DEPDIR)
     769        @: > SymTab/$(DEPDIR)/$(am__dirstamp)
     770SymTab/Demangle.$(OBJEXT): SymTab/$(am__dirstamp) \
     771        SymTab/$(DEPDIR)/$(am__dirstamp)
     772SymTab/ManglerCommon.$(OBJEXT): SymTab/$(am__dirstamp) \
     773        SymTab/$(DEPDIR)/$(am__dirstamp)
     774SynTree/$(am__dirstamp):
     775        @$(MKDIR_P) SynTree
     776        @: > SynTree/$(am__dirstamp)
     777SynTree/$(DEPDIR)/$(am__dirstamp):
     778        @$(MKDIR_P) SynTree/$(DEPDIR)
     779        @: > SynTree/$(DEPDIR)/$(am__dirstamp)
     780SynTree/Type.$(OBJEXT): SynTree/$(am__dirstamp) \
     781        SynTree/$(DEPDIR)/$(am__dirstamp)
     782SynTree/VoidType.$(OBJEXT): SynTree/$(am__dirstamp) \
     783        SynTree/$(DEPDIR)/$(am__dirstamp)
     784SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \
     785        SynTree/$(DEPDIR)/$(am__dirstamp)
     786SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \
     787        SynTree/$(DEPDIR)/$(am__dirstamp)
     788SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \
     789        SynTree/$(DEPDIR)/$(am__dirstamp)
     790SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \
     791        SynTree/$(DEPDIR)/$(am__dirstamp)
     792SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \
     793        SynTree/$(DEPDIR)/$(am__dirstamp)
     794SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \
     795        SynTree/$(DEPDIR)/$(am__dirstamp)
     796SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \
     797        SynTree/$(DEPDIR)/$(am__dirstamp)
     798SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \
     799        SynTree/$(DEPDIR)/$(am__dirstamp)
     800SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \
     801        SynTree/$(DEPDIR)/$(am__dirstamp)
     802SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \
     803        SynTree/$(DEPDIR)/$(am__dirstamp)
     804SynTree/ZeroOneType.$(OBJEXT): SynTree/$(am__dirstamp) \
     805        SynTree/$(DEPDIR)/$(am__dirstamp)
     806SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \
     807        SynTree/$(DEPDIR)/$(am__dirstamp)
     808SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \
     809        SynTree/$(DEPDIR)/$(am__dirstamp)
     810SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     811        SynTree/$(DEPDIR)/$(am__dirstamp)
     812SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     813        SynTree/$(DEPDIR)/$(am__dirstamp)
     814SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     815        SynTree/$(DEPDIR)/$(am__dirstamp)
     816SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     817        SynTree/$(DEPDIR)/$(am__dirstamp)
     818SynTree/AddressExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     819        SynTree/$(DEPDIR)/$(am__dirstamp)
     820SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \
     821        SynTree/$(DEPDIR)/$(am__dirstamp)
     822SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
     823        SynTree/$(DEPDIR)/$(am__dirstamp)
     824SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
     825        SynTree/$(DEPDIR)/$(am__dirstamp)
     826SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \
     827        SynTree/$(DEPDIR)/$(am__dirstamp)
     828SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \
     829        SynTree/$(DEPDIR)/$(am__dirstamp)
     830SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     831        SynTree/$(DEPDIR)/$(am__dirstamp)
     832SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     833        SynTree/$(DEPDIR)/$(am__dirstamp)
     834SynTree/AggregateDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     835        SynTree/$(DEPDIR)/$(am__dirstamp)
     836SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     837        SynTree/$(DEPDIR)/$(am__dirstamp)
     838SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     839        SynTree/$(DEPDIR)/$(am__dirstamp)
     840SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \
     841        SynTree/$(DEPDIR)/$(am__dirstamp)
     842SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \
     843        SynTree/$(DEPDIR)/$(am__dirstamp)
     844SynTree/Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \
     845        SynTree/$(DEPDIR)/$(am__dirstamp)
     846SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \
     847        SynTree/$(DEPDIR)/$(am__dirstamp)
    706848CodeGen/$(am__dirstamp):
    707849        @$(MKDIR_P) CodeGen
     
    714856CodeGen/FixMain.$(OBJEXT): CodeGen/$(am__dirstamp) \
    715857        CodeGen/$(DEPDIR)/$(am__dirstamp)
     858CodeGen/Generate.$(OBJEXT): CodeGen/$(am__dirstamp) \
     859        CodeGen/$(DEPDIR)/$(am__dirstamp)
    716860CodeGen/GenType.$(OBJEXT): CodeGen/$(am__dirstamp) \
    717861        CodeGen/$(DEPDIR)/$(am__dirstamp)
    718862CodeGen/OperatorTable.$(OBJEXT): CodeGen/$(am__dirstamp) \
    719863        CodeGen/$(DEPDIR)/$(am__dirstamp)
    720 Concurrency/$(am__dirstamp):
    721         @$(MKDIR_P) Concurrency
    722         @: > Concurrency/$(am__dirstamp)
    723 Concurrency/$(DEPDIR)/$(am__dirstamp):
    724         @$(MKDIR_P) Concurrency/$(DEPDIR)
    725         @: > Concurrency/$(DEPDIR)/$(am__dirstamp)
    726 Concurrency/Keywords.$(OBJEXT): Concurrency/$(am__dirstamp) \
    727         Concurrency/$(DEPDIR)/$(am__dirstamp)
    728864Common/$(am__dirstamp):
    729865        @$(MKDIR_P) Common
     
    736872Common/Eval.$(OBJEXT): Common/$(am__dirstamp) \
    737873        Common/$(DEPDIR)/$(am__dirstamp)
    738 Common/PassVisitor.$(OBJEXT): Common/$(am__dirstamp) \
    739         Common/$(DEPDIR)/$(am__dirstamp)
    740874Common/SemanticError.$(OBJEXT): Common/$(am__dirstamp) \
    741875        Common/$(DEPDIR)/$(am__dirstamp)
    742 Common/Stats/$(am__dirstamp):
    743         @$(MKDIR_P) Common/Stats
    744         @: > Common/Stats/$(am__dirstamp)
    745 Common/Stats/$(DEPDIR)/$(am__dirstamp):
    746         @$(MKDIR_P) Common/Stats/$(DEPDIR)
    747         @: > Common/Stats/$(DEPDIR)/$(am__dirstamp)
    748 Common/Stats/Counter.$(OBJEXT): Common/Stats/$(am__dirstamp) \
    749         Common/Stats/$(DEPDIR)/$(am__dirstamp)
    750 Common/Stats/Heap.$(OBJEXT): Common/Stats/$(am__dirstamp) \
    751         Common/Stats/$(DEPDIR)/$(am__dirstamp)
    752 Common/Stats/Stats.$(OBJEXT): Common/Stats/$(am__dirstamp) \
    753         Common/Stats/$(DEPDIR)/$(am__dirstamp)
    754 Common/Stats/Time.$(OBJEXT): Common/Stats/$(am__dirstamp) \
    755         Common/Stats/$(DEPDIR)/$(am__dirstamp)
    756876Common/UniqueName.$(OBJEXT): Common/$(am__dirstamp) \
    757877        Common/$(DEPDIR)/$(am__dirstamp)
     878Concurrency/$(am__dirstamp):
     879        @$(MKDIR_P) Concurrency
     880        @: > Concurrency/$(am__dirstamp)
     881Concurrency/$(DEPDIR)/$(am__dirstamp):
     882        @$(MKDIR_P) Concurrency/$(DEPDIR)
     883        @: > Concurrency/$(DEPDIR)/$(am__dirstamp)
     884Concurrency/Keywords.$(OBJEXT): Concurrency/$(am__dirstamp) \
     885        Concurrency/$(DEPDIR)/$(am__dirstamp)
    758886ControlStruct/$(am__dirstamp):
    759887        @$(MKDIR_P) ControlStruct
     
    812940ResolvExpr/AlternativeFinder.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    813941        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     942ResolvExpr/ExplodedActual.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
     943        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    814944ResolvExpr/CastCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    815945        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     
    820950ResolvExpr/CurrentObject.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    821951        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    822 ResolvExpr/ExplodedActual.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    823         ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    824952ResolvExpr/FindOpenVars.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    825953        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     
    846974ResolvExpr/Unify.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    847975        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    848 SymTab/$(am__dirstamp):
    849         @$(MKDIR_P) SymTab
    850         @: > SymTab/$(am__dirstamp)
    851 SymTab/$(DEPDIR)/$(am__dirstamp):
    852         @$(MKDIR_P) SymTab/$(DEPDIR)
    853         @: > SymTab/$(DEPDIR)/$(am__dirstamp)
    854976SymTab/Autogen.$(OBJEXT): SymTab/$(am__dirstamp) \
    855977        SymTab/$(DEPDIR)/$(am__dirstamp)
     
    860982SymTab/Mangler.$(OBJEXT): SymTab/$(am__dirstamp) \
    861983        SymTab/$(DEPDIR)/$(am__dirstamp)
    862 SymTab/ManglerCommon.$(OBJEXT): SymTab/$(am__dirstamp) \
    863         SymTab/$(DEPDIR)/$(am__dirstamp)
    864984SymTab/Validate.$(OBJEXT): SymTab/$(am__dirstamp) \
    865985        SymTab/$(DEPDIR)/$(am__dirstamp)
    866 SymTab/Demangle.$(OBJEXT): SymTab/$(am__dirstamp) \
    867         SymTab/$(DEPDIR)/$(am__dirstamp)
    868 SynTree/$(am__dirstamp):
    869         @$(MKDIR_P) SynTree
    870         @: > SynTree/$(am__dirstamp)
    871 SynTree/$(DEPDIR)/$(am__dirstamp):
    872         @$(MKDIR_P) SynTree/$(DEPDIR)
    873         @: > SynTree/$(DEPDIR)/$(am__dirstamp)
    874 SynTree/Type.$(OBJEXT): SynTree/$(am__dirstamp) \
    875         SynTree/$(DEPDIR)/$(am__dirstamp)
    876 SynTree/VoidType.$(OBJEXT): SynTree/$(am__dirstamp) \
    877         SynTree/$(DEPDIR)/$(am__dirstamp)
    878 SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \
    879         SynTree/$(DEPDIR)/$(am__dirstamp)
    880 SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \
    881         SynTree/$(DEPDIR)/$(am__dirstamp)
    882 SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \
    883         SynTree/$(DEPDIR)/$(am__dirstamp)
    884 SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \
    885         SynTree/$(DEPDIR)/$(am__dirstamp)
    886 SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \
    887         SynTree/$(DEPDIR)/$(am__dirstamp)
    888 SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \
    889         SynTree/$(DEPDIR)/$(am__dirstamp)
    890 SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \
    891         SynTree/$(DEPDIR)/$(am__dirstamp)
    892 SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \
    893         SynTree/$(DEPDIR)/$(am__dirstamp)
    894 SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \
    895         SynTree/$(DEPDIR)/$(am__dirstamp)
    896 SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \
    897         SynTree/$(DEPDIR)/$(am__dirstamp)
    898 SynTree/ZeroOneType.$(OBJEXT): SynTree/$(am__dirstamp) \
    899         SynTree/$(DEPDIR)/$(am__dirstamp)
    900 SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \
    901         SynTree/$(DEPDIR)/$(am__dirstamp)
    902 SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \
    903         SynTree/$(DEPDIR)/$(am__dirstamp)
    904 SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    905         SynTree/$(DEPDIR)/$(am__dirstamp)
    906 SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    907         SynTree/$(DEPDIR)/$(am__dirstamp)
    908 SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    909         SynTree/$(DEPDIR)/$(am__dirstamp)
    910 SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    911         SynTree/$(DEPDIR)/$(am__dirstamp)
    912 SynTree/AddressExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    913         SynTree/$(DEPDIR)/$(am__dirstamp)
    914 SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \
    915         SynTree/$(DEPDIR)/$(am__dirstamp)
    916 SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
    917         SynTree/$(DEPDIR)/$(am__dirstamp)
    918 SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
    919         SynTree/$(DEPDIR)/$(am__dirstamp)
    920 SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \
    921         SynTree/$(DEPDIR)/$(am__dirstamp)
    922 SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \
    923         SynTree/$(DEPDIR)/$(am__dirstamp)
    924 SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    925         SynTree/$(DEPDIR)/$(am__dirstamp)
    926 SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    927         SynTree/$(DEPDIR)/$(am__dirstamp)
    928 SynTree/AggregateDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    929         SynTree/$(DEPDIR)/$(am__dirstamp)
    930 SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    931         SynTree/$(DEPDIR)/$(am__dirstamp)
    932 SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    933         SynTree/$(DEPDIR)/$(am__dirstamp)
    934 SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \
    935         SynTree/$(DEPDIR)/$(am__dirstamp)
    936 SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \
    937         SynTree/$(DEPDIR)/$(am__dirstamp)
    938 SynTree/Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \
    939         SynTree/$(DEPDIR)/$(am__dirstamp)
    940 SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \
    941         SynTree/$(DEPDIR)/$(am__dirstamp)
    942986Tuples/$(am__dirstamp):
    943987        @$(MKDIR_P) Tuples
     
    946990        @$(MKDIR_P) Tuples/$(DEPDIR)
    947991        @: > Tuples/$(DEPDIR)/$(am__dirstamp)
     992Tuples/Explode.$(OBJEXT): Tuples/$(am__dirstamp) \
     993        Tuples/$(DEPDIR)/$(am__dirstamp)
    948994Tuples/TupleAssignment.$(OBJEXT): Tuples/$(am__dirstamp) \
    949995        Tuples/$(DEPDIR)/$(am__dirstamp)
    950996Tuples/TupleExpansion.$(OBJEXT): Tuples/$(am__dirstamp) \
    951         Tuples/$(DEPDIR)/$(am__dirstamp)
    952 Tuples/Explode.$(OBJEXT): Tuples/$(am__dirstamp) \
    953997        Tuples/$(DEPDIR)/$(am__dirstamp)
    954998Validate/$(am__dirstamp):
     
    10161060        echo " rm -f" $$list; \
    10171061        rm -f $$list
    1018 CodeGen/Generate.$(OBJEXT): CodeGen/$(am__dirstamp) \
    1019         CodeGen/$(DEPDIR)/$(am__dirstamp)
    10201062CodeGen/FixNames.$(OBJEXT): CodeGen/$(am__dirstamp) \
    10211063        CodeGen/$(DEPDIR)/$(am__dirstamp)
     
    10351077        Concurrency/$(DEPDIR)/$(am__dirstamp)
    10361078Common/DebugMalloc.$(OBJEXT): Common/$(am__dirstamp) \
     1079        Common/$(DEPDIR)/$(am__dirstamp)
     1080Common/Heap.$(OBJEXT): Common/$(am__dirstamp) \
    10371081        Common/$(DEPDIR)/$(am__dirstamp)
    10381082ControlStruct/ExceptTranslate.$(OBJEXT):  \
     
    11051149        -rm -f CodeTools/*.$(OBJEXT)
    11061150        -rm -f Common/*.$(OBJEXT)
    1107         -rm -f Common/Stats/*.$(OBJEXT)
    11081151        -rm -f Concurrency/*.$(OBJEXT)
    11091152        -rm -f ControlStruct/*.$(OBJEXT)
     
    11361179@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/DebugMalloc.Po@am__quote@
    11371180@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/Eval.Po@am__quote@
    1138 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/PassVisitor.Po@am__quote@
     1181@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/Heap.Po@am__quote@
    11391182@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/SemanticError.Po@am__quote@
    11401183@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/UniqueName.Po@am__quote@
    1141 @AMDEP_TRUE@@am__include@ @am__quote@Common/Stats/$(DEPDIR)/Counter.Po@am__quote@
    1142 @AMDEP_TRUE@@am__include@ @am__quote@Common/Stats/$(DEPDIR)/Heap.Po@am__quote@
    1143 @AMDEP_TRUE@@am__include@ @am__quote@Common/Stats/$(DEPDIR)/Stats.Po@am__quote@
    1144 @AMDEP_TRUE@@am__include@ @am__quote@Common/Stats/$(DEPDIR)/Time.Po@am__quote@
    11451184@AMDEP_TRUE@@am__include@ @am__quote@Concurrency/$(DEPDIR)/Keywords.Po@am__quote@
    11461185@AMDEP_TRUE@@am__include@ @am__quote@Concurrency/$(DEPDIR)/Waitfor.Po@am__quote@
     
    14051444        -rm -f Common/$(DEPDIR)/$(am__dirstamp)
    14061445        -rm -f Common/$(am__dirstamp)
    1407         -rm -f Common/Stats/$(DEPDIR)/$(am__dirstamp)
    1408         -rm -f Common/Stats/$(am__dirstamp)
    14091446        -rm -f Concurrency/$(DEPDIR)/$(am__dirstamp)
    14101447        -rm -f Concurrency/$(am__dirstamp)
     
    14441481
    14451482distclean: distclean-am
    1446         -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Common/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)
     1483        -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)
    14471484        -rm -f Makefile
    14481485distclean-am: clean-am distclean-compile distclean-generic \
     
    14901527
    14911528maintainer-clean: maintainer-clean-am
    1492         -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Common/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)
     1529        -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)
    14931530        -rm -f Makefile
    14941531maintainer-clean-am: distclean-am maintainer-clean-generic
     
    15301567
    15311568
    1532 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h
    1533 
    1534 $(srcdir)/SynTree/Type.h : BasicTypes-gen.cc
    1535         ${AM_V_GEN}${CXXCOMPILE} $< -o BasicTypes-gen -Wall -Wextra
    1536         @./BasicTypes-gen
    1537         @rm BasicTypes-gen
     1569Parser/gcc-flags.h :
     1570        ${AM_V_GEN}$(CC) -dM -E - < /dev/null | sed 's/define /define __GCC__/' > $(@)
     1571
     1572Parser/lex.ll : Parser/gcc-flags.h
    15381573
    15391574# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • src/Parser/DeclarationNode.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  1 16:49:17 2019
    13 // Update Count     : 1113
     12// Last Modified On : Thu Nov  1 20:54:26 2018
     13// Update Count     : 1108
    1414//
    1515
     
    4141
    4242// These must harmonize with the corresponding DeclarationNode enumerations.
    43 const char * DeclarationNode::basicTypeNames[] = { "void", "_Bool", "char", "int", "int128",
    44                                                                                                    "float", "double", "long double", "float80", "float128",
    45                                                                                                    "_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x", "NoBasicTypeNames" };
    46 const char * DeclarationNode::complexTypeNames[] = { "_Complex", "NoComplexTypeNames", "_Imaginary" }; // Imaginary unsupported => parse, but make invisible and print error message
     43const char * DeclarationNode::basicTypeNames[] = { "void", "_Bool", "char", "int", "float", "double", "long double", "int128", "float80", "float128", "NoBasicTypeNames" };
     44const char * DeclarationNode::complexTypeNames[] = { "_Complex", "_Imaginary", "NoComplexTypeNames" };
    4745const char * DeclarationNode::signednessNames[] = { "signed", "unsigned", "NoSignednessNames" };
    4846const char * DeclarationNode::lengthNames[] = { "short", "long", "long long", "NoLengthNames" };
  • src/Parser/ExpressionNode.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Sat May 16 13:17:07 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Mar 10 16:10:32 2019
    13 // Update Count     : 976
     12// Last Modified On : Mon Jun  4 21:24:45 2018
     13// Update Count     : 802
    1414//
    1515
     
    5151extern const Type::Qualifiers noQualifiers;                             // no qualifiers on constants
    5252
    53 // static inline bool checkH( char c ) { return c == 'h' || c == 'H'; }
    54 // static inline bool checkZ( char c ) { return c == 'z' || c == 'Z'; }
    55 // static inline bool checkU( char c ) { return c == 'u' || c == 'U'; }
     53static inline bool checkH( char c ) { return c == 'h' || c == 'H'; }
     54static inline bool checkL( char c ) { return c == 'l' || c == 'L'; }
     55static inline bool checkZ( char c ) { return c == 'z' || c == 'Z'; }
     56static inline bool checkU( char c ) { return c == 'u' || c == 'U'; }
    5657static inline bool checkF( char c ) { return c == 'f' || c == 'F'; }
    5758static inline bool checkD( char c ) { return c == 'd' || c == 'D'; }
    58 static inline bool checkF80( char c ) { return c == 'w' || c == 'W'; }
    59 static inline bool checkF128( char c ) { return c == 'q' || c == 'Q'; }
    60 static inline bool checkL( char c ) { return c == 'l' || c == 'L'; }
    6159static inline bool checkI( char c ) { return c == 'i' || c == 'I'; }
    6260static inline bool checkB( char c ) { return c == 'b' || c == 'B'; }
    6361static inline bool checkX( char c ) { return c == 'x' || c == 'X'; }
    64 // static inline bool checkN( char c ) { return c == 'n' || c == 'N'; }
    65 
    66 void lnthSuffix( string & str, int & type, int & ltype ) {
    67         string::size_type posn = str.find_last_of( "lL" );
    68 
    69         if ( posn == string::npos ) return;                                     // no suffix
    70         if ( posn == str.length() - 1 ) { type = 3; return; } // no length => long
    71 
    72         string::size_type next = posn + 1;                                      // advance to length
    73         if ( str[next] == '3' ) {                                                       // 32
    74                 type = ltype = 2;
    75         } else if ( str[next] == '6' ) {                                        // 64
    76                 type = ltype = 3;
    77         } else if ( str[next] == '8' ) {                                        // 8
    78                 type = ltype = 1;
    79         } else if ( str[next] == '1' ) {
    80                 if ( str[next + 1] == '6' ) {                                   // 16
    81                         type = ltype = 0;
     62
     63static const char * lnthsInt[2][6] = {
     64        { "int8_t", "int16_t", "int32_t", "int64_t", "size_t", },
     65        { "uint8_t", "uint16_t", "uint32_t", "uint64_t", "size_t", }
     66}; // lnthsInt
     67
     68static inline void checkLNInt( string & str, int & lnth, int & size ) {
     69        string::size_type posn = str.find_first_of( "lL" ), start = posn;
     70  if ( posn == string::npos ) return;
     71        size = 4;                                                                                       // assume largest size
     72        posn += 1;                                                                                      // advance to size
     73        if ( str[posn] == '8' ) {                                                       // 8
     74                lnth = 0;
     75        } else if ( str[posn] == '1' ) {
     76                posn += 1;
     77                if ( str[posn] == '6' ) {                                               // 16
     78                        lnth = 1;
    8279                } else {                                                                                // 128
    83                         type = 5; ltype = 6;
    84                 } // if
    85         } // if
    86         // remove "lL" for these cases because it may not imply long
    87         str.erase( posn );                                                                      // remove length
    88 } // lnthSuffix
    89 
    90 void valueToType( unsigned long long int & v, bool dec, int & type, bool & Unsigned ) {
    91         // use value to determine type
    92         if ( v <= INT_MAX ) {                                                           // signed int
    93                 type = 2;
    94         } else if ( v <= UINT_MAX && ! dec ) {                          // unsigned int
    95                 type = 2;
    96                 Unsigned = true;                                                                // unsigned
    97         } else if ( v <= LONG_MAX ) {                                           // signed long int
    98                 type = 3;
    99         } else if ( v <= ULONG_MAX && ( ! dec || LONG_MAX == LLONG_MAX ) ) { // signed long int
    100                 type = 3;
    101                 Unsigned = true;                                                                // unsigned long int
    102         } else if ( v <= LLONG_MAX ) {                                          // signed long long int
    103                 type = 4;
    104         } else {                                                                                        // unsigned long long int
    105                 type = 4;
    106                 Unsigned = true;                                                                // unsigned long long int
    107         } // if
    108 } // valueToType
     80                        posn += 1;
     81                        lnth = 5;
     82                } // if
     83        } else {
     84                if ( str[posn] == '3' ) {                                               // 32
     85                        lnth = 2;
     86                } else if ( str[posn] == '6' ) {                                // 64
     87                        lnth = 3;
     88                } else {
     89                        assertf( false, "internal error, bad integral length %s", str.c_str() );
     90                } // if
     91                posn += 1;
     92        } // if
     93        str.erase( start, posn - start + 1 );                           // remove length suffix
     94} // checkLNInt
    10995
    11096Expression * build_constantInteger( string & str ) {
    111         static const BasicType::Kind kind[2][7] = {
    112                 // short (h) must be before char (hh) because shorter type has the longer suffix
     97        static const BasicType::Kind kind[2][6] = {
     98                // short (h) must be before char (hh)
    11399                { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, BasicType::SignedInt128, },
    114100                { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::UnsignedInt128, },
    115101        };
    116102
    117         static const char * lnthsInt[2][6] = {
    118                 { "int16_t",  "int8_t",  "int32_t",  "int64_t",  "size_t",  "uintptr_t", },
    119                 { "uint16_t", "uint8_t", "uint32_t", "uint64_t", "size_t",  "uintptr_t", },
    120         }; // lnthsInt
     103        bool dec = true, Unsigned = false;                                      // decimal, unsigned constant
     104        int size;                                                                                       // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128
     105        int lnth = -1;                                                                          // literal length
    121106
    122107        unsigned long long int v;                                                       // converted integral value
    123108        size_t last = str.length() - 1;                                         // last subscript of constant
    124109        Expression * ret;
    125         //string fred( str );
    126 
    127         int type = -1;                                                                          // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128
    128         int ltype = -1;                                                                         // 0 => 16 bits, 1 => 8 bits, 2 => 32 bits, 3 => 64 bits, 4 => size_t, 5 => intptr, 6 => pointer
    129         bool dec = true, Unsigned = false;                                      // decimal, unsigned constant
    130110
    131111        // special constants
     
    139119        } // if
    140120
    141         // Cannot be just "0"/"1"; sscanf stops at the suffix, if any; value goes over the wall => always generate
     121        // Cannot be "0"
    142122
    143123        if ( str[0] == '0' ) {                                                          // radix character ?
     
    147127                        //printf( "%llx %llu\n", v, v );
    148128                } else if ( checkB( str[1] ) ) {                                // binary constant ?
    149                         v = 0;                                                                          // compute value
    150                         for ( unsigned int i = 2;; ) {                          // ignore prefix
     129                        v = 0;
     130                        for ( unsigned int i = 2;; i += 1 ) {           // compute value
    151131                                if ( str[i] == '1' ) v |= 1;
    152                                 i += 1;
    153                           if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
     132                          if ( i == last ) break;
    154133                                v <<= 1;
    155134                        } // for
    156                         //printf( "%#llx %llu\n", v, v );
     135                        //printf( "%llx %llu\n", v, v );
    157136                } else {                                                                                // octal constant
    158137                        sscanf( (char *)str.c_str(), "%llo", &v );
    159                         //printf( "%#llo %llu\n", v, v );
     138                        //printf( "%llo %llu\n", v, v );
    160139                } // if
    161140        } else {                                                                                        // decimal constant ?
    162141                sscanf( (char *)str.c_str(), "%llu", &v );
    163                 //printf( "%llu\n", v );
    164         } // if
    165 
    166         string::size_type posn;
    167 
    168         if ( isdigit( str[last] ) ) {                                           // no suffix ?
    169                 lnthSuffix( str, type, ltype );                                 // could have length suffix
    170                 if ( type == -1 ) {                                                             // no suffix
    171                         valueToType( v, dec, type, Unsigned );
    172                 } // if
    173         } else {
    174                 // At least one digit in integer constant, so safe to backup while looking for suffix.
    175 
    176                 posn = str.find_last_of( "pP" );
    177                 if ( posn != string::npos ) { valueToType( v, dec, type, Unsigned ); ltype = 5; str.erase( posn, 1 ); goto FINI; }
    178 
    179                 posn = str.find_last_of( "zZ" );
    180                 if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; }
    181 
    182                 // 'u' can appear before or after length suffix
    183                 if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true;
    184 
    185                 posn = str.rfind( "hh" );
    186                 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
    187 
    188                 posn = str.rfind( "HH" );
    189                 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
    190 
    191                 posn = str.find_last_of( "hH" );
    192                 if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; }
    193 
    194                 posn = str.find_last_of( "nN" );
    195                 if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; }
    196 
    197                 if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; }
    198 
    199                 lnthSuffix( str, type, ltype );                                 // must be after check for "ll"
    200                 if ( type == -1 ) {                                                             // only 'u' suffix ?
    201                         valueToType( v, dec, type, Unsigned );
    202                 } // if
    203           FINI: ;
    204         } // if
    205 
    206         //if ( !( 0 <= type && type <= 6 ) ) { printf( "%s %lu %d %s\n", fred.c_str(), fred.length(), type, str.c_str() ); }
    207         assert( 0 <= type && type <= 6 );
    208 
     142                //printf( "%llu %llu\n", v, v );
     143        } // if
     144
     145        if ( v <= INT_MAX ) {                                                           // signed int
     146                size = 2;
     147        } else if ( v <= UINT_MAX && ! dec ) {                          // unsigned int
     148                size = 2;
     149                Unsigned = true;                                                                // unsigned
     150        } else if ( v <= LONG_MAX ) {                                           // signed long int
     151                size = 3;
     152        } else if ( v <= ULONG_MAX && ( ! dec || LONG_MAX == LLONG_MAX ) ) { // signed long int
     153                size = 3;
     154                Unsigned = true;                                                                // unsigned long int
     155        } else if ( v <= LLONG_MAX ) {                                          // signed long long int
     156                size = 4;
     157        } else {                                                                                        // unsigned long long int
     158                size = 4;
     159                Unsigned = true;                                                                // unsigned long long int
     160        } // if
     161
     162        // At least one digit in integer constant, so safe to backup while looking for suffix.
     163
     164        if ( checkU( str[last] ) ) {                                            // suffix 'u' ?
     165                Unsigned = true;
     166                if ( checkL( str[last - 1] ) ) {                                // suffix 'l' ?
     167                        size = 3;
     168                        if ( checkL( str[last - 2] ) ) {                        // suffix "ll" ?
     169                                size = 4;
     170                        } // if
     171                } else if ( checkH( str[last - 1] ) ) {                 // suffix 'h' ?
     172                        size = 0;
     173                        if ( checkH( str[last - 2] ) ) {                        // suffix "hh" ?
     174                                size = 1;
     175                        } // if
     176                        str.erase( last - size - 1, size + 1 );         // remove 'h'/"hh"
     177                } else {                                                                                // suffix "ln" ?
     178                        checkLNInt( str, lnth, size );
     179                } // if
     180        } else if ( checkL( str[ last ] ) ) {                           // suffix 'l' ?
     181                size = 3;
     182                if ( checkL( str[last - 1] ) ) {                                // suffix 'll' ?
     183                        size = 4;
     184                        if ( checkU( str[last - 2] ) ) {                        // suffix 'u' ?
     185                                Unsigned = true;
     186                        } // if
     187                } else if ( checkU( str[last - 1] ) ) {                 // suffix 'u' ?
     188                        Unsigned = true;
     189                } // if
     190        } else if ( checkH( str[ last ] ) ) {                           // suffix 'h' ?
     191                size = 0;
     192                if ( checkH( str[last - 1] ) ) {                                // suffix "hh" ?
     193                        size = 1;
     194                        if ( checkU( str[last - 2] ) ) {                        // suffix 'u' ?
     195                                Unsigned = true;
     196                        } // if
     197                } else if ( checkU( str[last - 1] ) ) {                 // suffix 'u' ?
     198                        Unsigned = true;
     199                } // if
     200                str.erase( last - size, size + 1 );                             // remove 'h'/"hh"
     201        } else if ( checkZ( str[last] ) ) {                                     // suffix 'z' ?
     202                lnth = 4;
     203                str.erase( last, 1 );                                                   // remove 'z'
     204        } else {                                                                                        // suffix "ln" ?
     205                checkLNInt( str, lnth, size );
     206        } // if
     207
     208        assert( 0 <= size && size < 6 );
    209209        // Constant type is correct for overload resolving.
    210         ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[Unsigned][type] ), str, v ) );
    211         if ( Unsigned && type < 2 ) {                                           // hh or h, less than int ?
     210        ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[Unsigned][size] ), str, v ) );
     211        if ( Unsigned && size < 2 ) {                                           // hh or h, less than int ?
    212212                // int i = -1uh => 65535 not -1, so cast is necessary for unsigned, which unfortunately eliminates warnings for large values.
    213                 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
    214         } else if ( ltype != -1 ) {                                                     // explicit length ?
    215                 if ( ltype == 6 ) {                                                             // int128, (int128)constant
    216                         ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
    217                 } else {                                                                                // explicit length, (length_type)constant
    218                         ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][ltype], false ), false );
    219                         if ( ltype == 5 ) {                                                     // pointer, intptr( (uintptr_t)constant )
    220                                 ret = build_func( new ExpressionNode( build_varref( new string( "intptr" ) ) ), new ExpressionNode( ret ) );
    221                         } // if
    222                 } // if
    223         } // if
    224 
    225   CLEANUP: ;
     213                ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][size] ), false );
     214        } else if ( lnth != -1 ) {                                                      // explicit length ?
     215                if ( lnth == 5 ) {                                                              // int128 ?
     216                        size = 5;
     217                        ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][size] ), false );
     218                } else {
     219                        ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][lnth], false ), false );
     220                } // if
     221        } // if
     222  CLEANUP:
     223
    226224        delete &str;                                                                            // created by lex
    227225        return ret;
     
    229227
    230228
    231 static inline void checkFnxFloat( string & str, size_t last, bool & explnth, int & type ) {
    232         string::size_type posn;
    233         // floating-point constant has minimum of 2 characters, 1. or .1, so safe to look ahead
    234         if ( str[1] == 'x' ) {                                                          // hex ?
    235                 posn = str.find_last_of( "pP" );                                // back for exponent (must have)
    236                 posn = str.find_first_of( "fF", posn + 1 );             // forward for size (fF allowed in hex constant)
    237         } else {
    238                 posn = str.find_last_of( "fF" );                                // back for size (fF not allowed)
    239         } // if
     229static inline void checkLNFloat( string & str, int & lnth, int & size ) {
     230        string::size_type posn = str.find_first_of( "lL" ), start = posn;
    240231  if ( posn == string::npos ) return;
    241         explnth = true;
     232        size = 2;                                                                                       // assume largest size
     233        lnth = 0;
    242234        posn += 1;                                                                                      // advance to size
    243235        if ( str[posn] == '3' ) {                                                       // 32
    244                 if ( str[last] != 'x' ) type = 6;
    245                 else type = 7;
     236                size = 0;
    246237        } else if ( str[posn] == '6' ) {                                        // 64
    247                 if ( str[last] != 'x' ) type = 8;
    248                 else type = 9;
    249         } else if ( str[posn] == '8' ) {                                        // 80
    250                 type = 3;
    251         } else if ( str[posn] == '1' ) {                                        // 16/128
    252                 if ( str[posn + 1] == '6' ) {                                   // 16
    253                         type = 5;
    254                 } else {                                                                                // 128
    255                         if ( str[last] != 'x' ) type = 10;
    256                         else type = 11;
    257                 } // if
     238                size = 1;
     239        } else if ( str[posn] == '8' || str[posn] == '1' ) { // 80, 128
     240                size = 2;
     241                if ( str[posn] == '1' ) posn += 1;
    258242        } else {
    259243                assertf( false, "internal error, bad floating point length %s", str.c_str() );
    260244        } // if
    261 } // checkFnxFloat
     245        posn += 1;
     246        str.erase( start, posn - start + 1 );                           // remove length suffix
     247} // checkLNFloat
    262248
    263249
    264250Expression * build_constantFloat( string & str ) {
    265         static const BasicType::Kind kind[2][12] = {
    266                 { BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::uuFloat80, BasicType::uuFloat128, BasicType::uFloat16, BasicType::uFloat32, BasicType::uFloat32x, BasicType::uFloat64, BasicType::uFloat64x, BasicType::uFloat128, BasicType::uFloat128x },
    267                 { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, (BasicType::Kind)-1, (BasicType::Kind)-1, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex },
     251        static const BasicType::Kind kind[2][3] = {
     252                { BasicType::Float, BasicType::Double, BasicType::LongDouble },
     253                { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex },
    268254        };
    269255
    270         // floating-point constant has minimum of 2 characters 1. or .1
     256        bool complx = false;                                                            // real, complex
     257        int size = 1;                                                                           // 0 => float, 1 => double, 2 => long double
     258        int lnth = -1;                                                                          // literal length
     259        // floating-point constant has minimum of 2 characters: 1. or .1
    271260        size_t last = str.length() - 1;
    272261        double v;
    273         int type;                                                                                       // 0 => float, 1 => double, 3 => long double, ...
    274         bool complx = false;                                                            // real, complex
    275         bool explnth = false;                                                           // explicit literal length
    276262
    277263        sscanf( str.c_str(), "%lg", &v );
     
    283269
    284270        if ( checkF( str[last] ) ) {                                            // float ?
    285                 type = 0;
     271                size = 0;
    286272        } else if ( checkD( str[last] ) ) {                                     // double ?
    287                 type = 1;
     273                size = 1;
    288274        } else if ( checkL( str[last] ) ) {                                     // long double ?
    289                 type = 2;
    290         } else if ( checkF80( str[last] ) ) {                           // __float80 ?
    291                 type = 3;
    292         } else if ( checkF128( str[last] ) ) {                          // __float128 ?
    293                 type = 4;
     275                size = 2;
    294276        } else {
    295                 type = 1;                                                                               // double (default if no suffix)
    296                 checkFnxFloat( str, last, explnth, type );
    297         } // if
    298 
     277                size = 1;                                                                               // double (default)
     278                checkLNFloat( str, lnth, size );
     279        } // if
    299280        if ( ! complx && checkI( str[last - 1] ) ) {            // imaginary ?
    300281                complx = true;
    301282        } // if
    302283
    303         assert( 0 <= type && type < 12 );
    304         Expression * ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[complx][type] ), str, v ) );
    305         if ( explnth ) {                                                                        // explicit length ?
    306                 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[complx][type] ), false );
     284        assert( 0 <= size && size < 3 );
     285        Expression * ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[complx][size] ), str, v ) );
     286        if ( lnth != -1 ) {                                                                     // explicit length ?
     287                ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[complx][size] ), false );
    307288        } // if
    308289
  • src/Parser/ParseNode.h

    r933f32f r6a9d4b4  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 15 14:22:39 2019
    13 // Update Count     : 874
     12// Last Modified On : Thu Nov  1 20:54:53 2018
     13// Update Count     : 854
    1414//
    1515
     
    132132        void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
    133133
     134        Expression *get_expr() const { return expr.get(); }
    134135        template<typename T>
    135136        bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); }
    136137
    137138        Expression * build() const { return const_cast<ExpressionNode *>(this)->expr.release(); }
    138 
    139         std::unique_ptr<Expression> expr;                                       // public because of lifetime implications
    140139  private:
    141140        bool extension = false;
     141        std::unique_ptr<Expression> expr;
    142142}; // ExpressionNode
    143143
     
    206206class DeclarationNode : public ParseNode {
    207207  public:
    208         // These enumerations must harmonize with their names in DeclarationNode.cc.
    209         enum BasicType { Void, Bool, Char, Int, Int128,
    210                                          Float, Double, LongDouble, uuFloat80, uuFloat128,
    211                                          uFloat16, uFloat32, uFloat32x, uFloat64, uFloat64x, uFloat128, uFloat128x, NoBasicType };
     208        // These enumerations must harmonize with their names.
     209        enum BasicType { Void, Bool, Char, Int, Float, Double, LongDouble, Int128, Float80, Float128, NoBasicType };
    212210        static const char * basicTypeNames[];
    213         enum ComplexType { Complex, NoComplexType, Imaginary }; // Imaginary unsupported => parse, but make invisible and print error message
     211        enum ComplexType { Complex, Imaginary, NoComplexType };
    214212        static const char * complexTypeNames[];
    215213        enum Signedness { Signed, Unsigned, NoSignedness };
  • src/Parser/TypeData.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Sat May 16 15:12:51 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 13 18:16:23 2019
    13 // Update Count     : 649
     12// Last Modified On : Fri Nov  2 07:54:26 2018
     13// Update Count     : 624
    1414//
    1515
     
    666666
    667667          case DeclarationNode::Float:
     668          case DeclarationNode::Float80:
     669          case DeclarationNode::Float128:
    668670          case DeclarationNode::Double:
    669671          case DeclarationNode::LongDouble:                                     // not set until below
    670           case DeclarationNode::uuFloat80:
    671           case DeclarationNode::uuFloat128:
    672           case DeclarationNode::uFloat16:
    673           case DeclarationNode::uFloat32:
    674           case DeclarationNode::uFloat32x:
    675           case DeclarationNode::uFloat64:
    676           case DeclarationNode::uFloat64x:
    677           case DeclarationNode::uFloat128:
    678           case DeclarationNode::uFloat128x:
    679                 static BasicType::Kind floattype[2][12] = {
    680                         { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, (BasicType::Kind)-1, (BasicType::Kind)-1, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex, },
    681                         { BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::uuFloat80, BasicType::uuFloat128, BasicType::uFloat16, BasicType::uFloat32, BasicType::uFloat32x, BasicType::uFloat64, BasicType::uFloat64x, BasicType::uFloat128, BasicType::uFloat128x, },
     672                static BasicType::Kind floattype[3][3] = {
     673                        { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex },
     674                        { BasicType::FloatImaginary, BasicType::DoubleImaginary, BasicType::LongDoubleImaginary },
     675                        { BasicType::Float, BasicType::Double, BasicType::LongDouble },
    682676                };
    683677
     
    692686                        genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype );
    693687                } // if
    694                 if ( td->complextype == DeclarationNode::Imaginary ) {
    695                         genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype );
    696                 } // if
    697                 if ( (td->basictype == DeclarationNode::uuFloat80 || td->basictype == DeclarationNode::uuFloat128) && td->complextype == DeclarationNode::Complex ) { // gcc unsupported
    698                         genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype );
    699                 } // if
    700688                if ( td->length == DeclarationNode::Long ) {
    701689                        const_cast<TypeData *>(td)->basictype = DeclarationNode::LongDouble;
    702690                } // if
    703691
     692                if ( td->basictype == DeclarationNode::Float80 || td->basictype == DeclarationNode::Float128 ) {
     693                        // if ( td->complextype != DeclarationNode::NoComplexType ) {
     694                        //      genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype );
     695                        // }
     696                        if ( td->basictype == DeclarationNode::Float80 ) ret = BasicType::Float80;
     697                        else ret = BasicType::Float128;
     698                        break;
     699                }
     700
    704701                ret = floattype[ td->complextype ][ td->basictype - DeclarationNode::Float ];
    705                 //printf( "XXXX %d %d %d %d\n", td->complextype, td->basictype, DeclarationNode::Float, ret );
    706702                break;
    707703
  • src/Parser/TypeData.h

    r933f32f r6a9d4b4  
    3131        struct Aggregate_t {
    3232                DeclarationNode::Aggregate kind;
    33                 const std::string * name = nullptr;
    34                 DeclarationNode * params = nullptr;
    35                 ExpressionNode * actuals = nullptr;                                             // holds actual parameters later applied to AggInst
    36                 DeclarationNode * fields = nullptr;
     33                const std::string * name;
     34                DeclarationNode * params;
     35                ExpressionNode * actuals;                                               // holds actual parameters later applied to AggInst
     36                DeclarationNode * fields;
    3737                bool body;
    3838                bool anon;
    3939
    4040                bool tagged;
    41                 const std::string * parent = nullptr;
     41                const std::string * parent;
    4242        };
    4343
    4444        struct AggInst_t {
    45                 TypeData * aggregate = nullptr;
    46                 ExpressionNode * params = nullptr;
     45                TypeData * aggregate;
     46                ExpressionNode * params;
    4747                bool hoistType;
    4848        };
    4949
    5050        struct Array_t {
    51                 ExpressionNode * dimension = nullptr;
     51                ExpressionNode * dimension;
    5252                bool isVarLen;
    5353                bool isStatic;
     
    5555
    5656        struct Enumeration_t {
    57                 const std::string * name = nullptr;
    58                 DeclarationNode * constants = nullptr;
     57                const std::string * name;
     58                DeclarationNode * constants;
    5959                bool body;
    6060                bool anon;
     
    6262
    6363        struct Function_t {
    64                 mutable DeclarationNode * params = nullptr;                             // mutables modified in buildKRFunction
    65                 mutable DeclarationNode * idList = nullptr;                             // old-style
    66                 mutable DeclarationNode * oldDeclList = nullptr;
    67                 StatementNode * body = nullptr;
    68                 ExpressionNode * withExprs = nullptr;                                           // expressions from function's with_clause
     64                mutable DeclarationNode * params;                               // mutables modified in buildKRFunction
     65                mutable DeclarationNode * idList;                               // old-style
     66                mutable DeclarationNode * oldDeclList;
     67                StatementNode * body;
     68                ExpressionNode * withExprs;                                             // expressions from function's with_clause
    6969        };
    7070
    7171        struct Symbolic_t {
    72                 const std::string * name = nullptr;
     72                const std::string * name;
    7373                bool isTypedef;                                                                 // false => TYPEGENname, true => TYPEDEFname
    74                 DeclarationNode * params = nullptr;
    75                 ExpressionNode * actuals = nullptr;
    76                 DeclarationNode * assertions = nullptr;
     74                DeclarationNode * params;
     75                ExpressionNode * actuals;
     76                DeclarationNode * assertions;
    7777        };
    7878
    7979        struct Qualified_t {                                                            // qualified type S.T
    80                 TypeData * parent = nullptr;
    81                 TypeData * child = nullptr;
     80                TypeData * parent;
     81                TypeData * child;
    8282        };
    8383
     
    9393
    9494        Type::Qualifiers qualifiers;
    95         DeclarationNode * forall = nullptr;
     95        DeclarationNode * forall;
    9696
    9797        Aggregate_t aggregate;
     
    102102        Symbolic_t symbolic;
    103103        Qualified_t qualified;
    104         DeclarationNode * tuple = nullptr;
    105         ExpressionNode * typeexpr = nullptr;
     104        DeclarationNode * tuple;
     105        ExpressionNode * typeexpr;
    106106
    107107        TypeData( Kind k = Unknown );
  • src/Parser/lex.ll

    r933f32f r6a9d4b4  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Wed May 15 21:25:27 2019
    13  * Update Count     : 708
     12 * Last Modified On : Thu Nov  1 20:57:35 2018
     13 * Update Count     : 687
    1414 */
    1515
     
    3939using namespace std;
    4040
    41 #include "config.h"                                                                             // configure info
    4241#include "ParseNode.h"
    4342#include "TypedefTable.h"
     
    6059#define IDENTIFIER_RETURN()     RETURN_VAL( typedefTable.isKind( yytext ) )
    6160#define ATTRIBUTE_RETURN()      RETURN_VAL( ATTR_IDENTIFIER )
    62 
    63 #ifdef HAVE_KEYWORDS_FLOATXX                                                            // GCC >= 7 => keyword, otherwise typedef
    64 #define FLOATXX(v) KEYWORD_RETURN(v);
    65 #else
    66 #define FLOATXX(v) IDENTIFIER_RETURN();
    67 #endif // HAVE_KEYWORDS_FLOATXX
    6861
    6962void rm_underscore() {
     
    9992hex_quad {hex}("_"?{hex}){3}
    10093size_opt (8|16|32|64|128)?
    101                                 // CFA: explicit l8/l16/l32/l64/l128, char 'hh', short 'h', int 'n'
    102 length ("ll"|"LL"|[lL]{size_opt})|("hh"|"HH"|[hHnN])
    103                                 // CFA: size_t 'z', pointer 'p', which define a sign and length
    104 integer_suffix_opt ("_"?(([uU]({length}?[iI]?)|([iI]{length}))|([iI]({length}?[uU]?)|([uU]{length}))|({length}([iI]?[uU]?)|([uU][iI]))|[zZ]|[pP]))?
     94length ("ll"|"LL"|[lL]{size_opt})|("hh"|"HH"|[hH])
     95integer_suffix_opt ("_"?(([uU]({length}?[iI]?)|([iI]{length}))|([iI]({length}?[uU]?)|([uU]{length}))|({length}([iI]?[uU]?)|([uU][iI]))|[zZ]))?
    10596
    10697octal_digits ({octal})|({octal}({octal}|"_")*{octal})
     
    121112                                // GCC: D (double) and iI (imaginary) suffixes, and DL (long double)
    122113exponent "_"?[eE]"_"?[+-]?{decimal_digits}
    123 floating_size 16|32|32x|64|64x|80|128|128x
    124 floating_length ([fFdDlLwWqQ]|[fF]{floating_size})
     114floating_size 32|64|80|128
     115floating_length ([fFdDlL]|[lL]{floating_size})
    125116floating_suffix ({floating_length}?[iI]?)|([iI]{floating_length})
    126117floating_suffix_opt ("_"?({floating_suffix}|"DL"))?
     
    226217char                    { KEYWORD_RETURN(CHAR); }
    227218choose                  { KEYWORD_RETURN(CHOOSE); }                             // CFA
    228 coerce                  { KEYWORD_RETURN(COERCE); }                             // CFA
    229219_Complex                { KEYWORD_RETURN(COMPLEX); }                    // C99
    230220__complex               { KEYWORD_RETURN(COMPLEX); }                    // GCC
     
    250240finally                 { KEYWORD_RETURN(FINALLY); }                    // CFA
    251241float                   { KEYWORD_RETURN(FLOAT); }
    252 __float80               { KEYWORD_RETURN(uuFLOAT80); }                  // GCC
    253 float80                 { KEYWORD_RETURN(uuFLOAT80); }                  // GCC
    254 __float128              { KEYWORD_RETURN(uuFLOAT128); }                 // GCC
    255 float128                { KEYWORD_RETURN(uuFLOAT128); }                 // GCC
    256 _Float16                { FLOATXX(uFLOAT16); }                                  // GCC
    257 _Float32                { FLOATXX(uFLOAT32); }                                  // GCC
    258 _Float32x               { FLOATXX(uFLOAT32X); }                                 // GCC
    259 _Float64                { FLOATXX(uFLOAT64); }                                  // GCC
    260 _Float64x               { FLOATXX(uFLOAT64X); }                                 // GCC
    261 _Float128               { FLOATXX(uFLOAT128); }                                 // GCC
    262 _Float128x              { FLOATXX(uFLOAT128); }                                 // GCC
     242_Float32                { KEYWORD_RETURN(FLOAT); }                              // GCC
     243_Float32x               { KEYWORD_RETURN(FLOAT); }                              // GCC
     244_Float64                { KEYWORD_RETURN(DOUBLE); }                             // GCC
     245_Float64x               { KEYWORD_RETURN(DOUBLE); }                             // GCC
     246__float80               { KEYWORD_RETURN(FLOAT80); }                    // GCC
     247float80                 { KEYWORD_RETURN(FLOAT80); }                    // GCC
     248_Float128               { KEYWORD_RETURN(FLOAT128); }                   // GCC
     249_Float128x              { KEYWORD_RETURN(FLOAT128); }                   // GCC
     250__float128              { KEYWORD_RETURN(FLOAT128); }                   // GCC
     251float128                { KEYWORD_RETURN(FLOAT128); }                   // GCC
    263252for                             { KEYWORD_RETURN(FOR); }
    264253forall                  { KEYWORD_RETURN(FORALL); }                             // CFA
    265254fortran                 { KEYWORD_RETURN(FORTRAN); }
    266255ftype                   { KEYWORD_RETURN(FTYPE); }                              // CFA
    267 generator               { KEYWORD_RETURN(GENERATOR); }                  // CFA
    268256_Generic                { KEYWORD_RETURN(GENERIC); }                    // C11
    269257goto                    { KEYWORD_RETURN(GOTO); }
  • src/Parser/module.mk

    r933f32f r6a9d4b4  
    3131       Parser/parserutility.cc
    3232
    33 SRCDEMANGLE += \
    34         Parser/LinkageSpec.cc
    35 
    36 
    3733MOSTLYCLEANFILES += Parser/lex.cc Parser/parser.cc Parser/parser.hh Parser/parser.output
  • src/Parser/parser.yy

    r933f32f r6a9d4b4  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May 15 21:25:27 2019
    13 // Update Count     : 4296
     12// Last Modified On : Thu Nov  8 18:08:23 2018
     13// Update Count     : 4052
    1414//
    1515
     
    9999        // distribute declaration_specifier across all declared variables, e.g., static, const, __attribute__.
    100100        DeclarationNode * cur = declList, * cl = (new DeclarationNode)->addType( specifier );
    101         for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {
     101        //cur->addType( specifier );
     102        for ( cur = dynamic_cast< DeclarationNode * >( cur->get_next() ); cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
    102103                cl->cloneBaseType( cur );
    103104        } // for
    104105        declList->addType( cl );
     106//      delete cl;
    105107        return declList;
    106108} // distAttr
     
    173175DeclarationNode * fieldDecl( DeclarationNode * typeSpec, DeclarationNode * fieldList ) {
    174176        if ( ! fieldList ) {                                                            // field declarator ?
    175                 if ( ! ( typeSpec->type && (typeSpec->type->kind == TypeData::Aggregate || typeSpec->type->kind == TypeData::Enum) ) ) {
     177                if ( ! ( typeSpec->type && typeSpec->type->kind == TypeData::Aggregate ) ) {
    176178                        stringstream ss;
    177179                        typeSpec->type->print( ss );
     
    185187
    186188ForCtrl * forCtrl( ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    187         ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->expr.get());
     189        ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->get_expr());
    188190        if ( constant && (constant->get_constant()->get_value() == "0" || constant->get_constant()->get_value() == "1") ) {
    189191        type = new ExpressionNode( new CastExpr( maybeMoveBuild< Expression >(type), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ) );
     
    191193        return new ForCtrl(
    192194                distAttr( DeclarationNode::newTypeof( type, true ), DeclarationNode::newName( index )->addInitializer( new InitializerNode( start ) ) ),
    193                 // NULL comp/inc => leave blank
    194                 comp ? new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index ) ) ), comp ) ) : 0,
    195                 inc ? new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto
    196                                                         OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index ) ) ), inc ) ) : 0 );
     195                new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index ) ) ), comp ) ),
     196                new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto
     197                                                                                          OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index ) ) ), inc ) ) );
    197198} // forCtrl
    198199
    199200ForCtrl * forCtrl( ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    200         if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->expr.get()) ) {
     201        if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->get_expr()) ) {
    201202                return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
    202         } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index->expr.get()) ) {
    203                 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(commaExpr->arg1 ) ) {
    204                         return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
    205                 } else {
    206                         SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr;
    207                 } // if
    208203        } else {
    209204                SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr;
     
    265260%token RESTRICT                                                                                 // C99
    266261%token ATOMIC                                                                                   // C11
    267 %token FORALL MUTEX VIRTUAL COERCE                                              // CFA
     262%token FORALL MUTEX VIRTUAL                                                             // CFA
    268263%token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED
    269264%token BOOL COMPLEX IMAGINARY                                                   // C99
    270 %token INT128 uuFLOAT80 uuFLOAT128                                              // GCC
    271 %token uFLOAT16 uFLOAT32 uFLOAT32X uFLOAT64 uFLOAT64X uFLOAT128 // GCC
     265%token INT128 FLOAT80 FLOAT128                                                  // GCC
    272266%token ZERO_T ONE_T                                                                             // CFA
    273267%token VALIST                                                                                   // GCC
     
    275269%token ENUM STRUCT UNION
    276270%token EXCEPTION                                                                                // CFA
    277 %token GENERATOR COROUTINE MONITOR THREAD                               // CFA
     271%token COROUTINE MONITOR THREAD                                                 // CFA
    278272%token OTYPE FTYPE DTYPE TTYPE TRAIT                                    // CFA
    279273%token SIZEOF OFFSETOF
     
    330324%type<en> argument_expression_list              argument_expression                     default_initialize_opt
    331325%type<ifctl> if_control_expression
    332 %type<fctl> for_control_expression              for_control_expression_list
     326%type<fctl> for_control_expression
    333327%type<compop> inclexcl
    334328%type<en> subrange
    335329%type<decl> asm_name_opt
    336 %type<en> asm_operands_opt                              asm_operands_list                       asm_operand
     330%type<en> asm_operands_opt asm_operands_list asm_operand
    337331%type<label> label_list
    338332%type<en> asm_clobbers_list_opt
    339333%type<flag> asm_volatile_opt
    340334%type<en> handler_predicate_opt
    341 %type<genexpr> generic_association              generic_assoc_list
     335%type<genexpr> generic_association generic_assoc_list
    342336
    343337// statements
     
    677671        // empty
    678672                { $$ = nullptr; }
    679         | '@'                                                                                           // CFA, default parameter
     673        | '?'                                                                                           // CFA, default parameter
    680674                { SemanticError( yylloc, "Default parameter for argument is currently unimplemented." ); $$ = nullptr; }
    681675                // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); }
     
    795789        | '(' type_no_function ')' cast_expression
    796790                { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
    797                 // keyword cast cannot be grouped because of reduction in aggregate_key
    798         | '(' GENERATOR '&' ')' cast_expression                         // CFA
    799                 { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }
    800791        | '(' COROUTINE '&' ')' cast_expression                         // CFA
    801792                { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }
     
    809800        | '(' VIRTUAL type_no_function ')' cast_expression      // CFA
    810801                { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild< Expression >( $5 ), maybeMoveBuildType( $3 ) ) ); }
    811         | '(' RETURN type_no_function ')' cast_expression       // CFA
    812                 { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; }
    813         | '(' COERCE type_no_function ')' cast_expression       // CFA
    814                 { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; }
    815         | '(' qualifier_cast_list ')' cast_expression           // CFA
    816                 { SemanticError( yylloc, "Qualifier cast is currently unimplemented." ); $$ = nullptr; }
    817802//      | '(' type_no_function ')' tuple
    818803//              { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
    819         ;
    820 
    821 qualifier_cast_list:
    822         cast_modifier type_qualifier_name
    823         | cast_modifier MUTEX
    824         | qualifier_cast_list cast_modifier type_qualifier_name
    825         | qualifier_cast_list cast_modifier MUTEX
    826         ;
    827 
    828 cast_modifier:
    829         '-'
    830         | '+'
    831804        ;
    832805
     
    1011984                // labels cannot be identifiers 0 or 1 or ATTR_IDENTIFIER
    1012985        identifier_or_type_name ':' attribute_list_opt statement
    1013                 { $$ = $4->add_label( $1, $3 ); }
     986                {
     987                        $$ = $4->add_label( $1, $3 );
     988                }
    1014989        ;
    1015990
     
    10271002        statement_decl
    10281003        | statement_decl_list statement_decl
    1029                 { assert( $1 ); $1->set_last( $2 ); $$ = $1; }
     1004                { if ( $1 != 0 ) { $1->set_last( $2 ); $$ = $1; } }
    10301005        ;
    10311006
     
    10341009                { $$ = new StatementNode( $1 ); }
    10351010        | EXTENSION declaration                                                         // GCC
    1036                 { distExt( $2 ); $$ = new StatementNode( $2 ); }
     1011                {
     1012                        distExt( $2 );
     1013                        $$ = new StatementNode( $2 );
     1014                }
    10371015        | function_definition
    10381016                { $$ = new StatementNode( $1 ); }
    10391017        | EXTENSION function_definition                                         // GCC
    1040                 { distExt( $2 ); $$ = new StatementNode( $2 ); }
     1018                {
     1019                        distExt( $2 );
     1020                        $$ = new StatementNode( $2 );
     1021                }
    10411022        | statement
    10421023        ;
     
    10451026        statement
    10461027        | statement_list_nodecl statement
    1047                 { assert( $1 ); $1->set_last( $2 ); $$ = $1; }
     1028                { if ( $1 != 0 ) { $1->set_last( $2 ); $$ = $1; } }
    10481029        ;
    10491030
     
    11571138        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    11581139                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2 ) ); }
    1159         | FOR '(' push for_control_expression_list ')' statement pop
     1140        | FOR '(' push for_control_expression ')' statement pop
    11601141                { $$ = new StatementNode( build_for( $4, $6 ) ); }
    11611142        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
     
    11631144        ;
    11641145
    1165 for_control_expression_list:
    1166         for_control_expression
    1167         | for_control_expression_list ':' for_control_expression
    1168                 // ForCtrl + ForCtrl:
    1169                 //    init + init => multiple declaration statements that are hoisted
    1170                 //    condition + condition => (expression) && (expression)
    1171                 //    change + change => (expression), (expression)
    1172                 {
    1173                         $1->init->set_last( $3->init );
    1174                         if ( $1->condition ) {
    1175                                 if ( $3->condition ) {
    1176                                         $1->condition->expr.reset( new LogicalExpr( $1->condition->expr.release(), $3->condition->expr.release(), true ) );
    1177                                 } // if
    1178                         } else $1->condition = $3->condition;
    1179                         if ( $1->change ) {
    1180                                 if ( $3->change ) {
    1181                                         $1->change->expr.reset( new CommaExpr( $1->change->expr.release(), $3->change->expr.release() ) );
    1182                                 } // if
    1183                         } else $1->change = $3->change;
    1184                         $$ = $1;
    1185                 }
    1186         ;
    1187 
    11881146for_control_expression:
    1189         ';' comma_expression_opt ';' comma_expression_opt
    1190                 { $$ = new ForCtrl( (ExpressionNode * )nullptr, $2, $4 ); }
    1191         | comma_expression ';' comma_expression_opt ';' comma_expression_opt
    1192                 { $$ = new ForCtrl( $1, $3, $5 ); }
    1193         | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';'
    1194                 { $$ = new ForCtrl( $1, $2, $4 ); }
    1195 
    1196         | comma_expression                                                                      // CFA
     1147        comma_expression                                                                        // CFA
    11971148                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11981149                                                OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1199         | comma_expression inclexcl comma_expression            // CFA
     1150        | constant_expression inclexcl constant_expression      // CFA
    12001151                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1201         | comma_expression inclexcl comma_expression '~' comma_expression // CFA
     1152        | constant_expression inclexcl constant_expression '~' constant_expression // CFA
    12021153                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, $5 ); }
    12031154        | comma_expression ';' comma_expression                         // CFA
    12041155                { $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    12051156                                                OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1206         | comma_expression ';' comma_expression inclexcl comma_expression // CFA
     1157        | comma_expression ';' constant_expression inclexcl constant_expression // CFA
    12071158                { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1208         | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA
     1159        | comma_expression ';' constant_expression inclexcl constant_expression '~' constant_expression // CFA
    12091160                { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); }
    1210 
    1211                 // There is a S/R conflicit if ~ and -~ are factored out.
    1212         | comma_expression ';' comma_expression '~' '@'         // CFA
    1213                 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1214         | comma_expression ';' comma_expression ErangeDown '@' // CFA
    1215                 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::GThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1216         | comma_expression ';' comma_expression '~' '@' '~' comma_expression // CFA
    1217                 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, $7 ); }
    1218         | comma_expression ';' comma_expression ErangeDown '@' '~' comma_expression // CFA
    1219                 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::GThan, nullptr, $7 ); }
    1220         | comma_expression ';' comma_expression '~' '@' '~' '@' // CFA
    1221                 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, nullptr ); }
     1161        | comma_expression ';' comma_expression_opt ';' comma_expression_opt
     1162                { $$ = new ForCtrl( $1, $3, $5 ); }
     1163        | ';' comma_expression_opt ';' comma_expression_opt
     1164                { $$ = new ForCtrl( (ExpressionNode * )nullptr, $2, $4 ); }
     1165        | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';'
     1166                { $$ = new ForCtrl( $1, $2, $4 ); }
    12221167        ;
    12231168
     
    18261771        | FLOAT
    18271772                { $$ = DeclarationNode::newBasicType( DeclarationNode::Float ); }
     1773        | FLOAT80
     1774                { $$ = DeclarationNode::newBasicType( DeclarationNode::Float80 ); }
     1775        | FLOAT128
     1776                { $$ = DeclarationNode::newBasicType( DeclarationNode::Float128 ); }
    18281777        | DOUBLE
    18291778                { $$ = DeclarationNode::newBasicType( DeclarationNode::Double ); }
    1830         | uuFLOAT80
    1831                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat80 ); }
    1832         | uuFLOAT128
    1833                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat128 ); }
    1834         | uFLOAT16
    1835                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat16 ); }
    1836         | uFLOAT32
    1837                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32 ); }
    1838         | uFLOAT32X
    1839                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32x ); }
    1840         | uFLOAT64
    1841                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64 ); }
    1842         | uFLOAT64X
    1843                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64x ); }
    1844         | uFLOAT128
    1845                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat128 ); }
    18461779        | COMPLEX                                                                                       // C99
    18471780                { $$ = DeclarationNode::newComplexType( DeclarationNode::Complex ); }
     
    20631996        | EXCEPTION
    20641997                { yyy = true; $$ = DeclarationNode::Exception; }
    2065         | GENERATOR
    2066                 { yyy = true; $$ = DeclarationNode::Coroutine; }
    20671998        | COROUTINE
    20681999                { yyy = true; $$ = DeclarationNode::Coroutine; }
  • src/ResolvExpr/AlternativeFinder.cc

    r933f32f r6a9d4b4  
    258258                        // - necessary pre-requisite to pruning
    259259                        AltList candidates;
    260                         std::list<std::string> errors;
    261260                        for ( unsigned i = 0; i < alternatives.size(); ++i ) {
    262                                 resolveAssertions( alternatives[i], indexer, candidates, errors );
     261                                resolveAssertions( alternatives[i], indexer, candidates );
    263262                        }
    264263                        // fail early if none such
    265264                        if ( mode.failFast && candidates.empty() ) {
    266265                                std::ostringstream stream;
    267                                 stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    268                                 //        << "Alternatives with failing assertions are:\n";
    269                                 // printAlts( alternatives, stream, 1 );
    270                                 for ( const auto& err : errors ) {
    271                                         stream << err;
    272                                 }
     266                                stream << "No resolvable alternatives for expression " << expr << "\n"
     267                                       << "Alternatives with failing assertions are:\n";
     268                                printAlts( alternatives, stream, 1 );
    273269                                SemanticError( expr->location, stream.str() );
    274270                        }
  • src/ResolvExpr/CommonType.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Sun May 17 06:59:27 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 14 17:10:10 2019
    13 // Update Count     : 24
     12// Last Modified On : Mon Sep 25 15:18:17 2017
     13// Update Count     : 9
    1414//
    1515
     
    176176        }
    177177
    178         // GENERATED START, DO NOT EDIT
    179         // GENERATED BY BasicTypes-gen.cc
    180         #define BT BasicType::
    181         static const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
    182                 /*                                      B                       C                      SC                      UC                      SI                     SUI
    183                                                         I                      UI                      LI                     LUI                     LLI                    LLUI
    184                                                        IB                     UIB                     _FH                     _FH                      _F                     _FC
    185                                                         F                      FC                     _FX                    _FXC                      FD                    _FDC
    186                                                         D                      DC                    F80X                   _FDXC                     F80                     _FB
    187                                                     _FLDC                      FB                      LD                     LDC                    _FBX                  _FLDXC
    188                                  */
    189                                   {
    190                 /*     B*/                BT Bool,                BT Char,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
    191                                              BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    192                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    193                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    194                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    195                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    196                                   },
    197                                   {
    198                 /*     C*/                BT Char,                BT Char,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
    199                                              BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    200                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    201                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    202                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    203                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    204                                   },
    205                                   {
    206                 /*    SC*/          BT SignedChar,          BT SignedChar,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
    207                                              BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    208                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    209                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    210                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    211                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    212                                   },
    213                                   {
    214                 /*    UC*/        BT UnsignedChar,        BT UnsignedChar,        BT UnsignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
    215                                              BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    216                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    217                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    218                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    219                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    220                                   },
    221                                   {
    222                 /*    SI*/      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,    BT ShortUnsignedInt,
    223                                              BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    224                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    225                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    226                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    227                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    228                                   },
    229                                   {
    230                 /*   SUI*/    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,
    231                                              BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    232                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    233                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    234                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    235                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    236                                   },
    237                                   {
    238                 /*     I*/           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,
    239                                              BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    240                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    241                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    242                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    243                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    244                                   },
    245                                   {
    246                 /*    UI*/         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,
    247                                            BT UnsignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    248                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    249                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    250                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    251                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    252                                   },
    253                                   {
    254                 /*    LI*/       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,
    255                                          BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    256                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    257                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    258                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    259                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    260                                   },
    261                                   {
    262                 /*   LUI*/     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,
    263                                        BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    264                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    265                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    266                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    267                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    268                                   },
    269                                   {
    270                 /*   LLI*/   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,
    271                                      BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
    272                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    273                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    274                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    275                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    276                                   },
    277                                   {
    278                 /*  LLUI*/ BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt,
    279                                    BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt,
    280                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    281                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    282                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    283                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    284                                   },
    285                                   {
    286                 /*    IB*/        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,
    287                                           BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,
    288                                           BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    289                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    290                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    291                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    292                                   },
    293                                   {
    294                 /*   UIB*/      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,
    295                                         BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,
    296                                         BT UnsignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    297                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    298                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    299                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    300                                   },
    301                                   {
    302                 /*   _FH*/            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,
    303                                               BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,
    304                                               BT uFloat16,            BT uFloat16,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
    305                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    306                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    307                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    308                                   },
    309                                   {
    310                 /*   _FH*/     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,
    311                                        BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,
    312                                        BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat32Complex,     BT uFloat32Complex,
    313                                           BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
    314                                          BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
    315                                       BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    316                                   },
    317                                   {
    318                 /*    _F*/            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,
    319                                               BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,
    320                                               BT uFloat32,            BT uFloat32,            BT uFloat32,     BT uFloat32Complex,            BT uFloat32,     BT uFloat32Complex,
    321                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    322                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    323                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    324                                   },
    325                                   {
    326                 /*   _FC*/     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
    327                                        BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
    328                                        BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
    329                                           BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
    330                                          BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
    331                                       BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    332                                   },
    333                                   {
    334                 /*     F*/               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,
    335                                                  BT Float,               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,
    336                                                  BT Float,               BT Float,               BT Float,        BT FloatComplex,               BT Float,        BT FloatComplex,
    337                                                  BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    338                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    339                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    340                                   },
    341                                   {
    342                 /*    FC*/        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
    343                                           BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
    344                                           BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
    345                                           BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
    346                                          BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
    347                                       BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    348                                   },
    349                                   {
    350                 /*   _FX*/           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,
    351                                              BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,
    352                                              BT uFloat32x,           BT uFloat32x,           BT uFloat32x,    BT uFloat32xComplex,           BT uFloat32x,    BT uFloat32xComplex,
    353                                              BT uFloat32x,    BT uFloat32xComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
    354                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    355                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    356                                   },
    357                                   {
    358                 /*  _FXC*/    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
    359                                       BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
    360                                       BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
    361                                       BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
    362                                          BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
    363                                       BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    364                                   },
    365                                   {
    366                 /*    FD*/            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,
    367                                               BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,
    368                                               BT uFloat64,            BT uFloat64,            BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,
    369                                               BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,
    370                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    371                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    372                                   },
    373                                   {
    374                 /*  _FDC*/     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
    375                                        BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
    376                                        BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
    377                                        BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
    378                                          BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
    379                                       BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    380                                   },
    381                                   {
    382                 /*     D*/              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,
    383                                                 BT Double,              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,
    384                                                 BT Double,              BT Double,              BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,
    385                                                 BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,
    386                                                 BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    387                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    388                                   },
    389                                   {
    390                 /*    DC*/       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
    391                                          BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
    392                                          BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
    393                                          BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
    394                                          BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
    395                                       BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    396                                   },
    397                                   {
    398                 /*  F80X*/           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,
    399                                              BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,
    400                                              BT uFloat64x,           BT uFloat64x,           BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,
    401                                              BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,
    402                                              BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    403                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    404                                   },
    405                                   {
    406                 /* _FDXC*/    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
    407                                       BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
    408                                       BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
    409                                       BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
    410                                       BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
    411                                       BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    412                                   },
    413                                   {
    414                 /*   F80*/           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,
    415                                              BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,
    416                                              BT uuFloat80,           BT uuFloat80,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,
    417                                              BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,
    418                                              BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
    419                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    420                                   },
    421                                   {
    422                 /*   _FB*/           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,
    423                                              BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,
    424                                              BT uFloat128,           BT uFloat128,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,
    425                                              BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,
    426                                              BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,           BT uFloat128,
    427                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    428                                   },
    429                                   {
    430                 /* _FLDC*/    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
    431                                       BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
    432                                       BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
    433                                       BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
    434                                       BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
    435                                       BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    436                                   },
    437                                   {
    438                 /*    FB*/          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,
    439                                             BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,
    440                                             BT uuFloat128,          BT uuFloat128,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,
    441                                             BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,
    442                                             BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,          BT uuFloat128,
    443                                       BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    444                                   },
    445                                   {
    446                 /*    LD*/          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,
    447                                             BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,
    448                                             BT LongDouble,          BT LongDouble,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,
    449                                             BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,
    450                                             BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,          BT LongDouble,
    451                                      BT LongDoubleComplex,          BT LongDouble,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
    452                                   },
    453                                   {
    454                 /*   LDC*/   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
    455                                      BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
    456                                      BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
    457                                      BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
    458                                      BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
    459                                      BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    460                                   },
    461                                   {
    462                 /*  _FBX*/          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,
    463                                             BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,
    464                                             BT uFloat128x,          BT uFloat128x,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
    465                                             BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
    466                                             BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,          BT uFloat128x,
    467                                      BT uFloat128xComplex,          BT uFloat128x,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
    468                                   },
    469                                   {
    470                 /*_FLDXC*/   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    471                                      BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    472                                      BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    473                                      BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    474                                      BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    475                                      BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
    476                                   },
    477         }; // commonTypes
    478         #undef BT
    479         // GENERATED END
     178        static const BasicType::Kind combinedType[][ BasicType::NUMBER_OF_BASIC_TYPES ] =
     179        {
     180/*              Bool            Char    SignedChar      UnsignedChar    ShortSignedInt  ShortUnsignedInt        SignedInt       UnsignedInt     LongSignedInt   LongUnsignedInt LongLongSignedInt       LongLongUnsignedInt     Float   Double  LongDouble      FloatComplex    DoubleComplex   LongDoubleComplex       FloatImaginary  DoubleImaginary LongDoubleImaginary   SignedInt128   UnsignedInt128   Float80   Float128 */
     181                /* Bool */      { BasicType::Bool,              BasicType::Char,        BasicType::SignedChar,  BasicType::UnsignedChar,        BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     182                /* Char */      { BasicType::Char,              BasicType::Char,        BasicType::UnsignedChar,        BasicType::UnsignedChar,        BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     183                /* SignedChar */        { BasicType::SignedChar,        BasicType::UnsignedChar,        BasicType::SignedChar,  BasicType::UnsignedChar,        BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     184                /* UnsignedChar */      { BasicType::UnsignedChar,      BasicType::UnsignedChar,        BasicType::UnsignedChar,        BasicType::UnsignedChar,        BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     185                /* ShortSignedInt */    { BasicType::ShortSignedInt,    BasicType::ShortSignedInt,      BasicType::ShortSignedInt,      BasicType::ShortSignedInt,      BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     186                /* ShortUnsignedInt */  { BasicType::ShortUnsignedInt,  BasicType::ShortUnsignedInt,    BasicType::ShortUnsignedInt,    BasicType::ShortUnsignedInt,    BasicType::ShortUnsignedInt,    BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     187                /* SignedInt */         { BasicType::SignedInt,         BasicType::SignedInt,   BasicType::SignedInt,   BasicType::SignedInt,   BasicType::SignedInt,   BasicType::SignedInt,   BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     188                /* UnsignedInt */       { BasicType::UnsignedInt,               BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     189                /* LongSignedInt */     { BasicType::LongSignedInt,             BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     190                /* LongUnsignedInt */   { BasicType::LongUnsignedInt,   BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     191                /* LongLongSignedInt */         { BasicType::LongLongSignedInt, BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     192                /* LongLongUnsignedInt */       { BasicType::LongLongUnsignedInt,       BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
     193                /* Float */     { BasicType::Float,     BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::Float,       BasicType::Float, BasicType::Float80, BasicType::Float128 },
     194                /* Double */    { BasicType::Double,    BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::LongDouble,  BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::Double,      BasicType::Double, BasicType::Float80, BasicType::Float128 },
     195                /* LongDouble */        { BasicType::LongDouble,                BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDouble,  BasicType::LongDouble, BasicType::BasicType::LongDouble, BasicType::Float128 },
     196                /* FloatComplex */      { BasicType::FloatComplex,      BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::FloatComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, },
     197                /* DoubleComplex */     { BasicType::DoubleComplex,     BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex },
     198                /* LongDoubleComplex */         { BasicType::LongDoubleComplex, BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, },
     199                /* FloatImaginary */    { BasicType::FloatComplex,      BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatImaginary,      BasicType::DoubleImaginary,     BasicType::LongDoubleImaginary, BasicType::FloatImaginary,      BasicType::FloatImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, },
     200                /* DoubleImaginary */   { BasicType::DoubleComplex,     BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleImaginary,     BasicType::DoubleImaginary,     BasicType::LongDoubleImaginary, BasicType::DoubleImaginary,     BasicType::DoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, },
     201                /* LongDoubleImaginary */       { BasicType::LongDoubleComplex, BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, },
     202                /* SignedInt128 */      { BasicType::SignedInt128,      BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128, },
     203                /* UnsignedInt128 */    { BasicType::UnsignedInt128,    BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::UnsignedInt128,      BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128, },
     204                /* Float80 */   { BasicType::Float80,   BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::LongDouble,  BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::Float80,     BasicType::Float80, BasicType::Float80, BasicType::Float128 },
     205                /* Float128 */  { BasicType::Float128,  BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::Float128,    BasicType::Float128, BasicType::Float128, BasicType::Float128 },
     206        };
    480207        static_assert(
    481                 sizeof(commonTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
     208                sizeof(combinedType)/sizeof(combinedType[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
    482209                "Each basic type kind should have a corresponding row in the combined type matrix"
    483210        );
     
    491218        void CommonType::postvisit( BasicType *basicType ) {
    492219                if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
    493                         BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ otherBasic->get_kind() ];
     220                        BasicType::Kind newType = combinedType[ basicType->get_kind() ][ otherBasic->get_kind() ];
    494221                        if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= otherBasic->get_qualifiers() ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->get_qualifiers() <= otherBasic->get_qualifiers() ) || widenSecond ) ) {
    495222                                result = new BasicType( basicType->get_qualifiers() | otherBasic->get_qualifiers(), newType );
     
    497224                } else if ( dynamic_cast< EnumInstType * > ( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) {
    498225                        // use signed int in lieu of the enum/zero/one type
    499                         BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];
     226                        BasicType::Kind newType = combinedType[ basicType->get_kind() ][ BasicType::SignedInt ];
    500227                        if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= type2->get_qualifiers() ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->get_qualifiers() <= type2->get_qualifiers() ) || widenSecond ) ) {
    501228                                result = new BasicType( basicType->get_qualifiers() | type2->get_qualifiers(), newType );
  • src/ResolvExpr/ConversionCost.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Sun May 17 07:06:19 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon May  6 14:18:22 2019
    13 // Update Count     : 25
     12// Last Modified On : Mon Sep 25 15:43:34 2017
     13// Update Count     : 10
    1414//
    1515
     
    2828
    2929namespace ResolvExpr {
    30 #if 0
    31         const Cost Cost::zero =      Cost{  0,  0,  0,  0,  0,  0,  0 };
    32         const Cost Cost::infinity =  Cost{ -1, -1, -1, -1, -1,  1, -1 };
    33         const Cost Cost::unsafe =    Cost{  1,  0,  0,  0,  0,  0,  0 };
    34         const Cost Cost::poly =      Cost{  0,  1,  0,  0,  0,  0,  0 };
    35         const Cost Cost::safe =      Cost{  0,  0,  1,  0,  0,  0,  0 };
    36         const Cost Cost::sign =      Cost{  0,  0,  0,  1,  0,  0,  0 };
    37         const Cost Cost::var =       Cost{  0,  0,  0,  0,  1,  0,  0 };
    38         const Cost Cost::spec =      Cost{  0,  0,  0,  0,  0, -1,  0 };
    39         const Cost Cost::reference = Cost{  0,  0,  0,  0,  0,  0,  1 };
    40 #endif
     30        const Cost Cost::zero =      Cost{  0,  0,  0,  0,  0,  0 };
     31        const Cost Cost::infinity =  Cost{ -1, -1, -1, -1,  1, -1 };
     32        const Cost Cost::unsafe =    Cost{  1,  0,  0,  0,  0,  0 };
     33        const Cost Cost::poly =      Cost{  0,  1,  0,  0,  0,  0 };
     34        const Cost Cost::safe =      Cost{  0,  0,  1,  0,  0,  0 };
     35        const Cost Cost::var =       Cost{  0,  0,  0,  1,  0,  0 };
     36        const Cost Cost::spec =      Cost{  0,  0,  0,  0, -1,  0 };
     37        const Cost Cost::reference = Cost{  0,  0,  0,  0,  0,  1 };
    4138
    4239#if 0
     
    4542#define PRINT(x)
    4643#endif
    47 
    4844        Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    4945                if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
     
    183179        }
    184180
    185         // GENERATED START, DO NOT EDIT
    186         // GENERATED BY BasicTypes-gen.cc
    187         /* EXTENDED INTEGRAL RANK HIERARCHY (root to leaves)
    188                                  _Bool
    189         char                signed char         unsigned char       
    190                   signed short int         unsigned short int       
    191                   signed int               unsigned int             
    192                   signed long int          unsigned long int       
    193                   signed long long int     unsigned long long int   
    194                   __int128                 unsigned __int128       
    195                   _Float16                 _Float16 _Complex       
    196                   _Float32                 _Float32 _Complex       
    197                   float                    float _Complex           
    198                   _Float32x                _Float32x _Complex       
    199                   _Float64                 _Float64 _Complex       
    200                   double                   double _Complex         
    201                   _Float64x                _Float64x _Complex       
    202                              __float80
    203                   _Float128                _Float128 _Complex       
    204                             __float128
    205                   long double              long double _Complex     
    206                   _Float128x               _Float128x _Complex     
    207         */
    208         // GENERATED END
    209 
    210         // GENERATED START, DO NOT EDIT
    211         // GENERATED BY BasicTypes-gen.cc
    212         static const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
    213                 /*             B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
    214                 /*     B*/ {   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,  17,  16,  18,  17, },
    215                 /*     C*/ {  -1,   0,   1,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
    216                 /*    SC*/ {  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
    217                 /*    UC*/ {  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
    218                 /*    SI*/ {  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
    219                 /*   SUI*/ {  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
    220                 /*     I*/ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
    221                 /*    UI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
    222                 /*    LI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
    223                 /*   LUI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
    224                 /*   LLI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
    225                 /*  LLUI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
    226                 /*    IB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
    227                 /*   UIB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
    228                 /*   _FH*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,  10,   9,  11,  10, },
    229                 /*   _FH*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,   6,  -1,  -1,   7,  -1,  -1,   8,  -1,   9, },
    230                 /*    _F*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   9,   8,  10,   9, },
    231                 /*   _FC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,  -1,   6,  -1,  -1,   7,  -1,   8, },
    232                 /*     F*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   8,   7,   9,   8, },
    233                 /*    FC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,  -1,   5,  -1,  -1,   6,  -1,   7, },
    234                 /*   _FX*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   6,   8,   7, },
    235                 /*  _FXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,  -1,   4,  -1,  -1,   5,  -1,   6, },
    236                 /*    FD*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   5,   7,   6, },
    237                 /*  _FDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,  -1,   3,  -1,  -1,   4,  -1,   5, },
    238                 /*     D*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   4,   6,   5, },
    239                 /*    DC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,  -1,   2,  -1,  -1,   3,  -1,   4, },
    240                 /*  F80X*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   3,   5,   4, },
    241                 /* _FDXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,  -1,   2,  -1,   3, },
    242                 /*   F80*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3,   3,   4,   4, },
    243                 /*   _FB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3, },
    244                 /* _FLDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,   2, },
    245                 /*    FB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3, },
    246                 /*    LD*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2, },
    247                 /*   LDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1, },
    248                 /*  _FBX*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1, },
    249                 /*_FLDXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
    250         }; // costMatrix
    251         static const int maxIntCost = 15;
    252         // GENERATED END
     181/*
     182            Old
     183            ===
     184           Double
     185             |
     186           Float
     187             |
     188           ULong
     189           /   \
     190        UInt    Long
     191           \   /
     192            Int
     193             |
     194           Ushort
     195             |
     196           Short
     197             |
     198           Uchar
     199           /   \
     200        Schar   Char
     201
     202                                New
     203                                ===
     204                       +-----LongDoubleComplex--+
     205           LongDouble--+          |             +-LongDoubleImag
     206             |         +---DoubleComplex---+         |
     207           Double------+        |          +----DoubleImag
     208             |           +-FloatComplex-+            |
     209           Float---------+              +-------FloatImag
     210             |
     211          ULongLong
     212             |
     213          LongLong
     214             |
     215           ULong
     216           /   \
     217        UInt    Long
     218           \   /
     219            Int
     220             |
     221           Ushort
     222             |
     223           Short
     224             |
     225           Uchar
     226           /   \
     227        Schar   Char
     228           \   /
     229            Bool
     230*/
     231
     232        static const int costMatrix[][ BasicType::NUMBER_OF_BASIC_TYPES ] = {
     233        /* Src \ Dest:  Bool    Char    SChar   UChar   Short   UShort  Int     UInt    Long    ULong   LLong   ULLong  Float   Double  LDbl    FCplex  DCplex  LDCplex FImag   DImag   LDImag  I128,   U128, F80, F128 */
     234                /* Bool */      { 0,    1,              1,              2,              3,              4,              5,              6,              6,              7,              8,              9,              12,             13,             14,             12,             13,             14,             -1,             -1,             -1,             10,             11,       14,   15},
     235                /* Char */      { -1,   0,              -1,             1,              2,              3,              4,              5,              5,              6,              7,              8,              11,             12,             13,             11,             12,             13,             -1,             -1,             -1,             9,              10,       13,   14},
     236                /* SChar */ { -1,       -1,             0,              1,              2,              3,              4,              5,              5,              6,              7,              8,              11,             12,             13,             11,             12,             13,             -1,             -1,             -1,             9,              10,       13,   14},
     237                /* UChar */ { -1,       -1,             -1,             0,              1,              2,              3,              4,              4,              5,              6,              7,              10,             11,             12,             10,             11,             12,             -1,             -1,             -1,             8,              9,        12,   13},
     238                /* Short */ { -1,       -1,             -1,             -1,             0,              1,              2,              3,              3,              4,              5,              6,              9,              10,             11,             9,              10,             11,             -1,             -1,             -1,             7,              8,        11,   12},
     239                /* UShort */{ -1,       -1,             -1,             -1,             -1,             0,              1,              2,              2,              3,              4,              5,              8,              9,              10,             8,              9,              10,             -1,             -1,             -1,             6,              7,        10,   11},
     240                /* Int */       { -1,   -1,             -1,             -1,             -1,             -1,             0,              1,              1,              2,              3,              4,              7,              8,              9,              7,              8,              9,              -1,             -1,             -1,             5,              6,        9,    10},
     241                /* UInt */      { -1,   -1,             -1,             -1,             -1,             -1,             -1,             0,              -1,             1,              2,              3,              6,              7,              8,              6,              7,              8,              -1,             -1,             -1,             4,              5,        8,    9},
     242                /* Long */      { -1,   -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              2,              3,              6,              7,              8,              6,              7,              8,              -1,             -1,             -1,             4,              5,        8,    9},
     243                /* ULong */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              2,              5,              6,              7,              5,              6,              7,              -1,             -1,             -1,             3,              4,        7,    8},
     244                /* LLong */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              4,              5,              6,              4,              5,              6,              -1,             -1,             -1,             2,              3,        6,    7},
     245                /* ULLong */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              3,              4,              5,              3,              4,              5,              -1,             -1,             -1,             1,              2,        5,    6},
     246
     247                /* Float */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              2,              1,              2,              3,              -1,             -1,             -1,             -1,             -1,       2,    3},
     248                /* Double */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              -1,             1,              2,              -1,             -1,             -1,             -1,             -1,       1,    2},
     249                /* LDbl */      { -1,   -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              -1,             -1,             1,              -1,             -1,             -1,             -1,             -1,       -1,   1},
     250                /* FCplex */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              2,              -1,             -1,             -1,             -1,             -1,       -1,   -1},
     251                /* DCplex */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              -1,             -1,             -1,             -1,             -1,       -1,   -1},
     252                /* LDCplex */{ -1,      -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              -1,             -1,             -1,             -1,             -1,       -1,   -1},
     253                /* FImag */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              2,              3,              0,              1,              2,              -1,             -1,       -1,   -1},
     254                /* DImag */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              2,              -1,             0,              1,              -1,             -1,       -1,   -1},
     255                /* LDImag */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              -1,             -1,             0,              -1,             -1,       -1,   -1},
     256
     257                /* I128 */  { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             2,              3,              4,              3,              4,              5,              -1,             -1,             -1,             0,              1,        4,    4},
     258                /* U128 */  { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              2,              3,              2,              3,              4,              -1,             -1,             -1,             -1,             0,        3,    3},
     259
     260                /* F80 */       { -1,   -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              -1,             -1,             1,              -1,             -1,             -1,             -1,             -1,       0,    1},
     261                /* F128 */      { -1,   -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              -1,             -1,             -1,             -1,             -1,       -1,   0},
     262        };
    253263        static_assert(
    254264                sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
    255                 "Missing row in the cost matrix"
     265                "Each basic type kind should have a corresponding row in the cost matrix"
    256266        );
    257267
    258         // GENERATED START, DO NOT EDIT
    259         // GENERATED BY BasicTypes-gen.cc
    260         static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
    261                 /*             B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
    262                 /*     B*/ {   0,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    263                 /*     C*/ {  -1,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    264                 /*    SC*/ {  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    265                 /*    UC*/ {  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    266                 /*    SI*/ {  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    267                 /*   SUI*/ {  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    268                 /*     I*/ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    269                 /*    UI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    270                 /*    LI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    271                 /*   LUI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    272                 /*   LLI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    273                 /*  LLUI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    274                 /*    IB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    275                 /*   UIB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    276                 /*   _FH*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    277                 /*   _FH*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
    278                 /*    _F*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    279                 /*   _FC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
    280                 /*     F*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    281                 /*    FC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
    282                 /*   _FX*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    283                 /*  _FXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
    284                 /*    FD*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    285                 /*  _FDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
    286                 /*     D*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    287                 /*    DC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
    288                 /*  F80X*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    289                 /* _FDXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
    290                 /*   F80*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
    291                 /*   _FB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0, },
    292                 /* _FLDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
    293                 /*    FB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0, },
    294                 /*    LD*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0, },
    295                 /*   LDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0, },
    296                 /*  _FBX*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0, },
    297                 /*_FLDXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
    298         }; // signMatrix
    299         // GENERATED END
    300         static_assert(
    301                 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
    302                 "Missing row in the sign matrix"
    303         );
    304268
    305269        void ConversionCost::postvisit( VoidType * ) {
     
    315279                                cost = Cost::zero;
    316280                                cost.incSafe( tableResult );
    317                                 cost.incSign( signMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ] );
    318281                        } // if
    319282                } else if ( dynamic_cast< EnumInstType *>( dest ) ) {
     
    337300                                        // types are the same, except otherPointer has more qualifiers
    338301                                        cost = Cost::safe;
    339                                 } // if
     302                                }
    340303                        } else {
    341304                                int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );
     
    459422                                cost = Cost::zero;
    460423                                cost.incSafe( tableResult + 1 );
    461                                 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] );
    462                         } // if
     424                        }
    463425                } else if ( dynamic_cast< PointerType* >( dest ) ) {
    464                         cost = Cost::zero;
    465                         cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation
    466                 } // if
     426                        cost = Cost::safe;
     427                }
    467428        }
    468429
     
    478439                                cost = Cost::zero;
    479440                                cost.incSafe( tableResult + 1 );
    480                                 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] );
    481                         } // if
    482                 } // if
     441                        }
     442                }
    483443        }
    484444} // namespace ResolvExpr
  • src/ResolvExpr/Cost.h

    r933f32f r6a9d4b4  
    77// Cost.h --
    88//
    9 // Author           : Peter Buhr and Aaron Moss
     9// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 09:39:50 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 29 18:33:44 2019
    13 // Update Count     : 49
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Oct 05 14:32:00 2018
     13// Update Count     : 7
    1414//
    1515
     
    1717
    1818#include <iostream>
    19 #include <cassert>
    20 #include <climits>
    2119
    2220namespace ResolvExpr {
    23 #if 0
    24 
    25         //*************************** OLD ***************************
    26 
    2721        class Cost {
    2822          private:
    29                 Cost( int unsafeCost, int polyCost, int safeCost, int signCost,
    30                           int varCost, int specCost, int referenceCost );
     23                Cost( int unsafeCost, int polyCost, int safeCost, int varCost, int specCost,
     24                        int referenceCost );
     25
    3126          public:
    3227                Cost & incUnsafe( int inc = 1 );
    3328                Cost & incPoly( int inc = 1 );
    3429                Cost & incSafe( int inc = 1 );
    35                 Cost & incSign( int inc = 1 );
    3630                Cost & incVar( int inc = 1 );
    3731                Cost & decSpec( int inc = 1 );
     
    4135                int get_polyCost() const { return polyCost; }
    4236                int get_safeCost() const { return safeCost; }
    43                 int get_signCost() const { return signCost; }
    4437                int get_varCost() const { return varCost; }
    4538                int get_specCost() const { return specCost; }
     
    4740
    4841                Cost operator+( const Cost &other ) const;
     42                Cost operator-( const Cost &other ) const;
    4943                Cost &operator+=( const Cost &other );
    5044                bool operator<( const Cost &other ) const;
     
    6155                static const Cost poly;
    6256                static const Cost safe;
    63                 static const Cost sign;
    6457                static const Cost var;
    6558                static const Cost spec;
     
    7063                int polyCost;       ///< Count of parameters and return values bound to some poly type
    7164                int safeCost;       ///< Safe (widening) conversions
    72                 int signCost;       ///< Count of safe sign conversions
    7365                int varCost;        ///< Count of polymorphic type variables
    7466                int specCost;       ///< Polymorphic type specializations (type assertions), negative cost
     
    7668        };
    7769
    78         inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int signCost,
    79                                            int varCost, int specCost, int referenceCost )
    80                 : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), signCost( signCost ),
    81                   varCost( varCost ), specCost( specCost ), referenceCost( referenceCost ) {}
     70        inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int varCost, int specCost,
     71                        int referenceCost )
     72                : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), varCost( varCost ),
     73                  specCost( specCost ), referenceCost( referenceCost ) {}
    8274
    8375        inline Cost & Cost::incUnsafe( int inc ) {
     
    9688                if ( *this == infinity ) return *this;
    9789                safeCost += inc;
    98                 return *this;
    99         }
    100 
    101         inline Cost & Cost::incSign( int inc ) {
    102                 if ( *this == infinity ) return *this;
    103                 signCost += inc;
    10490                return *this;
    10591        }
     
    125111        inline Cost Cost::operator+( const Cost &other ) const {
    126112                if ( *this == infinity || other == infinity ) return infinity;
    127                 return Cost{
    128                         unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost,
    129                                 signCost + other.signCost, varCost + other.varCost, specCost + other.specCost,
    130                                 referenceCost + other.referenceCost };
     113                return Cost{
     114                        unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost,
     115                        varCost + other.varCost, specCost + other.specCost,
     116                        referenceCost + other.referenceCost };
     117        }
     118
     119        inline Cost Cost::operator-( const Cost &other ) const {
     120                if ( *this == infinity || other == infinity ) return infinity;
     121                return Cost{
     122                        unsafeCost - other.unsafeCost, polyCost - other.polyCost, safeCost - other.safeCost,
     123                        varCost - other.varCost, specCost - other.specCost,
     124                        referenceCost - other.referenceCost };
    131125        }
    132126
     
    140134                polyCost += other.polyCost;
    141135                safeCost += other.safeCost;
    142                 signCost += other.signCost;
    143136                varCost += other.varCost;
    144137                specCost += other.specCost;
     
    163156                } else if ( safeCost < other.safeCost ) {
    164157                        return true;
    165                 } else if ( signCost > other.signCost ) {
    166                         return false;
    167                 } else if ( signCost < other.signCost ) {
    168                         return true;
    169158                } else if ( varCost > other.varCost ) {
    170159                        return false;
     
    191180                c = polyCost - other.polyCost; if ( c ) return c;
    192181                c = safeCost - other.safeCost; if ( c ) return c;
    193                 c = signCost - other.signCost; if ( c ) return c;
    194182                c = varCost - other.varCost; if ( c ) return c;
    195183                c = specCost - other.specCost; if ( c ) return c;
     
    201189                        && polyCost == other.polyCost
    202190                        && safeCost == other.safeCost
    203                         && signCost == other.signCost
    204191                        && varCost == other.varCost
    205192                        && specCost == other.specCost
     
    212199
    213200        inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {
    214                 return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", "
    215                           << cost.safeCost << ", " << cost.signCost << ", "
    216                                   << cost.varCost << ", " << cost.specCost << ", "
     201                return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", "
     202                          << cost.safeCost << ", " << cost.varCost << ", " << cost.specCost << ", "
    217203                          << cost.referenceCost << " )";
    218204        }
    219 
    220 #else
    221 
    222         //*************************** NEW ***************************
    223 
    224         // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the
    225         // specialization cost is a negative value so a correction is needed is a few places.
    226 
    227         class Cost {
    228                 union {
    229                         struct {
    230                         #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    231                                 // Little-endian => first value is low priority and last is high priority.
    232                                 unsigned char padding;                                  ///< unused
    233                                 unsigned char referenceCost;                    ///< reference conversions
    234                                 unsigned char specCost;                                 ///< Polymorphic type specializations (type assertions), negative cost
    235                                 unsigned char varCost;                                  ///< Count of polymorphic type variables
    236                                 unsigned char signCost;                                 ///< Count of safe sign conversions
    237                                 unsigned char safeCost;                                 ///< Safe (widening) conversions
    238                                 unsigned char polyCost;                                 ///< Count of parameters and return values bound to some poly type
    239                                 unsigned char unsafeCost;                               ///< Unsafe (narrowing) conversions
    240                         #else
    241                                 #error Cost BIG_ENDIAN unsupported
    242                         #endif
    243                         } v;
    244                         uint64_t all;
    245                 };
    246                 static const unsigned char correctb = 0xff;             // byte correction for negative spec cost
    247                 static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost
    248           public:
    249                 // Compiler adjusts constants for correct endian.
    250                 enum : uint64_t {
    251                         zero      = 0x00'00'00'00'00'ff'00'00,
    252                         infinity  = 0xff'ff'ff'ff'ff'00'ff'ff,
    253                         unsafe    = 0x01'00'00'00'00'ff'00'00,
    254                         poly      = 0x00'01'00'00'00'ff'00'00,
    255                         safe      = 0x00'00'01'00'00'ff'00'00,
    256                         sign      = 0x00'00'00'01'00'ff'00'00,
    257                         var       = 0x00'00'00'00'01'ff'00'00,
    258                         spec      = 0x00'00'00'00'00'fe'00'00,
    259                         reference = 0x00'00'00'00'00'ff'01'00,
    260                 }; //'
    261 
    262                 Cost( uint64_t all ) { Cost::all = all; }
    263                 Cost( int unsafeCost, int polyCost, int safeCost, int signCost, int varCost, int specCost, int referenceCost ) {
    264                         // Assume little-endian => first value is low priority and last is high priority.
    265                         v = {
    266                         #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    267                                 (unsigned char)0,                                               // padding
    268                                 (unsigned char)referenceCost,                   // low priority
    269                                 (unsigned char)(specCost + correctb),   // correct for signedness
    270                                 (unsigned char)varCost,
    271                                 (unsigned char)signCost,
    272                                 (unsigned char)safeCost,
    273                                 (unsigned char)polyCost,
    274                                 (unsigned char)unsafeCost,                              // high priority
    275                         #else
    276                                 #error Cost BIG_ENDIAN unsupported
    277                         #endif
    278                         };
    279                 }
    280 
    281                 int get_unsafeCost() const { return v.unsafeCost; }
    282                 int get_polyCost() const { return v.polyCost; }
    283                 int get_safeCost() const { return v.safeCost; }
    284                 int get_signCost() const { return v.signCost; }
    285                 int get_varCost() const { return v.varCost; }
    286                 int get_specCost() const { return -(correctb - v.specCost); }
    287                 int get_referenceCost() const { return v.referenceCost; }
    288 
    289                 friend bool operator==( const Cost, const Cost );
    290                 friend bool operator!=( const Cost lhs, const Cost rhs );
    291                 // returns negative for *this < rhs, 0 for *this == rhs, positive for *this > rhs
    292                 int compare( const Cost rhs ) const {
    293                         if ( all == infinity ) return 1;
    294                         if ( rhs.all == infinity ) return -1;
    295                         return all > rhs.all ? 1 : all == rhs.all ? 0 : -1;
    296                 }
    297                 friend bool operator<( const Cost lhs, const Cost rhs );
    298 
    299                 friend Cost operator+( const Cost lhs, const Cost rhs );
    300  
    301                 Cost operator+=( const Cost rhs ) {
    302                         if ( all == infinity ) return *this;
    303                         if ( rhs.all == infinity ) {
    304                                 all = infinity;
    305                                 return *this;
    306                         }
    307                         all += rhs.all - correctw;                                      // correct for negative spec cost
    308                         return *this;
    309                 }
    310 
    311                 Cost incUnsafe( int inc = 1 ) {
    312                         if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; }
    313                         return *this;
    314                 }
    315 
    316                 Cost incPoly( int inc = 1 ) {
    317                         if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; }
    318                         return *this;
    319                 }
    320 
    321                 Cost incSafe( int inc = 1 ) {
    322                         if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; }
    323                         return *this;
    324                 }
    325 
    326                 Cost incSign( int inc = 1 ) {
    327                         if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; }
    328                         return *this;
    329                 }
    330 
    331                 Cost incVar( int inc = 1 ) {
    332                         if ( all != infinity ) { assert( v.varCost + inc <= UCHAR_MAX ); v.varCost += inc; }
    333                         return *this;
    334                 }
    335 
    336                 Cost decSpec( int dec = 1 ) {
    337                         if ( all != infinity ) { assert( v.specCost - dec >= 0 ); v.specCost -= dec; }
    338                         return *this;
    339                 }
    340 
    341                 Cost incReference( int inc = 1 ) {
    342                         if ( all != infinity ) { assert( v.referenceCost + inc <= UCHAR_MAX ); v.referenceCost += inc; }
    343                         return *this;
    344                 }
    345 
    346                 friend std::ostream & operator<<( std::ostream & os, const Cost cost );
    347         };
    348 
    349         inline bool operator==( const Cost lhs, const Cost rhs ) {
    350                 return lhs.all == rhs.all;
    351         }
    352 
    353         inline bool operator!=( const Cost lhs, const Cost rhs ) {
    354                 return !( lhs.all == rhs.all );
    355         }
    356 
    357         inline bool operator<( const Cost lhs, const Cost rhs ) {
    358                 if ( lhs.all == Cost::infinity ) return false;
    359                 if ( rhs.all == Cost::infinity ) return true;
    360                 return lhs.all < rhs.all;
    361         }
    362 
    363         inline Cost operator+( const Cost lhs, const Cost rhs ) {
    364                 if ( lhs.all == Cost::infinity || rhs.all == Cost::infinity ) return Cost{ Cost::infinity };
    365                 return Cost{ lhs.all + rhs.all - Cost::correctw }; // correct for negative spec cost
    366         }
    367 
    368         inline std::ostream & operator<<( std::ostream & os, const Cost cost ) {
    369                 return os << "( " << cost.get_unsafeCost() << ", " << cost.get_polyCost() << ", " << cost.get_safeCost()
    370                                   << ", " << cost.get_signCost() << ", " << cost.get_varCost() << ", " << cost.get_specCost()
    371                                   << ", " << cost.get_referenceCost() << " )";
    372         }
    373 #endif // 0
    374205} // namespace ResolvExpr
    375206
  • src/ResolvExpr/RenameVars.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Sun May 17 12:05:18 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 30 17:07:57 2019
    13 // Update Count     : 7
     12// Last Modified On : Wed Mar  2 17:36:32 2016
     13// Update Count     : 5
    1414//
    1515
     
    3939                  private:
    4040                        int level, resetCount;
    41                         std::list< std::unordered_map< std::string, std::string > > mapStack;
     41                        std::list< std::map< std::string, std::string > > mapStack;
    4242                };
    4343
     
    5555        namespace {
    5656                RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) {
    57                         mapStack.push_front( std::unordered_map< std::string, std::string >() );
     57                        mapStack.push_front( std::map< std::string, std::string >() );
    5858                }
    5959
     
    6565                void RenameVars::previsit( TypeInstType * instType ) {
    6666                        previsit( (Type *)instType );
    67                         std::unordered_map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name );
     67                        std::map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name );
    6868                        if ( i != mapStack.front().end() ) {
    6969                                instType->name = i->second;
  • src/ResolvExpr/ResolveAssertions.cc

    r933f32f r6a9d4b4  
    2020#include <list>                     // for list
    2121#include <memory>                   // for unique_ptr
    22 #include <sstream>                  // for ostringstream
    23 #include <string>                   // for string
     22#include <string>
    2423#include <unordered_map>            // for unordered_map, unordered_multimap
    2524#include <utility>                  // for move
     
    2827#include "Alternative.h"            // for Alternative, AssertionItem, AssertionList
    2928#include "Common/FilterCombos.h"    // for filterCombos
    30 #include "Common/Indenter.h"        // for Indenter
    3129#include "Common/utility.h"         // for sort_mins
    3230#include "ResolvExpr/RenameVars.h"  // for renameTyVars
     
    3533#include "SynTree/Expression.h"     // for InferredParams
    3634#include "TypeEnvironment.h"        // for TypeEnvironment, etc.
    37 #include "typeops.h"                // for adjustExprType, specCost
     35#include "typeops.h"                // for adjustExprType
    3836#include "Unify.h"                  // for unify
    3937
     
    5856        using CandidateList = std::vector<AssnCandidate>;
    5957
     58        /// Unique identifier for a yet-to-be-resolved assertion
     59        struct AssnId {
     60                DeclarationWithType* decl;  ///< Declaration of assertion
     61                AssertionSetValue info;     ///< Information about assertion
     62
     63                AssnId(DeclarationWithType* decl, const AssertionSetValue& info) : decl(decl), info(info) {}
     64        };
     65
     66        /// Cached assertion items
     67        struct AssnCacheItem {
     68                CandidateList matches;         ///< Possible matches for this assertion
     69                std::vector<AssnId> deferIds;  ///< Deferred assertions which resolve to this item
     70
     71                AssnCacheItem( CandidateList&& m ) : matches(std::move(m)), deferIds() {}
     72        };
     73
     74        /// Cache of resolved assertions
     75        using AssnCache = std::unordered_map<std::string, AssnCacheItem>;
     76
    6077        /// Reference to single deferred item
    6178        struct DeferRef {
    62                 const DeclarationWithType* decl;
    63                 const AssertionSetValue& info;
     79                const AssnCacheItem& item;
    6480                const AssnCandidate& match;
    6581        };
     
    6884        /// Acts like indexed list of DeferRef
    6985        struct DeferItem {
    70                 const DeclarationWithType* decl;
    71                 const AssertionSetValue& info;
    72                 CandidateList matches;
    73 
    74                 DeferItem( DeclarationWithType* decl, const AssertionSetValue& info, CandidateList&& matches )
    75                 : decl(decl), info(info), matches(std::move(matches)) {}
    76 
    77                 bool empty() const { return matches.empty(); }
    78 
    79                 CandidateList::size_type size() const { return matches.size(); }
    80 
    81                 DeferRef operator[] ( unsigned i ) const { return { decl, info, matches[i] }; }
     86                const AssnCache* cache;     ///< Cache storing assertion item
     87                std::string key;            ///< Key into cache
     88               
     89                DeferItem( const AssnCache& cache, const std::string& key ) : cache(&cache), key(key) {}
     90
     91                bool empty() const { return cache->at(key).matches.empty(); }
     92
     93                CandidateList::size_type size() const { return cache->at(key).matches.size(); }
     94
     95                DeferRef operator[] ( unsigned i ) const {
     96                        const AssnCacheItem& item = cache->at(key);
     97                        return { item, item.matches[i] };
     98                }
     99
     100                // sortable by key
     101                // TODO look into optimizing combination process with other sort orders (e.g. by number
     102                // of matches in candidate)
     103                bool operator< ( const DeferItem& o ) const { return key < o.key; }
     104                bool operator== ( const DeferItem& o ) const { return key == o.key; }
    82105        };
    83106
     
    154177                                for ( const auto& assn : x.assns ) {
    155178                                        k += computeConversionCost(
    156                                                 assn.match.adjType, assn.decl->get_type(), indexer, x.env );
    157                                        
    158                                         // mark vars+specialization cost on function-type assertions
    159                                         PointerType* ptr = dynamic_cast< PointerType* >( assn.decl->get_type() );
    160                                         if ( ! ptr ) continue;
    161                                         FunctionType* func = dynamic_cast< FunctionType* >( ptr->base );
    162                                         if ( ! func ) continue;
    163                                        
    164                                         for ( DeclarationWithType* formal : func->parameters ) {
    165                                                 k.decSpec( specCost( formal->get_type() ) );
    166                                         }
    167                                         k.incVar( func->forall.size() );
    168                                         for ( TypeDecl* td : func->forall ) {
    169                                                 k.decSpec( td->assertions.size() );
    170                                         }
     179                                                assn.match.adjType, assn.item.deferIds[0].decl->get_type(), indexer,
     180                                                x.env );
    171181                                }
    172182                                it = cache.emplace_hint( it, &x, k );
     
    239249
    240250        /// Resolve a single assertion, in context
    241         bool resolveAssertion( AssertionItem& assn, ResnState& resn ) {
     251        bool resolveAssertion( AssertionItem& assn, ResnState& resn, AssnCache& cache ) {
    242252                // skip unused assertions
    243253                if ( ! assn.info.isUsed ) return true;
    244254
    245                 // lookup candidates for this assertion
    246                 std::list< SymTab::Indexer::IdData > candidates;
    247                 resn.indexer.lookupId( assn.decl->name, candidates );
    248 
    249                 // find the candidates that unify with the desired type
    250                 CandidateList matches;
    251                 for ( const auto& cdata : candidates ) {
    252                         DeclarationWithType* candidate = cdata.id;
    253 
    254                         // build independent unification context for candidate
    255                         AssertionSet have, newNeed;
    256                         TypeEnvironment newEnv{ resn.alt.env };
    257                         OpenVarSet newOpenVars{ resn.alt.openVars };
    258                         Type* adjType = candidate->get_type()->clone();
    259                         adjustExprType( adjType, newEnv, resn.indexer );
    260                         renameTyVars( adjType );
    261 
    262                         // keep unifying candidates
    263                         if ( unify( assn.decl->get_type(), adjType, newEnv, newNeed, have, newOpenVars,
    264                                         resn.indexer ) ) {
    265                                 // set up binding slot for recursive assertions
    266                                 UniqueId crntResnSlot = 0;
    267                                 if ( ! newNeed.empty() ) {
    268                                         crntResnSlot = ++globalResnSlot;
    269                                         for ( auto& a : newNeed ) {
    270                                                 a.second.resnSlot = crntResnSlot;
     255                // check cache for this assertion
     256                std::string assnKey = SymTab::Mangler::mangleAssnKey( assn.decl, resn.alt.env );
     257                auto it = cache.find( assnKey );
     258
     259                // attempt to resolve assertion if this is the first time seen
     260                if ( it == cache.end() ) {
     261                        // lookup candidates for this assertion
     262                        std::list< SymTab::Indexer::IdData > candidates;
     263                        resn.indexer.lookupId( assn.decl->name, candidates );
     264
     265                        // find the candidates that unify with the desired type
     266                        CandidateList matches;
     267                        for ( const auto& cdata : candidates ) {
     268                                DeclarationWithType* candidate = cdata.id;
     269
     270                                // build independent unification context for candidate
     271                                AssertionSet have, newNeed;
     272                                TypeEnvironment newEnv{ resn.alt.env };
     273                                OpenVarSet newOpenVars{ resn.alt.openVars };
     274                                Type* adjType = candidate->get_type()->clone();
     275                                adjustExprType( adjType, newEnv, resn.indexer );
     276                                renameTyVars( adjType );
     277
     278                                // keep unifying candidates
     279                                if ( unify( assn.decl->get_type(), adjType, newEnv, newNeed, have, newOpenVars,
     280                                                resn.indexer ) ) {
     281                                        // set up binding slot for recursive assertions
     282                                        UniqueId crntResnSlot = 0;
     283                                        if ( ! newNeed.empty() ) {
     284                                                crntResnSlot = ++globalResnSlot;
     285                                                for ( auto& a : newNeed ) {
     286                                                        a.second.resnSlot = crntResnSlot;
     287                                                }
    271288                                        }
    272                                 }
    273 
    274                                 matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have),
    275                                         std::move(newNeed), std::move(newOpenVars), crntResnSlot );
    276                         } else {
    277                                 delete adjType;
     289
     290                                        matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have),
     291                                                std::move(newNeed), std::move(newOpenVars), crntResnSlot );
     292                                } else {
     293                                        delete adjType;
     294                                }
    278295                        }
    279                 }
     296
     297                        it = cache.emplace_hint( it, assnKey, AssnCacheItem{ std::move(matches) } );
     298                }
     299
     300                CandidateList& matches = it->second.matches;
    280301
    281302                // break if no suitable assertion
     
    284305                // defer if too many suitable assertions
    285306                if ( matches.size() > 1 ) {
    286                         resn.deferred.emplace_back( assn.decl, assn.info, std::move(matches) );
     307                        it->second.deferIds.emplace_back( assn.decl, assn.info );
     308                        resn.deferred.emplace_back( cache, assnKey );
    287309                        return true;
    288310                }
     
    292314                addToIndexer( match.have, resn.indexer );
    293315                resn.newNeed.insert( match.need.begin(), match.need.end() );
    294                 resn.alt.env = std::move(match.env);
    295                 resn.alt.openVars = std::move(match.openVars);
     316                resn.alt.env = match.env;
     317                resn.alt.openVars = match.openVars;
    296318
    297319                bindAssertion( assn.decl, assn.info, resn.alt, match, resn.inferred );
     
    342364        static const int recursionLimit = /* 10 */ 4;
    343365
    344         void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out, std::list<std::string>& errors ) {
     366        void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ) {
    345367                // finish early if no assertions to resolve
    346368                if ( alt.need.empty() ) {
     
    354376                ResnList resns{ ResnState{ alt, root_indexer } };
    355377                ResnList new_resns{};
     378                AssnCache assnCache;
    356379
    357380                // resolve assertions in breadth-first-order up to a limited number of levels deep
     
    362385                                for ( auto& assn : resn.need ) {
    363386                                        // fail early if any assertion is not resolvable
    364                                         if ( ! resolveAssertion( assn, resn ) ) {
    365                                                 Indenter tabs{ Indenter::tabsize, 3 };
    366                                                 std::ostringstream ss;
    367                                                 ss << tabs << "Unsatisfiable alternative:\n";
    368                                                 resn.alt.print( ss, ++tabs );
    369                                                 ss << --tabs << "Could not satisfy assertion:\n";
    370                                                 assn.decl->print( ss, ++tabs );
    371                                                
    372                                                 errors.emplace_back( ss.str() );
    373                                                 goto nextResn;
    374                                         }
     387                                        if ( ! resolveAssertion( assn, resn, assnCache ) ) goto nextResn;
    375388                                }
    376389
     
    383396                                        }
    384397                                } else {
     398                                        // only resolve each deferred assertion once
     399                                        std::sort( resn.deferred.begin(), resn.deferred.end() );
     400                                        auto last = std::unique( resn.deferred.begin(), resn.deferred.end() );
     401                                        resn.deferred.erase( last, resn.deferred.end() );
    385402                                        // resolve deferred assertions by mutual compatibility
    386403                                        std::vector<CandidateEnvMerger::OutType> compatible = filterCombos(
    387404                                                resn.deferred,
    388405                                                CandidateEnvMerger{ resn.alt.env, resn.alt.openVars, resn.indexer } );
    389                                         // fail early if no mutually-compatible assertion satisfaction
    390                                         if ( compatible.empty() ) {
    391                                                 Indenter tabs{ Indenter::tabsize, 3 };
    392                                                 std::ostringstream ss;
    393                                                 ss << tabs << "Unsatisfiable alternative:\n";
    394                                                 resn.alt.print( ss, ++tabs );
    395                                                 ss << --tabs << "No mutually-compatible satisfaction for assertions:\n";
    396                                                 ++tabs;
    397                                                 for ( const auto& d : resn.deferred ) {
    398                                                         d.decl->print( ss, tabs );
    399                                                 }
    400 
    401                                                 errors.emplace_back( ss.str() );
    402                                                 goto nextResn;
    403                                         }
    404406                                        // sort by cost
    405407                                        CandidateCost coster{ resn.indexer };
     
    427429                                                        new_resn.newNeed.insert( match.need.begin(), match.need.end() );
    428430
    429                                                         bindAssertion( r.decl, r.info, new_resn.alt, match, new_resn.inferred );
     431                                                        // for each deferred assertion with the same form
     432                                                        for ( AssnId id : r.item.deferIds ) {
     433                                                                bindAssertion(
     434                                                                        id.decl, id.info, new_resn.alt, match, new_resn.inferred );
     435                                                        }
    430436                                                }
    431437
  • src/ResolvExpr/ResolveAssertions.h

    r933f32f r6a9d4b4  
    2424namespace ResolvExpr {
    2525        /// Recursively resolves all assertions provided in an alternative; returns true iff succeeds
    26         void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out, std::list<std::string>& errors );
     26        void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out );
    2727} // namespace ResolvExpr
    2828
  • src/ResolvExpr/Resolver.cc

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:17:01 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 19 18:09:56 2019
    13 // Update Count     : 240
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Oct 05 09:43:00 2018
     13// Update Count     : 214
    1414//
    1515
     
    5454                }
    5555
    56                 void previsit( FunctionDecl * functionDecl );
    57                 void postvisit( FunctionDecl * functionDecl );
    58                 void previsit( ObjectDecl * objectDecll );
     56                void previsit( FunctionDecl *functionDecl );
     57                void postvisit( FunctionDecl *functionDecl );
     58                void previsit( ObjectDecl *objectDecll );
    5959                void previsit( EnumDecl * enumDecl );
    6060                void previsit( StaticAssertDecl * assertDecl );
     
    6363                void previsit( PointerType * at );
    6464
    65                 void previsit( ExprStmt * exprStmt );
    66                 void previsit( AsmExpr * asmExpr );
    67                 void previsit( AsmStmt * asmStmt );
    68                 void previsit( IfStmt * ifStmt );
    69                 void previsit( WhileStmt * whileStmt );
    70                 void previsit( ForStmt * forStmt );
    71                 void previsit( SwitchStmt * switchStmt );
    72                 void previsit( CaseStmt * caseStmt );
    73                 void previsit( BranchStmt * branchStmt );
    74                 void previsit( ReturnStmt * returnStmt );
    75                 void previsit( ThrowStmt * throwStmt );
    76                 void previsit( CatchStmt * catchStmt );
     65                void previsit( ExprStmt *exprStmt );
     66                void previsit( AsmExpr *asmExpr );
     67                void previsit( AsmStmt *asmStmt );
     68                void previsit( IfStmt *ifStmt );
     69                void previsit( WhileStmt *whileStmt );
     70                void previsit( ForStmt *forStmt );
     71                void previsit( SwitchStmt *switchStmt );
     72                void previsit( CaseStmt *caseStmt );
     73                void previsit( BranchStmt *branchStmt );
     74                void previsit( ReturnStmt *returnStmt );
     75                void previsit( ThrowStmt *throwStmt );
     76                void previsit( CatchStmt *catchStmt );
    7777                void previsit( WaitForStmt * stmt );
    7878
    79                 void previsit( SingleInit * singleInit );
    80                 void previsit( ListInit * listInit );
    81                 void previsit( ConstructorInit * ctorInit );
     79                void previsit( SingleInit *singleInit );
     80                void previsit( ListInit *listInit );
     81                void previsit( ConstructorInit *ctorInit );
    8282          private:
    8383                typedef std::list< Initializer * >::iterator InitIterator;
     
    105105        }
    106106
    107         void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {
     107        void resolveDecl( Declaration * decl, const SymTab::Indexer &indexer ) {
    108108                PassVisitor<Resolver> resolver( indexer );
    109109                maybeAccept( decl, resolver );
     
    149149                };
    150150
    151                 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {
     151                void finishExpr( Expression *&expr, const TypeEnvironment &env, TypeSubstitution * oldenv = nullptr ) {
    152152                        expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;
    153153                        env.makeSubstitution( *expr->env );
     
    280280
    281281        // used in resolveTypeof
    282         Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {
     282        Expression * resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer ) {
    283283                TypeEnvironment env;
    284284                return resolveInVoidContext( expr, indexer, env );
    285285        }
    286286
    287         Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {
     287        Expression * resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {
    288288                // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
    289289                // interpretations, an exception has already been thrown.
    290290                assertf( expr, "expected a non-null expression." );
    291291
    292                 CastExpr * untyped = new CastExpr( expr ); // cast to void
    293                 untyped->location = expr->location;
     292                static CastExpr untyped( nullptr ); // cast to void
     293                untyped.location = expr->location;
    294294
    295295                // set up and resolve expression cast to void
     296                untyped.arg = expr;
    296297                Alternative choice;
    297                 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
     298                findUnfinishedKindExpression( &untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
    298299                CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );
    299                 assert( castExpr );
    300300                env = std::move( choice.env );
    301301
     
    305305
    306306                // unlink the arg so that it isn't deleted twice at the end of the program
    307                 untyped->arg = nullptr;
     307                untyped.arg = nullptr;
    308308                return ret;
    309309        }
    310310
    311         void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
     311        void findVoidExpression( Expression *& untyped, const SymTab::Indexer &indexer ) {
    312312                resetTyVarRenaming();
    313313                TypeEnvironment env;
     
    318318        }
    319319
    320         void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
     320        void findSingleExpression( Expression *&untyped, const SymTab::Indexer &indexer ) {
    321321                findKindExpression( untyped, indexer, "", standardAlternativeFilter );
    322322        }
     
    337337                        if ( dynamic_cast< EnumInstType * >( type ) ) {
    338338                                return true;
    339                         } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {
     339                        } else if ( BasicType *bt = dynamic_cast< BasicType * >( type ) ) {
    340340                                return bt->isInteger();
    341341                        } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {
     
    346346                }
    347347
    348                 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
     348                void findIntegralExpression( Expression *& untyped, const SymTab::Indexer &indexer ) {
    349349                        findKindExpression( untyped, indexer, "condition", isIntegralType );
    350350                }
     
    402402        }
    403403
    404         void Resolver::previsit( ObjectDecl * objectDecl ) {
     404        void Resolver::previsit( ObjectDecl *objectDecl ) {
    405405                // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that
    406406                // class-variable initContext is changed multiple time because the LHS is analysed twice.
     
    432432        }
    433433
    434         void Resolver::previsit( FunctionDecl * functionDecl ) {
     434        void Resolver::previsit( FunctionDecl *functionDecl ) {
    435435#if 0
    436436                std::cerr << "resolver visiting functiondecl ";
     
    442442        }
    443443
    444         void Resolver::postvisit( FunctionDecl * functionDecl ) {
     444        void Resolver::postvisit( FunctionDecl *functionDecl ) {
    445445                // default value expressions have an environment which shouldn't be there and trips up
    446446                // later passes.
     
    467467        }
    468468
    469         void Resolver::previsit( ExprStmt * exprStmt ) {
     469        void Resolver::previsit( ExprStmt *exprStmt ) {
    470470                visit_children = false;
    471471                assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );
     
    473473        }
    474474
    475         void Resolver::previsit( AsmExpr * asmExpr ) {
     475        void Resolver::previsit( AsmExpr *asmExpr ) {
    476476                visit_children = false;
    477477                findVoidExpression( asmExpr->operand, indexer );
     
    481481        }
    482482
    483         void Resolver::previsit( AsmStmt * asmStmt ) {
     483        void Resolver::previsit( AsmStmt *asmStmt ) {
    484484                visit_children = false;
    485485                acceptAll( asmStmt->get_input(), *visitor );
     
    487487        }
    488488
    489         void Resolver::previsit( IfStmt * ifStmt ) {
     489        void Resolver::previsit( IfStmt *ifStmt ) {
    490490                findIntegralExpression( ifStmt->condition, indexer );
    491491        }
    492492
    493         void Resolver::previsit( WhileStmt * whileStmt ) {
     493        void Resolver::previsit( WhileStmt *whileStmt ) {
    494494                findIntegralExpression( whileStmt->condition, indexer );
    495495        }
    496496
    497         void Resolver::previsit( ForStmt * forStmt ) {
     497        void Resolver::previsit( ForStmt *forStmt ) {
    498498                if ( forStmt->condition ) {
    499499                        findIntegralExpression( forStmt->condition, indexer );
     
    505505        }
    506506
    507         void Resolver::previsit( SwitchStmt * switchStmt ) {
     507        void Resolver::previsit( SwitchStmt *switchStmt ) {
    508508                GuardValue( currentObject );
    509509                findIntegralExpression( switchStmt->condition, indexer );
     
    512512        }
    513513
    514         void Resolver::previsit( CaseStmt * caseStmt ) {
     514        void Resolver::previsit( CaseStmt *caseStmt ) {
    515515                if ( caseStmt->condition ) {
    516516                        std::list< InitAlternative > initAlts = currentObject.getOptions();
     
    531531        }
    532532
    533         void Resolver::previsit( BranchStmt * branchStmt ) {
     533        void Resolver::previsit( BranchStmt *branchStmt ) {
    534534                visit_children = false;
    535535                // must resolve the argument for a computed goto
     
    542542        }
    543543
    544         void Resolver::previsit( ReturnStmt * returnStmt ) {
     544        void Resolver::previsit( ReturnStmt *returnStmt ) {
    545545                visit_children = false;
    546546                if ( returnStmt->expr ) {
     
    549549        }
    550550
    551         void Resolver::previsit( ThrowStmt * throwStmt ) {
     551        void Resolver::previsit( ThrowStmt *throwStmt ) {
    552552                visit_children = false;
    553553                // TODO: Replace *exception type with &exception type.
     
    561561        }
    562562
    563         void Resolver::previsit( CatchStmt * catchStmt ) {
     563        void Resolver::previsit( CatchStmt *catchStmt ) {
    564564                if ( catchStmt->cond ) {
    565565                        findSingleExpression( catchStmt->cond, new BasicType( noQualifiers, BasicType::Bool ), indexer );
     
    725725
    726726                                                }
    727                                                 catch( SemanticErrorException & e ) {
     727                                                catch( SemanticErrorException &e ) {
    728728                                                        errors.append( e );
    729729                                                }
    730730                                        }
    731731                                }
    732                                 catch( SemanticErrorException & e ) {
     732                                catch( SemanticErrorException &e ) {
    733733                                        errors.append( e );
    734734                                }
     
    782782        }
    783783
    784         void Resolver::previsit( SingleInit * singleInit ) {
     784        void Resolver::previsit( SingleInit *singleInit ) {
    785785                visit_children = false;
    786786                // resolve initialization using the possibilities as determined by the currentObject cursor
     
    814814                                if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {
    815815                                        if ( isCharType( pt->get_base() ) ) {
    816                                                 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {
     816                                                if ( CastExpr *ce = dynamic_cast< CastExpr * >( newExpr ) ) {
    817817                                                        // strip cast if we're initializing a char[] with a char *,
    818818                                                        // e.g.  char x[] = "hello";
     
    894894        }
    895895
    896         void Resolver::previsit( ConstructorInit * ctorInit ) {
     896        void Resolver::previsit( ConstructorInit *ctorInit ) {
    897897                visit_children = false;
    898898                // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit
  • src/ResolvExpr/Resolver.h

    r933f32f r6a9d4b4  
    1010// Created On       : Sun May 17 12:18:34 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Feb 18 20:40:38 2019
    13 // Update Count     : 4
     12// Last Modified On : Sat Jul 22 09:36:57 2017
     13// Update Count     : 3
    1414//
    1515
     
    2929        /// Checks types and binds syntactic constructs to typed representations
    3030        void resolve( std::list< Declaration * > translationUnit );
    31         void resolveDecl( Declaration *, const SymTab::Indexer & indexer );
    32         Expression *resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer );
    33         void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer );
    34         void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer );
    35         void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer );
     31        void resolveDecl( Declaration *, const SymTab::Indexer &indexer );
     32        Expression *resolveInVoidContext( Expression * expr, const SymTab::Indexer &indexer );
     33        void findVoidExpression( Expression *& untyped, const SymTab::Indexer &indexer );
     34        void findSingleExpression( Expression *& untyped, const SymTab::Indexer &indexer );
     35        void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer &indexer );
    3636        void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer );
    3737        void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer );
  • src/ResolvExpr/TypeEnvironment.cc

    r933f32f r6a9d4b4  
    386386        }
    387387
    388         bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2,
    389                         TypeDecl::Data && data, AssertionSet &need, AssertionSet &have,
    390                         const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
     388        bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    391389
    392390                auto class1 = internal_lookup( var1->get_name() );
     
    430428                                        class1->set_type( common );
    431429                                }
    432                                 class1->data.isComplete |= data.isComplete;
    433430                                env.erase( class2 );
    434431                        } else return false;
     
    438435                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
    439436                                class1->allowWidening = widen1;
    440                                 class1->data.isComplete |= data.isComplete;
    441437                                env.erase( class2 );
    442438                        } else {
    443439                                class2->vars.insert( class1->vars.begin(), class1->vars.end() );
    444440                                class2->allowWidening = widen2;
    445                                 class2->data.isComplete |= data.isComplete;
    446441                                env.erase( class1 );
    447442                        } // if
     
    450445                        class1->vars.insert( var2->get_name() );
    451446                        class1->allowWidening = widen1;
    452                         class1->data.isComplete |= data.isComplete;
    453447                } else if ( class2 != env.end() ) {
    454448                        // var1 unbound, add to class2
    455449                        class2->vars.insert( var1->get_name() );
    456450                        class2->allowWidening = widen2;
    457                         class2->data.isComplete |= data.isComplete;
    458451                } else {
    459452                        // neither var bound, create new class
  • src/ResolvExpr/TypeEnvironment.h

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:24:58 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 30 23:04:10 2019
    13 // Update Count     : 9
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon Jun 18 11:58:00 2018
     13// Update Count     : 4
    1414//
    1515
     
    1818#include <iostream>                    // for ostream
    1919#include <list>                        // for list, list<>::iterator, list<>...
    20 #include <map>                                             // for map, map<>::value_compare
    21 #include <unordered_map>
    22 #include <set>                                             // for set
     20#include <map>                         // for map, map<>::value_compare
     21#include <set>                         // for set
    2322#include <string>                      // for string
    2423#include <utility>                     // for move, swap
     
    6564                AssertionSetValue() : isUsed(false), resnSlot(0) {}
    6665        };
    67         typedef std::map< DeclarationWithType *, AssertionSetValue, AssertCompare > AssertionSet;
    68         typedef std::unordered_map< std::string, TypeDecl::Data > OpenVarSet;
     66        typedef std::map< DeclarationWithType*, AssertionSetValue, AssertCompare > AssertionSet;
     67        typedef std::map< std::string, TypeDecl::Data > OpenVarSet;
    6968
    7069        /// merges one set of open vars into another
     
    140139                /// Binds the type classes represented by `var1` and `var2` together; will add
    141140                /// one or both classes if needed. Returns false on failure.
    142                 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
     141                bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
    143142
    144143                /// Disallows widening for all bindings in the environment
  • src/ResolvExpr/Unify.cc

    r933f32f r6a9d4b4  
    2121#include <string>                 // for string, operator==, operator!=, bas...
    2222#include <utility>                // for pair, move
    23 #include <vector>
    24 
    25 #include "AST/Node.hpp"
    26 #include "AST/Type.hpp"
     23
    2724#include "Common/PassVisitor.h"   // for PassVisitor
    2825#include "FindOpenVars.h"         // for findOpenVars
     
    175172                bool isopen2 = var2 && ( entry2 != openVars.end() );
    176173
    177                 if ( isopen1 && isopen2 ) {
    178                         if ( entry1->second.kind != entry2->second.kind ) {
    179                                 result = false;
    180                         } else {
    181                                 result = env.bindVarToVar(
    182                                         var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,
    183                                         haveAssertions, openVars, widenMode, indexer );
    184                         }
     174                if ( isopen1 && isopen2 && entry1->second == entry2->second ) {
     175                        result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
    185176                } else if ( isopen1 ) {
    186177                        result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
     
    633624        }
    634625
     626        // xxx - compute once and store in the FunctionType?
    635627        Type * extractResultType( FunctionType * function ) {
    636628                if ( function->get_returnVals().size() == 0 ) {
     
    646638                }
    647639        }
    648 
    649         ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
    650                 assert(!"restore after AST added to build");
    651                 // if ( func->returns.empty() ) return new ast::VoidType{};
    652                 // if ( func->returns.size() == 1 ) return func->returns[0]->get_type();
    653 
    654                 // std::vector<ast::ptr<ast::Type>> tys;
    655                 // for ( const ast::DeclWithType * decl : func->returns ) {
    656                 //      tys.emplace_back( decl->get_type() );
    657                 // }
    658                 // return new ast::TupleType{ std::move(tys) };
    659         }
    660640} // namespace ResolvExpr
    661641
  • src/ResolvExpr/module.mk

    r933f32f r6a9d4b4  
    1515###############################################################################
    1616
    17 SRC_RESOLVEXPR = \
    18       ResolvExpr/AdjustExprType.cc \
    19       ResolvExpr/Alternative.cc \
    20       ResolvExpr/AlternativeFinder.cc \
    21       ResolvExpr/CastCost.cc \
    22       ResolvExpr/CommonType.cc \
    23       ResolvExpr/ConversionCost.cc \
    24       ResolvExpr/CurrentObject.cc \
    25       ResolvExpr/ExplodedActual.cc \
    26       ResolvExpr/FindOpenVars.cc \
    27       ResolvExpr/Occurs.cc \
    28       ResolvExpr/PolyCost.cc \
    29       ResolvExpr/PtrsAssignable.cc \
    30       ResolvExpr/PtrsCastable.cc \
    31       ResolvExpr/RenameVars.cc \
    32       ResolvExpr/ResolveAssertions.cc \
    33       ResolvExpr/Resolver.cc \
    34       ResolvExpr/ResolveTypeof.cc \
    35       ResolvExpr/SpecCost.cc \
    36       ResolvExpr/TypeEnvironment.cc \
    37       ResolvExpr/Unify.cc
    38 
    39 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc
    40 SRCDEMANGLE += $(SRC_RESOLVEXPR)
     17SRC += ResolvExpr/AlternativeFinder.cc \
     18       ResolvExpr/Alternative.cc \
     19       ResolvExpr/Unify.cc \
     20       ResolvExpr/PtrsAssignable.cc \
     21       ResolvExpr/CommonType.cc \
     22       ResolvExpr/ConversionCost.cc \
     23       ResolvExpr/CastCost.cc \
     24       ResolvExpr/PtrsCastable.cc \
     25       ResolvExpr/AdjustExprType.cc \
     26       ResolvExpr/AlternativePrinter.cc \
     27       ResolvExpr/Resolver.cc \
     28       ResolvExpr/ResolveTypeof.cc \
     29       ResolvExpr/RenameVars.cc \
     30       ResolvExpr/FindOpenVars.cc \
     31       ResolvExpr/PolyCost.cc \
     32       ResolvExpr/Occurs.cc \
     33       ResolvExpr/TypeEnvironment.cc \
     34       ResolvExpr/CurrentObject.cc \
     35       ResolvExpr/ExplodedActual.cc \
     36       ResolvExpr/SpecCost.cc \
     37       ResolvExpr/ResolveAssertions.cc
  • src/ResolvExpr/typeops.h

    r933f32f r6a9d4b4  
    1010// Created On       : Sun May 17 07:28:22 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  8 09:30:34 2019
    13 // Update Count     : 4
     12// Last Modified On : Sat Jul 22 09:36:18 2017
     13// Update Count     : 3
    1414//
    1515
     
    1818#include <vector>
    1919
    20 #include "AST/Node.hpp"
    21 #include "AST/Type.hpp"
    2220#include "SynTree/SynTree.h"
    2321#include "SynTree/Type.h"
     
    10199        /// creates the type represented by the list of returnVals in a FunctionType. The caller owns the return value.
    102100        Type * extractResultType( FunctionType * functionType );
    103         /// Creates or extracts the type represented by the list of returns in a `FunctionType`.
    104         ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
    105101
    106102        // in CommonType.cc
    107         Type * commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
     103        Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
    108104
    109105        // in PolyCost.cc
  • src/SymTab/Indexer.cc

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:37:33 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Fri Mar  8 13:55:00 2019
    13 // Update Count     : 21
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Aug 17 16:08:40 2017
     13// Update Count     : 20
    1414//
    1515
     
    1717
    1818#include <cassert>                 // for assert, strict_dynamic_cast
     19#include <iostream>                // for operator<<, basic_ostream, ostream
    1920#include <string>                  // for string, operator<<, operator!=
    20 #include <memory>                  // for shared_ptr, make_shared
    2121#include <unordered_map>           // for operator!=, unordered_map<>::const...
    2222#include <unordered_set>           // for unordered_set
    2323#include <utility>                 // for pair, make_pair, move
    24 #include <vector>                  // for vector
    2524
    2625#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
    2726#include "Common/SemanticError.h"  // for SemanticError
    2827#include "Common/utility.h"        // for cloneAll
    29 #include "Common/Stats/Counter.h"  // for counters
    30 #include "GenPoly/GenPoly.h"       // for getFunctionType
     28#include "GenPoly/GenPoly.h"
    3129#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    3230#include "Mangler.h"               // for Mangler
     
    4038#include "SynTree/Type.h"          // for Type, StructInstType, UnionInstType
    4139
     40#define debugPrint(x) if ( doDebug ) { std::cerr << x; }
     41
    4242namespace SymTab {
    43 
    44         // Statistics block
    45         namespace {
    46                 static inline auto stats() {
    47                         using namespace Stats::Counters;
    48                         static auto group   = build<CounterGroup>("Indexers");
    49                         static struct {
    50                                 SimpleCounter * count;
    51                                 AverageCounter<double> * size;
    52                                 SimpleCounter * new_scopes;
    53                                 SimpleCounter * lazy_scopes;
    54                                 AverageCounter<double> * avg_scope_depth;
    55                                 MaxCounter<size_t> * max_scope_depth;
    56                                 SimpleCounter * add_calls;
    57                                 SimpleCounter * lookup_calls;
    58                                 SimpleCounter * map_lookups;
    59                                 SimpleCounter * map_mutations;
    60                         } ret = {
    61                                 .count   = build<SimpleCounter>("Count", group),
    62                                 .size    = build<AverageCounter<double>>("Average Size", group),
    63                                 .new_scopes = build<SimpleCounter>("Scopes", group),
    64                                 .lazy_scopes = build<SimpleCounter>("Lazy Scopes", group),
    65                                 .avg_scope_depth = build<AverageCounter<double>>("Average Scope", group),
    66                                 .max_scope_depth = build<MaxCounter<size_t>>("Max Scope", group),
    67                                 .add_calls = build<SimpleCounter>("Add Calls", group),
    68                                 .lookup_calls = build<SimpleCounter>("Lookup Calls", group),
    69                                 .map_lookups = build<SimpleCounter>("Map Lookups", group),
    70                                 .map_mutations = build<SimpleCounter>("Map Mutations", group)
     43        std::ostream & operator<<( std::ostream & out, const Indexer::IdData & data ) {
     44                return out << "(" << data.id << "," << data.baseExpr << ")";
     45        }
     46
     47        typedef std::unordered_map< std::string, Indexer::IdData > MangleTable;
     48        typedef std::unordered_map< std::string, MangleTable > IdTable;
     49        typedef std::unordered_map< std::string, NamedTypeDecl* > TypeTable;
     50        typedef std::unordered_map< std::string, StructDecl* > StructTable;
     51        typedef std::unordered_map< std::string, EnumDecl* > EnumTable;
     52        typedef std::unordered_map< std::string, UnionDecl* > UnionTable;
     53        typedef std::unordered_map< std::string, TraitDecl* > TraitTable;
     54
     55        void dump( const IdTable &table, std::ostream &os ) {
     56                for ( IdTable::const_iterator id = table.begin(); id != table.end(); ++id ) {
     57                        for ( MangleTable::const_iterator mangle = id->second.begin(); mangle != id->second.end(); ++mangle ) {
     58                                os << mangle->second << std::endl;
     59                        }
     60                }
     61        }
     62
     63        template< typename Decl >
     64        void dump( const std::unordered_map< std::string, Decl* > &table, std::ostream &os ) {
     65                for ( typename std::unordered_map< std::string, Decl* >::const_iterator it = table.begin(); it != table.end(); ++it ) {
     66                        os << it->second << std::endl;
     67                } // for
     68        }
     69
     70        struct Indexer::Impl {
     71                Impl( unsigned long _scope ) : refCount(1), scope( _scope ), size( 0 ), base(),
     72                                idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
     73                Impl( unsigned long _scope, Indexer &&_base ) : refCount(1), scope( _scope ), size( 0 ), base( _base ),
     74                                idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
     75                unsigned long refCount;   ///< Number of references to these tables
     76                unsigned long scope;      ///< Scope these tables are associated with
     77                unsigned long size;       ///< Number of elements stored in this table
     78                const Indexer base;       ///< Base indexer this extends
     79
     80                IdTable idTable;          ///< Identifier namespace
     81                TypeTable typeTable;      ///< Type namespace
     82                StructTable structTable;  ///< Struct namespace
     83                EnumTable enumTable;      ///< Enum namespace
     84                UnionTable unionTable;    ///< Union namespace
     85                TraitTable traitTable;    ///< Trait namespace
     86        };
     87
     88        Indexer::Impl *Indexer::newRef( Indexer::Impl *toClone ) {
     89                if ( ! toClone ) return 0;
     90
     91                // shorten the search chain by skipping empty links
     92                Indexer::Impl *ret = toClone->size == 0 ? toClone->base.tables : toClone;
     93                if ( ret ) { ++ret->refCount; }
     94
     95                return ret;
     96        }
     97
     98        void Indexer::deleteRef( Indexer::Impl *toFree ) {
     99                if ( ! toFree ) return;
     100
     101                if ( --toFree->refCount == 0 ) delete toFree;
     102        }
     103
     104        void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const {
     105                // only need to perform this step for constructors, destructors, and assignment functions
     106                if ( ! CodeGen::isCtorDtorAssign( id ) ) return;
     107
     108                // helpful data structure to organize properties for a type
     109                struct ValueType {
     110                        struct DeclBall { // properties for this particular decl
     111                                IdData decl;
     112                                bool isUserDefinedFunc;
     113                                bool isCopyFunc;
    71114                        };
    72                         return ret;
    73                 }
    74         }
    75 
    76         Indexer::Indexer()
    77         : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
    78           prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
     115                        // properties for this type
     116                        bool existsUserDefinedCopyFunc = false;    // user-defined copy ctor found
     117                        BaseSyntaxNode * deleteStmt = nullptr;     // non-null if a user-defined function is found
     118                        std::list< DeclBall > decls;
     119
     120                        // another FunctionDecl for the current type was found - determine
     121                        // if it has special properties and update data structure accordingly
     122                        ValueType & operator+=( IdData data ) {
     123                                DeclarationWithType * function = data.id;
     124                                bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
     125                                bool isCopyFunc = InitTweak::isCopyFunction( function, function->name );
     126                                decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } );
     127                                existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc);
     128                                if ( isUserDefinedFunc && ! deleteStmt ) {
     129                                        // any user-defined function can act as an implicit delete statement for generated constructors.
     130                                        // a delete stmt should not act as an implicit delete statement.
     131                                        deleteStmt = data.id;
     132                                }
     133                                return *this;
     134                        }
     135                }; // ValueType
     136
     137                std::list< IdData > copy;
     138                copy.splice( copy.end(), out );
     139
     140                // organize discovered declarations by type
     141                std::unordered_map< std::string, ValueType > funcMap;
     142                for ( auto decl : copy ) {
     143                        if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) {
     144                                std::list< DeclarationWithType * > & params = function->type->parameters;
     145                                assert( ! params.empty() );
     146                                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
     147                                Type * base = InitTweak::getPointerBase( params.front()->get_type() );
     148                                assert( base );
     149                                funcMap[ Mangler::mangle( base ) ] += decl;
     150                        } else {
     151                                out.push_back( decl );
     152                        }
     153                }
     154
     155                // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine
     156                // the set of ctor/dtor/assign that can be used  by the requester. In particular, if the user defines
     157                // a default ctor, then the generated default ctor is unavailable, likewise for copy ctor
     158                // and dtor. If the user defines any ctor/dtor, then no generated field ctors are available.
     159                // If the user defines any ctor then the generated default ctor is unavailable (intrinsic default
     160                // ctor must be overridden exactly). If the user defines anything that looks like a copy constructor,
     161                // then the generated copy constructor is unavailable, and likewise for the assignment operator.
     162                for ( std::pair< const std::string, ValueType > & pair : funcMap ) {
     163                        ValueType & val = pair.second;
     164                        for ( ValueType::DeclBall ball : val.decls ) {
     165                                bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic;
     166                                bool isCopyFunc = ball.isCopyFunc;
     167                                bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc;
     168
     169                                // only implicitly delete non-user defined functions that are not intrinsic, and are
     170                                // not copy functions (assignment or copy constructor). If a  user-defined copy function exists,
     171                                // do not pass along the non-user-defined copy functions since signatures do not have to match,
     172                                // and the generated functions will often be cheaper.
     173                                if ( isNotUserDefinedFunc ) {
     174                                        if ( isCopyFunc ) {
     175                                                // Skip over non-user-defined copy functions when there is a user-defined copy function.
     176                                                // Since their signatures do not have to be exact, deleting them is the wrong choice.
     177                                                if ( existsUserDefinedCopyFunc ) continue;
     178                                        } else {
     179                                                // delete non-user-defined non-copy functions if applicable.
     180                                                // deleteStmt will be non-null only if a user-defined function is found.
     181                                                ball.decl.deleteStmt = val.deleteStmt;
     182                                        }
     183                                }
     184                                out.push_back( ball.decl );
     185                        }
     186                }
     187        }
     188
     189        void Indexer::makeWritable() {
     190                if ( ! tables ) {
     191                        // create indexer if not yet set
     192                        tables = new Indexer::Impl( scope );
     193                } else if ( tables->refCount > 1 || tables->scope != scope ) {
     194                        // make this indexer the base of a fresh indexer at the current scope
     195                        tables = new Indexer::Impl( scope, std::move( *this ) );
     196                }
     197        }
     198
     199        Indexer::Indexer() : tables( 0 ), scope( 0 ) {}
     200
     201        Indexer::Indexer( const Indexer &that ) : doDebug( that.doDebug ), tables( newRef( that.tables ) ), scope( that.scope ) {}
     202
     203        Indexer::Indexer( Indexer &&that ) : doDebug( that.doDebug ), tables( that.tables ), scope( that.scope ) {
     204                that.tables = 0;
     205        }
    79206
    80207        Indexer::~Indexer() {
    81                 stats().size->push( idTable ? idTable->size() : 0 );
    82         }
    83 
    84         void Indexer::lazyInitScope() {
    85                 if ( repScope < scope ) {
    86                         ++*stats().lazy_scopes;
    87                         // create rollback
    88                         prevScope = std::make_shared<Indexer>( *this );
    89                         // update repScope
    90                         repScope = scope;
    91                 }
    92         }
    93 
    94         void Indexer::enterScope() {
    95                 ++scope;
    96 
    97                 ++*stats().new_scopes;
    98                 stats().avg_scope_depth->push( scope );
    99                 stats().max_scope_depth->push( scope );
    100         }
    101 
    102         void Indexer::leaveScope() {
    103                 if ( repScope == scope ) {
    104                         Ptr prev = prevScope;           // make sure prevScope stays live
    105                         *this = std::move(*prevScope);  // replace with previous scope
    106                 }
    107 
    108                 --scope;
     208                deleteRef( tables );
     209        }
     210
     211        Indexer& Indexer::operator= ( const Indexer &that ) {
     212                deleteRef( tables );
     213
     214                tables = newRef( that.tables );
     215                scope = that.scope;
     216                doDebug = that.doDebug;
     217
     218                return *this;
     219        }
     220
     221        Indexer& Indexer::operator= ( Indexer &&that ) {
     222                deleteRef( tables );
     223
     224                tables = that.tables;
     225                scope = that.scope;
     226                doDebug = that.doDebug;
     227
     228                that.tables = 0;
     229
     230                return *this;
    109231        }
    110232
    111233        void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
    112                 ++*stats().lookup_calls;
    113                 if ( ! idTable ) return;
    114 
    115                 ++*stats().map_lookups;
    116                 auto decls = idTable->find( id );
    117                 if ( decls == idTable->end() ) return;
    118 
    119                 for ( auto decl : *(decls->second) ) {
    120                         out.push_back( decl.second );
    121                 }
     234                std::unordered_set< std::string > foundMangleNames;
     235
     236                Indexer::Impl *searchTables = tables;
     237                while ( searchTables ) {
     238
     239                        IdTable::const_iterator decls = searchTables->idTable.find( id );
     240                        if ( decls != searchTables->idTable.end() ) {
     241                                const MangleTable &mangleTable = decls->second;
     242                                for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
     243                                        // mark the mangled name as found, skipping this insertion if a declaration for that name has already been found
     244                                        if ( foundMangleNames.insert( decl->first ).second == false ) continue;
     245
     246                                        out.push_back( decl->second );
     247                                }
     248                        }
     249
     250                        // get declarations from base indexers
     251                        searchTables = searchTables->base.tables;
     252                }
     253
     254                // some special functions, e.g. constructors and destructors
     255                // remove autogenerated functions when they are defined so that
     256                // they can never be matched
     257                removeSpecialOverrides( id, out );
    122258        }
    123259
    124260        NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
    125                 ++*stats().lookup_calls;
    126                 if ( ! typeTable ) return nullptr;
    127                 ++*stats().map_lookups;
    128                 auto it = typeTable->find( id );
    129                 return it == typeTable->end() ? nullptr : it->second.decl;
     261                if ( ! tables ) return 0;
     262
     263                TypeTable::const_iterator ret = tables->typeTable.find( id );
     264                return ret != tables->typeTable.end() ? ret->second : tables->base.lookupType( id );
    130265        }
    131266
    132267        StructDecl *Indexer::lookupStruct( const std::string &id ) const {
    133                 ++*stats().lookup_calls;
    134                 if ( ! structTable ) return nullptr;
    135                 ++*stats().map_lookups;
    136                 auto it = structTable->find( id );
    137                 return it == structTable->end() ? nullptr : it->second.decl;
     268                if ( ! tables ) return 0;
     269
     270                StructTable::const_iterator ret = tables->structTable.find( id );
     271                return ret != tables->structTable.end() ? ret->second : tables->base.lookupStruct( id );
     272        }
     273
     274        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
     275                return lookupTypeAtScope( id, 0 );
     276        }
     277
     278        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
     279                return lookupStructAtScope( id, 0 );
     280        }
     281
     282        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
     283                return lookupUnionAtScope( id, 0 );
     284        }
     285
     286        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
     287                return lookupEnumAtScope( id, 0 );
    138288        }
    139289
    140290        EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
    141                 ++*stats().lookup_calls;
    142                 if ( ! enumTable ) return nullptr;
    143                 ++*stats().map_lookups;
    144                 auto it = enumTable->find( id );
    145                 return it == enumTable->end() ? nullptr : it->second.decl;
     291                if ( ! tables ) return 0;
     292
     293                EnumTable::const_iterator ret = tables->enumTable.find( id );
     294                return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnum( id );
    146295        }
    147296
    148297        UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
    149                 ++*stats().lookup_calls;
    150                 if ( ! unionTable ) return nullptr;
    151                 ++*stats().map_lookups;
    152                 auto it = unionTable->find( id );
    153                 return it == unionTable->end() ? nullptr : it->second.decl;
     298                if ( ! tables ) return 0;
     299
     300                UnionTable::const_iterator ret = tables->unionTable.find( id );
     301                return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnion( id );
    154302        }
    155303
    156304        TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
    157                 ++*stats().lookup_calls;
    158                 if ( ! traitTable ) return nullptr;
    159                 ++*stats().map_lookups;
    160                 auto it = traitTable->find( id );
    161                 return it == traitTable->end() ? nullptr : it->second.decl;
    162         }
    163 
    164         const Indexer* Indexer::atScope( unsigned long target ) const {
    165                 // by lazy construction, final indexer in list has repScope 0, cannot be > target
    166                 // otherwise, will find first scope representing the target
    167                 const Indexer* indexer = this;
    168                 while ( indexer->repScope > target ) {
    169                         indexer = indexer->prevScope.get();
    170                 }
    171                 return indexer;
    172         }
    173 
    174         NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
    175                 return atScope( 0 )->lookupType( id );
    176         }
    177 
    178         StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
    179                 return atScope( 0 )->lookupStruct( id );
    180         }
    181 
    182         UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
    183                 return atScope( 0 )->lookupUnion( id );
    184         }
    185 
    186         EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
    187                 return atScope( 0 )->lookupEnum( id );
     305                if ( ! tables ) return 0;
     306
     307                TraitTable::const_iterator ret = tables->traitTable.find( id );
     308                return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTrait( id );
     309        }
     310
     311        const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
     312                if ( ! tables ) return nullptr;
     313                if ( tables->scope < scope ) return nullptr;
     314
     315                IdTable::const_iterator decls = tables->idTable.find( id );
     316                if ( decls != tables->idTable.end() ) {
     317                        const MangleTable &mangleTable = decls->second;
     318                        MangleTable::const_iterator decl = mangleTable.find( mangleName );
     319                        if ( decl != mangleTable.end() ) return &decl->second;
     320                }
     321
     322                return tables->base.lookupIdAtScope( id, mangleName, scope );
     323        }
     324
     325        Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) {
     326                return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope ));
     327        }
     328
     329        bool Indexer::hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
     330                if ( ! tables ) return false;
     331                if ( tables->scope < scope ) return false;
     332
     333                IdTable::const_iterator decls = tables->idTable.find( id );
     334                if ( decls != tables->idTable.end() ) {
     335                        const MangleTable &mangleTable = decls->second;
     336                        for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
     337                                // check for C decls with the same name, skipping those with a compatible type (by mangleName)
     338                                if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first != mangleName ) return true;
     339                        }
     340                }
     341
     342                return tables->base.hasIncompatibleCDecl( id, mangleName, scope );
     343        }
     344
     345        bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
     346                if ( ! tables ) return false;
     347                if ( tables->scope < scope ) return false;
     348
     349                IdTable::const_iterator decls = tables->idTable.find( id );
     350                if ( decls != tables->idTable.end() ) {
     351                        const MangleTable &mangleTable = decls->second;
     352                        for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
     353                                // check for C decls with the same name, skipping
     354                                // those with an incompatible type (by mangleName)
     355                                if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first == mangleName ) return true;
     356                        }
     357                }
     358
     359                return tables->base.hasCompatibleCDecl( id, mangleName, scope );
     360        }
     361
     362        NamedTypeDecl *Indexer::lookupTypeAtScope( const std::string &id, unsigned long scope ) const {
     363                if ( ! tables ) return 0;
     364                if ( tables->scope < scope ) return 0;
     365                if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope );
     366
     367                TypeTable::const_iterator ret = tables->typeTable.find( id );
     368                return ret != tables->typeTable.end() ? ret->second : tables->base.lookupTypeAtScope( id, scope );
     369        }
     370
     371        StructDecl *Indexer::lookupStructAtScope( const std::string &id, unsigned long scope ) const {
     372                if ( ! tables ) return 0;
     373                if ( tables->scope < scope ) return 0;
     374                if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope );
     375
     376                StructTable::const_iterator ret = tables->structTable.find( id );
     377                return ret != tables->structTable.end() ? ret->second : tables->base.lookupStructAtScope( id, scope );
     378        }
     379
     380        EnumDecl *Indexer::lookupEnumAtScope( const std::string &id, unsigned long scope ) const {
     381                if ( ! tables ) return 0;
     382                if ( tables->scope < scope ) return 0;
     383                if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope );
     384
     385                EnumTable::const_iterator ret = tables->enumTable.find( id );
     386                return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnumAtScope( id, scope );
     387        }
     388
     389        UnionDecl *Indexer::lookupUnionAtScope( const std::string &id, unsigned long scope ) const {
     390                if ( ! tables ) return 0;
     391                if ( tables->scope < scope ) return 0;
     392                if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope );
     393
     394                UnionTable::const_iterator ret = tables->unionTable.find( id );
     395                return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnionAtScope( id, scope );
     396        }
     397
     398        TraitDecl *Indexer::lookupTraitAtScope( const std::string &id, unsigned long scope ) const {
     399                if ( ! tables ) return 0;
     400                if ( tables->scope < scope ) return 0;
     401                if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope );
     402
     403                TraitTable::const_iterator ret = tables->traitTable.find( id );
     404                return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTraitAtScope( id, scope );
    188405        }
    189406
     
    207424        }
    208425
    209        
    210         bool Indexer::addedIdConflicts(
    211                         const Indexer::IdData & existing, DeclarationWithType *added,
    212                         Indexer::OnConflict handleConflicts, BaseSyntaxNode * deleteStmt ) {
    213                 // if we're giving the same name mangling to things of different types then there is
    214                 // something wrong
     426        bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) {
     427                // if we're giving the same name mangling to things of different types then there is something wrong
    215428                assert( (isObject( added ) && isObject( existing.id ) )
    216429                        || ( isFunction( added ) && isFunction( existing.id ) ) );
    217430
    218                 if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
     431                if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
    219432                        // new definition shadows the autogenerated one, even at the same scope
    220433                        return false;
    221                 } else if ( LinkageSpec::isMangled( added->linkage )
    222                                 || ResolvExpr::typesCompatible(
    223                                         added->get_type(), existing.id->get_type(), Indexer() ) ) {
     434                } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) {
    224435
    225436                        // it is a conflict if one declaration is deleted and the other is not
    226437                        if ( deleteStmt && ! existing.deleteStmt ) {
    227                                 if ( handleConflicts.mode == OnConflict::Error ) {
    228                                         SemanticError( added, "deletion of defined identifier " );
    229                                 }
    230                                 return true;
     438                                return handleConflicts( existing, "deletion of defined identifier " );
    231439                        } else if ( ! deleteStmt && existing.deleteStmt ) {
    232                                 if ( handleConflicts.mode == OnConflict::Error ) {
    233                                         SemanticError( added, "definition of deleted identifier " );
    234                                 }
    235                                 return true;
     440                                return handleConflicts( existing, "definition of deleted identifier " );
    236441                        }
    237442
    238443                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    239                                 if ( handleConflicts.mode == OnConflict::Error ) {
    240                                         SemanticError( added,
    241                                                 isFunction( added ) ?
    242                                                         "duplicate function definition for " :
    243                                                         "duplicate object definition for " );
    244                                 }
    245                                 return true;
     444                                if ( isFunction( added ) ) {
     445                                        return handleConflicts( existing, "duplicate function definition for " );
     446                                } else {
     447                                        return handleConflicts( existing, "duplicate object definition for " );
     448                                } // if
    246449                        } // if
    247450                } else {
    248                         if ( handleConflicts.mode == OnConflict::Error ) {
    249                                 SemanticError( added, "duplicate definition for " );
    250                         }
    251                         return true;
     451                        return handleConflicts( existing, "duplicate definition for " );
    252452                } // if
    253453
     
    255455        }
    256456
    257         bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const {
    258                 if ( ! idTable ) return false;
    259 
    260                 ++*stats().map_lookups;
    261                 auto decls = idTable->find( id );
    262                 if ( decls == idTable->end() ) return false;
    263 
    264                 for ( auto decl : *(decls->second) ) {
    265                         // skip other scopes (hidden by this decl)
    266                         if ( decl.second.scope != scope ) continue;
    267                         // check for C decl with compatible type (by mangleName)
    268                         if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first == mangleName ) {
    269                                 return true;
    270                         }
    271                 }
    272                
    273                 return false;
    274         }
    275 
    276         bool Indexer::hasIncompatibleCDecl(
    277                         const std::string &id, const std::string &mangleName ) const {
    278                 if ( ! idTable ) return false;
    279 
    280                 ++*stats().map_lookups;
    281                 auto decls = idTable->find( id );
    282                 if ( decls == idTable->end() ) return false;
    283 
    284                 for ( auto decl : *(decls->second) ) {
    285                         // skip other scopes (hidden by this decl)
    286                         if ( decl.second.scope != scope ) continue;
    287                         // check for C decl with incompatible type (by manglename)
    288                         if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first != mangleName ) {
    289                                 return true;
    290                         }
    291                 }
    292 
    293                 return false;
    294         }
    295 
    296         /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
    297         std::string getOtypeKey( FunctionDecl* function ) {
    298                 auto& params = function->type->parameters;
    299                 assert( ! params.empty() );
    300                 // use base type of pointer, so that qualifiers on the pointer type aren't considered.
    301                 Type* base = InitTweak::getPointerBase( params.front()->get_type() );
    302                 assert( base );
    303                 return Mangler::mangle( base );
    304         }
    305 
    306         /// gets the declaration for the function acting on a type specified by otype key,
    307         /// nullptr if none such
    308         FunctionDecl * getFunctionForOtype( DeclarationWithType * decl, const std::string& otypeKey ) {
    309                 FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl );
    310                 if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;
    311                 return func;
    312         }
    313 
    314         bool Indexer::removeSpecialOverrides(
    315                         Indexer::IdData& data, Indexer::MangleTable::Ptr& mangleTable ) {
    316                 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which
    317                 // determinethe set of ctor/dtor/assign that can be used  by the requester. In particular,
    318                 // if the user defines a default ctor, then the generated default ctor is unavailable,
    319                 // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated
    320                 // field ctors are available. If the user defines any ctor then the generated default ctor
    321                 // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines
    322                 // anything that looks like a copy constructor, then the generated copy constructor is
    323                 // unavailable, and likewise for the assignment operator.
    324 
    325                 // only relevant on function declarations
    326                 FunctionDecl * function = dynamic_cast< FunctionDecl * >( data.id );
    327                 if ( ! function ) return true;
    328                 // only need to perform this check for constructors, destructors, and assignment functions
    329                 if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true;
    330 
    331                 // set up information for this type
    332                 bool dataIsUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
    333                 bool dataIsCopyFunc = InitTweak::isCopyFunction( function, function->name );
    334                 std::string dataOtypeKey = getOtypeKey( function );
    335 
    336                 if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
    337                         // this is a user-defined copy function
    338                         // if this is the first such, delete/remove non-user-defined overloads as needed
    339                         std::vector< std::string > removed;
    340                         std::vector< MangleTable::value_type > deleted;
    341                         bool alreadyUserDefinedFunc = false;
    342                        
    343                         for ( const auto& entry : *mangleTable ) {
    344                                 // skip decls that aren't functions or are for the wrong type
    345                                 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
    346                                 if ( ! decl ) continue;
    347 
    348                                 bool isCopyFunc = InitTweak::isCopyFunction( decl, decl->name );
    349                                 if ( ! LinkageSpec::isOverridable( decl->linkage ) ) {
    350                                         // matching user-defined function
    351                                         if ( isCopyFunc ) {
    352                                                 // mutation already performed, return early
    353                                                 return true;
    354                                         } else {
    355                                                 // note that non-copy deletions already performed
    356                                                 alreadyUserDefinedFunc = true;
    357                                         }
    358                                 } else {
    359                                         // non-user-defined function; mark for deletion/removal as appropriate
    360                                         if ( isCopyFunc ) {
    361                                                 removed.push_back( entry.first );
    362                                         } else if ( ! alreadyUserDefinedFunc ) {
    363                                                 deleted.push_back( entry );
    364                                         }
    365                                 }
    366                         }
    367 
    368                         // perform removals from mangle table, and deletions if necessary
    369                         for ( const auto& key : removed ) {
    370                                 ++*stats().map_mutations;
    371                                 mangleTable = mangleTable->erase( key );
    372                         }
    373                         if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) {
    374                                 ++*stats().map_mutations;
    375                                 mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
    376                         }
    377                 } else if ( dataIsUserDefinedFunc ) {
    378                         // this is a user-defined non-copy function
    379                         // if this is the first user-defined function, delete non-user-defined overloads
    380                         std::vector< MangleTable::value_type > deleted;
    381                        
    382                         for ( const auto& entry : *mangleTable ) {
    383                                 // skip decls that aren't functions or are for the wrong type
    384                                 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
    385                                 if ( ! decl ) continue;
    386 
    387                                 // exit early if already a matching user-defined function;
    388                                 // earlier function will have mutated table
    389                                 if ( ! LinkageSpec::isOverridable( decl->linkage ) ) return true;
    390 
    391                                 // skip mutating intrinsic functions
    392                                 if ( decl->linkage == LinkageSpec::Intrinsic ) continue;
    393 
    394                                 // user-defined non-copy functions do not override copy functions
    395                                 if ( InitTweak::isCopyFunction( decl, decl->name ) ) continue;
    396 
    397                                 // this function to be deleted after mangleTable iteration is complete
    398                                 deleted.push_back( entry );
    399                         }
    400 
    401                         // mark deletions to update mangle table
    402                         // this needs to be a separate loop because of iterator invalidation
    403                         for ( const auto& entry : deleted ) {
    404                                 ++*stats().map_mutations;
    405                                 mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
    406                         }
    407                 } else if ( function->linkage != LinkageSpec::Intrinsic ) {
    408                         // this is an overridable generated function
    409                         // if there already exists a matching user-defined function, delete this appropriately
    410                         for ( const auto& entry : *mangleTable ) {
    411                                 // skip decls that aren't functions or are for the wrong type
    412                                 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
    413                                 if ( ! decl ) continue;
    414 
    415                                 // skip non-user-defined functions
    416                                 if ( LinkageSpec::isOverridable( decl->linkage ) ) continue;
    417 
    418                                 if ( dataIsCopyFunc ) {
    419                                         // remove current function if exists a user-defined copy function
    420                                         // since the signatures for copy functions don't need to match exactly, using
    421                                         // a delete statement is the wrong approach
    422                                         if ( InitTweak::isCopyFunction( decl, decl->name ) ) return false;
    423                                 } else {
    424                                         // mark current function deleted by first user-defined function found
    425                                         data.deleteStmt = decl;
    426                                         return true;
    427                                 }
    428                         }
    429                 }
    430                
    431                 // nothing (more) to fix, return true
    432                 return true;
    433         }
    434 
    435         void Indexer::addId(
    436                         DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr,
    437                         BaseSyntaxNode * deleteStmt ) {
    438                 ++*stats().add_calls;
     457        void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) {
     458                if ( decl->name == "" ) return;
     459                debugPrint( "Adding Id " << decl->name << std::endl );
     460                makeWritable();
     461
    439462                const std::string &name = decl->name;
    440                 if ( name == "" ) return;
    441                
    442463                std::string mangleName;
    443464                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
    444                         // mangle the name without including the appropriate suffix, so overridable routines
    445                         // are placed into the same "bucket" as their user defined versions.
     465                        // mangle the name without including the appropriate suffix, so overridable routines are placed into the
     466                        // same "bucket" as their user defined versions.
    446467                        mangleName = Mangler::mangle( decl, false );
    447468                } else {
     
    449470                } // if
    450471
    451                 // this ensures that no two declarations with the same unmangled name at the same scope
    452                 // both have C linkage
    453                 if ( LinkageSpec::isMangled( decl->linkage ) ) {
     472                // this ensures that no two declarations with the same unmangled name at the same scope both have C linkage
     473                if ( ! LinkageSpec::isMangled( decl->linkage ) ) {
     474                        // NOTE this is broken in Richard's original code in such a way that it never triggers (it
     475                        // doesn't check decls that have the same manglename, and all C-linkage decls are defined to
     476                        // have their name as their manglename, hence the error can never trigger).
     477                        // The code here is closer to correct, but name mangling would have to be completely
     478                        // isomorphic to C type-compatibility, which it may not be.
     479                        if ( hasIncompatibleCDecl( name, mangleName, scope ) ) {
     480                                SemanticError( decl, "conflicting overload of C function " );
     481                        }
     482                } else {
    454483                        // Check that a Cforall declaration doesn't override any C declaration
    455                         if ( hasCompatibleCDecl( name, mangleName ) ) {
     484                        if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
    456485                                SemanticError( decl, "Cforall declaration hides C function " );
    457486                        }
    458                 } else {
    459                         // NOTE: only correct if name mangling is completely isomorphic to C
    460                         // type-compatibility, which it may not be.
    461                         if ( hasIncompatibleCDecl( name, mangleName ) ) {
    462                                 SemanticError( decl, "conflicting overload of C function " );
    463                         }
    464                 }
    465 
    466                 // ensure tables exist and add identifier
    467                 MangleTable::Ptr mangleTable;
    468                 if ( ! idTable ) {
    469                         idTable = IdTable::new_ptr();
    470                         mangleTable = MangleTable::new_ptr();
    471                 } else {
    472                         ++*stats().map_lookups;
    473                         auto decls = idTable->find( name );
    474                         if ( decls == idTable->end() ) {
    475                                 mangleTable = MangleTable::new_ptr();
    476                         } else {
    477                                 mangleTable = decls->second;
    478                                 // skip in-scope repeat declarations of same identifier
    479                                 ++*stats().map_lookups;
    480                                 auto existing = mangleTable->find( mangleName );
    481                                 if ( existing != mangleTable->end()
    482                                                 && existing->second.scope == scope
    483                                                 && existing->second.id ) {
    484                                         if ( addedIdConflicts( existing->second, decl, handleConflicts, deleteStmt ) ) {
    485                                                 if ( handleConflicts.mode == OnConflict::Delete ) {
    486                                                         // set delete expression for conflicting identifier
    487                                                         lazyInitScope();
    488                                                         *stats().map_mutations += 2;
    489                                                         idTable = idTable->set(
    490                                                                 name,
    491                                                                 mangleTable->set(
    492                                                                         mangleName,
    493                                                                         IdData{ existing->second, handleConflicts.deleteStmt } ) );
    494                                                 }
    495                                                 return;
    496                                         }
    497                                 }
    498                         }
    499                 }
    500 
    501                 // add/overwrite with new identifier
    502                 lazyInitScope();
    503                 IdData data{ decl, baseExpr, deleteStmt, scope };
    504                 // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary
    505                 if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
    506                 *stats().map_mutations += 2;
    507                 idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );
     487                }
     488
     489                // Skip repeat declarations of the same identifier
     490                IdData * existing = lookupIdAtScope( name, mangleName, scope );
     491                if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return;
     492
     493                // add to indexer
     494                tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt };
     495                ++tables->size;
    508496        }
    509497
    510498        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
    511499                // default handling of conflicts is to raise an error
    512                 addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     500                addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );
    513501        }
    514502
    515503        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
    516504                // default handling of conflicts is to raise an error
    517                 addId( decl, OnConflict::error(), nullptr, deleteStmt );
     505                addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
    518506        }
    519507
     
    530518                        }
    531519                }
    532                 // does not need to be added to the table if both existing and added have a base that are
    533                 // the same
     520                // does not need to be added to the table if both existing and added have a base that are the same
    534521                return true;
    535522        }
    536523
    537524        void Indexer::addType( NamedTypeDecl *decl ) {
    538                 ++*stats().add_calls;
     525                debugPrint( "Adding type " << decl->name << std::endl );
     526                makeWritable();
     527
    539528                const std::string &id = decl->name;
    540 
    541                 if ( ! typeTable ) {
    542                         typeTable = TypeTable::new_ptr();
    543                 } else {
    544                         ++*stats().map_lookups;
    545                         auto existing = typeTable->find( id );
    546                         if ( existing != typeTable->end()
    547                                 && existing->second.scope == scope
    548                                 && addedTypeConflicts( existing->second.decl, decl ) ) return;
    549                 }
    550                
    551                 lazyInitScope();
    552                 ++*stats().map_mutations;
    553                 typeTable = typeTable->set( id, Scoped<NamedTypeDecl>{ decl, scope } );
     529                TypeTable::iterator existing = tables->typeTable.find( id );
     530                if ( existing == tables->typeTable.end() ) {
     531                        NamedTypeDecl *parent = tables->base.lookupTypeAtScope( id, scope );
     532                        if ( ! parent || ! addedTypeConflicts( parent, decl ) ) {
     533                                tables->typeTable.insert( existing, std::make_pair( id, decl ) );
     534                                ++tables->size;
     535                        }
     536                } else {
     537                        if ( ! addedTypeConflicts( existing->second, decl ) ) {
     538                                existing->second = decl;
     539                        }
     540                }
    554541        }
    555542
     
    564551
    565552        void Indexer::addStruct( const std::string &id ) {
     553                debugPrint( "Adding fwd decl for struct " << id << std::endl );
    566554                addStruct( new StructDecl( id ) );
    567555        }
    568556
    569557        void Indexer::addStruct( StructDecl *decl ) {
    570                 ++*stats().add_calls;
     558                debugPrint( "Adding struct " << decl->name << std::endl );
     559                makeWritable();
     560
    571561                const std::string &id = decl->name;
    572 
    573                 if ( ! structTable ) {
    574                         structTable = StructTable::new_ptr();
    575                 } else {
    576                         ++*stats().map_lookups;
    577                         auto existing = structTable->find( id );
    578                         if ( existing != structTable->end() 
    579                                 && existing->second.scope == scope
    580                                 && addedDeclConflicts( existing->second.decl, decl ) ) return;
    581                 }
    582 
    583                 lazyInitScope();
    584                 ++*stats().map_mutations;
    585                 structTable = structTable->set( id, Scoped<StructDecl>{ decl, scope } );
     562                StructTable::iterator existing = tables->structTable.find( id );
     563                if ( existing == tables->structTable.end() ) {
     564                        StructDecl *parent = tables->base.lookupStructAtScope( id, scope );
     565                        if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
     566                                tables->structTable.insert( existing, std::make_pair( id, decl ) );
     567                                ++tables->size;
     568                        }
     569                } else {
     570                        if ( ! addedDeclConflicts( existing->second, decl ) ) {
     571                                existing->second = decl;
     572                        }
     573                }
    586574        }
    587575
    588576        void Indexer::addEnum( EnumDecl *decl ) {
    589                 ++*stats().add_calls;
     577                debugPrint( "Adding enum " << decl->name << std::endl );
     578                makeWritable();
     579
    590580                const std::string &id = decl->name;
    591 
    592                 if ( ! enumTable ) {
    593                         enumTable = EnumTable::new_ptr();
    594                 } else {
    595                         ++*stats().map_lookups;
    596                         auto existing = enumTable->find( id );
    597                         if ( existing != enumTable->end() 
    598                                 && existing->second.scope == scope
    599                                 && addedDeclConflicts( existing->second.decl, decl ) ) return;
    600                 }
    601                
    602                 lazyInitScope();
    603                 ++*stats().map_mutations;
    604                 enumTable = enumTable->set( id, Scoped<EnumDecl>{ decl, scope } );
     581                EnumTable::iterator existing = tables->enumTable.find( id );
     582                if ( existing == tables->enumTable.end() ) {
     583                        EnumDecl *parent = tables->base.lookupEnumAtScope( id, scope );
     584                        if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
     585                                tables->enumTable.insert( existing, std::make_pair( id, decl ) );
     586                                ++tables->size;
     587                        }
     588                } else {
     589                        if ( ! addedDeclConflicts( existing->second, decl ) ) {
     590                                existing->second = decl;
     591                        }
     592                }
    605593        }
    606594
    607595        void Indexer::addUnion( const std::string &id ) {
     596                debugPrint( "Adding fwd decl for union " << id << std::endl );
    608597                addUnion( new UnionDecl( id ) );
    609598        }
    610599
    611600        void Indexer::addUnion( UnionDecl *decl ) {
    612                 ++*stats().add_calls;
     601                debugPrint( "Adding union " << decl->name << std::endl );
     602                makeWritable();
     603
    613604                const std::string &id = decl->name;
    614 
    615                 if ( ! unionTable ) {
    616                         unionTable = UnionTable::new_ptr();
    617                 } else {
    618                         ++*stats().map_lookups;
    619                         auto existing = unionTable->find( id );
    620                         if ( existing != unionTable->end()
    621                                 && existing->second.scope == scope
    622                                 && addedDeclConflicts( existing->second.decl, decl ) ) return;
    623                 }
    624 
    625                 lazyInitScope();
    626                 ++*stats().map_mutations;
    627                 unionTable = unionTable->set( id, Scoped<UnionDecl>{ decl, scope } );
     605                UnionTable::iterator existing = tables->unionTable.find( id );
     606                if ( existing == tables->unionTable.end() ) {
     607                        UnionDecl *parent = tables->base.lookupUnionAtScope( id, scope );
     608                        if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
     609                                tables->unionTable.insert( existing, std::make_pair( id, decl ) );
     610                                ++tables->size;
     611                        }
     612                } else {
     613                        if ( ! addedDeclConflicts( existing->second, decl ) ) {
     614                                existing->second = decl;
     615                        }
     616                }
    628617        }
    629618
    630619        void Indexer::addTrait( TraitDecl *decl ) {
    631                 ++*stats().add_calls;
     620                debugPrint( "Adding trait " << decl->name << std::endl );
     621                makeWritable();
     622
    632623                const std::string &id = decl->name;
    633 
    634                 if ( ! traitTable ) {
    635                         traitTable = TraitTable::new_ptr();
    636                 } else {
    637                         ++*stats().map_lookups;
    638                         auto existing = traitTable->find( id );
    639                         if ( existing != traitTable->end()
    640                                 && existing->second.scope == scope
    641                                 && addedDeclConflicts( existing->second.decl, decl ) ) return;
    642                 }
    643 
    644                 lazyInitScope();
    645                 ++*stats().map_mutations;
    646                 traitTable = traitTable->set( id, Scoped<TraitDecl>{ decl, scope } );
    647         }
    648 
    649         void Indexer::addMembers( AggregateDecl * aggr, Expression * expr,
    650                         OnConflict handleConflicts ) {
     624                TraitTable::iterator existing = tables->traitTable.find( id );
     625                if ( existing == tables->traitTable.end() ) {
     626                        TraitDecl *parent = tables->base.lookupTraitAtScope( id, scope );
     627                        if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
     628                                tables->traitTable.insert( existing, std::make_pair( id, decl ) );
     629                                ++tables->size;
     630                        }
     631                } else {
     632                        if ( ! addedDeclConflicts( existing->second, decl ) ) {
     633                                existing->second = decl;
     634                        }
     635                }
     636        }
     637
     638        void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) {
    651639                for ( Declaration * decl : aggr->members ) {
    652640                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     
    654642                                if ( dwt->name == "" ) {
    655643                                        Type * t = dwt->get_type()->stripReferences();
    656                                         if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {
     644                                        if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
    657645                                                Expression * base = expr->clone();
    658646                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
     
    671659                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
    672660
    673                                 addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
     661                                addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
     662                                        // on conflict, delete the identifier
     663                                        existing.deleteStmt = withStmt;
     664                                        return true;
     665                                });
    674666                        }
    675667                }
     
    693685                addIds( ftype->returnVals );
    694686                addIds( ftype->parameters );
     687        }
     688
     689        void Indexer::enterScope() {
     690                ++scope;
     691
     692                if ( doDebug ) {
     693                        std::cerr << "--- Entering scope " << scope << std::endl;
     694                }
     695        }
     696
     697        void Indexer::leaveScope() {
     698                using std::cerr;
     699
     700                assert( scope > 0 && "cannot leave initial scope" );
     701                if ( doDebug ) {
     702                        cerr << "--- Leaving scope " << scope << " containing" << std::endl;
     703                }
     704                --scope;
     705
     706                while ( tables && tables->scope > scope ) {
     707                        if ( doDebug ) {
     708                                dump( tables->idTable, cerr );
     709                                dump( tables->typeTable, cerr );
     710                                dump( tables->structTable, cerr );
     711                                dump( tables->enumTable, cerr );
     712                                dump( tables->unionTable, cerr );
     713                                dump( tables->traitTable, cerr );
     714                        }
     715
     716                        // swap tables for base table until we find one at an appropriate scope
     717                        Indexer::Impl *base = newRef( tables->base.tables );
     718                        deleteRef( tables );
     719                        tables = base;
     720                }
     721        }
     722
     723        void Indexer::print( std::ostream &os, int indent ) const {
     724                using std::cerr;
     725
     726                if ( tables ) {
     727                        os << "--- scope " << tables->scope << " ---" << std::endl;
     728
     729                        os << "===idTable===" << std::endl;
     730                        dump( tables->idTable, os );
     731                        os << "===typeTable===" << std::endl;
     732                        dump( tables->typeTable, os );
     733                        os << "===structTable===" << std::endl;
     734                        dump( tables->structTable, os );
     735                        os << "===enumTable===" << std::endl;
     736                        dump( tables->enumTable, os );
     737                        os << "===unionTable===" << std::endl;
     738                        dump( tables->unionTable, os );
     739                        os << "===contextTable===" << std::endl;
     740                        dump( tables->traitTable, os );
     741
     742                        tables->base.print( os, indent );
     743                } else {
     744                        os << "--- end ---" << std::endl;
     745                }
     746
    695747        }
    696748
  • src/SymTab/Indexer.h

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:38:55 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Fri Mar  8 13:55:00 2019
    13 // Update Count     : 9
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Aug 17 16:09:12 2017
     13// Update Count     : 8
    1414//
    1515
    1616#pragma once
    1717
    18 #include <functional>              // for function
    19 #include <list>                    // for list
    20 #include <memory>                  // for shared_ptr, enable_shared_from_this
    21 #include <string>                  // for string
     18#include <iosfwd>             // for ostream
     19#include <list>               // for list
     20#include <string>             // for string
     21#include <functional>         // for function
    2222
    23 #include "Common/PersistentMap.h"  // for PersistentMap
    24 #include "SynTree/SynTree.h"       // for AST nodes
     23#include "SynTree/Visitor.h"  // for Visitor
     24#include "SynTree/SynTree.h"  // for AST nodes
    2525
    2626namespace ResolvExpr {
    27         class Cost;
     27class Cost;
    2828}
    2929
    3030namespace SymTab {
    31         class Indexer : public std::enable_shared_from_this<SymTab::Indexer> {
    32         public:
     31        class Indexer {
     32          public:
    3333                explicit Indexer();
     34
     35                Indexer( const Indexer &that );
     36                Indexer( Indexer &&that );
    3437                virtual ~Indexer();
     38                Indexer& operator= ( const Indexer &that );
     39                Indexer& operator= ( Indexer &&that );
    3540
    36                 // when using an indexer manually (e.g., within a mutator traversal), it is necessary to
    37                 // tell the indexer explicitly when scopes begin and end
     41                // when using an indexer manually (e.g., within a mutator traversal), it is necessary to tell the indexer
     42                // explicitly when scopes begin and end
    3843                void enterScope();
    3944                void leaveScope();
     
    4550                        /// non-null if this declaration is deleted
    4651                        BaseSyntaxNode * deleteStmt = nullptr;
    47                         /// scope of identifier
    48                         unsigned long scope = 0;
    4952
    5053                        // NOTE: shouldn't need either of these constructors, but gcc-4 does not properly support initializer lists with default members.
    5154                        IdData() = default;
    52                         IdData(
    53                                 DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt,
    54                                 unsigned long scope )
    55                                 : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ), scope( scope ) {}
    56                         IdData( const IdData& o, BaseSyntaxNode * deleteStmt )
    57                                 : id( o.id ), baseExpr( o.baseExpr ), deleteStmt( deleteStmt ), scope( o.scope ) {}
     55                        IdData( DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ) {}
    5856
    5957                        Expression * combine( ResolvExpr::Cost & cost ) const;
     
    8280                EnumDecl *globalLookupEnum( const std::string &id ) const;
    8381
     82                void print( std::ostream &os, int indent = 0 ) const;
     83
     84                /// looks up a specific mangled ID at the given scope
     85                IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope );
     86                const IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
     87                /// returns true if there exists a declaration with C linkage and the given name with a different mangled name
     88                bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
     89                /// returns true if there exists a declaration with C linkage and the given name with the same mangled name
     90                bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
     91                // equivalents to lookup functions that only look at tables at scope `scope` (which should be >= tables->scope)
     92                NamedTypeDecl *lookupTypeAtScope( const std::string &id, unsigned long scope ) const;
     93                StructDecl *lookupStructAtScope( const std::string &id, unsigned long scope ) const;
     94                EnumDecl *lookupEnumAtScope( const std::string &id, unsigned long scope ) const;
     95                UnionDecl *lookupUnionAtScope( const std::string &id, unsigned long scope ) const;
     96                TraitDecl *lookupTraitAtScope( const std::string &id, unsigned long scope ) const;
     97
     98                typedef std::function<bool(IdData &, const std::string &)> ConflictFunction;
     99
    84100                void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr );
    85101                void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt );
     
    96112                void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt );
    97113
     114                /// adds all of the members of the Aggregate (addWith helper)
     115                void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction );
     116
    98117                /// convenience function for adding a list of Ids to the indexer
    99118                void addIds( const std::list< DeclarationWithType * > & decls );
     
    105124                void addFunctionType( FunctionType * ftype );
    106125
     126                bool doDebug = false; ///< Display debugging trace?
    107127          private:
    108                 /// Wraps a Decl* with a scope
    109                 template<typename Decl>
    110                 struct Scoped {
    111                         Decl* decl;           ///< declaration
    112                         unsigned long scope;  ///< scope of this declaration
     128                struct Impl;
    113129
    114                         Scoped(Decl* d, unsigned long s) : decl(d), scope(s) {}
    115                 };
     130                Impl *tables;         ///< Copy-on-write instance of table data structure
     131                unsigned long scope;  ///< Scope index of this pointer
    116132
    117                 using Ptr = std::shared_ptr<const Indexer>;
     133                /// Takes a new ref to a table (returns null if null)
     134                static Impl *newRef( Impl *toClone );
     135                /// Clears a ref to a table (does nothing if null)
     136                static void deleteRef( Impl *toFree );
    118137
    119                 using MangleTable = PersistentMap< std::string, IdData >;
    120                 using IdTable = PersistentMap< std::string, MangleTable::Ptr >;
    121                 using TypeTable = PersistentMap< std::string, Scoped<NamedTypeDecl> >;
    122                 using StructTable = PersistentMap< std::string, Scoped<StructDecl> >;
    123                 using EnumTable = PersistentMap< std::string, Scoped<EnumDecl> >;
    124                 using UnionTable = PersistentMap< std::string, Scoped<UnionDecl> >;
    125                 using TraitTable = PersistentMap< std::string, Scoped<TraitDecl> >;
     138                // Removes matching autogenerated constructors and destructors
     139                // so that they will not be selected
     140                // void removeSpecialOverrides( FunctionDecl *decl );
     141                void removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const;
    126142
    127                 IdTable::Ptr idTable;          ///< identifier namespace
    128                 TypeTable::Ptr typeTable;      ///< type namespace
    129                 StructTable::Ptr structTable;  ///< struct namespace
    130                 EnumTable::Ptr enumTable;      ///< enum namespace
    131                 UnionTable::Ptr unionTable;    ///< union namespace
    132                 TraitTable::Ptr traitTable;    ///< trait namespace
    133 
    134                 Ptr prevScope;                 ///< reference to indexer for parent scope
    135                 unsigned long scope;           ///< Scope index of this indexer
    136                 unsigned long repScope;        ///< Scope index of currently represented scope
    137 
    138                 /// Ensures that a proper backtracking scope exists before a mutation
    139                 void lazyInitScope();
    140 
    141                 /// Gets the indexer at the given scope
    142                 const Indexer* atScope( unsigned long scope ) const;
    143 
    144                 /// Removes matching autogenerated constructors and destructors so that they will not be
    145                 /// selected. If returns false, passed decl should not be added.
    146                 bool removeSpecialOverrides( IdData& decl, MangleTable::Ptr& mangleTable );
    147 
    148                 /// Options for handling identifier conflicts
    149                 struct OnConflict {
    150                         enum {
    151                                 Error,  ///< Throw a semantic error
    152                                 Delete  ///< Delete the earlier version with the delete statement
    153                         } mode;
    154                         BaseSyntaxNode * deleteStmt;  ///< Statement that deletes this expression
    155 
    156                 private:
    157                         OnConflict() : mode(Error), deleteStmt(nullptr) {}
    158                         OnConflict( BaseSyntaxNode * d ) : mode(Delete), deleteStmt(d) {}
    159                 public:
    160                         OnConflict( const OnConflict& ) = default;
    161 
    162                         static OnConflict error() { return {}; }
    163                         static OnConflict deleteWith( BaseSyntaxNode * d ) { return { d }; }
    164                 };
    165 
    166                 /// true if the existing identifier conflicts with the added identifier
    167                 bool addedIdConflicts(
    168                         const IdData& existing, DeclarationWithType * added, OnConflict handleConflicts,
    169                         BaseSyntaxNode * deleteStmt );
     143                /// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope)
     144                void makeWritable();
    170145
    171146                /// common code for addId, addDeletedId, etc.
    172                 void addId(
    173                         DeclarationWithType * decl, OnConflict handleConflicts,
    174                         Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
    175 
    176                 /// adds all of the members of the Aggregate (addWith helper)
    177                 void addMembers( AggregateDecl * aggr, Expression * expr, OnConflict handleConflicts );
    178 
    179                 /// returns true if there exists a declaration with C linkage and the given name with the same mangled name
    180                 bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
    181                 /// returns true if there exists a declaration with C linkage and the given name with a different mangled name
    182                 bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
     147                void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
    183148        };
    184149} // namespace SymTab
  • src/SymTab/Mangler.cc

    r933f32f r6a9d4b4  
    3838                        struct Mangler : public WithShortCircuiting, public WithVisitorRef<Mangler>, public WithGuards {
    3939                                Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
     40                                Mangler( const ResolvExpr::TypeEnvironment& env );
    4041                                Mangler( const Mangler & ) = delete;
    4142
     
    6667                          private:
    6768                                std::ostringstream mangleName;  ///< Mangled name being constructed
    68                                 typedef std::map< std::string, std::pair< int, int > > VarMapType;
     69                                typedef std::map< std::string, std::pair< std::string, int > > VarMapType;
    6970                                VarMapType varNums;             ///< Map of type variables to indices
    7071                                int nextVarNum;                 ///< Next type variable index
     72                                const ResolvExpr::TypeEnvironment* env;  ///< optional environment for substitutions
    7173                                bool isTopLevel;                ///< Is the Mangler at the top level
    7274                                bool mangleOverridable;         ///< Specially mangle overridable built-in methods
     
    7880                          public:
    7981                                Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    80                                         int nextVarNum, const VarMapType& varNums );
     82                                        int nextVarNum, const ResolvExpr::TypeEnvironment* env,
     83                                        const VarMapType& varNums );
    8184
    8285                          private:
     
    106109                }
    107110
     111                std::string mangleAssnKey( DeclarationWithType* decl,
     112                                const ResolvExpr::TypeEnvironment& env ) {
     113                        PassVisitor<Mangler> mangler( env );
     114                        maybeAccept( decl, mangler );
     115                        return mangler.pass.get_mangleName();
     116                }
     117
    108118                namespace {
    109119                        Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams )
    110                                 : nextVarNum( 0 ), isTopLevel( true ),
     120                                : nextVarNum( 0 ), env(nullptr), isTopLevel( true ),
    111121                                mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    112122                                mangleGenericParams( mangleGenericParams ) {}
    113123                       
     124                        Mangler::Mangler( const ResolvExpr::TypeEnvironment& env )
     125                                : nextVarNum( 0 ), env( &env ), isTopLevel( true ), mangleOverridable( false ),
     126                                typeMode( false ), mangleGenericParams( true ) {}
     127                       
    114128                        Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    115                                 int nextVarNum, const VarMapType& varNums )
    116                                 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
     129                                int nextVarNum, const ResolvExpr::TypeEnvironment* env,
     130                                const VarMapType& varNums )
     131                                : varNums( varNums ), nextVarNum( nextVarNum ), env( env ), isTopLevel( false ),
    117132                                mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    118133                                mangleGenericParams( mangleGenericParams ) {}
     
    343358                                                        assert( false );
    344359                                                } // switch
    345                                                 varNums[ (*i)->name ] = std::make_pair( nextVarNum, (int)(*i)->get_kind() );
     360                                                std::string varName;
     361                                                // replace type with substitution name if environment is available and bound
     362                                                if ( env ) {
     363                                                        const ResolvExpr::EqvClass* varClass = env->lookup( (*i)->name );
     364                                                        if ( varClass && varClass->type ) {
     365                                                                PassVisitor<Mangler> sub_mangler(
     366                                                                        mangleOverridable, typeMode, mangleGenericParams, nextVarNum,
     367                                                                        env, varNums );
     368                                                                varClass->type->accept( sub_mangler );
     369                                                                varName = std::string{"%"} + sub_mangler.pass.get_mangleName();
     370                                                        }
     371                                                }
     372                                                // otherwise just give type numeric name
     373                                                if ( varName.empty() ) {
     374                                                        varName = std::to_string( nextVarNum++ );
     375                                                }
     376                                                varNums[ (*i)->name ] = std::make_pair( varName, (int)(*i)->get_kind() );
    346377                                                for ( std::list< DeclarationWithType* >::iterator assert = (*i)->assertions.begin(); assert != (*i)->assertions.end(); ++assert ) {
    347378                                                        PassVisitor<Mangler> sub_mangler(
    348                                                                 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
     379                                                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, env,
     380                                                                varNums );
    349381                                                        (*assert)->accept( sub_mangler );
    350382                                                        assertionNames.push_back( sub_mangler.pass.get_mangleName() );
  • src/SymTab/Mangler.h

    r933f32f r6a9d4b4  
    4444                /// Mangle ignoring generic type parameters
    4545                std::string mangleConcrete( Type* ty );
     46                /// Mangle for assertion key
     47                std::string mangleAssnKey( DeclarationWithType* decl,
     48                        const ResolvExpr::TypeEnvironment& env );
    4649
    4750                namespace Encoding {
  • src/SymTab/ManglerCommon.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Sun May 17 21:44:03 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 14 17:06:37 2019
    13 // Update Count     : 26
     12// Last Modified On : Sat Jul 22 09:45:30 2017
     13// Update Count     : 15
    1414//
    1515
     
    2323                        const std::string manglePrefix = "_X";
    2424
    25                         // GENERATED START, DO NOT EDIT
    26                         // GENERATED BY BasicTypes-gen.cc
    27                         // NOTES ON MANGLING:
    28                         // * Itanium spec says that Float80 encodes to "e" (like LongDouble), but the distinct lengths cause resolution problems.
    29                         // * Float128 is supposed to encode to "g", but I wanted it to mangle equal to LongDouble.
    30                         // * Mangling for non-standard complex types is by best guess
    31                         // * _FloatN is supposed to encode as "DF"N"_"; modified for same reason as above.
    32                         // * unused mangling identifiers:
    33                         //   - "z" ellipsis
    34                         //   - "Dd" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x)
    35                         //   - "De" IEEE 754r 128-bit decimal floating point
    36                         //   - "Df" IEEE 754r 32-bit decimal floating point
    37                         //   - "Dh" IEEE 754r 16-bit decimal floating point (borrowed for _Float16)
    38                         //   - "DF"N"_" ISO/IEC TS 18661 N-bit binary floating point (_FloatN)
    39                         //   - "Di" char32_t
    40                         //   - "Ds" char16_t
    41                         const std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = {
    42                                 "b",        // _Bool
    43                                 "c",        // char
    44                                 "a",        // signed char
    45                                 "h",        // unsigned char
    46                                 "s",        // signed short int
    47                                 "t",        // unsigned short int
    48                                 "i",        // signed int
    49                                 "j",        // unsigned int
    50                                 "l",        // signed long int
    51                                 "m",        // unsigned long int
    52                                 "x",        // signed long long int
    53                                 "y",        // unsigned long long int
    54                                 "n",        // __int128
    55                                 "o",        // unsigned __int128
    56                                 "DF16_",    // _Float16
    57                                 "CDF16_",   // _Float16 _Complex
    58                                 "DF32_",    // _Float32
    59                                 "CDF32_",   // _Float32 _Complex
    60                                 "f",        // float
    61                                 "Cf",       // float _Complex
    62                                 "DF32x_",   // _Float32x
    63                                 "CDF32x_",  // _Float32x _Complex
    64                                 "DF64_",    // _Float64
    65                                 "CDF64_",   // _Float64 _Complex
    66                                 "d",        // double
    67                                 "Cd",       // double _Complex
    68                                 "DF64x_",   // _Float64x
    69                                 "CDF64x_",  // _Float64x _Complex
    70                                 "Dq",       // __float80
    71                                 "DF128_",   // _Float128
    72                                 "CDF128_",  // _Float128 _Complex
    73                                 "g",        // __float128
    74                                 "e",        // long double
    75                                 "Ce",       // long double _Complex
    76                                 "DF128x_",  // _Float128x
    77                                 "CDF128x_", // _Float128x _Complex
    78                         }; // basicTypes
    79                         // GENERATED END
     25                        const std::string basicTypes[] = {
     26                                "b",  // Bool
     27                                "c",  // Char
     28                                "a",  // SignedChar
     29                                "h",  // UnsignedChar
     30                                "s",  // ShortSignedInt
     31                                "t",  // ShortUnsignedInt
     32                                "i",  // SignedInt
     33                                "j",  // UnsignedInt
     34                                "l",  // LongSignedInt
     35                                "m",  // LongUnsignedInt
     36                                "x",  // LongLongSignedInt
     37                                "y",  // LongLongUnsignedInt
     38                                "f",  // Float
     39                                "d",  // Double
     40                                "e",  // LongDouble
     41                                "Cf", // FloatComplex
     42                                "Cd", // DoubleComplex
     43                                "Ce", // LongDoubleComplex
     44                                // Note: imaginary is not an overloadable type in C++
     45                                "If", // FloatImaginary
     46                                "Id", // DoubleImaginary
     47                                "Ie", // LongDoubleImaginary
     48                                "n",  // SignedInt128
     49                                "o",  // UnsignedInt128
     50                                "Dq",  // Float80 -- TODO: itanium says Float80 and LongDouble both encode to "e", but doing this causes problems with constructing long double, because the cost tables are incorrect
     51                                "g",  // Float128
     52                                // "z", // ellipsis
     53                                // "Dd" // # IEEE 754r decimal floating point (64 bits)
     54                                // "De" // # IEEE 754r decimal floating point (128 bits)
     55                                // "Df" // # IEEE 754r decimal floating point (32 bits)
     56                                // "Dh" // # IEEE 754r half-precision floating point (16 bits)
     57                                // "DF"N_ // # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
     58                                // "Di" // char32_t
     59                                // "Ds" // char16_t
     60                        };
    8061                        static_assert(
    8162                                sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES,
  • src/SymTab/Validate.cc

    r933f32f r6a9d4b4  
    4949#include "CodeGen/OperatorTable.h"     // for isCtorDtor, isCtorDtorAssign
    5050#include "ControlStruct/Mutate.h"      // for ForExprMutator
    51 #include "Common/Stats.h"              // for Stats::Heap
    5251#include "Common/PassVisitor.h"        // for PassVisitor, WithDeclsToAdd
    5352#include "Common/ScopedMap.h"          // for ScopedMap
     
    299298                PassVisitor<FixQualifiedTypes> fixQual;
    300299
    301                 {
    302                         Stats::Heap::newPass("validate-A");
    303                         Stats::Time::BlockGuard guard("validate-A");
    304                         acceptAll( translationUnit, hoistDecls );
    305                         ReplaceTypedef::replaceTypedef( translationUnit );
    306                         ReturnTypeFixer::fix( translationUnit ); // must happen before autogen
    307                         acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes because it is an indexer and needs correct types for mangling
    308                 }
    309                 {
    310                         Stats::Heap::newPass("validate-B");
    311                         Stats::Time::BlockGuard guard("validate-B");
    312                         Stats::Time::TimeBlock("Link Reference To Types", [&]() {
    313                                 acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions
    314                         });
    315                         Stats::Time::TimeBlock("Fix Qualified Types", [&]() {
    316                                 mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes, because aggregate members are accessed
    317                         });
    318                         Stats::Time::TimeBlock("Hoist Structs", [&]() {
    319                                 HoistStruct::hoistStruct( translationUnit ); // must happen after EliminateTypedef, so that aggregate typedefs occur in the correct order
    320                         });
    321                         Stats::Time::TimeBlock("Eliminate Typedefs", [&]() {
    322                                 EliminateTypedef::eliminateTypedef( translationUnit ); //
    323                         });
    324                 }
    325                 {
    326                         Stats::Heap::newPass("validate-C");
    327                         Stats::Time::BlockGuard guard("validate-C");
    328                         acceptAll( translationUnit, genericParams );  // check as early as possible - can't happen before LinkReferenceToTypes
    329                         VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
    330                         ReturnChecker::checkFunctionReturns( translationUnit );
    331                         InitTweak::fixReturnStatements( translationUnit ); // must happen before autogen
    332                 }
    333                 {
    334                         Stats::Heap::newPass("validate-D");
    335                         Stats::Time::BlockGuard guard("validate-D");
    336                         Stats::Time::TimeBlock("Apply Concurrent Keywords", [&]() {
    337                                 Concurrency::applyKeywords( translationUnit );
    338                         });
    339                         Stats::Time::TimeBlock("Forall Pointer Decay", [&]() {
    340                                 acceptAll( translationUnit, fpd ); // must happen before autogenerateRoutines, after Concurrency::applyKeywords because uniqueIds must be set on declaration before resolution
    341                         });
    342                         Stats::Time::TimeBlock("Hoist Control Declarations", [&]() {
    343                                 ControlStruct::hoistControlDecls( translationUnit );  // hoist initialization out of for statements; must happen before autogenerateRoutines
    344                         });
    345                         Stats::Time::TimeBlock("Generate Autogen routines", [&]() {
    346                                 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay
    347                         });
    348                 }
    349                 {
    350                         Stats::Heap::newPass("validate-E");
    351                         Stats::Time::BlockGuard guard("validate-E");
    352                         Stats::Time::TimeBlock("Implement Mutex Func", [&]() {
    353                                 Concurrency::implementMutexFuncs( translationUnit );
    354                         });
    355                         Stats::Time::TimeBlock("Implement Thread Start", [&]() {
    356                                 Concurrency::implementThreadStarter( translationUnit );
    357                         });
    358                         Stats::Time::TimeBlock("Compound Literal", [&]() {
    359                                 mutateAll( translationUnit, compoundliteral );
    360                         });
    361                         Stats::Time::TimeBlock("Resolve With Expressions", [&]() {
    362                                 ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables
    363                         });
    364                 }
    365                 {
    366                         Stats::Heap::newPass("validate-F");
    367                         Stats::Time::BlockGuard guard("validate-F");
    368                         Stats::Time::TimeBlock("Fix Object Type", [&]() {
    369                                 FixObjectType::fix( translationUnit );
    370                         });
    371                         Stats::Time::TimeBlock("Array Length", [&]() {
    372                                 ArrayLength::computeLength( translationUnit );
    373                         });
    374                         Stats::Time::TimeBlock("Find Special Declarations", [&]() {
    375                                 Validate::findSpecialDecls( translationUnit );
    376                         });
    377                         Stats::Time::TimeBlock("Fix Label Address", [&]() {
    378                                 mutateAll( translationUnit, labelAddrFixer );
    379                         });
    380                         Stats::Time::TimeBlock("Handle Attributes", [&]() {
    381                                 Validate::handleAttributes( translationUnit );
    382                         });
    383                 }
     300                acceptAll( translationUnit, hoistDecls );
     301                ReplaceTypedef::replaceTypedef( translationUnit );
     302                ReturnTypeFixer::fix( translationUnit ); // must happen before autogen
     303                acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes because it is an indexer and needs correct types for mangling
     304                acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions
     305                mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes, because aggregate members are accessed
     306                HoistStruct::hoistStruct( translationUnit ); // must happen after EliminateTypedef, so that aggregate typedefs occur in the correct order
     307                EliminateTypedef::eliminateTypedef( translationUnit ); //
     308                acceptAll( translationUnit, genericParams );  // check as early as possible - can't happen before LinkReferenceToTypes
     309                VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
     310                ReturnChecker::checkFunctionReturns( translationUnit );
     311                InitTweak::fixReturnStatements( translationUnit ); // must happen before autogen
     312                Concurrency::applyKeywords( translationUnit );
     313                acceptAll( translationUnit, fpd ); // must happen before autogenerateRoutines, after Concurrency::applyKeywords because uniqueIds must be set on declaration before resolution
     314                ControlStruct::hoistControlDecls( translationUnit );  // hoist initialization out of for statements; must happen before autogenerateRoutines
     315                autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay
     316                Concurrency::implementMutexFuncs( translationUnit );
     317                Concurrency::implementThreadStarter( translationUnit );
     318                mutateAll( translationUnit, compoundliteral );
     319                ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables
     320                FixObjectType::fix( translationUnit );
     321                ArrayLength::computeLength( translationUnit );
     322                Validate::findSpecialDecls( translationUnit );
     323                mutateAll( translationUnit, labelAddrFixer );
     324                Validate::handleAttributes( translationUnit );
    384325        }
    385326
  • src/SymTab/module.mk

    r933f32f r6a9d4b4  
    1515###############################################################################
    1616
    17 SRC_SYMTAB = \
    18       SymTab/Autogen.cc \
    19       SymTab/FixFunction.cc \
    20       SymTab/Indexer.cc \
    21       SymTab/Mangler.cc \
    22       SymTab/ManglerCommon.cc \
    23       SymTab/Validate.cc
    24 
    25 SRC += $(SRC_SYMTAB)
    26 SRCDEMANGLE += $(SRC_SYMTAB) SymTab/Demangle.cc
     17SRC += SymTab/Indexer.cc \
     18       SymTab/Mangler.cc \
     19       SymTab/ManglerCommon.cc \
     20       SymTab/Validate.cc \
     21       SymTab/FixFunction.cc \
     22       SymTab/Autogen.cc
  • src/SynTree/AddressExpr.cc

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 23:54:44 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 28 13:13:38 2019
    13 // Update Count     : 10
     11// Last Modified By : Rob Schluntz
     12// Last Modified On : Tue Apr 26 12:35:13 2016
     13// Update Count     : 6
    1414//
    1515
     
    4747                } else {
    4848                        // taking address of non-lvalue -- must be a reference, loses one layer of reference
    49                         if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( arg->result ) ) {
    50                                 set_result( addrType( refType->base ) );
    51                         } else {
    52                                 SemanticError( arg->result, "Attempt to take address of non-lvalue expression: " );
    53                         } // if
     49                        ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( arg->result );
     50                        set_result( addrType( refType->base ) );
    5451                }
    5552                // result of & is never an lvalue
  • src/SynTree/Attribute.cc

    r933f32f r6a9d4b4  
    2121#include "Expression.h"      // for Expression
    2222
    23 Attribute::Attribute( const Attribute &other ) : BaseSyntaxNode( other ), name( other.name ) {
     23Attribute::Attribute( const Attribute &other ) : name( other.name ) {
    2424        cloneAll( other.parameters, parameters );
    2525}
  • src/SynTree/BaseSyntaxNode.h

    r933f32f r6a9d4b4  
    1818#include "Common/CodeLocation.h"
    1919#include "Common/Indenter.h"
    20 #include "Common/Stats.h"
    21 
    2220class Visitor;
    2321class Mutator;
     
    2523class BaseSyntaxNode {
    2624  public:
    27   static Stats::Counters::SimpleCounter* new_nodes;
    28 
    2925        CodeLocation location;
    30 
    31   BaseSyntaxNode() { ++*new_nodes; }
    32   BaseSyntaxNode( const BaseSyntaxNode& o ) : location(o.location) { ++*new_nodes; }
    3326
    3427        virtual ~BaseSyntaxNode() {}
  • src/SynTree/BasicType.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan 31 21:37:36 2019
    13 // Update Count     : 12
     12// Last Modified On : Mon Sep 25 14:14:03 2017
     13// Update Count     : 11
    1414//
    1515
     
    3030
    3131bool BasicType::isInteger() const {
    32         return kind <= UnsignedInt128;
    33 #if 0
    3432        switch ( kind ) {
    3533          case Bool:
     
    6563        assert( false );
    6664        return false;
    67 #endif
    6865}
    6966
  • src/SynTree/Constant.cc

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 13 18:11:22 2019
    13 // Update Count     : 32
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Spt 28 14:49:00 2018
     13// Update Count     : 30
    1414//
    1515
     
    2525Constant::Constant( Type * type, std::string rep, double val ) : type( type ), rep( rep ), val( val ) {}
    2626
    27 Constant::Constant( const Constant &other ) : BaseSyntaxNode( other ), rep( other.rep ), val( other.val ) {
     27Constant::Constant( const Constant &other ) : rep( other.rep ), val( other.val ) {
    2828        type = other.type->clone();
    2929}
  • src/SynTree/Declaration.cc

    r933f32f r6a9d4b4  
    3131
    3232Declaration::Declaration( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage )
    33                 : name( name ), linkage( linkage ), uniqueId( 0 ), storageClasses( scs ) {
     33                : name( name ), linkage( linkage ), storageClasses( scs ), uniqueId( 0 ) {
    3434}
    3535
    3636Declaration::Declaration( const Declaration &other )
    37         : BaseSyntaxNode( other ), name( other.name ), linkage( other.linkage ), extension( other.extension ), uniqueId( other.uniqueId ), storageClasses( other.storageClasses ) {
     37        : BaseSyntaxNode( other ), name( other.name ), linkage( other.linkage ), extension( other.extension ), storageClasses( other.storageClasses ), uniqueId( other.uniqueId ) {
    3838}
    3939
  • src/SynTree/Declaration.h

    r933f32f r6a9d4b4  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr May  2 10:47:00 2019
    13 // Update Count     : 135
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Sep  3 19:24:06 2017
     13// Update Count     : 131
    1414//
    1515
     
    1919#include <iosfwd>                // for ostream
    2020#include <list>                  // for list
    21 #include <unordered_map>         // for unordered_map
    2221#include <string>                // for string, operator+, allocator, to_string
    2322
     
    7170        static Declaration *declFromId( UniqueId id );
    7271
     72  private:
     73        Type::StorageClasses storageClasses;
    7374        UniqueId uniqueId;
    74         Type::StorageClasses storageClasses;
    75   private:
    7675};
    7776
     
    167166        CompoundStmt *get_statements() const { return statements; }
    168167        void set_statements( CompoundStmt *newValue ) { statements = newValue; }
    169         bool has_body() const { return NULL != statements; }
    170168
    171169        static FunctionDecl * newFunction( const std::string & name, FunctionType * type, CompoundStmt * statements );
     
    213211                TypeDecl::Kind kind;
    214212                bool isComplete;
    215 
    216213                Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {}
    217214                Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {}
    218215                Data( Kind kind, bool isComplete ) : kind( kind ), isComplete( isComplete ) {}
    219                 Data( const Data& d1, const Data& d2 )
    220                 : kind( d1.kind ), isComplete ( d1.isComplete || d2.isComplete ) {}
    221 
    222216                bool operator==(const Data & other) const { return kind == other.kind && isComplete == other.isComplete; }
    223217                bool operator!=(const Data & other) const { return !(*this == other);}
     
    245239        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    246240
     241  private:
    247242        Kind kind;
    248243};
     
    305300        virtual void accept( Visitor &v ) override { v.visit( this ); }
    306301        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     302  private:
    307303        DeclarationNode::Aggregate kind;
    308   private:
    309304        virtual std::string typeString() const override;
    310305};
     
    335330        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    336331  private:
    337         std::unordered_map< std::string, long long int > enumValues;
     332        std::map< std::string, long long int > enumValues;
    338333        virtual std::string typeString() const override;
    339334};
  • src/SynTree/Expression.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 19 18:10:55 2019
    13 // Update Count     : 60
     12// Last Modified On : Tue Jul 25 14:15:47 2017
     13// Update Count     : 54
    1414//
    1515
     
    3333#include "GenPoly/Lvalue.h"
    3434
    35 void printInferParams( const InferredParams & inferParams, std::ostream & os, Indenter indent, int level ) {
     35void printInferParams( const InferredParams & inferParams, std::ostream &os, Indenter indent, int level ) {
    3636        if ( ! inferParams.empty() ) {
    3737                os << indent << "with inferred parameters " << level << ":" << std::endl;
     
    4747Expression::Expression() : result( 0 ), env( 0 ) {}
    4848
    49 Expression::Expression( const Expression & other ) : BaseSyntaxNode( other ), result( maybeClone( other.result ) ), env( maybeClone( other.env ) ), extension( other.extension ), inferParams( other.inferParams ), resnSlots( other.resnSlots ) {}
     49Expression::Expression( const Expression &other ) : BaseSyntaxNode( other ), result( maybeClone( other.result ) ), env( maybeClone( other.env ) ), extension( other.extension ), inferParams( other.inferParams ), resnSlots( other.resnSlots ) {}
    5050
    5151void Expression::spliceInferParams( Expression * other ) {
     
    6262}
    6363
    64 void Expression::print( std::ostream & os, Indenter indent ) const {
     64void Expression::print( std::ostream &os, Indenter indent ) const {
    6565        printInferParams( inferParams, os, indent+1, 0 );
    6666
     
    7979}
    8080
    81 ConstantExpr::ConstantExpr( const ConstantExpr & other) : Expression( other ), constant( other.constant ) {
     81ConstantExpr::ConstantExpr( const ConstantExpr &other) : Expression( other ), constant( other.constant ) {
    8282}
    8383
    8484ConstantExpr::~ConstantExpr() {}
    8585
    86 void ConstantExpr::print( std::ostream & os, Indenter indent ) const {
     86void ConstantExpr::print( std::ostream &os, Indenter indent ) const {
    8787        os << "constant expression " ;
    8888        constant.print( os );
     
    124124}
    125125
    126 VariableExpr::VariableExpr( const VariableExpr & other ) : Expression( other ), var( other.var ) {
     126VariableExpr::VariableExpr( const VariableExpr &other ) : Expression( other ), var( other.var ) {
    127127}
    128128
     
    137137}
    138138
    139 void VariableExpr::print( std::ostream & os, Indenter indent ) const {
     139void VariableExpr::print( std::ostream &os, Indenter indent ) const {
    140140        os << "Variable Expression: ";
    141141        var->printShort(os, indent);
     
    143143}
    144144
    145 SizeofExpr::SizeofExpr( Expression * expr_ ) :
     145SizeofExpr::SizeofExpr( Expression *expr_ ) :
    146146                Expression(), expr(expr_), type(0), isType(false) {
    147147        set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
    148148}
    149149
    150 SizeofExpr::SizeofExpr( Type * type_ ) :
     150SizeofExpr::SizeofExpr( Type *type_ ) :
    151151                Expression(), expr(0), type(type_), isType(true) {
    152152        set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
    153153}
    154154
    155 SizeofExpr::SizeofExpr( const SizeofExpr & other ) :
     155SizeofExpr::SizeofExpr( const SizeofExpr &other ) :
    156156        Expression( other ), expr( maybeClone( other.expr ) ), type( maybeClone( other.type ) ), isType( other.isType ) {
    157157}
     
    162162}
    163163
    164 void SizeofExpr::print( std::ostream & os, Indenter indent) const {
     164void SizeofExpr::print( std::ostream &os, Indenter indent) const {
    165165        os << "Sizeof Expression on: ";
    166166        if (isType) type->print(os, indent+1);
     
    169169}
    170170
    171 AlignofExpr::AlignofExpr( Expression * expr_ ) :
     171AlignofExpr::AlignofExpr( Expression *expr_ ) :
    172172                Expression(), expr(expr_), type(0), isType(false) {
    173173        set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
    174174}
    175175
    176 AlignofExpr::AlignofExpr( Type * type_ ) :
     176AlignofExpr::AlignofExpr( Type *type_ ) :
    177177                Expression(), expr(0), type(type_), isType(true) {
    178178        set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) );
    179179}
    180180
    181 AlignofExpr::AlignofExpr( const AlignofExpr & other ) :
     181AlignofExpr::AlignofExpr( const AlignofExpr &other ) :
    182182        Expression( other ), expr( maybeClone( other.expr ) ), type( maybeClone( other.type ) ), isType( other.isType ) {
    183183}
     
    188188}
    189189
    190 void AlignofExpr::print( std::ostream & os, Indenter indent) const {
     190void AlignofExpr::print( std::ostream &os, Indenter indent) const {
    191191        os << "Alignof Expression on: ";
    192192        if (isType) type->print(os, indent+1);
     
    195195}
    196196
    197 UntypedOffsetofExpr::UntypedOffsetofExpr( Type * type, const std::string & member ) :
     197UntypedOffsetofExpr::UntypedOffsetofExpr( Type *type, const std::string &member ) :
    198198                Expression(), type(type), member(member) {
    199199        assert( type );
     
    201201}
    202202
    203 UntypedOffsetofExpr::UntypedOffsetofExpr( const UntypedOffsetofExpr & other ) :
     203UntypedOffsetofExpr::UntypedOffsetofExpr( const UntypedOffsetofExpr &other ) :
    204204        Expression( other ), type( maybeClone( other.type ) ), member( other.member ) {}
    205205
     
    208208}
    209209
    210 void UntypedOffsetofExpr::print( std::ostream & os, Indenter indent) const {
     210void UntypedOffsetofExpr::print( std::ostream &os, Indenter indent) const {
    211211        os << "Untyped Offsetof Expression on member " << member << " of ";
    212212        type->print(os, indent+1);
     
    214214}
    215215
    216 OffsetofExpr::OffsetofExpr( Type * type, DeclarationWithType * member ) :
     216OffsetofExpr::OffsetofExpr( Type *type, DeclarationWithType *member ) :
    217217                Expression(), type(type), member(member) {
    218218        assert( member );
     
    221221}
    222222
    223 OffsetofExpr::OffsetofExpr( const OffsetofExpr & other ) :
     223OffsetofExpr::OffsetofExpr( const OffsetofExpr &other ) :
    224224        Expression( other ), type( maybeClone( other.type ) ), member( other.member ) {}
    225225
     
    228228}
    229229
    230 void OffsetofExpr::print( std::ostream & os, Indenter indent) const {
     230void OffsetofExpr::print( std::ostream &os, Indenter indent) const {
    231231        os << "Offsetof Expression on member " << member->name << " of ";
    232232        type->print(os, indent+1);
     
    234234}
    235235
    236 OffsetPackExpr::OffsetPackExpr( StructInstType * type ) : Expression(), type( type ) {
     236OffsetPackExpr::OffsetPackExpr( StructInstType *type ) : Expression(), type( type ) {
    237237        assert( type );
    238238        set_result( new ArrayType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), 0, false, false ) );
    239239}
    240240
    241 OffsetPackExpr::OffsetPackExpr( const OffsetPackExpr & other ) : Expression( other ), type( maybeClone( other.type ) ) {}
     241OffsetPackExpr::OffsetPackExpr( const OffsetPackExpr &other ) : Expression( other ), type( maybeClone( other.type ) ) {}
    242242
    243243OffsetPackExpr::~OffsetPackExpr() { delete type; }
    244244
    245 void OffsetPackExpr::print( std::ostream & os, Indenter indent ) const {
     245void OffsetPackExpr::print( std::ostream &os, Indenter indent ) const {
    246246        os << "Offset pack expression on ";
    247247        type->print(os, indent+1);
     
    249249}
    250250
    251 AttrExpr::AttrExpr( Expression * attr, Expression * expr_ ) :
     251AttrExpr::AttrExpr( Expression *attr, Expression *expr_ ) :
    252252                Expression(), attr( attr ), expr(expr_), type(0), isType(false) {
    253253}
    254254
    255 AttrExpr::AttrExpr( Expression * attr, Type * type_ ) :
     255AttrExpr::AttrExpr( Expression *attr, Type *type_ ) :
    256256                Expression(), attr( attr ), expr(0), type(type_), isType(true) {
    257257}
    258258
    259 AttrExpr::AttrExpr( const AttrExpr & other ) :
     259AttrExpr::AttrExpr( const AttrExpr &other ) :
    260260                Expression( other ), attr( maybeClone( other.attr ) ), expr( maybeClone( other.expr ) ), type( maybeClone( other.type ) ), isType( other.isType ) {
    261261}
     
    267267}
    268268
    269 void AttrExpr::print( std::ostream & os, Indenter indent) const {
     269void AttrExpr::print( std::ostream &os, Indenter indent) const {
    270270        os << "Attr ";
    271271        attr->print( os, indent+1);
     
    278278}
    279279
    280 CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) {
     280CastExpr::CastExpr( Expression *arg, Type *toType, bool isGenerated ) : Expression(), arg(arg), isGenerated( isGenerated ) {
    281281        set_result(toType);
    282282}
    283283
    284 CastExpr::CastExpr( Expression * arg, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) {
     284CastExpr::CastExpr( Expression *arg, bool isGenerated ) : Expression(), arg(arg), isGenerated( isGenerated ) {
    285285        set_result( new VoidType( Type::Qualifiers() ) );
    286286}
    287287
    288 CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ) {
     288CastExpr::CastExpr( const CastExpr &other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ) {
    289289}
    290290
     
    293293}
    294294
    295 void CastExpr::print( std::ostream & os, Indenter indent ) const {
    296         os << (isGenerated ? "Generated " : "Explicit ") << "Cast of:" << std::endl << indent+1;
     295void CastExpr::print( std::ostream &os, Indenter indent ) const {
     296        os << "Cast of:" << std::endl << indent+1;
    297297        arg->print(os, indent+1);
    298298        os << std::endl << indent << "... to:";
     
    306306}
    307307
    308 KeywordCastExpr::KeywordCastExpr( Expression * arg, Target target ) : Expression(), arg(arg), target( target ) {
    309 }
    310 
    311 KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {
     308KeywordCastExpr::KeywordCastExpr( Expression *arg, Target target ) : Expression(), arg(arg), target( target ) {
     309}
     310
     311KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr &other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {
    312312}
    313313
     
    327327}
    328328
    329 void KeywordCastExpr::print( std::ostream & os, Indenter indent ) const {
     329void KeywordCastExpr::print( std::ostream &os, Indenter indent ) const {
    330330        os << "Keyword Cast of:" << std::endl << indent+1;
    331331        arg->print(os, indent+1);
     
    335335}
    336336
    337 VirtualCastExpr::VirtualCastExpr( Expression * arg_, Type * toType ) : Expression(), arg(arg_) {
     337VirtualCastExpr::VirtualCastExpr( Expression *arg_, Type *toType ) : Expression(), arg(arg_) {
    338338        set_result(toType);
    339339}
    340340
    341 VirtualCastExpr::VirtualCastExpr( const VirtualCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ) {
     341VirtualCastExpr::VirtualCastExpr( const VirtualCastExpr &other ) : Expression( other ), arg( maybeClone( other.arg ) ) {
    342342}
    343343
     
    346346}
    347347
    348 void VirtualCastExpr::print( std::ostream & os, Indenter indent ) const {
     348void VirtualCastExpr::print( std::ostream &os, Indenter indent ) const {
    349349        os << "Virtual Cast of:" << std::endl << indent+1;
    350350        arg->print(os, indent+1);
     
    359359}
    360360
    361 UntypedMemberExpr::UntypedMemberExpr( Expression * member, Expression * aggregate ) :
     361UntypedMemberExpr::UntypedMemberExpr( Expression * member, Expression *aggregate ) :
    362362                Expression(), member(member), aggregate(aggregate) {
    363363        assert( aggregate );
    364364}
    365365
    366 UntypedMemberExpr::UntypedMemberExpr( const UntypedMemberExpr & other ) :
     366UntypedMemberExpr::UntypedMemberExpr( const UntypedMemberExpr &other ) :
    367367                Expression( other ), member( maybeClone( other.member ) ), aggregate( maybeClone( other.aggregate ) ) {
    368368}
     
    373373}
    374374
    375 void UntypedMemberExpr::print( std::ostream & os, Indenter indent ) const {
     375void UntypedMemberExpr::print( std::ostream &os, Indenter indent ) const {
    376376        os << "Untyped Member Expression, with field: " << std::endl << indent+1;
    377377        member->print(os, indent+1 );
     
    381381}
    382382
    383 MemberExpr::MemberExpr( DeclarationWithType * member, Expression * aggregate ) :
     383MemberExpr::MemberExpr( DeclarationWithType *member, Expression *aggregate ) :
    384384                Expression(), member(member), aggregate(aggregate) {
    385385        assert( member );
     
    395395}
    396396
    397 MemberExpr::MemberExpr( const MemberExpr & other ) :
     397MemberExpr::MemberExpr( const MemberExpr &other ) :
    398398                Expression( other ), member( other.member ), aggregate( maybeClone( other.aggregate ) ) {
    399399}
     
    404404}
    405405
    406 void MemberExpr::print( std::ostream & os, Indenter indent ) const {
     406void MemberExpr::print( std::ostream &os, Indenter indent ) const {
    407407        os << "Member Expression, with field:" << std::endl;
    408408        os << indent+1;
     
    413413}
    414414
    415 UntypedExpr::UntypedExpr( Expression * function, const std::list<Expression *> & args ) :
     415UntypedExpr::UntypedExpr( Expression *function, const std::list<Expression *> &args ) :
    416416                Expression(), function(function), args(args) {}
    417417
    418 UntypedExpr::UntypedExpr( const UntypedExpr & other ) :
     418UntypedExpr::UntypedExpr( const UntypedExpr &other ) :
    419419                Expression( other ), function( maybeClone( other.function ) ) {
    420420        cloneAll( other.args, args );
     
    455455
    456456
    457 void UntypedExpr::print( std::ostream & os, Indenter indent ) const {
     457void UntypedExpr::print( std::ostream &os, Indenter indent ) const {
    458458        os << "Applying untyped:" << std::endl;
    459459        os << indent+1;
     
    469469}
    470470
    471 NameExpr::NameExpr( const NameExpr & other ) : Expression( other ), name( other.name ) {
     471NameExpr::NameExpr( const NameExpr &other ) : Expression( other ), name( other.name ) {
    472472}
    473473
    474474NameExpr::~NameExpr() {}
    475475
    476 void NameExpr::print( std::ostream & os, Indenter indent ) const {
     476void NameExpr::print( std::ostream &os, Indenter indent ) const {
    477477        os << "Name: " << get_name();
    478478        Expression::print( os, indent );
    479479}
    480480
    481 LogicalExpr::LogicalExpr( Expression * arg1_, Expression * arg2_, bool andp ) :
     481LogicalExpr::LogicalExpr( Expression *arg1_, Expression *arg2_, bool andp ) :
    482482                Expression(), arg1(arg1_), arg2(arg2_), isAnd(andp) {
    483483        set_result( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    484484}
    485485
    486 LogicalExpr::LogicalExpr( const LogicalExpr & other ) :
     486LogicalExpr::LogicalExpr( const LogicalExpr &other ) :
    487487                Expression( other ), arg1( maybeClone( other.arg1 ) ), arg2( maybeClone( other.arg2 ) ), isAnd( other.isAnd ) {
    488488}
     
    493493}
    494494
    495 void LogicalExpr::print( std::ostream & os, Indenter indent )const {
     495void LogicalExpr::print( std::ostream &os, Indenter indent )const {
    496496        os << "Short-circuited operation (" << (isAnd ? "and" : "or") << ") on: ";
    497497        arg1->print(os);
     
    504504                Expression(), arg1(arg1), arg2(arg2), arg3(arg3) {}
    505505
    506 ConditionalExpr::ConditionalExpr( const ConditionalExpr & other ) :
     506ConditionalExpr::ConditionalExpr( const ConditionalExpr &other ) :
    507507                Expression( other ), arg1( maybeClone( other.arg1 ) ), arg2( maybeClone( other.arg2 ) ), arg3( maybeClone( other.arg3 ) ) {
    508508}
     
    514514}
    515515
    516 void ConditionalExpr::print( std::ostream & os, Indenter indent ) const {
     516void ConditionalExpr::print( std::ostream &os, Indenter indent ) const {
    517517        os << "Conditional expression on: " << std::endl << indent+1;
    518518        arg1->print( os, indent+1 );
     
    527527
    528528
    529 void AsmExpr::print( std::ostream & os, Indenter indent ) const {
     529void AsmExpr::print( std::ostream &os, Indenter indent ) const {
    530530        os << "Asm Expression: " << std::endl;
    531531        if ( inout ) inout->print( os, indent+1 );
     
    549549}
    550550
    551 void ImplicitCopyCtorExpr::print( std::ostream & os, Indenter indent ) const {
     551void ImplicitCopyCtorExpr::print( std::ostream &os, Indenter indent ) const {
    552552        os <<  "Implicit Copy Constructor Expression: " << std::endl << indent+1;
    553553        callExpr->print( os, indent+1 );
     
    570570}
    571571
    572 void ConstructorExpr::print( std::ostream & os, Indenter indent ) const {
     572void ConstructorExpr::print( std::ostream &os, Indenter indent ) const {
    573573        os <<  "Constructor Expression: " << std::endl << indent+1;
    574574        callExpr->print( os, indent + 2 );
     
    583583}
    584584
    585 CompoundLiteralExpr::CompoundLiteralExpr( const CompoundLiteralExpr & other ) : Expression( other ), initializer( other.initializer->clone() ) {}
     585CompoundLiteralExpr::CompoundLiteralExpr( const CompoundLiteralExpr &other ) : Expression( other ), initializer( other.initializer->clone() ) {}
    586586
    587587CompoundLiteralExpr::~CompoundLiteralExpr() {
     
    589589}
    590590
    591 void CompoundLiteralExpr::print( std::ostream & os, Indenter indent ) const {
     591void CompoundLiteralExpr::print( std::ostream &os, Indenter indent ) const {
    592592        os << "Compound Literal Expression: " << std::endl << indent+1;
    593593        result->print( os, indent+1 );
     
    597597}
    598598
    599 RangeExpr::RangeExpr( Expression * low, Expression * high ) : low( low ), high( high ) {}
    600 RangeExpr::RangeExpr( const RangeExpr & other ) : Expression( other ), low( other.low->clone() ), high( other.high->clone() ) {}
    601 void RangeExpr::print( std::ostream & os, Indenter indent ) const {
     599RangeExpr::RangeExpr( Expression *low, Expression *high ) : low( low ), high( high ) {}
     600RangeExpr::RangeExpr( const RangeExpr &other ) : Expression( other ), low( other.low->clone() ), high( other.high->clone() ) {}
     601void RangeExpr::print( std::ostream &os, Indenter indent ) const {
    602602        os << "Range Expression: ";
    603603        low->print( os, indent );
     
    607607}
    608608
    609 StmtExpr::StmtExpr( CompoundStmt * statements ) : statements( statements ) {
     609StmtExpr::StmtExpr( CompoundStmt *statements ) : statements( statements ) {
    610610        computeResult();
    611611}
    612 StmtExpr::StmtExpr( const StmtExpr & other ) : Expression( other ), statements( other.statements->clone() ) {
     612StmtExpr::StmtExpr( const StmtExpr &other ) : Expression( other ), statements( other.statements->clone() ) {
    613613        cloneAll( other.returnDecls, returnDecls );
    614614        cloneAll( other.dtors, dtors );
     
    639639        }
    640640}
    641 void StmtExpr::print( std::ostream & os, Indenter indent ) const {
     641void StmtExpr::print( std::ostream &os, Indenter indent ) const {
    642642        os << "Statement Expression: " << std::endl << indent+1;
    643643        statements->print( os, indent+1 );
     
    655655
    656656long long UniqueExpr::count = 0;
    657 UniqueExpr::UniqueExpr( Expression * expr, long long idVal ) : expr( expr ), object( nullptr ), var( nullptr ), id( idVal ) {
     657UniqueExpr::UniqueExpr( Expression *expr, long long idVal ) : expr( expr ), object( nullptr ), var( nullptr ), id( idVal ) {
    658658        assert( expr );
    659659        assert( count != -1 );
     
    663663        }
    664664}
    665 UniqueExpr::UniqueExpr( const UniqueExpr & other ) : Expression( other ), expr( maybeClone( other.expr ) ), object( maybeClone( other.object ) ), var( maybeClone( other.var ) ), id( other.id ) {
     665UniqueExpr::UniqueExpr( const UniqueExpr &other ) : Expression( other ), expr( maybeClone( other.expr ) ), object( maybeClone( other.object ) ), var( maybeClone( other.var ) ), id( other.id ) {
    666666}
    667667UniqueExpr::~UniqueExpr() {
     
    670670        delete var;
    671671}
    672 void UniqueExpr::print( std::ostream & os, Indenter indent ) const {
     672void UniqueExpr::print( std::ostream &os, Indenter indent ) const {
    673673        os << "Unique Expression with id:" << id << std::endl << indent+1;
    674674        expr->print( os, indent+1 );
  • src/SynTree/Expression.h

    r933f32f r6a9d4b4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Feb 18 18:29:51 2019
    13 // Update Count     : 49
     12// Last Modified On : Sun Sep  3 19:23:46 2017
     13// Update Count     : 48
    1414//
    1515
     
    195195  public:
    196196        Expression * arg;
    197         bool isGenerated = true; // cast generated implicitly by code generation or explicit in program
     197        bool isGenerated = true; // whether this cast appeared in the source program
    198198
    199199        CastExpr( Expression * arg, bool isGenerated = true );
  • src/SynTree/Label.h

    r933f32f r6a9d4b4  
    3535        operator std::string() const { return name; }
    3636        bool empty() { return name.empty(); }
    37 
     37  private:
    3838        std::string name;
    3939        Statement * labelled;
  • src/SynTree/Mutator.h

    r933f32f r6a9d4b4  
    121121        virtual Initializer * mutate( ConstructorInit * ctorInit ) = 0 ;
    122122
     123        virtual Subrange * mutate( Subrange * subrange ) = 0;
     124
    123125        virtual Constant * mutate( Constant * constant ) = 0;
    124126
  • src/SynTree/Statement.h

    r933f32f r6a9d4b4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 12 09:01:53 2019
    13 // Update Count     : 83
     12// Last Modified On : Thu Mar  8 14:53:02 2018
     13// Update Count     : 78
    1414//
    1515
     
    1919#include <list>                    // for list
    2020#include <memory>                  // for allocator
    21 #include <vector>                                  // for vector
     21#include <vector>                        // for vector
    2222
    2323#include "BaseSyntaxNode.h"        // for BaseSyntaxNode
     
    4343        const std::list<Label> & get_labels() const { return labels; }
    4444
    45         virtual Statement * clone() const override = 0;
    46         virtual void accept( Visitor & v ) override = 0;
    47         virtual Statement * acceptMutator( Mutator & m ) override = 0;
    48         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     45        virtual Statement *clone() const override = 0;
     46        virtual void accept( Visitor &v ) override = 0;
     47        virtual Statement *acceptMutator( Mutator &m ) override = 0;
     48        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    4949};
    5050
     
    5555        CompoundStmt();
    5656        CompoundStmt( std::list<Statement *> stmts );
    57         CompoundStmt( const CompoundStmt & other );
     57        CompoundStmt( const CompoundStmt &other );
    5858        virtual ~CompoundStmt();
    5959
     
    6262        void push_front( Statement * stmt ) { kids.push_front( stmt ); }
    6363
    64         virtual CompoundStmt * clone() const override { return new CompoundStmt( *this ); }
    65         virtual void accept( Visitor & v ) override { v.visit( this ); }
    66         virtual CompoundStmt * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    67         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     64        virtual CompoundStmt *clone() const override { return new CompoundStmt( *this ); }
     65        virtual void accept( Visitor &v ) override { v.visit( this ); }
     66        virtual CompoundStmt *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     67        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    6868};
    6969
     
    7272        NullStmt( const std::list<Label> & labels = {} );
    7373
    74         virtual NullStmt * clone() const override { return new NullStmt( *this ); }
    75         virtual void accept( Visitor & v ) override { v.visit( this ); }
    76         virtual NullStmt * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    77         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     74        virtual NullStmt *clone() const override { return new NullStmt( *this ); }
     75        virtual void accept( Visitor &v ) override { v.visit( this ); }
     76        virtual NullStmt *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     77        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    7878};
    7979
    8080class ExprStmt : public Statement {
    8181  public:
    82         Expression * expr;
    83 
    84         ExprStmt( Expression * expr );
    85         ExprStmt( const ExprStmt & other );
     82        Expression *expr;
     83
     84        ExprStmt( Expression *expr );
     85        ExprStmt( const ExprStmt &other );
    8686        virtual ~ExprStmt();
    8787
    88         Expression * get_expr() { return expr; }
    89         void set_expr( Expression * newValue ) { expr = newValue; }
    90 
    91         virtual ExprStmt * clone() const override { return new ExprStmt( *this ); }
    92         virtual void accept( Visitor & v ) override { v.visit( this ); }
    93         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    94         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     88        Expression *get_expr() { return expr; }
     89        void set_expr( Expression *newValue ) { expr = newValue; }
     90
     91        virtual ExprStmt *clone() const override { return new ExprStmt( *this ); }
     92        virtual void accept( Visitor &v ) override { v.visit( this ); }
     93        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     94        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    9595};
    9696
     
    9898  public:
    9999        bool voltile;
    100         Expression * instruction;
     100        Expression *instruction;
    101101        std::list<Expression *> output, input;
    102102        std::list<ConstantExpr *> clobber;
    103103        std::list<Label> gotolabels;
    104104
    105         AsmStmt( bool voltile, Expression * instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels );
    106         AsmStmt( const AsmStmt & other );
     105        AsmStmt( bool voltile, Expression *instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels );
     106        AsmStmt( const AsmStmt &other );
    107107        virtual ~AsmStmt();
    108108
     
    114114        void set_output( const std::list<Expression *> & newValue ) { output = newValue; }
    115115        std::list<Expression *> & get_input() { return input; }
    116         void set_input( const std::list<Expression *> & newValue ) { input = newValue; }
     116        void set_input( const std::list<Expression *> &newValue ) { input = newValue; }
    117117        std::list<ConstantExpr *> & get_clobber() { return clobber; }
    118         void set_clobber( const std::list<ConstantExpr *> & newValue ) { clobber = newValue; }
     118        void set_clobber( const std::list<ConstantExpr *> &newValue ) { clobber = newValue; }
    119119        std::list<Label> & get_gotolabels() { return gotolabels; }
    120         void set_gotolabels( const std::list<Label> & newValue ) { gotolabels = newValue; }
     120        void set_gotolabels( const std::list<Label> &newValue ) { gotolabels = newValue; }
    121121
    122122        virtual AsmStmt * clone() const { return new AsmStmt( *this ); }
     
    141141class IfStmt : public Statement {
    142142  public:
    143         Expression * condition;
    144         Statement * thenPart;
    145         Statement * elsePart;
     143        Expression *condition;
     144        Statement *thenPart;
     145        Statement *elsePart;
    146146        std::list<Statement *> initialization;
    147147
    148         IfStmt( Expression * condition, Statement * thenPart, Statement * elsePart,
     148        IfStmt( Expression *condition, Statement *thenPart, Statement *elsePart,
    149149                        std::list<Statement *> initialization = std::list<Statement *>() );
    150         IfStmt( const IfStmt & other );
     150        IfStmt( const IfStmt &other );
    151151        virtual ~IfStmt();
    152152
    153         std::list<Statement *> & get_initialization() { return initialization; }
    154         Expression * get_condition() { return condition; }
    155         void set_condition( Expression * newValue ) { condition = newValue; }
    156         Statement * get_thenPart() { return thenPart; }
    157         void set_thenPart( Statement * newValue ) { thenPart = newValue; }
    158         Statement * get_elsePart() { return elsePart; }
    159         void set_elsePart( Statement * newValue ) { elsePart = newValue; }
    160 
    161         virtual IfStmt * clone() const override { return new IfStmt( *this ); }
    162         virtual void accept( Visitor & v ) override { v.visit( this ); }
    163         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    164         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     153        std::list<Statement *> &get_initialization() { return initialization; }
     154        Expression *get_condition() { return condition; }
     155        void set_condition( Expression *newValue ) { condition = newValue; }
     156        Statement *get_thenPart() { return thenPart; }
     157        void set_thenPart( Statement *newValue ) { thenPart = newValue; }
     158        Statement *get_elsePart() { return elsePart; }
     159        void set_elsePart( Statement *newValue ) { elsePart = newValue; }
     160
     161        virtual IfStmt *clone() const override { return new IfStmt( *this ); }
     162        virtual void accept( Visitor &v ) override { v.visit( this ); }
     163        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     164        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    165165};
    166166
     
    170170        std::list<Statement *> statements;
    171171
    172         SwitchStmt( Expression * condition, const std::list<Statement *> & statements );
    173         SwitchStmt( const SwitchStmt & other );
     172        SwitchStmt( Expression *condition, const std::list<Statement *> &statements );
     173        SwitchStmt( const SwitchStmt &other );
    174174        virtual ~SwitchStmt();
    175175
    176         Expression * get_condition() { return condition; }
    177         void set_condition( Expression * newValue ) { condition = newValue; }
     176        Expression *get_condition() { return condition; }
     177        void set_condition( Expression *newValue ) { condition = newValue; }
    178178
    179179        std::list<Statement *> & get_statements() { return statements; }
    180180
    181         virtual void accept( Visitor & v ) override { v.visit( this ); }
    182         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    183 
    184         virtual SwitchStmt * clone() const override { return new SwitchStmt( *this ); }
    185         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     181        virtual void accept( Visitor &v ) override { v.visit( this ); }
     182        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     183
     184        virtual SwitchStmt *clone() const override { return new SwitchStmt( *this ); }
     185        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    186186
    187187};
     
    192192        std::list<Statement *> stmts;
    193193
    194         CaseStmt( Expression * conditions, const std::list<Statement *> & stmts, bool isdef = false ) throw (SemanticErrorException);
    195         CaseStmt( const CaseStmt & other );
     194        CaseStmt( Expression *conditions, const std::list<Statement *> &stmts, bool isdef = false ) throw (SemanticErrorException);
     195        CaseStmt( const CaseStmt &other );
    196196        virtual ~CaseStmt();
    197197
     
    201201        void set_default(bool b) { _isDefault = b; }
    202202
    203         Expression * & get_condition() { return condition; }
    204         void set_condition( Expression * newValue ) { condition = newValue; }
    205 
    206         std::list<Statement *> & get_statements() { return stmts; }
    207         void set_statements( std::list<Statement *> & newValue ) { stmts = newValue; }
    208 
    209         virtual void accept( Visitor & v ) override { v.visit( this ); }
    210         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    211 
    212         virtual CaseStmt * clone() const override { return new CaseStmt( *this ); }
    213         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     203        Expression * &get_condition() { return condition; }
     204        void set_condition( Expression *newValue ) { condition = newValue; }
     205
     206        std::list<Statement *> &get_statements() { return stmts; }
     207        void set_statements( std::list<Statement *> &newValue ) { stmts = newValue; }
     208
     209        virtual void accept( Visitor &v ) override { v.visit( this ); }
     210        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     211
     212        virtual CaseStmt *clone() const override { return new CaseStmt( *this ); }
     213        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    214214  private:
    215215        bool _isDefault;
     
    218218class WhileStmt : public Statement {
    219219  public:
    220         Expression * condition;
    221         Statement * body;
     220        Expression *condition;
     221        Statement *body;
    222222        std::list<Statement *> initialization;
    223223        bool isDoWhile;
    224224
    225         WhileStmt( Expression * condition, Statement * body, std::list<Statement *> & initialization, bool isDoWhile = false );
    226         WhileStmt( const WhileStmt & other );
     225        WhileStmt( Expression *condition,
     226               Statement *body, std::list<Statement *> & initialization, bool isDoWhile = false );
     227        WhileStmt( const WhileStmt &other );
    227228        virtual ~WhileStmt();
    228229
    229         Expression * get_condition() { return condition; }
    230         void set_condition( Expression * newValue ) { condition = newValue; }
    231         Statement * get_body() { return body; }
    232         void set_body( Statement * newValue ) { body = newValue; }
     230        Expression *get_condition() { return condition; }
     231        void set_condition( Expression *newValue ) { condition = newValue; }
     232        Statement *get_body() { return body; }
     233        void set_body( Statement *newValue ) { body = newValue; }
    233234        bool get_isDoWhile() { return isDoWhile; }
    234235        void set_isDoWhile( bool newValue ) { isDoWhile = newValue; }
    235236
    236         virtual WhileStmt * clone() const override { return new WhileStmt( *this ); }
    237         virtual void accept( Visitor & v ) override { v.visit( this ); }
    238         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    239         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     237        virtual WhileStmt *clone() const override { return new WhileStmt( *this ); }
     238        virtual void accept( Visitor &v ) override { v.visit( this ); }
     239        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     240        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    240241};
    241242
     
    243244  public:
    244245        std::list<Statement *> initialization;
    245         Expression * condition;
    246         Expression * increment;
    247         Statement * body;
    248 
    249         ForStmt( std::list<Statement *> initialization, Expression * condition = 0, Expression * increment = 0, Statement * body = 0 );
    250         ForStmt( const ForStmt & other );
     246        Expression *condition;
     247        Expression *increment;
     248        Statement *body;
     249
     250        ForStmt( std::list<Statement *> initialization,
     251             Expression *condition = 0, Expression *increment = 0, Statement *body = 0 );
     252        ForStmt( const ForStmt &other );
    251253        virtual ~ForStmt();
    252254
    253         std::list<Statement *> & get_initialization() { return initialization; }
    254         Expression * get_condition() { return condition; }
    255         void set_condition( Expression * newValue ) { condition = newValue; }
    256         Expression * get_increment() { return increment; }
    257         void set_increment( Expression * newValue ) { increment = newValue; }
    258         Statement * get_body() { return body; }
    259         void set_body( Statement * newValue ) { body = newValue; }
    260 
    261         virtual ForStmt * clone() const override { return new ForStmt( *this ); }
    262         virtual void accept( Visitor & v ) override { v.visit( this ); }
    263         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    264         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     255        std::list<Statement *> &get_initialization() { return initialization; }
     256        Expression *get_condition() { return condition; }
     257        void set_condition( Expression *newValue ) { condition = newValue; }
     258        Expression *get_increment() { return increment; }
     259        void set_increment( Expression *newValue ) { increment = newValue; }
     260        Statement *get_body() { return body; }
     261        void set_body( Statement *newValue ) { body = newValue; }
     262
     263        virtual ForStmt *clone() const override { return new ForStmt( *this ); }
     264        virtual void accept( Visitor &v ) override { v.visit( this ); }
     265        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     266        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    265267};
    266268
     
    272274        const Label originalTarget;
    273275        Label target;
    274         Expression * computedTarget;
     276        Expression *computedTarget;
    275277        Type type;
    276278
    277279        BranchStmt( Label target, Type ) throw (SemanticErrorException);
    278         BranchStmt( Expression * computedTarget, Type ) throw (SemanticErrorException);
     280        BranchStmt( Expression *computedTarget, Type ) throw (SemanticErrorException);
    279281
    280282        Label get_originalTarget() { return originalTarget; }
     
    282284        void set_target( Label newValue ) { target = newValue; }
    283285
    284         Expression * get_computedTarget() { return computedTarget; }
     286        Expression *get_computedTarget() { return computedTarget; }
    285287        void set_target( Expression * newValue ) { computedTarget = newValue; }
    286288
    287289        Type get_type() { return type; }
    288         const char * get_typename() { return brType[ type ]; }
    289 
    290         virtual BranchStmt * clone() const override { return new BranchStmt( *this ); }
    291         virtual void accept( Visitor & v ) override { v.visit( this ); }
    292         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    293         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     290        const char *get_typename() { return brType[ type ]; }
     291
     292        virtual BranchStmt *clone() const override { return new BranchStmt( *this ); }
     293        virtual void accept( Visitor &v ) override { v.visit( this ); }
     294        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     295        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    294296  private:
    295         static const char * brType[];
     297        static const char *brType[];
    296298};
    297299
    298300class ReturnStmt : public Statement {
    299301  public:
    300         Expression * expr;
    301 
    302         ReturnStmt( Expression * expr );
    303         ReturnStmt( const ReturnStmt & other );
     302        Expression *expr;
     303
     304        ReturnStmt( Expression *expr );
     305        ReturnStmt( const ReturnStmt &other );
    304306        virtual ~ReturnStmt();
    305307
    306         Expression * get_expr() { return expr; }
    307         void set_expr( Expression * newValue ) { expr = newValue; }
    308 
    309         virtual ReturnStmt * clone() const override { return new ReturnStmt( *this ); }
    310         virtual void accept( Visitor & v ) override { v.visit( this ); }
    311         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    312         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     308        Expression *get_expr() { return expr; }
     309        void set_expr( Expression *newValue ) { expr = newValue; }
     310
     311        virtual ReturnStmt *clone() const override { return new ReturnStmt( *this ); }
     312        virtual void accept( Visitor &v ) override { v.visit( this ); }
     313        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     314        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    313315};
    314316
     
    322324
    323325        ThrowStmt( Kind kind, Expression * expr, Expression * target = nullptr );
    324         ThrowStmt( const ThrowStmt & other );
     326        ThrowStmt( const ThrowStmt &other );
    325327        virtual ~ThrowStmt();
    326328
     
    331333        void set_target( Expression * newTarget ) { target = newTarget; }
    332334
    333         virtual ThrowStmt * clone() const override { return new ThrowStmt( *this ); }
    334         virtual void accept( Visitor & v ) override { v.visit( this ); }
    335         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    336         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     335        virtual ThrowStmt *clone() const override { return new ThrowStmt( *this ); }
     336        virtual void accept( Visitor &v ) override { v.visit( this ); }
     337        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     338        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    337339};
    338340
     
    343345        FinallyStmt * finallyBlock;
    344346
    345         TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = 0 );
    346         TryStmt( const TryStmt & other );
     347        TryStmt( CompoundStmt *tryBlock, std::list<CatchStmt *> &handlers, FinallyStmt *finallyBlock = 0 );
     348        TryStmt( const TryStmt &other );
    347349        virtual ~TryStmt();
    348350
    349         CompoundStmt * get_block() const { return block; }
    350         void set_block( CompoundStmt * newValue ) { block = newValue; }
     351        CompoundStmt *get_block() const { return block; }
     352        void set_block( CompoundStmt *newValue ) { block = newValue; }
    351353        std::list<CatchStmt *>& get_catchers() { return handlers; }
    352354
    353         FinallyStmt * get_finally() const { return finallyBlock; }
    354         void set_finally( FinallyStmt * newValue ) { finallyBlock = newValue; }
    355 
    356         virtual TryStmt * clone() const override { return new TryStmt( *this ); }
    357         virtual void accept( Visitor & v ) override { v.visit( this ); }
    358         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    359         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     355        FinallyStmt *get_finally() const { return finallyBlock; }
     356        void set_finally( FinallyStmt *newValue ) { finallyBlock = newValue; }
     357
     358        virtual TryStmt *clone() const override { return new TryStmt( *this ); }
     359        virtual void accept( Visitor &v ) override { v.visit( this ); }
     360        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     361        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    360362};
    361363
     
    365367
    366368        const Kind kind;
    367         Declaration * decl;
    368         Expression * cond;
    369         Statement * body;
    370 
    371         CatchStmt( Kind kind, Declaration * decl,
    372                    Expression * cond, Statement * body );
    373         CatchStmt( const CatchStmt & other );
     369        Declaration *decl;
     370        Expression *cond;
     371        Statement *body;
     372
     373        CatchStmt( Kind kind, Declaration *decl,
     374                   Expression *cond, Statement *body );
     375        CatchStmt( const CatchStmt &other );
    374376        virtual ~CatchStmt();
    375377
    376378        Kind get_kind() { return kind; }
    377         Declaration * get_decl() { return decl; }
    378         void set_decl( Declaration * newValue ) { decl = newValue; }
    379         Expression * get_cond() { return cond; }
    380         void set_cond( Expression * newCond ) { cond = newCond; }
    381         Statement * get_body() { return body; }
    382         void set_body( Statement * newValue ) { body = newValue; }
    383 
    384         virtual CatchStmt * clone() const override { return new CatchStmt( *this ); }
    385         virtual void accept( Visitor & v ) override { v.visit( this ); }
    386         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    387         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     379        Declaration *get_decl() { return decl; }
     380        void set_decl( Declaration *newValue ) { decl = newValue; }
     381        Expression *get_cond() { return cond; }
     382        void set_cond( Expression *newCond ) { cond = newCond; }
     383        Statement *get_body() { return body; }
     384        void set_body( Statement *newValue ) { body = newValue; }
     385
     386        virtual CatchStmt *clone() const override { return new CatchStmt( *this ); }
     387        virtual void accept( Visitor &v ) override { v.visit( this ); }
     388        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     389        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    388390};
    389391
    390392class FinallyStmt : public Statement {
    391393  public:
    392         CompoundStmt * block;
    393 
    394         FinallyStmt( CompoundStmt * block );
    395         FinallyStmt( const FinallyStmt & other );
     394        CompoundStmt *block;
     395
     396        FinallyStmt( CompoundStmt *block );
     397        FinallyStmt( const FinallyStmt &other );
    396398        virtual ~FinallyStmt();
    397399
    398         CompoundStmt * get_block() const { return block; }
    399         void set_block( CompoundStmt * newValue ) { block = newValue; }
    400 
    401         virtual FinallyStmt * clone() const override { return new FinallyStmt( *this ); }
    402         virtual void accept( Visitor & v ) override { v.visit( this ); }
    403         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    404         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     400        CompoundStmt *get_block() const { return block; }
     401        void set_block( CompoundStmt *newValue ) { block = newValue; }
     402
     403        virtual FinallyStmt *clone() const override { return new FinallyStmt( *this ); }
     404        virtual void accept( Visitor &v ) override { v.visit( this ); }
     405        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     406        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    405407};
    406408
     
    436438        } orelse;
    437439
    438         virtual WaitForStmt * clone() const override { return new WaitForStmt( *this ); }
    439         virtual void accept( Visitor & v ) override { v.visit( this ); }
    440         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    441         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     440        virtual WaitForStmt *clone() const override { return new WaitForStmt( *this ); }
     441        virtual void accept( Visitor &v ) override { v.visit( this ); }
     442        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     443        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    442444
    443445};
     
    462464class DeclStmt : public Statement {
    463465  public:
    464         Declaration * decl;
    465 
    466         DeclStmt( Declaration * decl );
    467         DeclStmt( const DeclStmt & other );
     466        Declaration *decl;
     467
     468        DeclStmt( Declaration *decl );
     469        DeclStmt( const DeclStmt &other );
    468470        virtual ~DeclStmt();
    469471
    470         Declaration * get_decl() const { return decl; }
    471         void set_decl( Declaration * newValue ) { decl = newValue; }
    472 
    473         virtual DeclStmt * clone() const override { return new DeclStmt( *this ); }
    474         virtual void accept( Visitor & v ) override { v.visit( this ); }
    475         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    476         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    477 };
    478 
    479 
    480 /// represents an implicit application of a constructor or destructor. Qualifiers are replaced immediately before and
    481 /// after the call so that qualified objects can be constructed with the same functions as unqualified objects.
     472        Declaration *get_decl() const { return decl; }
     473        void set_decl( Declaration *newValue ) { decl = newValue; }
     474
     475        virtual DeclStmt *clone() const override { return new DeclStmt( *this ); }
     476        virtual void accept( Visitor &v ) override { v.visit( this ); }
     477        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     478        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     479};
     480
     481
     482/// represents an implicit application of a constructor or destructor. Qualifiers are replaced
     483/// immediately before and after the call so that qualified objects can be constructed
     484/// with the same functions as unqualified objects.
    482485class ImplicitCtorDtorStmt : public Statement {
    483486  public:
     
    489492        virtual ~ImplicitCtorDtorStmt();
    490493
    491         Statement * get_callStmt() const { return callStmt; }
     494        Statement *get_callStmt() const { return callStmt; }
    492495        void set_callStmt( Statement * newValue ) { callStmt = newValue; }
    493496
    494         virtual ImplicitCtorDtorStmt * clone() const override { return new ImplicitCtorDtorStmt( *this ); }
    495         virtual void accept( Visitor & v ) override { v.visit( this ); }
    496         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    497         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     497        virtual ImplicitCtorDtorStmt *clone() const override { return new ImplicitCtorDtorStmt( *this ); }
     498        virtual void accept( Visitor &v ) override { v.visit( this ); }
     499        virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     500        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    498501};
    499502
  • src/SynTree/SynTree.h

    r933f32f r6a9d4b4  
    3434class NamedTypeDecl;
    3535class TypeDecl;
     36class FtypeDecl;
     37class DtypeDecl;
    3638class TypedefDecl;
    3739class AsmDecl;
     
    8890class ConstructorExpr;
    8991class CompoundLiteralExpr;
     92class UntypedValofExpr;
    9093class RangeExpr;
    9194class UntypedTupleExpr;
     
    129132class ConstructorInit;
    130133
     134class Subrange;
     135
    131136//template <class T>    // emulate a union with templates?
    132137class Constant;
  • src/SynTree/Type.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan 31 21:54:16 2019
    13 // Update Count     : 43
     12// Last Modified On : Fri Jun 22 10:17:19 2018
     13// Update Count     : 39
    1414//
    1515#include "Type.h"
     
    2525
    2626const char *BasicType::typeNames[] = {
    27 #if 0
    2827        "_Bool",
    2928        "char",
     
    5049        "unsigned __int128",
    5150        "__float80",
    52         "__float128",
    53         "_Float16",
    54         "_Float32",
    55         "_Float32x",
    56         "_Float64",
    57         "_Float64x",
    58         "_Float128",
    59         "_Float128x",
    60         "_Float16 _Complex",
    61         "_Float32 _Complex",
    62         "_Float32x _Complex",
    63         "_Float64 _Complex",
    64         "_Float64x _Complex",
    65         "_Float128 _Complex",
    66         "_Float128x _Complex",
    67 #endif
    68         "_Bool",
    69         "char",
    70         "signed char",
    71         "unsigned char",
    72         "signed short int",
    73         "unsigned short int",
    74         "signed int",
    75         "unsigned int",
    76         "signed long int",
    77         "unsigned long int",
    78         "signed long long int",
    79         "unsigned long long int",
    80         "__int128",
    81         "unsigned __int128",
    82         "_Float16",
    83         "_Float16 _Complex",
    84         "_Float32",
    85         "_Float32 _Complex",
    86         "float",
    87         "float _Complex",
    88         //"float _Imaginary",
    89         "_Float32x",
    90         "_Float32x _Complex",
    91         "_Float64",
    92         "_Float64 _Complex",
    93         "double",
    94         "double _Complex",
    95         //"double _Imaginary",
    96         "_Float64x",
    97         "_Float64x _Complex",
    98         "__float80",
    99         "_Float128",
    100         "_Float128 _Complex",
    101         "__float128",
    102         "long double",
    103         "long double _Complex",
    104         //"long double _Imaginary",
    105         "_Float128x",
    106         "_Float128x _Complex",
     51        "__float128"
    10752};
    10853static_assert(
  • src/SynTree/Type.h

    r933f32f r6a9d4b4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 14 17:11:24 2019
    13 // Update Count     : 169
     12// Last Modified On : Mon Sep 25 14:14:01 2017
     13// Update Count     : 154
    1414//
    1515
     
    207207class BasicType : public Type {
    208208  public:
    209         // GENERATED START, DO NOT EDIT
    210         // GENERATED BY BasicTypes-gen.cc
    211209        enum Kind {
    212210                Bool,
     
    222220                LongLongSignedInt,
    223221                LongLongUnsignedInt,
     222                Float,
     223                Double,
     224                LongDouble,
     225                FloatComplex,
     226                DoubleComplex,
     227                LongDoubleComplex,
     228                FloatImaginary,
     229                DoubleImaginary,
     230                LongDoubleImaginary,
    224231                SignedInt128,
    225232                UnsignedInt128,
    226                 uFloat16,
    227                 uFloat16Complex,
    228                 uFloat32,
    229                 uFloat32Complex,
    230                 Float,
    231                 FloatComplex,
    232                 uFloat32x,
    233                 uFloat32xComplex,
    234                 uFloat64,
    235                 uFloat64Complex,
    236                 Double,
    237                 DoubleComplex,
    238                 uFloat64x,
    239                 uFloat64xComplex,
    240                 uuFloat80,
    241                 uFloat128,
    242                 uFloat128Complex,
    243                 uuFloat128,
    244                 LongDouble,
    245                 LongDoubleComplex,
    246                 uFloat128x,
    247                 uFloat128xComplex,
     233                Float80,
     234                Float128,
    248235                NUMBER_OF_BASIC_TYPES
    249236        } kind;
    250         // GENERATED END
    251237
    252238        static const char *typeNames[];                                         // string names for basic types, MUST MATCH with Kind
  • src/SynTree/TypeSubstitution.cc

    r933f32f r6a9d4b4  
    6464}
    6565
    66 void TypeSubstitution::addVar( std::string formalExpr, Expression *actualExpr ) {
    67         varEnv[ formalExpr ] = actualExpr;
    68 }
    69 
    7066void TypeSubstitution::remove( std::string formalType ) {
    7167        TypeEnvType::iterator i = typeEnv.find( formalType );
     
    112108namespace {
    113109        struct EnvTrimmer {
    114                 const TypeSubstitution * env;
    115                 TypeSubstitution * newEnv;
    116                 EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
     110                TypeSubstitution * env, * newEnv;
     111                EnvTrimmer( TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
    117112                void previsit( TypeDecl * tyDecl ) {
    118113                        // transfer known bindings for seen type variables
     
    125120
    126121/// reduce environment to just the parts that are referenced in a given expression
    127 TypeSubstitution * TypeSubstitution::newFromExpr( Expression * expr, const TypeSubstitution * env ) {
     122TypeSubstitution * TypeSubstitution::newFromExpr( Expression * expr, TypeSubstitution * env ) {
    128123        if ( env ) {
    129124                TypeSubstitution * newEnv = new TypeSubstitution();
  • src/SynTree/TypeSubstitution.h

    r933f32f r6a9d4b4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 30 22:52:47 2019
    13 // Update Count     : 9
     12// Last Modified On : Sat Jul 22 09:52:24 2017
     13// Update Count     : 3
    1414//
    1515
     
    1919#include <iosfwd>                  // for ostream
    2020#include <list>                    // for list<>::iterator, _List_iterator
    21 #include <unordered_map>
    22 #include <unordered_set>
     21#include <map>                     // for _Rb_tree_iterator, map, map<>::val...
     22#include <set>                     // for set
    2323#include <string>                  // for string, operator!=
    2424#include <utility>                 // for pair
     
    3939        TypeSubstitution &operator=( const TypeSubstitution &other );
    4040
    41         template< typename SynTreeClass > int apply( SynTreeClass *&input ) const;
    42         template< typename SynTreeClass > int applyFree( SynTreeClass *&input ) const;
     41        template< typename SynTreeClass > int apply( SynTreeClass *&input );
     42        template< typename SynTreeClass > int applyFree( SynTreeClass *&input );
    4343
    4444        void add( std::string formalType, Type *actualType );
     
    4848        bool empty() const;
    4949
    50         void addVar( std::string formalExpr, Expression *actualExpr );
    51 
    5250        template< typename FormalIterator, typename ActualIterator >
    5351        void add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
     
    5856
    5957        /// create a new TypeSubstitution using bindings from env containing all of the type variables in expr
    60         static TypeSubstitution * newFromExpr( Expression * expr, const TypeSubstitution * env );
     58        static TypeSubstitution * newFromExpr( Expression * expr, TypeSubstitution * env );
    6159
    6260        void normalize();
     
    8078        friend class PassVisitor;
    8179
    82         typedef std::unordered_map< std::string, Type * > TypeEnvType;
    83         typedef std::unordered_map< std::string, Expression * > VarEnvType;
     80        typedef std::map< std::string, Type* > TypeEnvType;
     81        typedef std::map< std::string, Expression* > VarEnvType;
    8482        TypeEnvType typeEnv;
    8583        VarEnvType varEnv;
     
    9189        auto begin() const -> decltype( typeEnv.begin() ) { return typeEnv.begin(); }
    9290        auto   end() const -> decltype( typeEnv.  end() ) { return typeEnv.  end(); }
    93 
    94         auto beginVar()       -> decltype( varEnv.begin() ) { return varEnv.begin(); }
    95         auto   endVar()       -> decltype( varEnv.  end() ) { return varEnv.  end(); }
    96         auto beginVar() const -> decltype( varEnv.begin() ) { return varEnv.begin(); }
    97         auto   endVar() const -> decltype( varEnv.  end() ) { return varEnv.  end(); }
    9891};
    9992
     
    10598        ActualIterator actualIt = actualBegin;
    10699        for ( ; formalIt != formalEnd; ++formalIt, ++actualIt ) {
    107                 if ( TypeDecl *formal = dynamic_cast< TypeDecl * >( *formalIt ) ) {
    108                         if ( TypeExpr *actual = dynamic_cast< TypeExpr * >( *actualIt ) ) {
     100                if ( TypeDecl *formal = dynamic_cast< TypeDecl* >( *formalIt ) ) {
     101                        if ( TypeExpr *actual = dynamic_cast< TypeExpr* >( *actualIt ) ) {
    109102                                if ( formal->get_name() != "" ) {
    110103                                        TypeEnvType::iterator i = typeEnv.find( formal->get_name() );
     
    137130// definitition must happen after PassVisitor is included so that WithGuards can be used
    138131struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
    139                 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
     132                Substituter( TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
    140133
    141134                Type * postmutate( TypeInstType * aggregateUseType );
     
    150143                void premutate( UnionInstType * aggregateUseType );
    151144
    152                 const TypeSubstitution & sub;
     145                TypeSubstitution & sub;
    153146                int subCount = 0;
    154147                bool freeOnly;
    155                 typedef std::unordered_set< std::string > BoundVarsType;
     148                typedef std::set< std::string > BoundVarsType;
    156149                BoundVarsType boundVars;
    157150};
    158151
    159152template< typename SynTreeClass >
    160 int TypeSubstitution::apply( SynTreeClass *&input ) const {
     153int TypeSubstitution::apply( SynTreeClass *&input ) {
    161154        assert( input );
    162155        PassVisitor<Substituter> sub( *this, false );
     
    170163
    171164template< typename SynTreeClass >
    172 int TypeSubstitution::applyFree( SynTreeClass *&input ) const {
     165int TypeSubstitution::applyFree( SynTreeClass *&input ) {
    173166        assert( input );
    174167        PassVisitor<Substituter> sub( *this, true );
  • src/SynTree/Visitor.h

    r933f32f r6a9d4b4  
    123123        virtual void visit( ConstructorInit * ctorInit ) = 0;
    124124
     125        virtual void visit( Subrange * subrange ) = 0;
     126
    125127        virtual void visit( Constant * constant ) = 0;
    126128
  • src/SynTree/module.mk

    r933f32f r6a9d4b4  
    1515###############################################################################
    1616
    17 SRC_SYNTREE = \
    18       SynTree/Type.cc \
    19       SynTree/VoidType.cc \
    20       SynTree/BasicType.cc \
    21       SynTree/PointerType.cc \
    22       SynTree/ArrayType.cc \
    23       SynTree/ReferenceType.cc \
    24       SynTree/FunctionType.cc \
    25       SynTree/ReferenceToType.cc \
    26       SynTree/TupleType.cc \
    27       SynTree/TypeofType.cc \
    28       SynTree/AttrType.cc \
    29       SynTree/VarArgsType.cc \
    30       SynTree/ZeroOneType.cc \
    31       SynTree/Constant.cc \
    32       SynTree/Expression.cc \
    33       SynTree/TupleExpr.cc \
    34       SynTree/CommaExpr.cc \
    35       SynTree/TypeExpr.cc \
    36       SynTree/ApplicationExpr.cc \
    37       SynTree/AddressExpr.cc \
    38       SynTree/Statement.cc \
    39       SynTree/CompoundStmt.cc \
    40       SynTree/DeclStmt.cc \
    41       SynTree/Declaration.cc \
    42       SynTree/DeclarationWithType.cc \
    43       SynTree/ObjectDecl.cc \
    44       SynTree/FunctionDecl.cc \
    45       SynTree/AggregateDecl.cc \
    46       SynTree/NamedTypeDecl.cc \
    47       SynTree/TypeDecl.cc \
    48       SynTree/Initializer.cc \
    49       SynTree/TypeSubstitution.cc \
    50       SynTree/Attribute.cc \
    51       SynTree/DeclReplacer.cc
     17SRC += SynTree/Type.cc \
     18       SynTree/VoidType.cc \
     19       SynTree/BasicType.cc \
     20       SynTree/PointerType.cc \
     21       SynTree/ArrayType.cc \
     22       SynTree/ReferenceType.cc \
     23       SynTree/FunctionType.cc \
     24       SynTree/ReferenceToType.cc \
     25       SynTree/TupleType.cc \
     26       SynTree/TypeofType.cc \
     27       SynTree/AttrType.cc \
     28       SynTree/VarArgsType.cc \
     29       SynTree/ZeroOneType.cc \
     30       SynTree/Constant.cc \
     31       SynTree/Expression.cc \
     32       SynTree/TupleExpr.cc \
     33       SynTree/CommaExpr.cc \
     34       SynTree/TypeExpr.cc \
     35       SynTree/ApplicationExpr.cc \
     36       SynTree/AddressExpr.cc \
     37       SynTree/Statement.cc \
     38       SynTree/CompoundStmt.cc \
     39       SynTree/DeclStmt.cc \
     40       SynTree/Declaration.cc \
     41       SynTree/DeclarationWithType.cc \
     42       SynTree/ObjectDecl.cc \
     43       SynTree/FunctionDecl.cc \
     44       SynTree/AggregateDecl.cc \
     45       SynTree/NamedTypeDecl.cc \
     46       SynTree/TypeDecl.cc \
     47       SynTree/Initializer.cc \
     48       SynTree/TypeSubstitution.cc \
     49       SynTree/Attribute.cc \
     50       SynTree/DeclReplacer.cc
    5251
    53 SRC += $(SRC_SYNTREE)
    54 SRCDEMANGLE += $(SRC_SYNTREE)
  • src/Tuples/TupleExpansion.cc

    r933f32f r6a9d4b4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 13 18:14:12 2019
    13 // Update Count     : 21
     12// Last Modified On : Wed Jun 21 17:35:04 2017
     13// Update Count     : 19
    1414//
    1515
     
    1717#include <cassert>                // for assert
    1818#include <list>                   // for list
    19 #include <vector>
    20 
    21 #include "AST/CVQualifiers.hpp"
    22 #include "AST/Expr.hpp"
    23 #include "AST/Node.hpp"
    24 #include "AST/Type.hpp"
     19
    2520#include "Common/PassVisitor.h"   // for PassVisitor, WithDeclsToAdd, WithGu...
    2621#include "Common/ScopedMap.h"     // for ScopedMap
     
    6358                };
    6459
    65                 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {
     60                struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithTypeSubstitution {
    6661                        Type * postmutate( TupleType * tupleType );
    6762
     
    319314                return new TupleType( qualifiers, types );
    320315        }
    321         const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {
    322                 (void) exprs;
    323                 #warning Not implemented; needs Type.cpp in build
    324                 assertf(false, "Not implemented; needs Type.cpp in build");
    325                 // // produce the TupleType which aggregates the types of the exprs
    326                 // std::vector<ast::ptr<ast::Type>> types;
    327                 // ast::CV::Qualifiers quals{
    328                 //      ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
    329                 //      ast::CV::Atomic | ast::CV::Mutex };
    330 
    331                 // for ( const ast::Expr * expr : exprs ) {
    332                 //      assert( expr->result );
    333                 //      // if the type of any expr is void, the type of the entire tuple is void
    334                 //      if ( expr->result->isVoid() ) return new ast::VoidType{};
    335 
    336                 //      // qualifiers on the tuple type are the qualifiers that exist on all components
    337                 //      quals &= expr->result->qualifiers;
    338 
    339                 //      types.emplace_back( expr->result );
    340                 // }
    341 
    342                 // if ( exprs.empty() ) { quals = ast::CV::Qualifiers{}; }
    343                 // return new ast::TupleType{ std::move(types), quals };
    344         }
    345316
    346317        TypeInstType * isTtype( Type * type ) {
  • src/Tuples/Tuples.h

    r933f32f r6a9d4b4  
    1919#include <vector>
    2020
    21 #include "AST/Fwd.hpp"
    22 #include "AST/Node.hpp"
    2321#include "SynTree/Expression.h"
    2422#include "SynTree/Declaration.h"
     
    2927namespace Tuples {
    3028        // TupleAssignment.cc
    31         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
     29        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 
    3230                std::vector< ResolvExpr::AlternativeFinder >& args );
    33 
     31       
    3432        // TupleExpansion.cc
    3533        /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
     
    4442        /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
    4543        Type * makeTupleType( const std::list< Expression * > & exprs );
    46         const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
    4744
    4845        /// returns a TypeInstType if `type` is a ttype, nullptr otherwise
    4946        TypeInstType * isTtype( Type * type );
    50         const ast::TypeInstType * isTtype( const ast::Type * type );
    5147
    5248        /// returns true if the expression may contain side-effects.
  • src/Tuples/module.mk

    r933f32f r6a9d4b4  
    1515###############################################################################
    1616
    17 SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc
    18 SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc
     17SRC +=  Tuples/TupleAssignment.cc \
     18        Tuples/TupleExpansion.cc \
     19        Tuples/Explode.cc
  • src/Validate/module.mk

    r933f32f r6a9d4b4  
    1515###############################################################################
    1616
    17 SRC += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
    18 SRCDEMANGLE += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
     17SRC += Validate/HandleAttributes.cc \
     18        Validate/FindSpecialDecls.cc
  • src/config.h.in

    r933f32f r6a9d4b4  
    5252#undef CFA_VERSION_SHORT
    5353
    54 /* Have compiler warning cast-function-type. */
    55 #undef HAVE_CAST_FUNCTION_TYPE
     54/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
     55   systems. This function is required for `alloca.c' support on those systems.
     56   */
     57#undef CRAY_STACKSEG_END
     58
     59/* Define to 1 if using `alloca.c'. */
     60#undef C_ALLOCA
     61
     62/* Define to 1 if you have `alloca', as a function or macro. */
     63#undef HAVE_ALLOCA
     64
     65/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
     66   */
     67#undef HAVE_ALLOCA_H
    5668
    5769/* Define to 1 if you have the <dlfcn.h> header file. */
    5870#undef HAVE_DLFCN_H
    5971
     72/* Define to 1 if you have the <fenv.h> header file. */
     73#undef HAVE_FENV_H
     74
     75/* Define to 1 if you have the <float.h> header file. */
     76#undef HAVE_FLOAT_H
     77
    6078/* Define to 1 if you have the <inttypes.h> header file. */
    6179#undef HAVE_INTTYPES_H
    6280
    63 /* Have keywords _FloatXX. */
    64 #undef HAVE_KEYWORDS_FLOATXX
    65 
    6681/* Define to 1 if you have the <libintl.h> header file. */
    6782#undef HAVE_LIBINTL_H
    6883
     84/* Define to 1 if you have the <limits.h> header file. */
     85#undef HAVE_LIMITS_H
     86
    6987/* Define to 1 if you have the <malloc.h> header file. */
    7088#undef HAVE_MALLOC_H
     
    7391#undef HAVE_MEMORY_H
    7492
     93/* Define to 1 if you have the `memset' function. */
     94#undef HAVE_MEMSET
     95
     96/* Define to 1 if you have the `putenv' function. */
     97#undef HAVE_PUTENV
     98
     99/* Define to 1 if stdbool.h conforms to C99. */
     100#undef HAVE_STDBOOL_H
     101
     102/* Define to 1 if you have the <stddef.h> header file. */
     103#undef HAVE_STDDEF_H
     104
    75105/* Define to 1 if you have the <stdint.h> header file. */
    76106#undef HAVE_STDINT_H
     
    79109#undef HAVE_STDLIB_H
    80110
     111/* Define to 1 if you have the `strchr' function. */
     112#undef HAVE_STRCHR
     113
    81114/* Define to 1 if you have the <strings.h> header file. */
    82115#undef HAVE_STRINGS_H
     
    85118#undef HAVE_STRING_H
    86119
     120/* Define to 1 if you have the `strtol' function. */
     121#undef HAVE_STRTOL
     122
    87123/* Define to 1 if you have the <sys/stat.h> header file. */
    88124#undef HAVE_SYS_STAT_H
     
    94130#undef HAVE_UNISTD_H
    95131
    96 /* Define to 1 if the system has the type `_Float32'. */
    97 #undef HAVE__FLOAT32
     132/* Define to 1 if the system has the type `_Bool'. */
     133#undef HAVE__BOOL
    98134
    99135/* Define to the sub-directory where libtool stores uninstalled libraries. */
     
    120156/* Define to the version of this package. */
    121157#undef PACKAGE_VERSION
     158
     159/* If using the C implementation of alloca, define if you know the
     160   direction of stack growth for your system; otherwise it will be
     161   automatically deduced at runtime.
     162        STACK_DIRECTION > 0 => grows toward higher addresses
     163        STACK_DIRECTION < 0 => grows toward lower addresses
     164        STACK_DIRECTION = 0 => direction of growth unknown */
     165#undef STACK_DIRECTION
    122166
    123167/* Define to 1 if you have the ANSI C header files. */
     
    136180   `char[]'. */
    137181#undef YYTEXT_POINTER
     182
     183/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
     184   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
     185   #define below would cause a syntax error. */
     186#undef _UINT32_T
     187
     188/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
     189   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
     190   #define below would cause a syntax error. */
     191#undef _UINT8_T
     192
     193/* Define to `__inline__' or `__inline' if that's what the C compiler
     194   calls it, or to nothing if 'inline' is not supported under any name.  */
     195#ifndef __cplusplus
     196#undef inline
     197#endif
     198
     199/* Define to the type of a signed integer type of width exactly 16 bits if
     200   such a type exists and the standard includes do not define it. */
     201#undef int16_t
     202
     203/* Define to the type of a signed integer type of width exactly 32 bits if
     204   such a type exists and the standard includes do not define it. */
     205#undef int32_t
     206
     207/* Define to the type of a signed integer type of width exactly 8 bits if such
     208   a type exists and the standard includes do not define it. */
     209#undef int8_t
     210
     211/* Define to the equivalent of the C99 'restrict' keyword, or to
     212   nothing if this is not supported.  Do not define if restrict is
     213   supported directly.  */
     214#undef restrict
     215/* Work around a bug in Sun C++: it does not support _Restrict or
     216   __restrict__, even though the corresponding Sun C compiler ends up with
     217   "#define restrict _Restrict" or "#define restrict __restrict__" in the
     218   previous line.  Perhaps some future version of Sun C++ will work with
     219   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
     220#if defined __SUNPRO_CC && !defined __RESTRICT
     221# define _Restrict
     222# define __restrict__
     223#endif
     224
     225/* Define to `unsigned int' if <sys/types.h> does not define. */
     226#undef size_t
     227
     228/* Define to the type of an unsigned integer type of width exactly 16 bits if
     229   such a type exists and the standard includes do not define it. */
     230#undef uint16_t
     231
     232/* Define to the type of an unsigned integer type of width exactly 32 bits if
     233   such a type exists and the standard includes do not define it. */
     234#undef uint32_t
     235
     236/* Define to the type of an unsigned integer type of width exactly 8 bits if
     237   such a type exists and the standard includes do not define it. */
     238#undef uint8_t
  • src/include/cassert

    r933f32f r6a9d4b4  
    4545}
    4646
    47 extern void abort(const char *fmt, ...  ) noexcept __attribute__((noreturn, format(printf, 1, 2)));
    4847// Local Variables: //
    4948// tab-width: 4 //
  • src/main.cc

    r933f32f r6a9d4b4  
    77// main.cc --
    88//
    9 // Author           : Peter Buhr and Rob Schluntz
     9// Author           : Richard C. Bilson
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri May  3 16:10:52 2019
    13 // Update Count     : 599
     12// Last Modified On : Wed Dec 26 08:11:19 2018
     13// Update Count     : 499
    1414//
    1515
     
    2424#include <fstream>                          // for ofstream
    2525#include <iostream>                         // for operator<<, basic_ostream
    26 #include <iomanip>
    2726#include <iterator>                         // for back_inserter
    2827#include <list>                             // for list
     
    3837#include "CodeTools/TrackLoc.h"             // for fillLocations
    3938#include "Common/CompilerError.h"           // for CompilerError
    40 #include "Common/Stats.h"
     39#include "Common/Heap.h"
    4140#include "Common/PassVisitor.h"
    42 // #include "AST/Pass.hpp"
    4341#include "Common/SemanticError.h"           // for SemanticError
    4442#include "Common/UnimplementedError.h"      // for UnimplementedError
     
    6765using namespace std;
    6866
    69 static void NewPass( const char * const name ) {
    70         Stats::Heap::newPass( name );
    71         using namespace Stats::Counters;
    72         {
    73                 static auto group = build<CounterGroup>( "Pass Visitor" );
    74                 auto pass = build<CounterGroup>( name, group );
    75                 pass_visitor_stats.depth = 0;
    76                 pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass );
    77                 pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass );
    78         }
    79         {
    80                 static auto group = build<CounterGroup>( "Syntax Node" );
    81                 auto pass = build<CounterGroup>( name, group );
    82                 BaseSyntaxNode::new_nodes = build<SimpleCounter>( "Allocs", pass );
    83         }
    84 }
    85 
    86 #define PASS( name, pass )                  \
     67#define PASS(name, pass)                   \
    8768        if ( errorp ) { cerr << name << endl; } \
    88         NewPass(name);                          \
    89         Stats::Time::StartBlock(name);          \
    90         pass;                                   \
    91         Stats::Time::StopBlock();
     69        HeapStats::newPass(name);               \
     70        pass;
    9271
    9372LinkageSpec::Spec linkage = LinkageSpec::Cforall;
     
    9574DeclarationNode * parseTree = nullptr;                                  // program parse tree
    9675
    97 static std::string PreludeDirector = "";
     76std::string PreludeDirector = "";
    9877
    9978static void parse_cmdline( int argc, char *argv[], const char *& filename );
     
    151130} // backtrace
    152131
    153 static void sigSegvBusHandler( int sig_num ) {
     132void sigSegvBusHandler( int sig_num ) {
    154133        cerr << "*CFA runtime error* program cfa-cpp terminated with "
    155134                 <<     (sig_num == SIGSEGV ? "segment fault" : "bus error")
     
    157136        backtrace( 2 );                                                                         // skip first 2 stack frames
    158137        //_exit( EXIT_FAILURE );
    159         abort();                                                                                        // cause core dump for debugging
     138        abort();
    160139} // sigSegvBusHandler
    161140
    162 static void sigAbortHandler( __attribute__((unused)) int sig_num ) {
     141void sigAbortHandler( __attribute__((unused)) int sig_num ) {
    163142        backtrace( 6 );                                                                         // skip first 6 stack frames
    164143        signal( SIGABRT, SIG_DFL);                                                      // reset default signal handler
    165                 raise( SIGABRT );                                                                       // reraise SIGABRT
     144    raise( SIGABRT );                                                                   // reraise SIGABRT
    166145} // sigAbortHandler
    167146
     
    169148int main( int argc, char * argv[] ) {
    170149        FILE * input;                                                                           // use FILE rather than istream because yyin is FILE
    171         ostream * output = & cout;
    172         const char * filename = nullptr;
     150        ostream *output = & cout;
     151        const char *filename = nullptr;
    173152        list< Declaration * > translationUnit;
    174153
     
    202181                } // if
    203182
    204                 Stats::Time::StartGlobal();
    205                 NewPass("Parse");
    206                 Stats::Time::StartBlock("Parse");
    207 
    208183                // read in the builtins, extras, and the prelude
    209184                if ( ! nopreludep ) {                                                   // include gcc builtins
     
    240215                        parseTree->printList( cout );
    241216                        delete parseTree;
    242                         return EXIT_SUCCESS;
     217                        return 0;
    243218                } // if
    244219
     
    249224                if ( astp ) {
    250225                        dump( translationUnit );
    251                         return EXIT_SUCCESS;
     226                        return 0;
    252227                } // if
    253228
     
    256231                // works okay for now.
    257232                CodeTools::fillLocations( translationUnit );
    258                 Stats::Time::StopBlock();
    259233
    260234                // add the assignment statement after the initialization of a type parameter
    261                 PASS( "Validate", SymTab::validate( translationUnit, symtabp ) );
     235                PASS( "validate", SymTab::validate( translationUnit, symtabp ) );
    262236                if ( symtabp ) {
    263237                        deleteAll( translationUnit );
    264                         return EXIT_SUCCESS;
     238                        return 0;
    265239                } // if
    266240
     
    268242                        PassVisitor<ResolvExpr::AlternativePrinter> printer( cout );
    269243                        acceptAll( translationUnit, printer );
    270                         return EXIT_SUCCESS;
     244                        return 0;
    271245                } // if
    272246
    273247                if ( validp ) {
    274248                        dump( translationUnit );
    275                         return EXIT_SUCCESS;
    276                 } // if
    277 
    278                 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
    279                 PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
    280                 PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
    281                 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) );
     249                        return 0;
     250                } // if
     251
     252                PASS( "fixLabels", ControlStruct::fixLabels( translationUnit ) );
     253                PASS( "fixNames", CodeGen::fixNames( translationUnit ) );
     254                PASS( "genInit", InitTweak::genInit( translationUnit ) );
     255                PASS( "expandMemberTuples" , Tuples::expandMemberTuples( translationUnit ) );
    282256                if ( libcfap ) {
    283257                        // generate the bodies of cfa library functions
     
    288262                        CodeTools::printDeclStats( translationUnit );
    289263                        deleteAll( translationUnit );
    290                         return EXIT_SUCCESS;
    291                 } // if
     264                        return 0;
     265                }
    292266
    293267                if ( bresolvep ) {
    294268                        dump( translationUnit );
    295                         return EXIT_SUCCESS;
     269                        return 0;
    296270                } // if
    297271
     
    300274                if ( resolvprotop ) {
    301275                        CodeTools::dumpAsResolvProto( translationUnit );
    302                         return EXIT_SUCCESS;
    303                 } // if
    304 
    305                 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
     276                        return 0;
     277                }
     278
     279                PASS( "resolve", ResolvExpr::resolve( translationUnit ) );
    306280                if ( exprp ) {
    307281                        dump( translationUnit );
    308                         return EXIT_SUCCESS;
     282                        return 0;
    309283                } // if
    310284
    311285                // fix ObjectDecl - replaces ConstructorInit nodes
    312                 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
     286                PASS( "fixInit", InitTweak::fix( translationUnit, buildingLibrary() ) );
    313287                if ( ctorinitp ) {
    314288                        dump ( translationUnit );
    315                         return EXIT_SUCCESS;
    316                 } // if
    317 
    318                 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // 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
    319 
    320                 PASS( "Translate EHM" , ControlStruct::translateEHM( translationUnit ) );
    321 
    322                 PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) );
    323 
    324                 PASS( "Convert Specializations",  GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded
    325 
    326                 PASS( "Expand Tuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this?
     289                        return 0;
     290                } // if
     291
     292                PASS( "expandUniqueExpr", Tuples::expandUniqueExpr( translationUnit ) ); // 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
     293
     294                PASS( "translateEHM" , ControlStruct::translateEHM( translationUnit ) );
     295
     296                PASS( "generateWaitfor" , Concurrency::generateWaitFor( translationUnit ) );
     297
     298                PASS( "convertSpecializations",  GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded
     299
     300                PASS( "expandTuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this?
    327301
    328302                if ( tuplep ) {
    329303                        dump( translationUnit );
    330                         return EXIT_SUCCESS;
    331                 } // if
    332 
    333                 PASS( "Virtual Expand Casts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM
    334 
    335                 PASS( "Instantiate Generics", GenPoly::instantiateGeneric( translationUnit ) );
     304                        return 0;
     305                }
     306
     307                PASS( "virtual expandCasts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM
     308
     309                PASS( "instantiateGenerics", GenPoly::instantiateGeneric( translationUnit ) );
    336310                if ( genericsp ) {
    337311                        dump( translationUnit );
    338                         return EXIT_SUCCESS;
    339                 } // if
    340                 PASS( "Convert L-Value", GenPoly::convertLvalue( translationUnit ) );
     312                        return 0;
     313                }
     314                PASS( "convertLvalue", GenPoly::convertLvalue( translationUnit ) );
    341315
    342316
    343317                if ( bboxp ) {
    344318                        dump( translationUnit );
    345                         return EXIT_SUCCESS;
    346                 } // if
    347                 PASS( "Box", GenPoly::box( translationUnit ) );
     319                        return 0;
     320                } // if
     321                PASS( "box", GenPoly::box( translationUnit ) );
    348322
    349323                if ( bcodegenp ) {
    350324                        dump( translationUnit );
    351                         return EXIT_SUCCESS;
    352                 } // if
     325                        return 0;
     326                }
    353327
    354328                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    357331
    358332                CodeTools::fillLocations( translationUnit );
    359                 PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
     333                PASS( "codegen", CodeGen::generate( translationUnit, *output, ! noprotop, prettycodegenp, true, linemarks ) );
    360334
    361335                CodeGen::FixMain::fix( *output, (PreludeDirector + "/bootloader.c").c_str() );
     
    373347                        delete output;
    374348                } // if
    375                 return EXIT_FAILURE;
     349                return 1;
    376350        } catch ( UnimplementedError &e ) {
    377351                cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl;
     
    379353                        delete output;
    380354                } // if
    381                 return EXIT_FAILURE;
     355                return 1;
    382356        } catch ( CompilerError &e ) {
    383357                cerr << "Compiler Error: " << e.get_what() << endl;
     
    386360                        delete output;
    387361                } // if
    388                 return EXIT_FAILURE;
    389         } catch ( ... ) {
     362                return 1;
     363        } catch(...) {
    390364                std::exception_ptr eptr = std::current_exception();
    391365                try {
    392366                        if (eptr) {
    393367                                std::rethrow_exception(eptr);
    394                         } else {
    395                                 std::cerr << "Exception Uncaught and Unknown" << std::endl;
    396                         } // if
     368                        }
     369                        else {
     370                                std::cerr << "Exception Uncaught and Unkown" << std::endl;
     371                        }
    397372                } catch(const std::exception& e) {
    398373                        std::cerr << "Uncaught Exception \"" << e.what() << "\"\n";
    399                 } // try
    400                 return EXIT_FAILURE;
    401         } // try
     374                }
     375                return 1;
     376        }// try
    402377
    403378        deleteAll( translationUnit );
    404         Stats::print();
    405         return EXIT_SUCCESS;
     379        if(!libcfap && !treep) HeapStats::printStats();
     380        return 0;
    406381} // main
    407382
    408 
    409 static const char optstring[] = ":hlLmNn:pP:S:twW:D:F:";
    410 
    411 enum { PreludeDir = 128 };
    412 static struct option long_opts[] = {
    413         { "help", no_argument, nullptr, 'h' },
    414         { "libcfa", no_argument, nullptr, 'l' },
    415         { "linemarks", no_argument, nullptr, 'L' },
    416         { "no-main", no_argument, 0, 'm' },
    417         { "no-linemarks", no_argument, nullptr, 'N' },
    418         { "no-prelude", no_argument, nullptr, 'n' },
    419         { "prototypes", no_argument, nullptr, 'p' },
    420         { "print", required_argument, nullptr, 'P' },
    421         { "prelude-dir", required_argument, nullptr, PreludeDir },
    422         { "statistics", required_argument, nullptr, 'S' },
    423         { "tree", no_argument, nullptr, 't' },
    424         { "", no_argument, nullptr, 0 },                                        // -w
    425         { "", no_argument, nullptr, 0 },                                        // -W
    426         { "", no_argument, nullptr, 0 },                                        // -D
    427         { "", no_argument, nullptr, 0 },                                        // -F
    428         { nullptr, 0, nullptr, 0 }
    429 }; // long_opts
    430 
    431 static const char * description[] = {
    432         "print help message",                                                           // -h
    433         "generate libcfa.c",                                                            // -l
    434         "generate line marks",                                                          // -L
    435         "do not replace main",                                                          // -m
    436         "do not generate line marks",                                           // -N
    437         "do not read prelude",                                                          // -n
    438         "generate prototypes for prelude functions",            // -p
    439         "print",                                                                                        // -P
    440         "<directory> prelude directory for debug/nodebug",      // no flag
    441         "<option-list> enable profiling information:\n          counters,heap,time,all,none", // -S
    442         "build in tree",                                                                        // -t
    443         "",                                                                                                     // -w
    444         "",                                                                                                     // -W
    445         "",                                                                                                     // -D
    446         "",                                                                                                     // -F
    447 }; // description
    448 
    449 static_assert( sizeof( long_opts ) / sizeof( long_opts[0] ) - 1 == sizeof( description ) / sizeof( description[0] ), "Long opts and description must match" );
    450 
    451 static struct Printopts {
    452         const char * name;
    453         int & flag;
    454         int val;
    455         const char * descript;
    456 } printopts[] = {
    457         { "altexpr", expraltp, true, "alternatives for expressions" },
    458         { "ascodegen", codegenp, true, "as codegen rather than AST" },
    459         { "ast", astp, true, "AST after parsing" },
    460         { "astdecl", validp, true, "AST after declaration validation pass" },
    461         { "asterr", errorp, true, "AST on error" },
    462         { "astexpr", exprp, true, "AST after expression analysis" },
    463         { "astgen", genericsp, true, "AST after instantiate generics" },
    464         { "box", bboxp, true, "before box step" },
    465         { "ctordtor", ctorinitp, true, "after ctor/dtor are replaced" },
    466         { "codegen", bcodegenp, true, "before code generation" },
    467         { "declstats", declstatsp, true, "code property statistics" },
    468         { "parse", yydebug, true, "yacc (parsing) debug information" },
    469         { "pretty", prettycodegenp, true, "prettyprint for ascodegen flag" },
    470         { "resolver", bresolvep, true, "before resolver step" },
    471         { "rproto", resolvprotop, true, "resolver-proto instance" },
    472         { "rsteps", resolvep, true, "resolver steps" },
    473         { "symevt", symtabp, true, "symbol table events" },
    474         { "tree", parsep, true, "parse tree" },
    475         { "tuple", tuplep, true, "after tuple expansion" },
    476 };
    477 enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) };
    478 
    479 static void usage( char *argv[] ) {
    480     cout << "Usage: " << argv[0] << " options are:" << endl;
    481         int i = 0, j = 1;                                                                       // j skips starting colon
    482         for ( ; long_opts[i].name != 0 && optstring[j] != '\0'; i += 1, j += 1 ) {
    483                 if ( long_opts[i].name[0] != '\0' ) {                   // hidden option, internal usage only
    484                         if ( strcmp( long_opts[i].name, "prelude-dir" ) != 0 ) { // flag
    485                                 cout << "  -" << optstring[j] << ",";
    486                         } else {                                                                        // no flag
    487                                 j -= 1;                                                                 // compensate
    488                                 cout << "     ";
    489                         } // if
    490                         cout << " --" << left << setw(12) << long_opts[i].name << "  ";
    491                         if ( strcmp( long_opts[i].name, "print" ) == 0 ) {
    492                                 cout << "one of: " << endl;
    493                                 for ( int i = 0; i < printoptsSize; i += 1 ) {
    494                                         cout << setw(10) << " " << left << setw(10) << printopts[i].name << "  " << printopts[i].descript << endl;
    495                                 } // for
    496                         } else {
    497                                 cout << description[i] << endl;
    498                         } // if
    499                 } // if
    500                 if ( optstring[j + 1] == ':' ) j += 1;
    501         } // for
    502         if ( long_opts[i].name != 0 || optstring[j] != '\0' ) assertf( false, "internal error, mismatch of option flags and names\n" );
    503     exit( EXIT_FAILURE );
    504 } // usage
    505 
    506 static void parse_cmdline( int argc, char * argv[], const char *& filename ) {
     383void parse_cmdline( int argc, char * argv[], const char *& filename ) {
     384        enum { Ast, Bbox, Bresolver, CtorInitFix, DeclStats, Expr, ExprAlt, Grammar, LibCFA, Linemarks, Nolinemarks, Nopreamble, Parse, PreludeDir, Prototypes, Resolver, ResolvProto, Symbol, Tree, TupleExpansion, Validate, };
     385
     386        static struct option long_opts[] = {
     387                { "ast", no_argument, 0, Ast },
     388                { "before-box", no_argument, 0, Bbox },
     389                { "before-resolver", no_argument, 0, Bresolver },
     390                { "ctorinitfix", no_argument, 0, CtorInitFix },
     391                { "decl-stats", no_argument, 0, DeclStats },
     392                { "expr", no_argument, 0, Expr },
     393                { "expralt", no_argument, 0, ExprAlt },
     394                { "grammar", no_argument, 0, Grammar },
     395                { "libcfa", no_argument, 0, LibCFA },
     396                { "line-marks", no_argument, 0, Linemarks },
     397                { "no-line-marks", no_argument, 0, Nolinemarks },
     398                { "no-preamble", no_argument, 0, Nopreamble },
     399                { "parse", no_argument, 0, Parse },
     400                { "prelude-dir", required_argument, 0, PreludeDir },
     401                { "no-prototypes", no_argument, 0, Prototypes },
     402                { "resolver", no_argument, 0, Resolver },
     403                { "resolv-proto", no_argument, 0, ResolvProto },
     404                { "symbol", no_argument, 0, Symbol },
     405                { "tree", no_argument, 0, Tree },
     406                { "tuple-expansion", no_argument, 0, TupleExpansion },
     407                { "validate", no_argument, 0, Validate },
     408                { 0, 0, 0, 0 }
     409        }; // long_opts
     410        int long_index;
     411
    507412        opterr = 0;                                                                                     // (global) prevent getopt from printing error messages
    508413
    509414        bool Wsuppress = false, Werror = false;
    510415        int c;
    511         while ( (c = getopt_long( argc, argv, optstring, long_opts, nullptr )) != -1 ) {
     416        while ( (c = getopt_long( argc, argv, "abBcCdefgGlLmnNpqrRstTvwW:yzZD:F:", long_opts, &long_index )) != -1 ) {
    512417                switch ( c ) {
    513                   case 'h':                                                                             // help message
    514                         usage( argv );                                                          // no return
    515                         break;
     418                  case Ast:
     419                  case 'a':                                                                             // dump AST
     420                        astp = true;
     421                        break;
     422                  case Bresolver:
     423                  case 'b':                                                                             // print before resolver steps
     424                        bresolvep = true;
     425                        break;
     426                  case 'B':                                                                             // print before box steps
     427                        bboxp = true;
     428                        break;
     429                  case CtorInitFix:
     430                  case 'c':                                                                             // print after constructors and destructors are replaced
     431                        ctorinitp = true;
     432                        break;
     433                  case 'C':                                                                             // print before code generation
     434                        bcodegenp = true;
     435                        break;
     436                  case DeclStats:
     437                  case 'd':
     438                    declstatsp = true;
     439                        break;
     440                  case Expr:
     441                  case 'e':                                                                             // dump AST after expression analysis
     442                        exprp = true;
     443                        break;
     444                  case ExprAlt:
     445                  case 'f':                                                                             // print alternatives for expressions
     446                        expraltp = true;
     447                        break;
     448                  case Grammar:
     449                  case 'g':                                                                             // bison debugging info (grammar rules)
     450                        yydebug = true;
     451                        break;
     452                  case 'G':                                                                             // dump AST after instantiate generics
     453                        genericsp = true;
     454                        break;
     455                  case LibCFA:
    516456                  case 'l':                                                                             // generate libcfa.c
    517457                        libcfap = true;
    518458                        break;
    519                   case 'L':                                                                             // generate line marks
     459                  case Linemarks:
     460                  case 'L':                                                                             // print lines marks
    520461                        linemarks = true;
    521462                        break;
    522                   case 'm':                                                                             // do not replace main
    523                         nomainp = true;
    524                         break;
    525                   case 'N':                                                                             // do not generate line marks
     463                  case Nopreamble:
     464                  case 'n':                                                                             // do not read preamble
     465                        nopreludep = true;
     466                        break;
     467                  case Nolinemarks:
     468                  case 'N':                                                                             // suppress line marks
    526469                        linemarks = false;
    527470                        break;
    528                   case 'n':                                                                             // do not read prelude
    529                         nopreludep = true;
    530                         break;
    531                   case 'p':                                                                             // generate prototypes for prelude functions
    532                         genproto = true;
    533                         break;
    534                   case 'P':                                                                             // print options
    535                         for ( int i = 0;; i += 1 ) {
    536                                 if ( i == printoptsSize ) {
    537                                         cout << "Unknown --print option " << optarg << endl;
    538                                         goto Default;
    539                                 } // if
    540                                 if ( strcmp( optarg, printopts[i].name ) == 0 ) {
    541                                         printopts[i].flag = printopts[i].val;
    542                                         break;
    543                                 } // if
    544                         } // for
    545                         break;
    546                   case PreludeDir:                                                              // prelude directory for debug/nodebug, hidden
    547                         PreludeDirector = optarg;
    548                         break;
    549                   case 'S':                                                                             // enable profiling information, argument comma separated list of names
    550                         Stats::parse_params( optarg );
    551                         break;
     471                  case Prototypes:
     472                  case 'p':                                                                             // generate prototypes for preamble functions
     473                        noprotop = true;
     474                        break;
     475                  case PreludeDir:
     476                        PreludeDirector = optarg;
     477                        break;
     478                  case 'm':                                                                             // don't replace the main
     479                        nomainp = true;
     480                        break;
     481                  case Parse:
     482                  case 'q':                                                                             // dump parse tree
     483                        parsep = true;
     484                        break;
     485                  case Resolver:
     486                  case 'r':                                                                             // print resolver steps
     487                        resolvep = true;
     488                        break;
     489                  case 'R':                                                                             // dump resolv-proto instance
     490                        resolvprotop = true;
     491                        break;
     492                  case Symbol:
     493                  case 's':                                                                             // print symbol table events
     494                        symtabp = true;
     495                        break;
     496                  case Tree:
    552497                  case 't':                                                                             // build in tree
    553498                        treep = true;
    554499                        break;
    555                   case 'w':                                                                             // suppress all warnings, hidden
     500                  case TupleExpansion:
     501                  case 'T':                                                                             // print after tuple expansion
     502                        tuplep = true;
     503                        break;
     504                  case 'v':                                                                             // dump AST after decl validation pass
     505                        validp = true;
     506                        break;
     507                  case 'w':
    556508                        Wsuppress = true;
    557509                        break;
    558                   case 'W':                                                                             // coordinate gcc -W with CFA, hidden
     510                  case 'W':
    559511                        if ( strcmp( optarg, "all" ) == 0 ) {
    560512                                SemanticWarning_EnableAll();
     
    573525                        } // if
    574526                        break;
    575                   case 'D':                                                                             // ignore -Dxxx, forwarded by cpp, hidden
    576                         break;
    577                   case 'F':                                                                             // source file-name without suffix, hidden
     527                  case 'y':                                                                             // dump AST on error
     528                        errorp = true;
     529                        break;
     530                  case 'z':                                                                             // dump as codegen rather than AST
     531                        codegenp = true;
     532                        break;
     533                        case 'Z':                                                                       // prettyprint during codegen (i.e. print unmangled names, etc.)
     534                        prettycodegenp = true;
     535                        break;
     536                  case 'D':                                                                             // ignore -Dxxx
     537                        break;
     538                  case 'F':                                                                             // source file-name without suffix
    578539                        filename = optarg;
    579540                        break;
    580                   case '?':                                                                             // unknown option
     541                  case '?':
    581542                        if ( optopt ) {                                                         // short option ?
    582                                 cout << "Unknown option -" << (char)optopt << endl;
     543                                assertf( false, "Unknown option: -%c\n", (char)optopt );
    583544                        } else {
    584                                 cout << "Unknown option " << argv[optind - 1] << endl;
     545                                assertf( false, "Unknown option: %s\n", argv[optind - 1] );
    585546                        } // if
    586                         goto Default;
    587                   case ':':                                                                             // missing option
    588                         if ( optopt ) {                                                         // short option ?
    589                                 cout << "Missing option for -" << (char)optopt << endl;
    590                         } else {
    591                                 cout << "Missing option for " << argv[optind - 1] << endl;
    592                         } // if
    593                         goto Default;
    594                   Default:
     547                        #if defined(__GNUC__) && __GNUC__ >= 7
     548                                __attribute__((fallthrough));
     549                        #endif
    595550                  default:
    596                         usage( argv );                                                          // no return
     551                        abort();
    597552                } // switch
    598553        } // while
     
    632587        list< Declaration * > decls;
    633588
    634         if ( genproto ) {
     589        if ( noprotop ) {
    635590                filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), notPrelude );
    636591        } else {
     
    640595        // depending on commandline options, either generate code or dump the AST
    641596        if ( codegenp ) {
    642                 CodeGen::generate( decls, out, ! genproto, prettycodegenp );
     597                CodeGen::generate( decls, out, ! noprotop, prettycodegenp );
    643598        } else {
    644599                printAll( decls, out );
    645         } // if
     600        }
    646601        deleteAll( translationUnit );
    647602} // dump
  • tests/.expect/KRfunctions.x64.txt

    r933f32f r6a9d4b4  
    6262    __attribute__ ((unused)) signed int _X10_retval_f5i_1;
    6363}
    64 signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(__attribute__ ((unused)) signed int __anonymous_object0){
     64signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(signed int __anonymous_object0){
    6565    __attribute__ ((unused)) signed int (*_X10_retval_f6Fi_i__1)(signed int __anonymous_object1);
    6666}
     
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
     106        signed int *(*_tmp_cp_ret2)(signed int _X1xi_1, signed int _X1yi_1);
     107        void __cleanup_dtor4(signed int *(**_dst)(signed int _X1xi_1, signed int _X1yi_1)){
     108            ((void)((*_dst)) /* ^?{} */);
     109        }
     110        __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object6))__cleanup_dtor4) };
     111        void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1));
     112        ((void)(_X1xFPi_ii__2=(((void)(((void)(_tmp_cp_ret2=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)));
    108113    }
    109114
  • tests/.expect/KRfunctions.x86.txt

    r933f32f r6a9d4b4  
    6262    __attribute__ ((unused)) signed int _X10_retval_f5i_1;
    6363}
    64 signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(__attribute__ ((unused)) signed int __anonymous_object0){
     64signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(signed int __anonymous_object0){
    6565    __attribute__ ((unused)) signed int (*_X10_retval_f6Fi_i__1)(signed int __anonymous_object1);
    6666}
     
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
     106        signed int *(*_tmp_cp_ret2)(signed int _X1xi_1, signed int _X1yi_1);
     107        void __cleanup_dtor4(signed int *(**_dst)(signed int _X1xi_1, signed int _X1yi_1)){
     108            ((void)((*_dst)) /* ^?{} */);
     109        }
     110        __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object6))__cleanup_dtor4) };
     111        void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1));
     112        ((void)(_X1xFPi_ii__2=(((void)(((void)(_tmp_cp_ret2=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)));
    108113    }
    109114
  • tests/.expect/abs.txt

    r933f32f r6a9d4b4  
    33signed long int         -65     abs 65
    44signed long long int    -65     abs 65
    5 float                   -65.    abs 65.
    6 double                  -65.    abs 65.
    7 long double             -65.    abs 65.
    8 float _Complex          -65.-2.i        abs 65.0308
    9 double _Complex         -65.-2.i        abs 65.0307619515564
    10 long double _Complex    -65.-2.i        abs 65.0307619515564342
     5float                   -65     abs 65
     6double                  -65     abs 65
     7long double             -65     abs 65
     8float _Complex          -65-2i  abs 65.0308
     9double _Complex         -65-2i  abs 65.0307619515564
     10long double _Complex    -65-2i  abs 65.0307619515564342
  • tests/.expect/ato.txt

    r933f32f r6a9d4b4  
    2222-123.456789012345679 -123.45678901234567890123456789
    2323-123.456-123.456i -123.456-123.456i
    24 0.+0.i 2  3
     240+0i 2  3
    2525-123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    2626123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i
  • tests/.expect/attributes.x64.txt

    r933f32f r6a9d4b4  
    640640}
    641641__attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1);
    642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){
     642__attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object2){
    643643    __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3);
    644644}
  • tests/.expect/attributes.x86.txt

    r933f32f r6a9d4b4  
    640640}
    641641__attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1);
    642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){
     642__attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object2){
    643643    __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3);
    644644}
  • tests/.expect/castError.txt

    r933f32f r6a9d4b4  
    1 castError.cfa:21:1 error: Cannot choose between 3 alternatives for expression
    2 Explicit Cast of:
     1castError.cfa:7:1 error: Cannot choose between 3 alternatives for expression
     2Cast of:
    33  Name: f
    44... to:
    55  char Alternatives are:
    6 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
     6Cost ( 1, 0, 0, 0, 0, 0 ): Cast of:
    77     Variable Expression: f: function
    88       accepting unspecified arguments
     
    1616 Environment:
    1717
    18 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
     18Cost ( 1, 0, 0, 0, 0, 0 ): Cast of:
    1919     Variable Expression: f: double
    2020   ... to:
     
    2525 Environment:
    2626
    27 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
     27Cost ( 1, 0, 0, 0, 0, 0 ): Cast of:
    2828     Variable Expression: f: signed int
    2929   ... to:
     
    3535
    3636
    37 castError.cfa:26:1 error: Cannot choose between 2 alternatives for expression
    38 Generated Cast of:
    39   Comma Expression:
    40     constant expression (3 3: signed int)
    41     Name: v
    42 ... to: nothing Alternatives are:
    43 Cost ( 0, 0, 2, 0, 0, 0, 0 ): Generated Cast of:
    44      Comma Expression:
    45        constant expression (3 3: signed int)
    46        Variable Expression: v: unsigned char
    47    ... to: nothing
    48  (types:
    49    void
    50  )
    51  Environment:
    52 
    53 Cost ( 0, 0, 2, 0, 0, 0, 0 ): Generated Cast of:
    54      Comma Expression:
    55        constant expression (3 3: signed int)
    56        Variable Expression: v: signed short int
    57    ... to: nothing
    58  (types:
    59    void
    60  )
    61  Environment:
    62 
    63 
  • tests/.expect/completeTypeError.txt

    r933f32f r6a9d4b4  
    1 completeTypeError.cfa:34:1 error: Cannot choose between 2 alternatives for expression
    2 Generated Cast of:
    3   Applying untyped:
    4     Name: *?
    5   ...to:
    6     Name: x
     1completeTypeError.cfa:33:1 error: No reasonable alternatives for expression Applying untyped:
     2  Name: *?
     3...to:
     4  Name: v
    75
    8 ... to: nothing Alternatives are:
    9 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
    10      Application of
    11        Variable Expression: *?: forall
    12          DT: object type
    13          function
    14        ... with parameters
    15          intrinsic pointer to instance of type DT (not function type)
    16        ... returning
    17          _retval__operator_deref: reference to instance of type DT (not function type)
    18          ... with attributes:
    19            Attribute with name: unused
    20 
    21 
    22      ... to arguments
    23        Variable Expression: x: pointer to instance of struct A with body 0
    24 
    25    ... to: nothing
    26  (types:
    27    void
    28  )
    29  Environment:( _80_4_DT ) -> instance of struct A with body 0 (no widening)
    30 
    31 
    32 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
    33      Application of
    34        Variable Expression: *?: forall
    35          DT: object type
    36          function
    37        ... with parameters
    38          intrinsic pointer to instance of type DT (not function type)
    39        ... returning
    40          _retval__operator_deref: reference to instance of type DT (not function type)
    41          ... with attributes:
    42            Attribute with name: unused
    43 
    44 
    45      ... to arguments
    46        Variable Expression: x: pointer to instance of struct B with body 1
    47 
    48    ... to: nothing
    49  (types:
    50    void
    51  )
    52  Environment:( _80_4_DT ) -> instance of struct B with body 1 (no widening)
    53 
    54 
     6completeTypeError.cfa:34:1 error: No reasonable alternatives for expression Applying untyped:
     7  Name: *?
     8...to:
     9  Name: y
    5510
    5611completeTypeError.cfa:35:1 error: No reasonable alternatives for expression Applying untyped:
     
    6924  Name: v
    7025
    71 completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
     26completeTypeError.cfa:58:1 error: No reasonable alternatives for expression Applying untyped:
    7227  Name: baz
    7328...to:
    7429  Name: y
    7530
    76 completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
     31completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
    7732  Name: quux
    7833...to:
    7934  Name: y
    8035
    81 completeTypeError.cfa:72:1 error: No alternatives with satisfiable assertions for Applying untyped:
     36completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
     37  Name: *?
     38...to:
     39  Name: y
     40
     41completeTypeError.cfa:72:1 error: No resolvable alternatives for expression Applying untyped:
    8242  Name: baz
    8343...to:
    8444  Name: z
    8545
    86    Unsatisfiable alternative:
    87 Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
    88          Variable Expression: baz: forall
    89            T: sized object type
    90            ... with assertions
    91              ?=?: pointer to function
    92              ... with parameters
    93                reference to instance of type T (not function type)
    94                instance of type T (not function type)
    95              ... returning
    96                _retval__operator_assign: instance of type T (not function type)
    97                ... with attributes:
    98                  Attribute with name: unused
     46Alternatives with failing assertions are:
     47Cost ( 0, 1, 0, 1, -5, 0 ): Application of
     48     Variable Expression: baz: forall
     49       T: sized object type
     50       ... with assertions
     51         ?=?: pointer to function
     52         ... with parameters
     53           reference to instance of type T (not function type)
     54           instance of type T (not function type)
     55         ... returning
     56           _retval__operator_assign: instance of type T (not function type)
     57           ... with attributes:
     58             Attribute with name: unused
    9959
    10060
    101              ?{}: pointer to function
    102              ... with parameters
    103                reference to instance of type T (not function type)
    104              ... returning nothing
     61         ?{}: pointer to function
     62         ... with parameters
     63           reference to instance of type T (not function type)
     64         ... returning nothing
    10565
    106              ?{}: pointer to function
    107              ... with parameters
    108                reference to instance of type T (not function type)
    109                instance of type T (not function type)
    110              ... returning nothing
     66         ?{}: pointer to function
     67         ... with parameters
     68           reference to instance of type T (not function type)
     69           instance of type T (not function type)
     70         ... returning nothing
    11171
    112              ^?{}: pointer to function
    113              ... with parameters
    114                reference to instance of type T (not function type)
    115              ... returning nothing
     72         ^?{}: pointer to function
     73         ... with parameters
     74           reference to instance of type T (not function type)
     75         ... returning nothing
    11676
    11777
    118            function
    119          ... with parameters
    120            pointer to instance of type T (not function type)
    121          ... returning nothing
     78       function
     79     ... with parameters
     80       pointer to instance of type T (not function type)
     81     ... returning nothing
    12282
    123        ... to arguments
    124          Variable Expression: z: pointer to instance of type T (not function type)
     83   ... to arguments
     84     Variable Expression: z: pointer to instance of type T (not function type)
    12585
    126      (types:
    127        void
    128      )
    129      Environment:( _99_0_T ) -> instance of type T (not function type) (no widening)
    130 
    131    Could not satisfy assertion:
    132 ?=?: pointer to function
    133      ... with parameters
    134        reference to instance of type _99_0_T (not function type)
    135        instance of type _99_0_T (not function type)
    136      ... returning
    137        _retval__operator_assign: instance of type _99_0_T (not function type)
    138        ... with attributes:
    139          Attribute with name: unused
     86 (types:
     87   void
     88 )
     89 Environment:( _73_0_T ) -> instance of type T (not function type) (no widening)
    14090
    14191
     92
  • tests/.expect/complex.txt

    r933f32f r6a9d4b4  
    11x:3+2i y:4+5i z:7+7i
    2 x:3.+2.i y:4.+5.i z:7.+7.i
     2x:3+2i y:4+5i z:7+7i
    33x:2.1+1.3i y:3.2+4.5i z:5.3+5.8i
    44x:2.1+1.3i y:3.2+4.5i z:5.3+5.8i
  • tests/.expect/declarationSpecifier.x64.txt

    r933f32f r6a9d4b4  
    11221122    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11231123    {
     1124        ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */);
     1125    }
     1126
     1127    return _X12_retval_maini_1;
     1128    {
    11241129        ((void)(_X12_retval_maini_1=0) /* ?{} */);
    11251130    }
     
    11321137    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11331138    {
    1134         signed int _tmp_cp_ret4;
    1135         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
     1139        signed int _tmp_cp_ret2;
     1140        __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) };
     1141        void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1));
     1142        ((void)(_X12_retval_maini_1=(((void)(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)) /* ?{} */);
    11361143    }
    11371144
  • tests/.expect/declarationSpecifier.x86.txt

    r933f32f r6a9d4b4  
    11221122    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11231123    {
     1124        ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */);
     1125    }
     1126
     1127    return _X12_retval_maini_1;
     1128    {
    11241129        ((void)(_X12_retval_maini_1=0) /* ?{} */);
    11251130    }
     
    11321137    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11331138    {
    1134         signed int _tmp_cp_ret4;
    1135         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
     1139        signed int _tmp_cp_ret2;
     1140        __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) };
     1141        void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1));
     1142        ((void)(_X12_retval_maini_1=(((void)(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)) /* ?{} */);
    11361143    }
    11371144
  • tests/.expect/extension.x64.txt

    r933f32f r6a9d4b4  
    457457
    458458    {
    459         signed int _tmp_cp_ret4;
    460         ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
     459        signed int _tmp_cp_ret2;
     460        __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) };
     461        void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1));
     462        ((void)(((void)(((void)(_tmp_cp_ret2=__extension__ _X4fredFi_i__1(3))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2));
    461463    }
    462464
  • tests/.expect/extension.x86.txt

    r933f32f r6a9d4b4  
    457457
    458458    {
    459         signed int _tmp_cp_ret4;
    460         ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
     459        signed int _tmp_cp_ret2;
     460        __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) };
     461        void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1));
     462        ((void)(((void)(((void)(_tmp_cp_ret2=__extension__ _X4fredFi_i__1(3))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2));
    461463    }
    462464
  • tests/.expect/functions.x64.txt

    r933f32f r6a9d4b4  
    11void _X1hFv___1(void){
    22}
    3 signed int _X1fFi_Fi__Fi_i_Fi__Fi_i_Fv____1(__attribute__ ((unused)) signed int (*__anonymous_object0)(void), __attribute__ ((unused)) signed int (*__anonymous_object1)(signed int __anonymous_object2), __attribute__ ((unused)) signed int (*__anonymous_object3)(void), __attribute__ ((unused)) signed int (*__anonymous_object4)(signed int __anonymous_object5), void (*_X1gFv___1)(void)){
     3signed int _X1fFi_Fi__Fi_i_Fi__Fi_i_Fv____1(signed int (*__anonymous_object0)(void), signed int (*__anonymous_object1)(signed int __anonymous_object2), signed int (*__anonymous_object3)(void), signed int (*__anonymous_object4)(signed int __anonymous_object5), void (*_X1gFv___1)(void)){
    44    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    55    {
     
    9999    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    100100}
    101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object7){
     101signed int _X1fFi_i__1(signed int __anonymous_object7){
    102102    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    103103}
     
    130130    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    131131}
    132 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object9, signed int _X1xi_1){
     132struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object9, signed int _X1xi_1){
    133133    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    134134}
     
    167167    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    168168}
    169 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object12, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object13){
     169struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object12, signed int _X1xi_1, signed int __anonymous_object13){
    170170    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    171171}
     
    180180    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    181181}
    182 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){
     182struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){
    183183    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    184184}
     
    190190const double _X3fooFd___1(void);
    191191const double _X3fooFd_i__1(signed int __anonymous_object19);
    192 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object20){
     192const double _X3fooFd_d__1(double __anonymous_object20){
    193193    __attribute__ ((unused)) const double _X11_retval_fooKd_1;
    194194    {
     
    242242
    243243}
    244 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object21){
     244struct S _X3rtnFS1S_i__1(signed int __anonymous_object21){
    245245    __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1;
    246246}
    247 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1), __attribute__ ((unused)) signed int (*__anonymous_object24)(signed int __anonymous_object25)){
     247signed int _X1fFi_Fi_ii_Fi_i___1(signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1), signed int (*__anonymous_object24)(signed int __anonymous_object25)){
    248248    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    249249    signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)];
     
    271271}
    272272signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object27)(), signed int *(*__anonymous_object28)(), signed int **(*__anonymous_object29)(), signed int *const *(*__anonymous_object30)(), signed int *const *const (*__anonymous_object31)(), signed int *__anonymous_object32, signed int __anonymous_object33[((unsigned long int )10)], signed int **__anonymous_object34, signed int *__anonymous_object35[((unsigned long int )10)], signed int ***__anonymous_object36, signed int **__anonymous_object37[((unsigned long int )10)], signed int *const **__anonymous_object38, signed int *const *__anonymous_object39[((unsigned long int )10)], signed int *const *const *__anonymous_object40, signed int *const *const __anonymous_object41[((unsigned long int )10)]);
    273 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object42)(), __attribute__ ((unused)) signed int *(*__anonymous_object43)(), __attribute__ ((unused)) signed int **(*__anonymous_object44)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object45)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object46)(), __attribute__ ((unused)) signed int *__anonymous_object47, __attribute__ ((unused)) signed int __anonymous_object48[((unsigned long int )10)], __attribute__ ((unused)) signed int **__anonymous_object49, __attribute__ ((unused)) signed int *__anonymous_object50[((unsigned long int )10)], __attribute__ ((unused)) signed int ***__anonymous_object51, __attribute__ ((unused)) signed int **__anonymous_object52[((unsigned long int )10)], __attribute__ ((unused)) signed int *const **__anonymous_object53, __attribute__ ((unused)) signed int *const *__anonymous_object54[((unsigned long int )10)], __attribute__ ((unused)) signed int *const *const *__anonymous_object55, __attribute__ ((unused)) signed int *const *const __anonymous_object56[((unsigned long int )10)]){
     273signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object42)(), signed int *(*__anonymous_object43)(), signed int **(*__anonymous_object44)(), signed int *const *(*__anonymous_object45)(), signed int *const *const (*__anonymous_object46)(), signed int *__anonymous_object47, signed int __anonymous_object48[((unsigned long int )10)], signed int **__anonymous_object49, signed int *__anonymous_object50[((unsigned long int )10)], signed int ***__anonymous_object51, signed int **__anonymous_object52[((unsigned long int )10)], signed int *const **__anonymous_object53, signed int *const *__anonymous_object54[((unsigned long int )10)], signed int *const *const *__anonymous_object55, signed int *const *const __anonymous_object56[((unsigned long int )10)]){
    274274    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    275275}
  • tests/.expect/functions.x86.txt

    r933f32f r6a9d4b4  
    11void _X1hFv___1(void){
    22}
    3 signed int _X1fFi_Fi__Fi_i_Fi__Fi_i_Fv____1(__attribute__ ((unused)) signed int (*__anonymous_object0)(void), __attribute__ ((unused)) signed int (*__anonymous_object1)(signed int __anonymous_object2), __attribute__ ((unused)) signed int (*__anonymous_object3)(void), __attribute__ ((unused)) signed int (*__anonymous_object4)(signed int __anonymous_object5), void (*_X1gFv___1)(void)){
     3signed int _X1fFi_Fi__Fi_i_Fi__Fi_i_Fv____1(signed int (*__anonymous_object0)(void), signed int (*__anonymous_object1)(signed int __anonymous_object2), signed int (*__anonymous_object3)(void), signed int (*__anonymous_object4)(signed int __anonymous_object5), void (*_X1gFv___1)(void)){
    44    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    55    {
     
    9999    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    100100}
    101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object7){
     101signed int _X1fFi_i__1(signed int __anonymous_object7){
    102102    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    103103}
     
    130130    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    131131}
    132 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object9, signed int _X1xi_1){
     132struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object9, signed int _X1xi_1){
    133133    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    134134}
     
    167167    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    168168}
    169 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object12, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object13){
     169struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object12, signed int _X1xi_1, signed int __anonymous_object13){
    170170    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    171171}
     
    180180    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    181181}
    182 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){
     182struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){
    183183    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    184184}
     
    190190const double _X3fooFd___1(void);
    191191const double _X3fooFd_i__1(signed int __anonymous_object19);
    192 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object20){
     192const double _X3fooFd_d__1(double __anonymous_object20){
    193193    __attribute__ ((unused)) const double _X11_retval_fooKd_1;
    194194    {
     
    242242
    243243}
    244 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object21){
     244struct S _X3rtnFS1S_i__1(signed int __anonymous_object21){
    245245    __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1;
    246246}
    247 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1), __attribute__ ((unused)) signed int (*__anonymous_object24)(signed int __anonymous_object25)){
     247signed int _X1fFi_Fi_ii_Fi_i___1(signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1), signed int (*__anonymous_object24)(signed int __anonymous_object25)){
    248248    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    249249    signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned int )10)])[][((unsigned int )3)];
     
    271271}
    272272signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object27)(), signed int *(*__anonymous_object28)(), signed int **(*__anonymous_object29)(), signed int *const *(*__anonymous_object30)(), signed int *const *const (*__anonymous_object31)(), signed int *__anonymous_object32, signed int __anonymous_object33[((unsigned int )10)], signed int **__anonymous_object34, signed int *__anonymous_object35[((unsigned int )10)], signed int ***__anonymous_object36, signed int **__anonymous_object37[((unsigned int )10)], signed int *const **__anonymous_object38, signed int *const *__anonymous_object39[((unsigned int )10)], signed int *const *const *__anonymous_object40, signed int *const *const __anonymous_object41[((unsigned int )10)]);
    273 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object42)(), __attribute__ ((unused)) signed int *(*__anonymous_object43)(), __attribute__ ((unused)) signed int **(*__anonymous_object44)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object45)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object46)(), __attribute__ ((unused)) signed int *__anonymous_object47, __attribute__ ((unused)) signed int __anonymous_object48[((unsigned int )10)], __attribute__ ((unused)) signed int **__anonymous_object49, __attribute__ ((unused)) signed int *__anonymous_object50[((unsigned int )10)], __attribute__ ((unused)) signed int ***__anonymous_object51, __attribute__ ((unused)) signed int **__anonymous_object52[((unsigned int )10)], __attribute__ ((unused)) signed int *const **__anonymous_object53, __attribute__ ((unused)) signed int *const *__anonymous_object54[((unsigned int )10)], __attribute__ ((unused)) signed int *const *const *__anonymous_object55, __attribute__ ((unused)) signed int *const *const __anonymous_object56[((unsigned int )10)]){
     273signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object42)(), signed int *(*__anonymous_object43)(), signed int **(*__anonymous_object44)(), signed int *const *(*__anonymous_object45)(), signed int *const *const (*__anonymous_object46)(), signed int *__anonymous_object47, signed int __anonymous_object48[((unsigned int )10)], signed int **__anonymous_object49, signed int *__anonymous_object50[((unsigned int )10)], signed int ***__anonymous_object51, signed int **__anonymous_object52[((unsigned int )10)], signed int *const **__anonymous_object53, signed int *const *__anonymous_object54[((unsigned int )10)], signed int *const *const *__anonymous_object55, signed int *const *const __anonymous_object56[((unsigned int )10)]){
    274274    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    275275}
  • tests/.expect/gccExtensions.x64.txt

    r933f32f r6a9d4b4  
    292292    signed int _X2m3A0A0i_2[((unsigned long int )10)][((unsigned long int )10)];
    293293    {
    294         ((void)(_X12_retval_maini_1=0) /* ?{} */);
     294        ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */);
    295295    }
    296296
     
    307307    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    308308    {
    309         signed int _tmp_cp_ret4;
    310         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
     309        signed int _tmp_cp_ret2;
     310        __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) };
     311        void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1));
     312        ((void)(_X12_retval_maini_1=(((void)(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)) /* ?{} */);
    311313    }
    312314
  • tests/.expect/gccExtensions.x86.txt

    r933f32f r6a9d4b4  
    292292    signed int _X2m3A0A0i_2[((unsigned int )10)][((unsigned int )10)];
    293293    {
    294         ((void)(_X12_retval_maini_1=0) /* ?{} */);
     294        ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */);
    295295    }
    296296
     
    307307    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    308308    {
    309         signed int _tmp_cp_ret4;
    310         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
     309        signed int _tmp_cp_ret2;
     310        __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) };
     311        void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1));
     312        ((void)(_X12_retval_maini_1=(((void)(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)) /* ?{} */);
    311313    }
    312314
  • tests/.expect/identity.txt

    r933f32f r6a9d4b4  
    99double                  4.1
    1010long double             4.1
    11 float _Complex          -4.1-2.i
    12 double _Complex         -4.1-2.i
    13 long double _Complex    -4.1-2.i
     11float _Complex          -4.1-2i
     12double _Complex         -4.1-2i
     13long double _Complex    -4.1-2i
  • tests/.expect/io1.txt

    r933f32f r6a9d4b4  
    119 6 28 0 7 1 2
    2 0 1 2 3
    3 0123
    4 0123
     21 2 3
     3123
     4123
    55
    66opening delimiters
  • tests/.expect/loopctrl.txt

    r933f32f r6a9d4b4  
    191910 8 6 4 2
    2020
    21 1 2 3 4 5 6 7 8 9 10
    22 10 9 8 7 6 5 4 3 2 1 0
    23 2 4 6 8 10
    24 2.1 3.8 5.5 7.2 8.9
    25 10 8 6 4 2 0
    26 12.1 10.4 8.7 7. 5.3 3.6
    2721
    2822N N N N N N N N N N
     
    302410 9 8 7 6 5 4 3 2 1
    3125
     26
    32273 6 9
     28
    3329
    3430(0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9)
     
    4440(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)
    4541(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)
    46 
    47 0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4
    48 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14
    49 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13
    50 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23
    51 
    52 0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4
    53 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14
    54 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13
    55 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23
    56 
    57 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5
    58 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5
    59 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5
  • tests/.expect/math1.txt

    r933f32f r6a9d4b4  
    1 fmod:1. 1. 1. 1. 1. 1.
    2 remainder:-1. -1. -1.
     1fmod:1 1 1 1 1 1
     2remainder:-1 -1 -1
    33remquo:7 0.0999999 7 0.1 7 0.0999999999999999999
    4 div:7., 0.2 7., 0.2 7., 0.2
    5 fma:-2. -2. -2.
    6 fdim:2. 2. 2.
     4div:7, 0.2 7, 0.2 7, 0.2
     5fma:-2 -2 -2
     6fdim:2 2 2
    77nan:nan nan nan
    88exp:2.71828 2.71828182845905 2.71828182845904524 1.46869+2.28736i 1.46869393991589+2.28735528717884i 1.46869393991588516+2.28735528717884239i
    9 exp2:2. 2. 2.
     9exp2:2 2 2
    1010expm1:1.71828 1.71828182845905 1.71828182845904524
    11 pow:1. 1. 1. 0.273957+0.583701i 0.273957253830121+0.583700758758615i -0.638110484918098871+0.705394566961838155i
    12 16 \ 2 = 256
    13 912673 256 64 -64 0 0
    14 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
    15 0 0 18.3791736799526 0.264715-1.1922i
    16 16
    17 4 16
     11pow:1 1 1 0.273957+0.583701i 0.273957253830121+0.583700758758615i -0.638110484918098871+0.705394566961838155i
     12\ 16 256
     13\ 912673 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
  • tests/.expect/math2.txt

    r933f32f r6a9d4b4  
    1 log:0. 0. 0. 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
    2 log2:3. 3. 3.
    3 log10:2. 2. 2.
     1log:0 0 0 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
     2log2:3 3 3
     3log10:2 2 2
    44log1p:0.693147 0.693147180559945 0.693147180559945309
    55ilogb:0 0 0
    6 logb:3. 3. 3.
    7 sqrt:1. 1. 1. 1.09868+0.45509i 1.09868411346781+0.455089860562227i 1.09868411346780997+0.455089860562227341i
    8 cbrt:3. 3. 3.
     6logb:3 3 3
     7sqrt:1 1 1 1.09868+0.45509i 1.09868411346781+0.455089860562227i 1.09868411346780997+0.455089860562227341i
     8cbrt:3 3 3
    99hypot:1.41421 1.4142135623731 1.41421356237309505
    1010sin:0.841471 0.841470984807897 0.841470984807896507 1.29846+0.634964i 1.29845758141598+0.634963914784736i 1.29845758141597729+0.634963914784736108i
     
    1212tan:1.55741 1.5574077246549 1.55740772465490223 0.271753+1.08392i 0.271752585319512+1.08392332733869i 0.271752585319511717+1.08392332733869454i
    1313asin:1.5708 1.5707963267949 1.57079632679489662 0.666239+1.06128i 0.666239432492515+1.06127506190504i 0.666239432492515255+1.06127506190503565i
    14 acos:0. 0. 0. 0.904557-1.06128i 0.904556894302381-1.06127506190504i 0.904556894302381364-1.06127506190503565i
     14acos:0 0 0 0.904557-1.06128i 0.904556894302381-1.06127506190504i 0.904556894302381364-1.06127506190503565i
    1515atan:0.785398 0.785398163397448 0.78539816339744831 1.01722+0.402359i 1.01722196789785+0.402359478108525i 1.01722196789785137+0.402359478108525094i
    1616atan2:0.785398 0.785398163397448 0.78539816339744831 atan:0.785398 0.785398163397448 0.78539816339744831
  • tests/.expect/math3.txt

    r933f32f r6a9d4b4  
    22cosh:1.54308 1.54308063481524 1.54308063481524378 0.83373+0.988898i 0.833730025131149+0.988897705762865i 0.833730025131149049+0.988897705762865096i
    33tanh:0.761594 0.761594155955765 0.761594155955764888 1.08392+0.271753i 1.08392332733869+0.271752585319512i 1.08392332733869454+0.271752585319511717i
    4 acosh:0. 0. 0. 1.06128+0.904557i 1.06127506190504+0.904556894302381i 1.06127506190503565+0.904556894302381364i
     4acosh:0 0 0 1.06128+0.904557i 1.06127506190504+0.904556894302381i 1.06127506190503565+0.904556894302381364i
    55asinh:0.881374 0.881373587019543 0.881373587019543025 1.06128+0.666239i 1.06127506190504+0.666239432492515i 1.06127506190503565+0.666239432492515255i
    66atanh:inf inf inf 0.402359+1.01722i 0.402359478108525+1.01722196789785i 0.402359478108525094+1.01722196789785137i
     
    99lgamma:1.79176 1.79175946922805 1.791759469228055
    1010lgamma:1.79176 1 1.79175946922805 1 1.791759469228055 1
    11 tgamma:6. 6. 6.
     11tgamma:6 6 6
  • tests/.expect/math4.txt

    r933f32f r6a9d4b4  
    1 floor:1. 1. 1.
    2 ceil:2. 2. 2.
    3 trunc:3. 3. 3.
    4 rint:2. 2. 2.
     1floor:1 1 1
     2ceil:2 2 2
     3trunc:3 3 3
     4rint:2 2 2
    55rint:2 2 2
    66rint:2 2 2
    77lrint:2 2 2
    88llrint:2 2 2
    9 nearbyint:4. 4. 4.
    10 round:2. 2. 2.
     9nearbyint:4 4 4
     10round:2 2 2
    1111round:2 2 2
    1212round:2 2 2
    1313lround:2 2 2
    1414llround:2 2 2
    15 copysign:-1. -1. -1.
     15copysign:-1 -1 -1
    1616frexp:0.5 3 0.5 3 0.5 3
    17 ldexp:8. 8. 8.
    18 modf:2. 0.3 2. 0.3 2. 0.3
    19 modf:2., 0.3 2., 0.3 2., 0.3
    20 nextafter:2. 2. 2.
    21 nexttoward:2. 2. 2.
    22 scalbn:16. 16. 16.
    23 scalbln:16. 16. 16.
     17ldexp:8 8 8
     18modf:2 0.3 2 0.3 2 0.3
     19modf:2, 0.3 2, 0.3 2, 0.3
     20nextafter:2 2 2
     21nexttoward:2 2 2
     22scalbn:16 16 16
     23scalbln:16 16 16
  • tests/.expect/minmax.txt

    r933f32f r6a9d4b4  
    66signed long long int    4 3     min 3
    77unsigned long long int  4 3     min 3
    8 float                   4. 3.1  min 3.1
    9 double                  4. 3.1  min 3.1
    10 long double             4. 3.1  min 3.1
     8float                   4 3.1   min 3.1
     9double                  4 3.1   min 3.1
     10long double             4 3.1   min 3.1
    1111
    1212char                    z a     max z
     
    1717signed long long int    4 3     max 4
    1818unsigned long long int  4 3     max 4
    19 float                   4. 3.1  max 4.
    20 double                  4. 3.1  max 4.
    21 long double             4. 3.1  max 4.
     19float                   4 3.1   max 4
     20double                  4 3.1   max 4
     21long double             4 3.1   max 4
  • tests/.expect/references.txt

    r933f32f r6a9d4b4  
    35353
    36363
    37 3 9 { 1., 7. }, [1, 2, 3]
     373 9 { 1, 7 }, [1, 2, 3]
    3838Destructing a Y
    3939Destructing a Y
  • tests/.expect/sum.txt

    r933f32f r6a9d4b4  
    1 sum from 5 to 15 is 95, check 95
    2 sum from 5 to 15 is 95, check 95
    31sum from 5 to 15 is 95, check 95
    42sum from 5 to 15 is 95, check 95
  • tests/Makefile.am

    r933f32f r6a9d4b4  
    2323installed=no
    2424
    25 INSTALL_FLAGS=-in-tree
    26 DEBUG_FLAGS=-debug -O0
    27 
    2825quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes
    2926
     
    3128timeouts=
    3229
    33 TEST_PY = python3 ${builddir}/test.py
     30TEST_PY = python ${builddir}/test.py
    3431
    3532# applies to both programs
     
    3936        -Wno-unused-function \
    4037        -quiet @CFA_FLAGS@ \
    41         -DIN_DIR="${abs_srcdir}/.in/"
     38        -DIN_DIR="${srcdir}/.in/"
    4239
    4340AM_CFLAGS += ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS}
    4441CC = @CFACC@
    4542
    46 PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
     43PRETTY_PATH=cd ${srcdir} &&
    4744
    4845.PHONY: list .validate
     
    5148
    5249avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa
    53 # automake doesn't know we still need C/CPP rules so pretend like we have a C program
    54 _dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp
     50# automake doesn't know we still need C rules so pretend like we have a C program
     51_dummy_hack_SOURCES = .dummy_hack.c
    5552
    5653#----------------------------------------------------------------------------------------------------------------
     
    7774        @echo "int main() { return 0; }" > ${@}
    7875
    79 .dummy_hackxx.cpp:
    80         @echo "int bar() { return 0; }" > ${@}
    81 
    8276concurrency :
    8377        @+${TEST_PY} --debug=${debug}  --install=${installed} -Iconcurrent
     
    8579#----------------------------------------------------------------------------------------------------------------
    8680
    87 # Use for all tests, make sure the path are correct and all flags are added
    88 CFACOMPILETEST=$(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) $($(shell echo "${@}_FLAGS" | sed 's/-\|\//_/g'))
    89 
    90 # Use for tests that either generate an executable, print directyl to stdout or the make command is expected to fail
    91 CFATEST_STDOUT=$(CFACOMPILETEST) -o $(abspath ${@})
    92 
    93 # Use for tests where the make command is expecte to succeed but the expected.txt should be compared to stderr
    94 CFATEST_STDERR=$(CFACOMPILETEST) 2> $(abspath ${@})
    95 
    96 #----------------------------------------------------------------------------------------------------------------
    97 
    9881# implicit rule so not all test require a rule
    9982% : %.cfa $(CFACC)
    100         $(CFATEST_STDOUT)
     83        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    10184
    102 % : %.cpp
    103         $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     85declarationSpecifier: declarationSpecifier.cfa $(CFACC)
     86        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    10487
    105 #------------------------------------------------------------------------------
    106 # TARGET WITH STANDARD RULE BUT CUSTOM FLAGS
    107 #------------------------------------------------------------------------------
    108 # Expected failures
    109 declarationSpecifier_FLAGS= -CFA -XCFA -p
    110 gccExtensions_FLAGS= -CFA -XCFA -p
    111 extension_FLAGS= -CFA -XCFA -p
    112 attributes_FLAGS= -CFA -XCFA -p
    113 functions_FLAGS= -CFA -XCFA -p
    114 KRfunctions_FLAGS= -CFA -XCFA -p
    115 gmp_FLAGS= -lgmp
     88gccExtensions : gccExtensions.cfa $(CFACC)
     89        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    11690
    117 #------------------------------------------------------------------------------
    118 # Expected failures
    119 completeTypeError_FLAGS= -DERR1
     91extension : extension.cfa $(CFACC)
     92        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    12093
    121 #------------------------------------------------------------------------------
    122 # CUSTOM TARGET
    123 #------------------------------------------------------------------------------
    124 typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
    125         $(CFATEST_STDOUT) -DERR1
     94attributes : attributes.cfa $(CFACC)
     95        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    12696
    127 alloc-ERROR: alloc.cfa $(CFACC)
    128         $(CFATEST_STDOUT) -DERR1
     97functions: functions.cfa $(CFACC)
     98        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    12999
    130 nested-types-ERR1: nested-types.cfa $(CFACC)
    131         $(CFATEST_STDOUT) -DERR1
     100KRfunctions : KRfunctions.cfa $(CFACC)
     101        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    132102
    133 nested-types-ERR2: nested-types.cfa $(CFACC)
    134         $(CFATEST_STDOUT) -DERR2
     103sched-ext-parse : sched-ext-parse.c $(CFACC)
     104        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    135105
    136 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
    137         $(CFATEST_STDOUT) -DERR1
    138 
    139 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
    140         $(CFATEST_STDOUT) -DERR2
    141 
    142 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
    143         $(CFATEST_STDOUT) -DERR1
    144 
    145 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
    146         $(CFATEST_STDOUT) -DERR1
     106gmp : gmp.cfa $(CFACC)
     107        $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    147108
    148109#builtins
    149110builtins/sync: builtins/sync.cfa $(CFACC)
    150         $(CFATEST_STDERR) -fsyntax-only
     111        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
     112
     113#------------------------------------------------------------------------------
     114
     115#To make errors path independent we need to cd into the correct directories
     116completeTypeError : completeTypeError.cfa $(CFACC)
     117        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     118
     119typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
     120        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     121
     122alloc-ERROR: alloc.cfa $(CFACC)
     123        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     124
     125fallthrough-ERROR: fallthrough.cfa $(CFACC)
     126        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     127
     128nested-types-ERR1: nested-types.cfa $(CFACC)
     129        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     130
     131nested-types-ERR2: nested-types.cfa $(CFACC)
     132        $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     133
     134# Constructor/destructor tests
     135raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
     136        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     137
     138raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
     139        $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     140
     141raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
     142        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     143
     144raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
     145        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    151146
    152147# Warnings
    153148warnings/self-assignment: warnings/self-assignment.cfa $(CFACC)
    154         $(CFATEST_STDERR) -fsyntax-only
     149        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
  • tests/Makefile.in

    r933f32f r6a9d4b4  
    107107CONFIG_CLEAN_FILES = config.py
    108108CONFIG_CLEAN_VPATH_FILES = test.py
    109 am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT) .dummy_hackxx.$(OBJEXT)
     109am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT)
    110110_dummy_hack_OBJECTS = $(am__dummy_hack_OBJECTS)
    111111_dummy_hack_LDADD = $(LDADD)
     
    155155am__v_CCLD_0 = @echo "  CCLD    " $@;
    156156am__v_CCLD_1 =
    157 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
    158         $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
    159 LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
    160         $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
    161         $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
    162         $(AM_CXXFLAGS) $(CXXFLAGS)
    163 AM_V_CXX = $(am__v_CXX_@AM_V@)
    164 am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
    165 am__v_CXX_0 = @echo "  CXX     " $@;
    166 am__v_CXX_1 =
    167 CXXLD = $(CXX)
    168 CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
    169         $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
    170         $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
    171 AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
    172 am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
    173 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
    174 am__v_CXXLD_1 =
    175157SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES)
    176158DIST_SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES)
     
    204186DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    205187ACLOCAL = @ACLOCAL@
     188ALLOCA = @ALLOCA@
    206189AMTAR = @AMTAR@
    207190AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    375358debug = yes
    376359installed = no
    377 INSTALL_FLAGS = -in-tree
    378 DEBUG_FLAGS = -debug -O0
    379360quick_test = avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes
    380361concurrent =
    381362timeouts =
    382 TEST_PY = python3 ${builddir}/test.py
     363TEST_PY = python ${builddir}/test.py
    383364
    384365# applies to both programs
    385366AM_CFLAGS = $(if $(test), 2> $(test), ) -g -Wall -Wno-unused-function \
    386         -quiet @CFA_FLAGS@ -DIN_DIR="${abs_srcdir}/.in/" \
    387         ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS}
    388 PRETTY_PATH = mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
     367        -quiet @CFA_FLAGS@ -DIN_DIR="${srcdir}/.in/" ${DEBUG_FLAGS} \
     368        ${INSTALL_FLAGS} ${ARCH_FLAGS}
     369PRETTY_PATH = cd ${srcdir} &&
    389370avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa
    390 # automake doesn't know we still need C/CPP rules so pretend like we have a C program
    391 _dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp
    392 
    393 #----------------------------------------------------------------------------------------------------------------
    394 
    395 # Use for all tests, make sure the path are correct and all flags are added
    396 CFACOMPILETEST = $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) $($(shell echo "${@}_FLAGS" | sed 's/-\|\//_/g'))
    397 
    398 # Use for tests that either generate an executable, print directyl to stdout or the make command is expected to fail
    399 CFATEST_STDOUT = $(CFACOMPILETEST) -o $(abspath ${@})
    400 
    401 # Use for tests where the make command is expecte to succeed but the expected.txt should be compared to stderr
    402 CFATEST_STDERR = $(CFACOMPILETEST) 2> $(abspath ${@})
    403 
    404 #------------------------------------------------------------------------------
    405 # TARGET WITH STANDARD RULE BUT CUSTOM FLAGS
    406 #------------------------------------------------------------------------------
    407 # Expected failures
    408 declarationSpecifier_FLAGS = -CFA -XCFA -p
    409 gccExtensions_FLAGS = -CFA -XCFA -p
    410 extension_FLAGS = -CFA -XCFA -p
    411 attributes_FLAGS = -CFA -XCFA -p
    412 functions_FLAGS = -CFA -XCFA -p
    413 KRfunctions_FLAGS = -CFA -XCFA -p
    414 gmp_FLAGS = -lgmp
    415 
    416 #------------------------------------------------------------------------------
    417 # Expected failures
    418 completeTypeError_FLAGS = -DERR1
     371# automake doesn't know we still need C rules so pretend like we have a C program
     372_dummy_hack_SOURCES = .dummy_hack.c
    419373all: all-am
    420374
    421375.SUFFIXES:
    422 .SUFFIXES: .c .cfa .cpp .dummy_hack .dummy_hackxx .lo .o .obj .validate
     376.SUFFIXES: .c .cfa .dummy_hack .lo .o .obj .validate
    423377$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/src/cfa.make $(am__configure_deps)
    424378        @for dep in $?; do \
     
    456410.dummy_hack$(EXEEXT): $(_dummy_hack_OBJECTS) $(_dummy_hack_DEPENDENCIES) $(EXTRA__dummy_hack_DEPENDENCIES)
    457411        @rm -f .dummy_hack$(EXEEXT)
    458         $(AM_V_CXXLD)$(CXXLINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)
     412        $(AM_V_CCLD)$(LINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)
    459413avltree/$(am__dirstamp):
    460414        @$(MKDIR_P) avltree
     
    490444
    491445@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/.dummy_hack.Po@am__quote@
    492 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/.dummy_hackxx.Po@am__quote@
    493446
    494447.c.o:
     
    515468@AMDEP_TRUE@@am__fastdepCC_FALSE@       DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
    516469@am__fastdepCC_FALSE@   $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
    517 
    518 .cpp.o:
    519 @am__fastdepCXX_TRUE@   $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
    520 @am__fastdepCXX_TRUE@   $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
    521 @am__fastdepCXX_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
    522 @AMDEP_TRUE@@am__fastdepCXX_FALSE@      $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
    523 @AMDEP_TRUE@@am__fastdepCXX_FALSE@      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
    524 @am__fastdepCXX_FALSE@  $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
    525 
    526 .cpp.obj:
    527 @am__fastdepCXX_TRUE@   $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
    528 @am__fastdepCXX_TRUE@   $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
    529 @am__fastdepCXX_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
    530 @AMDEP_TRUE@@am__fastdepCXX_FALSE@      $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
    531 @AMDEP_TRUE@@am__fastdepCXX_FALSE@      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
    532 @am__fastdepCXX_FALSE@  $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
    533 
    534 .cpp.lo:
    535 @am__fastdepCXX_TRUE@   $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
    536 @am__fastdepCXX_TRUE@   $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
    537 @am__fastdepCXX_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Plo
    538 @AMDEP_TRUE@@am__fastdepCXX_FALSE@      $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
    539 @AMDEP_TRUE@@am__fastdepCXX_FALSE@      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
    540 @am__fastdepCXX_FALSE@  $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
    541470
    542471mostlyclean-libtool:
     
    789718        @echo "int main() { return 0; }" > ${@}
    790719
    791 .dummy_hackxx.cpp:
    792         @echo "int bar() { return 0; }" > ${@}
    793 
    794720concurrency :
    795721        @+${TEST_PY} --debug=${debug}  --install=${installed} -Iconcurrent
     
    799725# implicit rule so not all test require a rule
    800726% : %.cfa $(CFACC)
    801         $(CFATEST_STDOUT)
    802 
    803 % : %.cpp
    804         $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    805 
    806 #------------------------------------------------------------------------------
    807 # CUSTOM TARGET
    808 #------------------------------------------------------------------------------
    809 typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
    810         $(CFATEST_STDOUT) -DERR1
    811 
    812 alloc-ERROR: alloc.cfa $(CFACC)
    813         $(CFATEST_STDOUT) -DERR1
    814 
    815 nested-types-ERR1: nested-types.cfa $(CFACC)
    816         $(CFATEST_STDOUT) -DERR1
    817 
    818 nested-types-ERR2: nested-types.cfa $(CFACC)
    819         $(CFATEST_STDOUT) -DERR2
    820 
    821 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
    822         $(CFATEST_STDOUT) -DERR1
    823 
    824 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
    825         $(CFATEST_STDOUT) -DERR2
    826 
    827 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
    828         $(CFATEST_STDOUT) -DERR1
    829 
    830 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
    831         $(CFATEST_STDOUT) -DERR1
     727        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     728
     729declarationSpecifier: declarationSpecifier.cfa $(CFACC)
     730        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     731
     732gccExtensions : gccExtensions.cfa $(CFACC)
     733        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     734
     735extension : extension.cfa $(CFACC)
     736        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     737
     738attributes : attributes.cfa $(CFACC)
     739        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     740
     741functions: functions.cfa $(CFACC)
     742        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     743
     744KRfunctions : KRfunctions.cfa $(CFACC)
     745        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     746
     747sched-ext-parse : sched-ext-parse.c $(CFACC)
     748        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     749
     750gmp : gmp.cfa $(CFACC)
     751        $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    832752
    833753#builtins
    834754builtins/sync: builtins/sync.cfa $(CFACC)
    835         $(CFATEST_STDERR) -fsyntax-only
     755        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
     756
     757#------------------------------------------------------------------------------
     758
     759#To make errors path independent we need to cd into the correct directories
     760completeTypeError : completeTypeError.cfa $(CFACC)
     761        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     762
     763typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
     764        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     765
     766alloc-ERROR: alloc.cfa $(CFACC)
     767        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     768
     769fallthrough-ERROR: fallthrough.cfa $(CFACC)
     770        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     771
     772nested-types-ERR1: nested-types.cfa $(CFACC)
     773        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     774
     775nested-types-ERR2: nested-types.cfa $(CFACC)
     776        $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     777
     778# Constructor/destructor tests
     779raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
     780        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     781
     782raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
     783        $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     784
     785raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
     786        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     787
     788raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
     789        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    836790
    837791# Warnings
    838792warnings/self-assignment: warnings/self-assignment.cfa $(CFACC)
    839         $(CFATEST_STDERR) -fsyntax-only
     793        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
    840794
    841795# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • tests/array.cfa

    r933f32f r6a9d4b4  
    1 //                               -*- Mode: C -*-
    2 //
    3 // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
    4 //
    5 // The contents of this file are covered under the licence agreement in the
    6 // file "LICENCE" distributed with Cforall.
    7 //
    8 // array.cfa -- test array declarations
    9 //
    10 // Author           : Peter A. Buhr
    11 // Created On       : Tue Feb 19 21:18:06 2019
    12 // Last Modified By : Peter A. Buhr
    13 // Last Modified On : Tue Feb 19 21:18:46 2019
    14 // Update Count     : 1
    15 //
    16 
     1//Testing array declarations
    172int a1[];
    183//int a2[*];
     
    4934}
    5035
    51 int main() {}
    52 
    53 // Local Variables: //
    54 // tab-width: 4 //
    55 // compile-command: "cfa array.cfa" //
    56 // End: //
     36//Dummy main
     37int main(int argc, char const *argv[])
     38{
     39        return 0;
     40}
  • tests/builtins/sync.cfa

    r933f32f r6a9d4b4  
    1111        volatile __int128 * vp16 = 0; __int128 * rp16 = 0; __int128 v16 = 0;
    1212        #endif
    13         struct type * volatile * vpp = 0; struct type ** rpp = 0; struct type * vp = 0;
    1413
    1514        { char ret; ret = __sync_fetch_and_add(vp1, v1); }
     
    181180        { _Bool ret; ret = __sync_bool_compare_and_swap_16(vp16, v16,v16); }
    182181        #endif
    183         { _Bool ret; ret = __sync_bool_compare_and_swap(vpp, vp, vp); }
    184182
    185183        { char ret; ret = __sync_val_compare_and_swap(vp1, v1, v1); }
     
    195193        { __int128 ret; ret = __sync_val_compare_and_swap_16(vp16, v16,v16); }
    196194        #endif
    197         { struct type * ret; ret = __sync_val_compare_and_swap(vpp, vp, vp); }
    198 
    199195
    200196        { char ret; ret = __sync_lock_test_and_set(vp1, v1); }
     
    234230        { __atomic_clear(vp1, v1); }
    235231
    236         { char ret; ret = __atomic_exchange_n(vp1, v1, __ATOMIC_SEQ_CST); }
     232        { char ret; ret = __atomic_exchange_n(vp1, &v1, __ATOMIC_SEQ_CST); }
    237233        { char ret; ret = __atomic_exchange_1(vp1, v1, __ATOMIC_SEQ_CST); }
    238234        { char ret; __atomic_exchange(vp1, &v1, &ret, __ATOMIC_SEQ_CST); }
    239         { short ret; ret = __atomic_exchange_n(vp2, v2, __ATOMIC_SEQ_CST); }
     235        { short ret; ret = __atomic_exchange_n(vp2, &v2, __ATOMIC_SEQ_CST); }
    240236        { short ret; ret = __atomic_exchange_2(vp2, v2, __ATOMIC_SEQ_CST); }
    241237        { short ret; __atomic_exchange(vp2, &v2, &ret, __ATOMIC_SEQ_CST); }
    242         { int ret; ret = __atomic_exchange_n(vp4, v4, __ATOMIC_SEQ_CST); }
     238        { int ret; ret = __atomic_exchange_n(vp4, &v4, __ATOMIC_SEQ_CST); }
    243239        { int ret; ret = __atomic_exchange_4(vp4, v4, __ATOMIC_SEQ_CST); }
    244240        { int ret; __atomic_exchange(vp4, &v4, &ret, __ATOMIC_SEQ_CST); }
    245         { long long int ret; ret = __atomic_exchange_n(vp8, v8, __ATOMIC_SEQ_CST); }
     241        { long long int ret; ret = __atomic_exchange_n(vp8, &v8, __ATOMIC_SEQ_CST); }
    246242        { long long int ret; ret = __atomic_exchange_8(vp8, v8, __ATOMIC_SEQ_CST); }
    247243        { long long int ret; __atomic_exchange(vp8, &v8, &ret, __ATOMIC_SEQ_CST); }
    248244        #if defined(__SIZEOF_INT128__)
    249         { __int128 ret; ret = __atomic_exchange_n(vp16, v16, __ATOMIC_SEQ_CST); }
     245        { __int128 ret; ret = __atomic_exchange_n(vp16, &v16, __ATOMIC_SEQ_CST); }
    250246        { __int128 ret; ret = __atomic_exchange_16(vp16, v16, __ATOMIC_SEQ_CST); }
    251247        { __int128 ret; __atomic_exchange(vp16, &v16, &ret, __ATOMIC_SEQ_CST); }
    252248        #endif
    253         { struct type * ret; ret = __atomic_exchange_n(vpp, vp, __ATOMIC_SEQ_CST); }
    254         { struct type * ret; __atomic_exchange(vpp, &vp, &ret, __ATOMIC_SEQ_CST); }
    255249
    256250        { char ret; ret = __atomic_load_n(vp1, __ATOMIC_SEQ_CST); }
     
    271265        { __int128 ret; __atomic_load(vp16, &ret, __ATOMIC_SEQ_CST); }
    272266        #endif
    273         { struct type * ret; ret = __atomic_load_n(vpp, __ATOMIC_SEQ_CST); }
    274         { struct type * ret; __atomic_load(vpp, &ret, __ATOMIC_SEQ_CST); }
    275267
    276268        { _Bool ret; ret = __atomic_compare_exchange_n(vp1, rp1, v1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     
    291283        { _Bool ret; ret = __atomic_compare_exchange(vp16, rp16, &v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    292284        #endif
    293         { _Bool ret; ret = __atomic_compare_exchange_n(vpp, rpp, vp, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    294         { _Bool ret; ret = __atomic_compare_exchange(vpp, rpp, &vp, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    295285
    296286        { __atomic_store_n(vp1, v1, __ATOMIC_SEQ_CST); }
     
    311301        { __atomic_store(vp16, &v16, __ATOMIC_SEQ_CST); }
    312302        #endif
    313         { __atomic_store_n(vpp, vp, __ATOMIC_SEQ_CST); }
    314         { __atomic_store(vpp, &vp, __ATOMIC_SEQ_CST); }
    315303
    316304        { char ret; ret = __atomic_add_fetch(vp1, v1, __ATOMIC_SEQ_CST); }
  • tests/castError.cfa

    r933f32f r6a9d4b4  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // castError.cfa -- test invalid casts
    8 //
    9 // Author           : Peter A. Buhr
    10 // Created On       : Tue Feb 19 21:15:39 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 19 21:16:44 2019
    13 // Update Count     : 1
    14 //
    15 
     1//Testing some of the invalid casts of chars
    162int f;
    173
     
    217        (char)f;
    228        (int(*)())f;
    23 
    24         unsigned char v;
    25         short int v;
    26         3, v;           // implicit void cast
    279}
    2810
    29 int main() {}
    30 
    31 // Local Variables: //
    32 // tab-width: 4 //
    33 // compile-command: "cfa castError.cfa" //
    34 // End: //
     11//Dummy main
     12int main(int argc, char const *argv[])
     13{
     14        return 0;
     15}
  • tests/completeTypeError.cfa

    r933f32f r6a9d4b4  
    55forall(dtype T | sized(T)) void quux(T *);
    66
    7 struct A;       // incomplete
    8 struct B {};    // complete
     7struct A; // incomplete
     8struct B {}; // complete
    99
    1010int main() {
    11         int * i;
    12         void * v;
     11        int *i;
     12        void *v;
    1313
    1414        A * x;
     
    1919        // okay
    2020        *i;
    21         *y;
     21        *x; // picks B
    2222        *z;
    2323        foo(i);
     
    3232        // bad
    3333        *v;
    34         *x;     // ambiguous
     34        *y;
    3535        foo(v);
    3636        baz(v);
     
    5252void qux(T * y) {
    5353        // okay
    54         *y;
    5554        bar(y);
    5655        qux(y);
     
    5958        baz(y);
    6059        quux(y);
     60        *y;
    6161}
    6262
  • tests/concurrent/examples/boundedBufferEXT.cfa

    r933f32f r6a9d4b4  
    11//
    2 // Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
    3 //
    42// The contents of this file are covered under the licence agreement in the
    53// file "LICENCE" distributed with Cforall.
     
    108// Created On       : Wed Apr 18 22:52:12 2018
    119// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:33 2019
    13 // Update Count     : 12
     10// Last Modified On : Tue Dec 11 21:55:02 2018
     11// Update Count     : 9
    1412//
    1513
    16 #include <stdlib.hfa>                                                                   // random
     14#include <stdlib.hfa>                                                                           // random
    1715#include <fstream.hfa>
    1816#include <kernel.hfa>
     
    122120// Local Variables: //
    123121// tab-width: 4 //
    124 // compile-command: "cfa boundedBufferEXT.cfa" //
     122// compile-command: "cfa boundedBufferEXT.c" //
    125123// End: //
  • tests/concurrent/examples/boundedBufferINT.cfa

    r933f32f r6a9d4b4  
    11//
    2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    3 //
    42// The contents of this file are covered under the licence agreement in the
    53// file "LICENCE" distributed with Cforall.
     
    108// Created On       : Mon Oct 30 12:45:13 2017
    119// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:52 2019
    13 // Update Count     : 88
     10// Last Modified On : Tue Dec 11 21:55:45 2018
     11// Update Count     : 84
    1412//
    1513
    16 #include <stdlib.hfa>                                                                   // random
     14#include <stdlib.hfa>                                                                           // random
    1715#include <fstream.hfa>
    1816#include <kernel.hfa>
     
    123121// Local Variables: //
    124122// tab-width: 4 //
    125 // compile-command: "cfa boundedBufferINT.cfa" //
     123// compile-command: "cfa boundedBufferINT.c" //
    126124// End: //
  • tests/concurrent/examples/datingService.cfa

    r933f32f r6a9d4b4  
    11//
    2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    3 //
    42// The contents of this file are covered under the licence agreement in the
    53// file "LICENCE" distributed with Cforall.
     
    108// Created On       : Mon Oct 30 12:56:20 2017
    119// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:39 2019
    13 // Update Count     : 31
     10// Last Modified On : Tue Dec 11 21:55:34 2018
     11// Update Count     : 28
    1412//
    1513
    16 #include <stdlib.hfa>                                                                   // random
     14#include <stdlib.hfa>                                                                           // random
    1715#include <fstream.hfa>
    1816#include <kernel.hfa>
     
    112110// Local Variables: //
    113111// tab-width: 4 //
    114 // compile-command: "cfa datingService.cfa" //
     112// compile-command: "cfa datingService.c" //
    115113// End: //
  • tests/concurrent/examples/matrixSum.cfa

    r933f32f r6a9d4b4  
     1//                               -*- Mode: C -*-
    12//
    23// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
     
    1011// Created On       : Mon Oct  9 08:29:28 2017
    1112// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 20 08:37:53 2019
    13 // Update Count     : 16
     13// Last Modified On : Tue Dec 11 21:54:55 2018
     14// Update Count     : 15
    1415//
    1516
  • tests/concurrent/examples/quickSort.cfa

    r933f32f r6a9d4b4  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    31//
    42// The contents of this file are covered under the licence agreement in the
     
    119// Created On       : Wed Dec  6 12:15:52 2017
    1210// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Fri Mar 22 13:42:01 2019
    14 // Update Count     : 170
     11// Last Modified On : Sat Dec 22 08:44:27 2018
     12// Update Count     : 168
    1513//
    1614
     
    180178// Local Variables: //
    181179// tab-width: 4 //
    182 // compile-command: "cfa quickSort.cfa" //
     180// compile-command: "cfa quickSort.c" //
    183181// End: //
  • tests/concurrent/waitfor/parse2.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed Aug 30 17:53:29 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:42:11 2019
    13 // Update Count     : 3
     12// Last Modified On : Wed Aug 30 17:55:17 2017
     13// Update Count     : 2
    1414//
    1515
     
    246246// Local Variables: //
    247247// tab-width: 4 //
    248 // compile-command: "cfa waitfor.cfa" //
     248// compile-command: "cfa waitfor.c" //
    249249// End: //
  • tests/config.py.in

    r933f32f r6a9d4b4  
    1 #!/usr/bin/env python3
     1#!/usr/bin/env python
    22# encoding: utf-8
    33"""
  • tests/coroutine/.expect/fmtLines.txt

    r933f32f r6a9d4b4  
    1616difi  ed B  y :   Pete  r A. 
    1717 Buh  r//   Last   Mod  ifie 
    18 d On   : F  ri M  ar 2  2 1
    19 :41:  03 2  019/  / Up  date 
    20  Cou  nt       :   33/  /#in 
     18d On   : T  ue D  ec 1  1 2
     19:31:  12 2  018/  / Up  date 
     20 Cou  nt       :   32/  /#in 
    2121clud  e <f  stre  am.h  fa># 
    2222incl  ude   <cor  outi  ne.h 
     
    7676th:   4 //  // c  ompi  le-c 
    7777omma  nd:   "cfa   fmt  Line 
    78 s.cf  a" /  ///   End:   //
     78s.c"   ///  / En  d: /  /
  • tests/coroutine/.in/fmtLines.txt

    r933f32f r6a9d4b4  
    1010// Created On       : Sun Sep 17 21:56:15 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:03 2019
    13 // Update Count     : 33
     12// Last Modified On : Tue Dec 11 23:31:12 2018
     13// Update Count     : 32
    1414//
    1515
     
    6464// Local Variables: //
    6565// tab-width: 4 //
    66 // compile-command: "cfa fmtLines.cfa" //
     66// compile-command: "cfa fmtLines.c" //
    6767// End: //
  • tests/coroutine/fibonacci.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Thu Jun  8 07:29:37 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:40:35 2019
    13 // Update Count     : 26
     12// Last Modified On : Tue Dec 11 21:57:33 2018
     13// Update Count     : 25
    1414//
    1515
     
    4545// Local Variables: //
    4646// tab-width: 4 //
    47 // compile-command: "cfa fibonacci.cfa" //
     47// compile-command: "cfa fibonacci.c" //
    4848// End: //
  • tests/coroutine/fibonacci_1.cfa

    r933f32f r6a9d4b4  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // fibonacci_1.cfa -- 1-state finite-state machine: precomputed first two states returning f(n - 1)
     7// fibonacci_1.c -- 1-state finite-state machine: precomputed first two states returning f(n - 2)
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Thu Apr 26 23:20:08 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar 21 08:10:45 2019
    13 // Update Count     : 25
     12// Last Modified On : Tue Dec 11 21:57:54 2018
     13// Update Count     : 14
    1414//
    1515
     
    1717#include <coroutine.hfa>
    1818
    19 coroutine Fibonacci { int fn1; };                                               // used for communication
     19coroutine Fibonacci { int ret; };                                               // used for communication
    2020
    2121void main( Fibonacci & fib ) with( fib ) {                              // called on first resume
    22         int fn;
    23         [fn1, fn] = [0, 1];                                                                     // precompute first two states
     22        int fn, fn1 = 1, fn2 = 0;                                                       // precompute first two states
    2423        for () {
     24                ret = fn2;
     25                fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;                  // general case
    2526                suspend();                                                                              // restart last resume
    26                 [fn1, fn] = [fn, fn1 + fn];                                             // general case
    2727        } // for
    2828}
     
    3030int next( Fibonacci & fib ) with( fib ) {
    3131        resume( fib );                                                                          // restart last suspend
    32         return fn1;
     32        return ret;
    3333}
    3434
     
    4242// Local Variables: //
    4343// tab-width: 4 //
    44 // compile-command: "cfa fibonacci_1.cfa" //
     44// compile-command: "cfa fibonacci_1.c" //
    4545// End: //
  • tests/coroutine/fmtLines.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Sun Sep 17 21:56:15 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:16 2019
    13 // Update Count     : 58
     12// Last Modified On : Sat Dec 22 18:27:00 2018
     13// Update Count     : 57
    1414//
    1515
     
    6363// Local Variables: //
    6464// tab-width: 4 //
    65 // compile-command: "cfa fmtLines.cfa" //
     65// compile-command: "cfa fmtLines.c" //
    6666// End: //
  • tests/coroutine/pingpong.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed Sep 20 11:55:23 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 26 17:54:14 2019
    13 // Update Count     : 35
     12// Last Modified On : Tue Dec 11 21:58:06 2018
     13// Update Count     : 29
    1414//
    1515
     
    2020        const char * name;
    2121        /* const */ unsigned int N;
    22         PingPong & part;
     22        PingPong * part;
    2323};
    2424
    2525void ?{}( PingPong & this, const char * name, unsigned int N, PingPong & part ) {
    26         this.[name, N] = [name, N];  &this.part = &part;
     26        (this.__cor){name};
     27        this.name = name;
     28        this.N = N;
     29        this.part = &part;
    2730}
    2831void ?{}( PingPong & this, const char * name, unsigned int N ) {
    29         this{ name, N, *0p };                                                           // call first constructor
     32        this{ name, N, *(PingPong *)0 };
    3033}
    3134void cycle( PingPong & pingpong ) {
     
    3336}
    3437void partner( PingPong & this, PingPong & part ) {
    35         &this.part = &part;
     38        this.part = &part;
    3639        resume( this );
    3740}
    38 void main( PingPong & pingpong ) with(pingpong) {               // ping's starter ::main, pong's starter ping
    39         for ( N ) {                                                                                     // N ping-pongs
    40                 sout | name;
    41                 cycle( part );
     41void main( PingPong & pingpong ) {                                              // ping's starter ::main, pong's starter ping
     42        for ( pingpong.N ) {                                                            // N ping-pongs
     43                sout | pingpong.name;
     44                cycle( *pingpong.part );
    4245        } // for
    4346}
     
    5053// Local Variables: //
    5154// tab-width: 4 //
    52 // compile-command: "cfa pingpong.cfa" //
     55// compile-command: "cfa pingpong.c" //
    5356// End: //
  • tests/coroutine/prodcons.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Mon Sep 18 12:23:39 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:10 2019
    13 // Update Count     : 54
     12// Last Modified On : Wed Dec 12 23:04:49 2018
     13// Update Count     : 53
    1414//
    1515
     
    9191// Local Variables: //
    9292// tab-width: 4 //
    93 // compile-command: "cfa prodcons.cfa" //
     93// compile-command: "cfa prodcons.c" //
    9494// End: //
  • tests/coroutine/runningTotal.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed Dec  6 08:05:27 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:40:49 2019
    13 // Update Count     : 5
     12// Last Modified On : Tue Dec 11 21:59:00 2018
     13// Update Count     : 4
    1414//
    1515
     
    4848// Local Variables: //
    4949// tab-width: 4 //
    50 // compile-command: "cfa runningTotal.cfa" //
     50// compile-command: "cfa runningTotal.c" //
    5151// End: //
  • tests/declarationSpecifier.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed Aug 17 08:21:04 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 30 18:20:36 2019
    13 // Update Count     : 4
     12// Last Modified On : Tue Nov  6 17:52:59 2018
     13// Update Count     : 3
    1414//
    1515
     
    8989
    9090//Dummy main
    91 int main( int argc, char const * argv[] ) {}
     91int main(int argc, char const *argv[])
     92{
     93        return 0;
     94}
    9295
    9396// Local Variables: //
  • tests/forall.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed May  9 08:48:15 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 19 08:29:38 2019
    13 // Update Count     : 32
     12// Last Modified On : Tue Nov  6 17:53:43 2018
     13// Update Count     : 31
    1414//
    1515
     
    5353        right = temp;
    5454}
     55
     56void ?{}( int & c, zero_t ) { c = 0; }                                  // not in prelude
    5557
    5658trait sumable( otype T ) {
  • tests/function-operator.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Fri Aug 25 15:21:11 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Apr 11 18:27:45 2019
    13 // Update Count     : 10
     12// Last Modified On : Tue Dec  4 21:37:09 2018
     13// Update Count     : 9
    1414//
    1515
     
    6262
    6363// test ?()(T, ...) -- ?() with function call-by-reference
    64 forall(otype Generator, otype GenRet | { GenRet ?()(Generator &); }, dtype Iter, otype T | Iterator(Iter, T) | Assignable(T, GenRet))
     64forall(otype Generator, otype GenRet | { GenRet ?()(Generator &); }, dtype Iter, otype T| Iterator(Iter, T) | Assignable(T, GenRet))
    6565void generate(Iter first, Iter last, Generator & gen) {
    6666        int i = 0;
  • tests/io1.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed Mar  2 16:56:02 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar  4 21:42:47 2019
    13 // Update Count     : 115
     12// Last Modified On : Fri Dec 21 16:02:55 2018
     13// Update Count     : 114
    1414//
    1515
     
    1919        int x = 3, y = 5, z = 7;
    2020        sout | x * 3 | y + 1 | z << 2 | x == y | (x | y) | (x || y) | (x > z ? 1 : 2);
    21         sout | 0 | 1 | 2 | 3;
    22         sout | '0' | '1' | '2' | '3';
    23         sout | 0 | "" | 1 | "" | 2 | "" | 3;
     21        sout | 1 | 2 | 3;
     22        sout | '1' | '2' | '3';
     23        sout | 1 | "" | 2 | "" | 3;
    2424        sout | nl;
    2525
  • tests/io2.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed Mar  2 16:56:02 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Apr 18 08:03:30 2019
    13 // Update Count     : 113
     12// Last Modified On : Fri Dec 21 08:20:14 2018
     13// Update Count     : 112
    1414//
    1515
     
    9797        sout | 1 | sepOff | 2 | 3;                                                      // locally turn off implicit separator
    9898        sout | sepOn | sepOn | 1 | 2 | 3 | sepOn | sepOff | sepOn | '\n' | nonl; // no separator at start/end of line
    99         sout | 1 | 2 | 3 | "\n\n" | sepOn | nonl;                       // no separator at start of next line
     99        sout | 1 | 2 | 3 | "\n\n" | sepOn | nonl;                                       // no separator at start of next line
    100100        sout | 1 | 2 | 3;
    101101        sout | nl;
  • tests/literals.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Sat Sep  9 16:34:38 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 12 08:07:39 2019
    13 // Update Count     : 224
    14 //
    15 
    16 #include <features.h>                                                                   // __GNUC_PREREQ
     12// Last Modified On : Tue Dec  4 21:44:01 2018
     13// Update Count     : 139
     14//
     15
    1716#ifdef __CFA__
     17#include <stdint.h>
    1818#include <fstream.hfa>
    1919
     
    151151        -0X0123456789.0123456789P-09;  -0X0123456789.0123456789P-09f;  -0X0123456789.0123456789P-09l;  -0X0123456789.0123456789P-09F;  -0X0123456789.0123456789P-09L;
    152152
    153 #if defined(__GNUC__) && __GNUC_PREREQ(7,0)                             // gcc version >= 7
    154 // floating with length, gcc f16/f128x unsupported and no prelude code for any _FloatXXx, so they work by conversion to long double
    155 
    156         /*  0123456789.f16; */   0123456789.f32;   0123456789.f32x;   0123456789.f64;   0123456789.f64x;   0123456789.W;   0123456789.f128;   0123456789.q;  /*  0123456789.f128x; */
    157         /* +0123456789.f16; */  +0123456789.f32;  +0123456789.f32x;  +0123456789.f64;  +0123456789.f64x;  +0123456789.w;  +0123456789.f128;  +0123456789.Q;  /* +0123456789.f128x; */
    158         /* -0123456789.f16; */  -0123456789.f32;  -0123456789.f32x;  -0123456789.f64;  -0123456789.f64x;  -0123456789.W;  -0123456789.f128;  -0123456789.q;  /* -0123456789.f128x; */
    159 
    160         /*  0123456789.e09F16; */    0123456789.e09F32;    0123456789.e09F32x;    0123456789.e09F64;    0123456789.e09F64x;    0123456789.e09W;    0123456789.e09F128;    0123456789.e09q;   /*  .0123456789e09q; */
    161         /* +0123456789.e+09F16; */  +0123456789.e+09F32;  +0123456789.e+09F32x;  +0123456789.e+09F64;  +0123456789.e+09F64x;  +0123456789.e+09w;  +0123456789.e+09F128;  +0123456789.e+09Q;  /* +.0123456789E+09Q; */
    162         /* -0123456789.e-09F16; */  -0123456789.e-09F32;  -0123456789.e-09F32x;  -0123456789.e-09F64;  -0123456789.e-09F64x;  -0123456789.e-09W;  -0123456789.e-09F128;  -0123456789.e-09q;  /* -.0123456789E-09q; */
    163 
    164         /*  .0123456789e09F16; */    .0123456789e09F32;    .0123456789e09F32x;    .0123456789e09F64;    .0123456789e09F64x;    .0123456789e09W;    .0123456789e09F128;    .0123456789e09q;   /*  .0123456789e09q; */
    165         /* +.0123456789e+09F16; */  +.0123456789e+09F32;  +.0123456789e+09F32x;  +.0123456789e+09F64;  +.0123456789e+09F64x;  +.0123456789e+09w;  +.0123456789e+09F128;  +.0123456789e+09Q;  /* +.0123456789E+09Q; */
    166         /* -.0123456789e-09F16; */  -.0123456789e-09F32;  -.0123456789e-09F32x;  -.0123456789e-09F64;  -.0123456789e-09F64x;  -.0123456789e-09W;  -.0123456789e-09F128;  -.0123456789e-09q;  /* -.0123456789E-09q; */
    167 
    168         /*  0123456789.0123456789F16; */   0123456789.0123456789F32;   0123456789.0123456789F32x;   0123456789.0123456789F64;   0123456789.0123456789F64x;   0123456789.0123456789W;   0123456789.0123456789F128;   0123456789.0123456789q;  /*  0123456789.0123456789q; */
    169         /* +0123456789.0123456789F16; */  +0123456789.0123456789F32;  +0123456789.0123456789F32x;  +0123456789.0123456789F64;  +0123456789.0123456789F64x;  +0123456789.0123456789w;  +0123456789.0123456789F128;  +0123456789.0123456789Q;  /* +0123456789.0123456789Q; */
    170         /* -0123456789.0123456789F16; */  -0123456789.0123456789F32;  -0123456789.0123456789F32x;  -0123456789.0123456789F64;  -0123456789.0123456789F64x;  -0123456789.0123456789W;  -0123456789.0123456789F128;  -0123456789.0123456789q;  /* -0123456789.0123456789q; */
    171 
    172         /*  0123456789.0123456789E09F16; */    0123456789.0123456789E09F32;    0123456789.0123456789E09F32x;    0123456789.0123456789E09F64;    0123456789.0123456789E09F64x;    0123456789.0123456789E09W;    0123456789.0123456789E09F128;    0123456789.0123456789E09q;   /*  0123456789.0123456789E09q; */
    173         /* +0123456789.0123456789E+09F16; */  +0123456789.0123456789E+09F32;  +0123456789.0123456789E+09F32x;  +0123456789.0123456789E+09F64;  +0123456789.0123456789E+09F64x;  +0123456789.0123456789E+09w;  +0123456789.0123456789E+09F128;  +0123456789.0123456789E+09Q;  /* +0123456789.0123456789E+09Q; */
    174         /* -0123456789.0123456789E-09F16; */  -0123456789.0123456789E-09F32;  -0123456789.0123456789E-09F32x;  -0123456789.0123456789E-09F64;  -0123456789.0123456789E-09F64x;  -0123456789.0123456789E-09W;  -0123456789.0123456789E-09F128;  -0123456789.0123456789E-09q;  /* -0123456789.0123456789E-09q; */
    175 
    176         /*  0x123456789.p09f16; */    0x123456789.p09f32;    0x123456789.p09f32x;    0x123456789.p09f64;    0x123456789.p09f64x;    0x123456789.p09W;    0x123456789.p09f128;    0x123456789.p09q;   /*  0x123456789.p09f128x; */
    177         /* +0x123456789.P+09f16; */  +0x123456789.P+09f32;  +0x123456789.P+09f32x;  +0x123456789.P+09f64;  +0x123456789.P+09f64x;  +0x123456789.P+09w;  +0x123456789.P+09f128;  +0x123456789.P+09Q;  /* +0x123456789.P+09f128x; */
    178         /* -0x123456789.P-09f16; */  -0x123456789.P-09f32;  -0x123456789.P-09f32x;  -0x123456789.P-09f64;  -0x123456789.P-09f64x;  -0x123456789.P-09W;  -0x123456789.P-09f128;  -0x123456789.P-09q;  /* -0x123456789.P-09f128x; */
    179 
    180         /*  0x123456789.p09F16; */    0x123456789.p09F32;    0x123456789.p09F32x;    0x123456789.p09F64;    0x123456789.p09F64x;    0x123456789.p09W;    0x123456789.p09F128;    0x123456789.p09q;   /*  .0123456789p09q; */
    181         /* +0x123456789.p+09F16; */  +0x123456789.p+09F32;  +0x123456789.p+09F32x;  +0x123456789.p+09F64;  +0x123456789.p+09F64x;  +0x123456789.p+09w;  +0x123456789.p+09F128;  +0x123456789.p+09Q;  /* +.0123456789p+09Q; */
    182         /* -0x123456789.p-09F16; */  -0x123456789.p-09F32;  -0x123456789.p-09F32x;  -0x123456789.p-09F64;  -0x123456789.p-09F64x;  -0x123456789.p-09W;  -0x123456789.p-09F128;  -0x123456789.p-09q;  /* -.0123456789P-09q; */
    183 
    184         /*  0X.0123456789p09F16; */    0X.0123456789p09F32;    0X.0123456789p09F32x;    0X.0123456789p09F64;    0X.0123456789p09F64x;    0X.0123456789p09W;    0X.0123456789p09F128;    0X.0123456789p09q;   /*  0X.0123456789p09q; */
    185         /* +0X.0123456789p+09F16; */  +0X.0123456789p+09F32;  +0X.0123456789p+09F32x;  +0X.0123456789p+09F64;  +0X.0123456789p+09F64x;  +0X.0123456789p+09w;  +0X.0123456789p+09F128;  +0X.0123456789p+09Q;  /* +0X.0123456789p+09Q; */
    186         /* -0X.0123456789p-09F16; */  -0X.0123456789p-09F32;  -0X.0123456789p-09F32x;  -0X.0123456789p-09F64;  -0X.0123456789p-09F64x;  -0X.0123456789p-09W;  -0X.0123456789p-09F128;  -0X.0123456789p-09q;  /* -0X.0123456789P-09q; */
    187 
    188         /*  0x123456789.0123456789P09F16; */    0x123456789.0123456789P09F32;    0x123456789.0123456789P09F32x;    0x123456789.0123456789P09F64;    0x123456789.0123456789P09F64x;    0x123456789.0123456789P09W;    0x123456789.0123456789P09F128;    0x123456789.0123456789P09q;   /*  0x123456789.0123456789P09q; */
    189         /* +0x123456789.0123456789P+09F16; */  +0x123456789.0123456789P+09F32;  +0x123456789.0123456789P+09F32x;  +0x123456789.0123456789P+09F64;  +0x123456789.0123456789P+09F64x;  +0x123456789.0123456789P+09w;  +0x123456789.0123456789P+09F128;  +0x123456789.0123456789P+09Q;  /* +0x123456789.0123456789P+09Q; */
    190         /* -0x123456789.0123456789p-09F16; */  -0x123456789.0123456789p-09F32;  -0x123456789.0123456789p-09F32x;  -0x123456789.0123456789p-09F64;  -0x123456789.0123456789p-09F64x;  -0x123456789.0123456789p-09W;  -0x123456789.0123456789p-09F128;  -0x123456789.0123456789p-09q;  /* -0x123456789.0123456789p-09q; */
    191 
    192         /*  0x123456789.0123456789P09F16; */    0x123456789.0123456789P09F32;    0x123456789.0123456789P09F32x;    0x123456789.0123456789P09F64;    0x123456789.0123456789P09F64x;    0x123456789.0123456789P09W;    0x123456789.0123456789P09F128;    0x123456789.0123456789P09q;   /*  0x123456789.0123456789P09q; */
    193         /* +0x123456789.0123456789p+09F16; */  +0x123456789.0123456789p+09F32;  +0x123456789.0123456789p+09F32x;  +0x123456789.0123456789p+09F64;  +0x123456789.0123456789p+09F64x;  +0x123456789.0123456789p+09w;  +0x123456789.0123456789p+09F128;  +0x123456789.0123456789p+09Q;  /* +0x123456789.0123456789p+09Q; */
    194         /* -0x123456789.0123456789P-09F16; */  -0x123456789.0123456789P-09F32;  -0x123456789.0123456789P-09F32x;  -0x123456789.0123456789P-09F64;  -0x123456789.0123456789P-09F64x;  -0x123456789.0123456789P-09W;  -0x123456789.0123456789P-09F128;  -0x123456789.0123456789P-09q;  /* -0x123456789.0123456789P-09q; */
    195 #endif // __GNUC_PREREQ(7,0)
    196 
    197153#ifdef __CFA__
    198154// fixed-size length
     
    211167        // octal
    212168         01234567_l8;   01234567_l16;   01234567_l32;   01234567_l64;   01234567_l8u;   01234567_ul16;   01234567_l32u;   01234567_ul64;
    213         +01234567_l8;  +01234567_l16;  +01234567_l32;  +01234567_l64;  +01234567_ul8;  +01234567_ul16;  +01234567_l32u;  +01234567_ul64;
     169        +01234567_l8;  +01234567_l16;  +01234567_l32;  +01234567_l64;  +01234567_l8u;  +01234567_ul16;  +01234567_l32u;  +01234567_ul64;
    214170        -01234567_l8;  -01234567_l16;  -01234567_l32;  -01234567_l64;  -01234567_l8u;  -01234567_ul16;  -01234567_l32u;  -01234567_ul64;
    215171
     
    247203        +0X0123456789ABCDEF_l8;  +0X0123456789ABCDEF_l16;  +0X0123456789ABCDEFl32;  +0X0123456789ABCDEFl64;  +0X0123456789ABCDEF_ul8;  +0X0123456789ABCDEF_l16u;  +0X0123456789ABCDEFul32;  +0X0123456789ABCDEFl64u;
    248204        -0X0123456789ABCDEF_l8;  -0X0123456789ABCDEF_l16;  -0X0123456789ABCDEFl32;  -0X0123456789ABCDEFl64;  -0X0123456789ABCDEF_ul8;  -0X0123456789ABCDEF_l16u;  -0X0123456789ABCDEFul32;  -0X0123456789ABCDEFl64u;
     205
     206        // floating
     207         0123456789.l32;   0123456789.l64;   0123456789.l80;   0123456789.l128;
     208        +0123456789.l32;  +0123456789.l64;  +0123456789.l80;  +0123456789.l128;
     209        -0123456789.l32;  -0123456789.l64;  -0123456789.l80;  -0123456789.l128;
     210
     211         0123456789.e09L32;    0123456789.e09L64;    0123456789.e09L80;    0123456789.e09L128;
     212        +0123456789.e+09L32;  +0123456789.e+09L64;  +0123456789.e+09L80;  +0123456789.e+09L128;
     213        -0123456789.e-09L32;  -0123456789.e-09L64;  -0123456789.e-09L80;  -0123456789.e-09L128;
     214
     215         .0123456789e09L32;    .0123456789e09L64;    .0123456789e09L80;    .0123456789e09L128;
     216        +.0123456789E+09L32;  +.0123456789E+09L64;  +.0123456789E+09L80;  +.0123456789E+09L128;
     217        -.0123456789E-09L32;  -.0123456789E-09L64;  -.0123456789E-09L80;  -.0123456789E-09L128;
     218
     219         0123456789.0123456789L32;       0123456789.0123456789L64;       0123456789.0123456789L80;       0123456789.0123456789L128;
     220        +0123456789.0123456789E09L32;   +0123456789.0123456789E09L64;   +0123456789.0123456789E09L80;   +0123456789.0123456789E09L128;
     221        -0123456789.0123456789E+09L32;  -0123456789.0123456789E+09L64;  -0123456789.0123456789E+09L80;  -0123456789.0123456789E+09L128;
     222         0123456789.0123456789E-09L32;   0123456789.0123456789E-09L64;   0123456789.0123456789E-09L80;   0123456789.0123456789E-09L128;
     223
     224         0x0123456789.p09l32;   0x0123456789.p09l64;   0x0123456789.p09l80;   0x0123456789.p09l128;
     225        +0x0123456789.p09l32;  +0x0123456789.p09l64;  +0x0123456789.p09l80;  +0x0123456789.p09l128;
     226        -0x0123456789.p09l32;  -0x0123456789.p09l64;  -0x0123456789.p09l80;  -0x0123456789.p09l128;
     227
     228         0x0123456789.p+09l32;   0x0123456789.p+09L64;   0x0123456789.p+09L80;   0x0123456789.p+09L128;
     229        +0x0123456789.p-09l32;  +0x0123456789.p-09L64;  +0x0123456789.p-09L80;  +0x0123456789.p-09L128;
     230        -0x.0123456789p09l32;   -0x.0123456789p09L64;   -0x.0123456789p09L80;   -0x.0123456789p09L128;
    249231
    250232// char, short, int suffix overloading
  • tests/loopctrl.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed Aug  8 18:32:59 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Apr 13 11:03:09 2019
    13 // Update Count     : 104
     12// Last Modified On : Sun Dec 23 23:00:29 2018
     13// Update Count     : 79
    1414//
    1515
     
    5454        for ( i; 5.5 -~ 0.5 ) { sout | i; }                                     sout | nl;
    5555        for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }                       sout | nl;
    56         for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; }                      sout | nl | nl;
     56        for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; }                      sout | nl | nl | nl;
    5757
    58         // @ means do nothing
    59         for ( i; 1 ~ @ ) {
    60           if ( i > 10 ) break;
    61                 sout | i;
    62         }                                                                                                       sout | nl;
    63         for ( i; 10 -~ @ ) {
    64           if ( i < 0 ) break;
    65                 sout | i;
    66         }                                                                                                       sout | nl;
    67         for ( i; 2 ~ @ ~ 2 ) {
    68           if ( i > 10 ) break;
    69                 sout | i;
    70         }                                                                                                       sout | nl;
    71         for ( i; 2.1 ~ @ ~ @ ) {
    72           if ( i > 10.5 ) break;
    73                 sout | i;
    74                 i += 1.7;
    75         }                                                                                                       sout | nl;
    76         for ( i; 10 -~ @ ~ 2 ) {
    77           if ( i < 0 ) break;
    78                 sout | i;
    79         }                                                                                                       sout | nl;
    80         for ( i; 12.1 ~ @ ~ @ ) {
    81           if ( i < 2.5 ) break;
    82                 sout | i;
    83                 i -= 1.7;
    84         }                                                                                                       sout | nl | nl;
    85        
    8658        enum { N = 10 };
    8759        for ( N ) { sout | "N"; }                                                       sout | nl;
    8860        for ( i; N ) { sout | i; }                                                      sout | nl;
    89         for ( i; N -~ 0 ) { sout | i; }                                         sout | nl | nl;
     61        for ( i; N -~ 0 ) { sout | i; }                                         sout | nl | nl | nl;
    9062
    9163        const int start = 3, comp = 10, inc = 2;
    9264        for ( i; start ~ comp ~ inc + 1 ) { sout | i; }         sout | nl | nl;
    9365
     66        sout | nl;
    9467        for ( S s = (S){0}; s < (S){10,10}; s += (S){1} ) { sout | s; } sout | nl;
    9568        for ( s; (S){10,10} ) { sout | s; } sout | nl;
     
    10376        for ( s; (S){10,10} -~ (S){0} ~ (S){1} ) { sout | s; } sout | nl;
    10477        for ( s; (S){10,10} -~= (S){0} ) { sout | s; }           sout | nl;
    105         for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl | nl;
    106 
    107         for ( i; 10 : j; -5 ~ @ ) { sout | i | j; } sout | nl;
    108         for ( i; 10 : j; -5 -~ @ ) { sout | i | j; } sout | nl;
    109         for ( i; 10 : j; -5 ~ @ ~ 2 ) { sout | i | j; } sout | nl;
    110         for ( i; 10 : j; -5 -~ @ ~ 2 ) { sout | i | j; } sout | nl | nl;
    111 
    112         for ( j; -5 ~ @ : i; 10 ) { sout | i | j; } sout | nl;
    113         for ( j; -5 -~ @ : i; 10 ) { sout | i | j; } sout | nl;
    114         for ( j; -5 ~ @ ~ 2 : i; 10 ) { sout | i | j; } sout | nl;
    115         for ( j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j; } sout | nl | nl;
    116 
    117         for ( j; -5 -~ @ ~ 2 : i; 10 : k; 1.5 ~ @ ) { sout | i | j | k; } sout | nl;
    118         for ( j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 10 ) { sout | i | j | k; } sout | nl;
    119         for ( k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j | k; } sout | nl;
     78        for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl;
    12079}
    12180
  • tests/math1.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Fri Apr 22 14:59:21 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 25 22:56:47 2019
    13 // Update Count     : 109
     12// Last Modified On : Wed Dec 12 16:28:49 2018
     13// Update Count     : 89
    1414//
    1515
     
    4949        unsigned int e = 2;
    5050    b \= e;
    51     sout | b | "\\" | e | "= " | b \ e;
    52     sout | 'a' \ 3 | 2 \ 8 | 4 \ 3 | -4 \ 3 | 4 \ -3 | -4 \ -3;
    53         sout | 4.0 \ -3 | -4.0 \ -3 | 4.0 \ 2.1 | (1.0f+2.0fi) \ (3.0f+2.0fi);
     51    sout | "\\" | b | b \ e;
     52    sout | "\\" | 'a' \ 3u | 2 \ 8u | 4 \ 3u | -4 \ 3u | nonl;
    5453        sout | 4 \ -3 | -4 \ -3 | 4.0 \ 2.1 | (1.0f+2.0fi) \ (3.0f+2.0fi);
    55 
    56         struct S { int i; };
    57         double ?*?( double d, S s ) { return d * s.i; }
    58         double ?/?( double d, S s ) { return d / s.i; }
    59         S ?\?( S s, unsigned long y ) { return (S){ s.i \ y }; }
    60         ofstream & ?|?( ofstream & os, S s ) { return os | s.i; }
    61         void ?|?( ofstream & os, S s ) { (ofstream &)(os | s); nl( os ); }
    62         S s = { 4 };
    63         S x = s \ 2;
    64         sout | x;
    65         sout | s.i | s \ 2u;
    6654} // main
    6755
  • tests/numericConstants.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Wed May 24 22:10:36 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  5 08:58:16 2019
    13 // Update Count     : 5
     12// Last Modified On : Tue Nov  6 17:59:53 2018
     13// Update Count     : 3
    1414//
    1515
     
    6767// Local Variables: //
    6868// tab-width: 4 //
    69 // compile-command: "cfa numericConstants.cfa" //
     69// compile-command: "cfa minmax.cfa" //
    7070// End: //
  • tests/pybin/settings.py

    r933f32f r6a9d4b4  
     1from __future__ import print_function
     2
    13import os
    2 import subprocess
    34import sys
    4 from . import tools
     5import tools
    56
    67try :
     
    3839        def __init__(self, arch):
    3940                try:
    40                         canonical_host = Architecture.make_canonical( config.HOSTARCH )
     41                        canonical_host = Architecture.makeCanonical( config.HOSTARCH )
    4142                except KeyError:
    4243                        print("Unkown host architecture %s" % config.HOSTARCH, file=sys.stderr)
     
    4546                if arch:
    4647                        try:
    47                                 arch = Architecture.make_canonical( arch )
     48                                arch = Architecture.makeCanonical( arch )
    4849                        except KeyError:
    4950                                print("Unkown architecture %s" % arch, file=sys.stderr)
     
    7677
    7778        @classmethod
    78         def make_canonical(_, arch):
     79        def makeCanonical(_, arch):
    7980                return Architecture.KnownArchitectures[arch]
    8081
     
    8384        def __init__(self, value):
    8485                self.string = "debug" if value else "no debug"
    85                 self.flags  = """DEBUG_FLAGS=%s""" % ("-debug -O0" if value else "-nodebug -O2")
     86                self.flags  = """DEBUG_FLAGS="%s" """ % ("-debug -O0" if value else "-nodebug -O2")
    8687
    8788class Install:
    8889        def __init__(self, value):
    8990                self.string = "installed" if value else "in-tree"
    90                 self.flags  = """INSTALL_FLAGS=%s""" % ("" if value else "-in-tree")
     91                self.flags  = """INSTALL_FLAGS="%s" """ % ("" if value else "-in-tree")
    9192
    9293class Timeouts:
     
    111112        global install
    112113        global timeout
    113         global output_width
    114114
    115         dry_run      = options.dry_run
    116         generating   = options.regenerate_expected
    117         make         = ['make']
    118         debug        = Debug(options.debug)
    119         install      = Install(options.install)
    120         arch         = Architecture(options.arch)
    121         timeout      = Timeouts(options.timeout, options.global_timeout)
    122         output_width = 24
     115        dry_run    = options.dry_run
     116        generating = options.regenerate_expected
     117        make       = 'make'
     118        debug        = Debug(options.debug)
     119        install    = Install(options.install)
     120        arch       = Architecture(options.arch)
     121        timeout    = Timeouts(options.timeout, options.global_timeout)
    123122
    124123
    125 def update_make_cmd(force, jobs):
     124def updateMakeCmd(force, jobs):
    126125        global make
    127126
    128         make = ['make'] if not force else ['make', "-j%i" % jobs]
     127        make = "make" if not force else ("make -j%i" % jobs)
    129128
    130129def validate():
    131130        errf = os.path.join(BUILDDIR, ".validate.err")
    132         make_ret, out = tools.make( ".validate", error_file = errf, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
     131        make_ret, _ = tools.make( ".validate", error_file = errf, redirects  = "2> /dev/null 1> /dev/null", )
    133132        if make_ret != 0:
    134133                with open (errf, "r") as myfile:
     
    140139
    141140        tools.rm(errf)
    142 
    143 def prep_output(tests):
    144         global output_width
    145         output_width = max(map(lambda t: len(t.target()), tests))
  • tests/pybin/test_run.py

    r933f32f r6a9d4b4  
    44
    55import pybin.settings
     6import datetime
     7
     8from string import Template
     9
     10class DeltaTemplate(Template):
     11    delimiter = "%"
     12
     13def strfdelta(tdelta, fmt):
     14    d["H"], rem = divmod(tdelta.seconds, 3600)
     15    d["M"], d["S"] = divmod(rem, 60)
     16    t = DeltaTemplate(fmt)
     17    return t.substitute(**d)
    618
    719# Test class that defines what a test is
  • tests/pybin/tools.py

    r933f32f r6a9d4b4  
     1from __future__ import print_function
     2
    13import __main__
    24import argparse
    3 import contextlib
    45import fileinput
    56import multiprocessing
     
    910import signal
    1011import stat
    11 import subprocess
    1212import sys
    13 import tempfile
    1413import time
    15 import types
    1614
    1715from pybin import settings
     16from subprocess import Popen, PIPE, STDOUT
    1817
    1918################################################################################
     
    2221
    2322# helper functions to run terminal commands
    24 def sh(*cmd, timeout = False, output = None, input = None, error = subprocess.STDOUT):
    25         cmd = list(cmd)
     23def sh(cmd, print2stdout = True, input = None):
     24        # add input redirection if needed
     25        if input and os.path.isfile(input):
     26                cmd += " < %s" % input
    2627
    2728        # if this is a dry_run, only print the commands that would be ran
    2829        if settings.dry_run :
    29                 cmd = "{} cmd: {}".format(os.getcwd(), ' '.join(cmd))
    30                 if output and not isinstance(output, int):
    31                         cmd += " > "
    32                         cmd += output
    33 
    34                 if error and not isinstance(error, int):
    35                         cmd += " 2> "
    36                         cmd += error
    37 
    38                 if input and not isinstance(input, int) and os.path.isfile(input):
    39                         cmd += " < "
    40                         cmd += input
    41 
    42                 print(cmd)
     30                print("cmd: %s" % cmd)
    4331                return 0, None
    4432
    45         with contextlib.ExitStack() as onexit:
    46                 # add input redirection if needed
    47                 input = openfd(input, 'r', onexit, True)
    48 
    49                 # add output redirection if needed
    50                 output = openfd(output, 'w', onexit, False)
    51 
    52                 # add error redirection if needed
    53                 error = openfd(error, 'w', onexit, False)
    54 
    55                 # run the desired command
    56                 try:
    57                         proc = subprocess.run(
    58                                 cmd,
    59                                 stdin =input,
    60                                 stdout=output,
    61                                 stderr=error,
    62                                 timeout=settings.timeout.single if timeout else None
    63                         )
    64                         return proc.returncode, proc.stdout.decode("utf-8") if proc.stdout else None
    65                 except subprocess.TimeoutExpired:
    66                         return 124, str(None)
     33        # otherwise create a pipe and run the desired command
     34        else :
     35                proc = Popen(cmd, stdout=None if print2stdout else PIPE, stderr=STDOUT, shell=True)
     36                out, err = proc.communicate()
     37                return proc.returncode, out
    6738
    6839def is_ascii(fname):
     
    7445                return False
    7546
    76         code, out = sh("file %s" % fname, output=subprocess.PIPE)
     47        code, out = sh("file %s" % fname, print2stdout = False)
    7748        if code != 0:
    7849                return False
     
    8455
    8556        return match.group(1).startswith("ASCII text")
    86 
    87 def is_exe(fname):
    88         return os.path.isfile(fname) and os.access(fname, os.X_OK)
    89 
    90 def openfd(file, mode, exitstack, checkfile):
    91         if not file:
    92                 return file
    93 
    94         if isinstance(file, int):
    95                 return file
    96 
    97         if checkfile and not os.path.isfile(file):
    98                 return None
    99 
    100         file = open(file, mode)
    101         exitstack.push(file)
    102         return file
    10357
    10458# Remove 1 or more files silently
    10559def rm( files ):
    106         if isinstance(files, str ): files = [ files ]
    107         for file in files:
    108                 sh( 'rm', '-f', file, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
     60        if isinstance( files, basestring ):
     61                sh("rm -f %s > /dev/null 2>&1" % files )
     62        else:
     63                for file in files:
     64                        sh("rm -f %s > /dev/null 2>&1" % file )
    10965
    11066# Create 1 or more directory
    11167def mkdir( files ):
    112         if isinstance(files, str ): files = [ files ]
    113         for file in files:
    114                 p = os.path.normpath( file )
    115                 d = os.path.dirname ( p )
    116                 sh( 'mkdir', '-p', d, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
     68        if isinstance( files, basestring ):
     69                sh("mkdir -p %s" % os.path.dirname(files) )
     70        else:
     71                for file in files:
     72                        sh("mkdir -p %s" % os.path.dirname(file) )
    11773
    11874
     
    12480# diff two files
    12581def diff( lhs, rhs ):
     82        # diff the output of the files
     83        diff_cmd = ("diff --text "
     84#                               "--ignore-all-space "
     85#                               "--ignore-blank-lines "
     86                                "--old-group-format='\t\tmissing lines :\n"
     87                                "%%<' \\\n"
     88                                "--new-group-format='\t\tnew lines :\n"
     89                                "%%>' \\\n"
     90                                "--unchanged-group-format='%%=' \\"
     91                                "--changed-group-format='\t\texpected :\n"
     92                                "%%<"
     93                                "\t\tgot :\n"
     94                                "%%>\n' \\\n"
     95                                "--new-line-format='\t\t%%dn\t%%L' \\\n"
     96                                "--old-line-format='\t\t%%dn\t%%L' \\\n"
     97                                "--unchanged-line-format='' \\\n"
     98                                "%s %s")
     99
    126100        # fetch return code and error from the diff command
    127         return sh(
    128                 '''diff''',
    129                 '''--text''',
    130                 '''--old-group-format=\t\tmissing lines :\n%<''',
    131                 '''--new-line-format=\t\t%dn\t%L''',
    132                 '''--new-group-format=\t\tnew lines : \n%>''',
    133                 '''--old-line-format=\t\t%dn\t%L''',
    134                 '''--unchanged-group-format=%=''',
    135                 '''--changed-group-format=\t\texpected :\n%<\t\tgot :\n%>''',
    136                 '''--unchanged-line-format=''',
    137                 lhs,
    138                 rhs,
    139                 output=subprocess.PIPE
    140         )
     101        return sh(diff_cmd % (lhs, rhs), False)
    141102
    142103# call make
    143 def make(target, *, flags = '', output = None, error = None, error_file = None, silent = False):
    144         test_param = """test="%s" """ % (error_file) if error_file else None
    145         cmd = [
    146                 *settings.make,
    147                 '-s' if silent else None,
     104def make(target, flags = '', redirects = '', error_file = None, silent = False):
     105        test_param = """test="%s" """ % (error_file) if error_file else ''
     106        cmd = ' '.join([
     107                settings.make,
     108                '-s' if silent else '',
    148109                test_param,
    149110                settings.arch.flags,
     
    151112                settings.install.flags,
    152113                flags,
    153                 target
    154         ]
    155         cmd = [s for s in cmd if s]
    156         return sh(*cmd, output=output, error=error)
     114                target,
     115                redirects
     116        ])
     117        return sh(cmd)
    157118
    158119def which(program):
     120    import os
     121    def is_exe(fpath):
     122        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
     123
    159124    fpath, fname = os.path.split(program)
    160125    if fpath:
     
    169134    return None
    170135
    171 @contextlib.contextmanager
    172 def tempdir():
    173         cwd = os.getcwd()
    174         with tempfile.TemporaryDirectory() as temp:
    175                 os.chdir(temp)
    176                 try:
    177                         yield temp
    178                 finally:
    179                         os.chdir(cwd)
     136def run(exe, output, input):
     137        ret, _ = sh("timeout %d %s > %s 2>&1" % (settings.timeout.single, exe, output), input = input)
     138        return ret
    180139
    181140################################################################################
     
    184143# move a file
    185144def mv(source, dest):
    186         ret, _ = sh("mv", source, dest)
     145        ret, _ = sh("mv %s %s" % (source, dest))
    187146        return ret
    188147
    189148# cat one file into the other
    190149def cat(source, dest):
    191         ret, _ = sh("cat", source, output=dest)
     150        ret, _ = sh("cat %s > %s" % (source, dest))
    192151        return ret
    193152
     
    204163
    205164# helper function to check if a files contains only a specific string
    206 def file_contains_only(file, text) :
     165def fileContainsOnly(file, text) :
    207166        with open(file) as f:
    208167                ff = f.read().strip()
    209168                result = ff == text.strip()
    210169
    211                 return result
     170                return result;
     171
     172# check whether or not a file is executable
     173def fileIsExecutable(file) :
     174        try :
     175                fileinfo = os.stat(file)
     176                return bool(fileinfo.st_mode & stat.S_IXUSR)
     177        except Exception as inst:
     178                print(type(inst))    # the exception instance
     179                print(inst.args)     # arguments stored in .args
     180                print(inst)
     181                return False
    212182
    213183# transform path to canonical form
    214 def canonical_path(path):
     184def canonicalPath(path):
    215185        abspath = os.path.abspath(__main__.__file__)
    216186        dname = os.path.dirname(abspath)
     
    218188
    219189# compare path even if form is different
    220 def path_cmp(lhs, rhs):
    221         return canonical_path( lhs ) == canonical_path( rhs )
     190def pathCmp(lhs, rhs):
     191        return canonicalPath( lhs ) == canonicalPath( rhs )
    222192
    223193# walk all files in a path
    224 def path_walk( op ):
    225         dname = settings.SRCDIR
    226         for dirname, _, names in os.walk(dname):
     194def pathWalk( op ):
     195        def step(_, dirname, names):
    227196                for name in names:
    228197                        path = os.path.join(dirname, name)
    229198                        op( path )
    230199
     200        # Start the walk
     201        dname = settings.SRCDIR
     202        os.path.walk(dname, step, '')
     203
    231204################################################################################
    232205#               system
    233206################################################################################
    234207# count number of jobs to create
    235 def job_count( options, tests ):
     208def jobCount( options, tests ):
    236209        # check if the user already passed in a number of jobs for multi-threading
    237210        if not options.jobs:
     
    255228        return min( options.jobs, len(tests) ), force
    256229
     230# setup a proper processor pool with correct signal handling
     231def setupPool(jobs):
     232        original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
     233        pool = multiprocessing.Pool(jobs)
     234        signal.signal(signal.SIGINT, original_sigint_handler)
     235
     236        return pool
     237
     238# handle signals in scope
     239class SignalHandling():
     240        def __enter__(self):
     241                # enable signal handling
     242                signal.signal(signal.SIGINT, signal.SIG_DFL)
     243
     244        def __exit__(self, type, value, traceback):
     245                # disable signal handling
     246                signal.signal(signal.SIGINT, signal.SIG_IGN)
     247
     248
    257249# enable core dumps for all the test children
    258250resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
     
    269261                return False
    270262        raise argparse.ArgumentTypeError(msg)
     263        return False
    271264
    272265def fancy_print(text):
    273266        column = which('column')
    274267        if column:
    275                 subprocess.run(column, input=bytes(text + "\n", "UTF-8"))
     268                cmd = "%s 2> /dev/null" % column
     269                proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True)
     270                proc.communicate(input=text + "\n")
    276271        else:
    277272                print(text)
    278273
    279274
    280 def core_info(path):
    281         if not os.path.isfile(path):
    282                 return 1, "ERR Executable path is wrong"
    283 
     275def coreInfo(path):
    284276        cmd   = os.path.join(settings.SRCDIR, "pybin/print-core.gdb")
    285277        if not os.path.isfile(cmd):
    286278                return 1, "ERR Printing format for core dumps not found"
    287279
    288         core  = os.path.join(os.getcwd(), "core" )
     280        dname = os.path.dirname(path)
     281        core  = os.path.join(dname, "core" )
     282        if not os.path.isfile(path):
     283                return 1, "ERR Executable path is wrong"
    289284
    290285        if not os.path.isfile(core):
    291286                return 1, "ERR No core dump"
    292287
    293         return sh('gdb', '-n', path, core, '-batch', '-x', cmd, output=subprocess.PIPE)
     288        return sh("gdb -n %s %s -batch -x %s" % (path, core, cmd), print2stdout=False)
    294289
    295290class Timed:
  • tests/raii/.expect/ctor-autogen-ERR1.txt

    r933f32f r6a9d4b4  
    1 raii/ctor-autogen.cfa:102:1 error: Unique best alternative includes deleted identifier in Generated Cast of:
     1raii/ctor-autogen.cfa:102:1 error: Unique best alternative includes deleted identifier in Cast of:
    22  Application of
    33    Deleted Expression
     
    2727
    2828            ... to arguments
    29               Generated Cast of:
     29              Cast of:
    3030                Member Expression, with field:
    3131                  x: signed int
    3232                ... from aggregate:
    33                   Generated Cast of:
     33                  Cast of:
    3434                    Variable Expression: m: reference to instance of struct Managed with body 1
    3535                  ... to:
     
    3737              ... to:
    3838                reference to signed int
    39               Generated Cast of:
     39              Cast of:
    4040                constant expression (0 0: zero_t)
    4141              ... to:
     
    4848
    4949  ... to arguments
    50     Generated Cast of:
     50    Cast of:
    5151      Variable Expression: x: instance of struct Managed with body 1
    5252    ... to:
  • tests/raii/init_once.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Tue Jun 14 15:43:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:41:26 2019
    13 // Update Count     : 4
     12// Last Modified On : Sat Jul  9 11:30:29 2016
     13// Update Count     : 3
    1414//
    1515
     
    192192// Local Variables: //
    193193// tab-width: 4 //
    194 // compile-command: "cfa init_once.cfa" //
     194// compile-command: "cfa init_once.c" //
    195195// End: //
  • tests/rational.cfa

    r933f32f r6a9d4b4  
    1010// Created On       : Mon Mar 28 08:43:12 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Mar 27 07:37:17 2019
    13 // Update Count     : 80
     12// Last Modified On : Tue Dec  4 21:46:42 2018
     13// Update Count     : 69
    1414//
    1515
     
    1919#include <fstream.hfa>
    2020
     21// UNNECESSARY, FIX ME
     22void ?{}( int & this ) { this = 0; }
     23void ?{}( int & this, zero_t ) { this = 0; }
     24void ?{}( int & this, one_t ) { this = 1; }
    2125double convert( int i ) { return (double)i; }
    2226int convert( double d ) { return (int)d; }
     
    5458        sout | a * b;
    5559        sout | a / b;
    56 //      sout | a \ 2 | b \ 2; // FIX ME
    57 //      sout | a \ -2 | b \ -2;
    5860
    5961        sout | "conversion";
  • tests/sum.cfa

    r933f32f r6a9d4b4  
    1111// Created On       : Wed May 27 17:56:53 2015
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Sun May 19 11:21:02 2019
    14 // Update Count     : 330
     13// Last Modified On : Sun Dec 23 23:00:38 2018
     14// Update Count     : 287
    1515//
    1616
    1717#include <fstream.hfa>
    1818#include <stdlib.hfa>
     19
     20void ?{}( int & c, zero_t ) { c = 0; }                                  // not in prelude
    1921
    2022trait sumable( otype T ) {
     
    2931T sum( size_t size, T a[] ) {
    3032        T total = 0;                                                                            // initialize by 0 constructor
    31         for ( i; size )
     33        for ( size_t i = 0; i < size; i += 1 )
    3234                total += a[i];                                                                  // select appropriate +
    3335        return total;
    3436} // sum
    3537
     38// Not in prelude.
     39unsigned char ?+?( unsigned char t1, unsigned char t2 ) { return (int)t1 + t2; } // cast forces integer addition, otherwise recursion
     40unsigned char ?+=?( unsigned char & t1, unsigned char t2 ) { t1 = t1 + t2; return t1; }
     41unsigned char ++?( unsigned char & t ) { t += 1; return t; }
     42unsigned char ?++( unsigned char & t ) { unsigned char temp = t; t += 1; return temp; }
     43
     44// Not in prelude.
     45void ?{}( unsigned char & c, zero_t ) { c = 0; }
     46void ?{}( float & f, zero_t ) { f = 0.0; }
     47void ?{}( double & d, zero_t ) { d = 0.0; }
     48
    3649int main( void ) {
    3750        const int low = 5, High = 15, size = High - low;
    3851
    39         signed char s = 0, a[size], v = (char)low;
    40         for ( int i = 0; i < size; i += 1, v += 1hh ) {
     52        unsigned char s = 0, a[size], v = (char)low;
     53        for ( int i = 0; i < size; i += 1, v += 1 ) {
    4154                s += v;
    4255                a[i] = v;
    4356        } // for
    4457        sout | "sum from" | low | "to" | High | "is"
    45                  | sum( size, (signed char *)a ) | ", check" | (signed char)s;
    46 
    47         unsigned char s = 0, a[size], v = low;
    48         for ( int i = 0; i < size; i += 1, v += 1hhu ) {
    49                 s += (unsigned char)v;
    50                 a[i] = (unsigned char)v;
    51         } // for
    52         sout | "sum from" | low | "to" | High | "is"
    53                  | sum( size, (unsigned char *)a ) | ", check" | (unsigned char)s;
    54 
    55         short int s = 0, a[size], v = low;
    56         for ( int i = 0; i < size; i += 1, v += 1h ) {
    57                 s += (short int)v;
    58                 a[i] = (short int)v;
    59         } // for
    60         sout | "sum from" | low | "to" | High | "is"
    61                  | sum( size, (short int *)a ) | ", check" | (short int)s;
     58                 | sum( size, (unsigned char *)a ) | ", check" | (int)s;
    6259
    6360        int s = 0, a[size], v = low;
  • tests/test.py

    r933f32f r6a9d4b4  
    1 #!/usr/bin/python3
     1#!/usr/bin/python
     2from __future__ import print_function
    23
    34from pybin.tools import *
     
    89import re
    910import sys
    10 import tempfile
    1111import time
    1212
     
    1515################################################################################
    1616
    17 def find_tests():
     17def findTests():
    1818        expected = []
    1919
    20         def match_test(path):
     20        def matchTest(path):
    2121                match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
    2222                if match :
     
    2828                                expected.append(test)
    2929
    30         path_walk( match_test )
     30        pathWalk( matchTest )
    3131
    3232        return expected
    3333
    3434# reads the directory ./.expect and indentifies the tests
    35 def list_tests( includes, excludes ):
     35def listTests( includes, excludes ):
    3636        # tests directly in the .expect folder will always be processed
    37         test_list = find_tests()
     37        test_list = findTests()
    3838
    3939        # if we have a limited number of includes, filter by them
     
    5252
    5353# from the found tests, filter all the valid tests/desired tests
    54 def valid_tests( options ):
     54def validTests( options ):
    5555        tests = []
    5656
     
    5959        if options.regenerate_expected :
    6060                for testname in options.tests :
    61                         testname = canonical_path( testname )
     61                        testname = canonicalPath( testname )
    6262                        if Test.valid_name(testname):
    63                                 found = [test for test in all_tests if canonical_path( test.target() ) == testname]
     63                                found = [test for test in allTests if canonicalPath( test.target() ) == testname]
    6464                                tests.append( found[0] if len(found) == 1 else Test.from_target(testname) )
    6565                        else :
     
    6969                # otherwise we only need to validate that all tests are present in the complete list
    7070                for testname in options.tests:
    71                         test = [t for t in all_tests if path_cmp( t.target(), testname )]
     71                        test = [t for t in allTests if pathCmp( t.target(), testname )]
    7272
    7373                        if test :
     
    7979
    8080# parses the option
    81 def parse_args():
     81def getOptions():
    8282        # create a parser with the arguments for the tests script
    8383        parser = argparse.ArgumentParser(description='Script which runs cforall tests')
     
    102102                print('ERROR: invalid arguments', file=sys.stderr)
    103103                parser.print_help(sys.stderr)
    104                 sys.exit(1)
     104                sys.exit(1)
    105105
    106106        # script must have at least some tests to run or be listing
     
    112112        # check that exactly one of the booleans is set to true
    113113        if not sum( (listing, all_tests, some_tests, some_dirs) ) > 0 :
    114                 print('''ERROR: must have option '--all', '--list', '--include', '-I' or non-empty test list''', file=sys.stderr)
     114                print('ERROR: must have option \'--all\', \'--list\', \'--include\', \'-I\' or non-empty test list', file=sys.stderr)
    115115                parser.print_help()
    116116                sys.exit(1)
     
    124124        return val == 0 or settings.dry_run
    125125
    126 def no_rule(file, target):
    127         return not settings.dry_run and file_contains_only(file, "make: *** No rule to make target `%s'.  Stop." % target)
     126def isExe(file):
     127        return settings.dry_run or fileIsExecutable(file)
     128
     129def noRule(file, target):
     130        return not settings.dry_run and fileContainsOnly(file, "make: *** No rule to make target `%s'.  Stop." % target)
    128131
    129132# logic to run a single test and return the result (No handling of printing or other test framework logic)
     
    142145        # build, skipping to next test on error
    143146        with Timed() as comp_dur:
    144                 make_ret, _ = make( test.target(), output=subprocess.DEVNULL, error=out_file, error_file = err_file )
    145 
     147                make_ret, _ = make( test.target(),      redirects  = ("2> %s 1> /dev/null" % out_file), error_file = err_file )
     148
     149        # if the make command succeds continue otherwise skip to diff
    146150        run_dur = None
    147         # run everything in a temp directory to make sure core file are handled properly
    148         with tempdir():
    149                 # if the make command succeds continue otherwise skip to diff
    150                 if success(make_ret):
    151                         with Timed() as run_dur:
    152                                 if settings.dry_run or is_exe(exe_file):
    153                                         # run test
    154                                         retcode, _ = sh(exe_file, output=out_file, input=in_file, timeout=True)
    155                                 else :
    156                                         # simply cat the result into the output
    157                                         retcode = cat(exe_file, out_file)
    158                 else:
    159                         retcode = mv(err_file, out_file)
    160 
    161                 if success(retcode):
    162                         if settings.generating :
    163                                 # if we are ounly generating the output we still need to check that the test actually exists
    164                                 if no_rule(out_file, test.target()) :
    165                                         retcode = 1
    166                                         error = "\t\tNo make target for test %s!" % test.target()
    167                                         rm(out_file)
    168                                 else:
    169                                         error = None
     151        if success(make_ret):
     152                with Timed() as run_dur:
     153                        if isExe(exe_file):
     154                                # run test
     155                                retcode = run(exe_file, out_file, in_file)
    170156                        else :
    171                                 # fetch return code and error from the diff command
    172                                 retcode, error = diff(cmp_file, out_file)
    173 
    174                 else:
    175                         with open (out_file, "r") as myfile:
    176                                 error = myfile.read()
    177 
    178                         ret, info = core_info(exe_file)
    179                         error = error + info if error else info
     157                                # simply cat the result into the output
     158                                retcode = cat(exe_file, out_file)
     159        else:
     160                retcode = mv(err_file, out_file)
     161
     162        if success(retcode):
     163                if settings.generating :
     164                        # if we are ounly generating the output we still need to check that the test actually exists
     165                        if noRule(out_file, test.target()) :
     166                                retcode = 1
     167                                error = "\t\tNo make target for test %s!" % test.target()
     168                                rm(out_file)
     169                        else:
     170                                error = None
     171                else :
     172                        # fetch return code and error from the diff command
     173                        retcode, error = diff(cmp_file, out_file)
     174
     175        else:
     176                with open (out_file, "r") as myfile:
     177                        error = myfile.read()
     178
     179                ret, info = coreInfo(exe_file)
     180                error = error + info
    180181
    181182
     
    188189# run a single test and handle the errors, outputs, printing, exception handling, etc.
    189190def run_test_worker(t) :
    190         try :
     191
     192        with SignalHandling():
    191193                # print formated name
    192                 name_txt = '{0:{width}}  '.format(t.target(), width=settings.output_width)
     194                name_txt = "%24s  " % t.name
    193195
    194196                retcode, error, duration = run_single_test(t)
     
    198200
    199201                #print result with error if needed
    200                 text = '\t' + name_txt + result_txt
     202                text = name_txt + result_txt
    201203                out = sys.stdout
    202204                if error :
    203                         text = text + '\n' + error
     205                        text = text + "\n" + error
    204206                        out = sys.stderr
    205207
     
    208210                sys.stderr.flush()
    209211
    210                 return retcode != TestResult.SUCCESS
    211         except KeyboardInterrupt:
    212                 False
     212        return retcode != TestResult.SUCCESS
    213213
    214214# run the given list of tests with the given parameters
    215215def run_tests(tests, jobs) :
    216216        # clean the sandbox from previous commands
    217         make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)
     217        make('clean', redirects = '> /dev/null 2>&1')
    218218
    219219        # create the executor for our jobs and handle the signal properly
    220         pool = multiprocessing.Pool(jobs)
     220        pool = setupPool(jobs)
    221221
    222222        # for each test to run
     
    233233
    234234        # clean the workspace
    235         make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)
     235        make('clean', redirects = '> /dev/null 2>&1')
    236236
    237237        for failed in results:
     
    248248
    249249        # parse the command line arguments
    250         options = parse_args()
     250        options = getOptions()
    251251
    252252        # init global settings
     
    254254
    255255        # fetch the liest of all valid tests
    256         all_tests = list_tests( options.include, options.exclude )
     256        allTests = listTests( options.include, options.exclude )
    257257
    258258
    259259        # if user wants all tests than no other treatement of the test list is required
    260260        if options.all or options.list or options.list_comp or options.include :
    261                 tests = all_tests
     261                tests = allTests
    262262
    263263        #otherwise we need to validate that the test list that was entered is valid
    264264        else :
    265                 tests = valid_tests( options )
     265                tests = validTests( options )
    266266
    267267        # make sure we have at least some test to run
     
    281281        elif options.list :
    282282                print("Listing for %s:%s"% (settings.arch.string, settings.debug.string))
    283                 fancy_print("\n".join(map(lambda t: t.toString(), tests)))
     283                fancy_print("\n".join(map(lambda t: "%s" % (t.toString()), tests)))
    284284
    285285        else :
    286286                # check the build configuration works
    287                 settings.prep_output(tests)
    288287                settings.validate()
    289288
    290                 options.jobs, forceJobs = job_count( options, tests )
    291                 settings.update_make_cmd(forceJobs, options.jobs)
    292 
    293                 print('%s %i tests on %i cores (%s:%s)' % (
    294                         'Regenerating' if settings.generating else 'Running',
    295                         len(tests),
    296                         options.jobs,
     289                options.jobs, forceJobs = jobCount( options, tests )
     290                settings.updateMakeCmd(forceJobs, options.jobs)
     291
     292                print('%s (%s:%s) on %i cores' % (
     293                        'Regenerate tests' if settings.generating else 'Running',
    297294                        settings.arch.string,
    298                         settings.debug.string
     295                        settings.debug.string,
     296                        options.jobs
    299297                ))
    300298
  • tests/warnings/.expect/self-assignment.txt

    r933f32f r6a9d4b4  
    1 warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Generated Cast of:
     1warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Cast of:
    22  Variable Expression: j: signed int
    33... to:
    44  reference to signed int
    5 warnings/self-assignment.cfa:30:1 warning: self assignment of expression: Generated Cast of:
     5warnings/self-assignment.cfa:30:1 warning: self assignment of expression: Cast of:
    66  Variable Expression: s: instance of struct S with body 1
    77... to:
    88  reference to instance of struct S with body 1
    9 warnings/self-assignment.cfa:31:1 warning: self assignment of expression: Generated Cast of:
     9warnings/self-assignment.cfa:31:1 warning: self assignment of expression: Cast of:
    1010  Member Expression, with field:
    1111    i: signed int
     
    1414... to:
    1515  reference to signed int
    16 warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Generated Cast of:
     16warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Cast of:
    1717  Member Expression, with field:
    1818    i: signed int
  • tests/warnings/self-assignment.cfa

    r933f32f r6a9d4b4  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Mar 1 13:53:57 2018
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 20 07:56:17 2019
    13 // Update Count     : 3
     11// Last Modified By : Rob Schluntz
     12// Last Modified On : Thu Mar 1 13:53:57 2018
     13// Update Count     : 2
    1414//
    1515
    1616struct S {
    17         int i;
     17  int i;
    1818};
    1919
    2020struct T {
    21         S s;
     21  S s;
    2222};
    2323
    2424int main() {
    25         int j = 0;
    26         S s = { 0 };
    27         T t = { { 0 } };
     25  int j = 0;
     26  S s = { 0 };
     27  T t = { { 0 } };
    2828
    29         j = j;
    30         s = s;
    31         s.i = s.i;
    32         t.s.i = t.s.i;
     29  j = j;
     30  s = s;
     31  s.i = s.i;
     32  t.s.i = t.s.i;
    3333}
    3434
  • tools/Makefile.in

    r933f32f r6a9d4b4  
    194194DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    195195ACLOCAL = @ACLOCAL@
     196ALLOCA = @ALLOCA@
    196197AMTAR = @AMTAR@
    197198AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
  • tools/PrettyGitLogs.sh

    r933f32f r6a9d4b4  
    2727git rev-list --format=short ${GitOldRef}...${GitNewRef} >  ${GIT_LOG}
    2828
    29 git diff --stat --color ${GitNewRef} ${GitOldRef} | sed -e 's/\[32m/<span style\=\"color\: \#00AA00\;\">/g' -e 's/\[31m/<span style\=\"color\: \#AA0000\;\">/g' -e 's/\[m/<\/span>/g' >  ${GIT_DIFF}
     29git diff --stat ${GitNewRef} ${GitOldRef} >  ${GIT_DIFF}
  • tools/prettyprinter/Makefile.in

    r933f32f r6a9d4b4  
    223223DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    224224ACLOCAL = @ACLOCAL@
     225ALLOCA = @ALLOCA@
    225226AMTAR = @AMTAR@
    226227AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
Note: See TracChangeset for help on using the changeset viewer.