Changeset 933f32f


Ignore:
Timestamp:
May 24, 2019, 10:19:41 AM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
d908563
Parents:
6a9d4b4 (diff), 292642a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into cleanup-dtors

Files:
143 added
9 deleted
224 edited
9 moved

Legend:

Unmodified
Added
Removed
  • .gitignore

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

    r6a9d4b4 r933f32f  
    1717
    1818                                parallel (
    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 ) },
     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' ) },
    2525                                )
    2626                        }
     27                }
    2728
    28                         //Push latest changes to do-lang repo
    29                         push_build()
    30                 }
     29                promote_email(true)
    3130        }
    3231
     
    4342
    4443                //Send email to notify the failure
    45                 promote_failure_email()
     44                promote_email(false)
    4645        }
    4746
     
    5756//===========================================================================================================
    5857
    59 def trigger_build(String cc, String arch, Boolean publish) {
     58def trigger_build(String cc, String arch) {
    6059        def result = build job: 'Cforall/master',               \
    6160                parameters: [                                           \
     
    7776                        [$class: 'BooleanParameterValue',               \
    7877                          name: 'Publish',                              \
    79                           value: publish],                              \
     78                          value: true],                                 \
    8079                        [$class: 'BooleanParameterValue',               \
    8180                          name: 'Silent',                               \
     
    8988                sh("wget -q -O - http://localhost:8084/jenkins/job/Cforall/job/master/${result.number}/consoleText")
    9089                error(result.result)
    91         }
    92 }
    93 
    94 def 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')
    11990        }
    12091}
     
    141112
    142113//Email notification on a full build failure
    143 def promote_failure_email() {
     114def promote_email(boolean success) {
    144115        echo('notifying users')
     116
     117        def result = success ? "PROMOTE - SUCCESS" : "PROMOTE - FAILURE"
    145118
    146119        //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
    147120        //Configurations for email format
    148         def email_subject = "[cforall git][PROMOTE - FAILURE]"
    149         def email_body = """This is an automated email from the Jenkins build machine. It was
    150 generated because of a git hooks/post-receive script following
    151 a ref change was pushed to the repository containing
    152 the project "UNNAMED PROJECT".
     121        def email_subject = "[cforall git][${result}]"
     122        def email_body = """<p>This is an automated email from the Jenkins build machine. It was
     123generated following the result of the C\u2200 nightly build.</p>
    153124
    154 Check console output at ${env.BUILD_URL} to view the results.
     125<p>Check console output at ${env.BUILD_URL} to view the results.</p>
    155126
    156 - Status --------------------------------------------------------------
     127<p>- Status --------------------------------------------------------------</p>
    157128
    158 PROMOTE FAILURE
     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>
    159136"""
    160137
     
    162139
    163140        //send email notification
    164         emailext body: email_body, subject: email_subject, to: email_to, attachLog: true
     141        emailext body: email_body, subject: email_subject, to: email_to, attachLog: !success
    165142}
  • Jenkinsfile

    r6a9d4b4 r933f32f  
    11#!groovy
     2
     3import groovy.transform.Field
    24
    35//===========================================================================================================
     
    2224                wrap([$class: 'TimestamperBuildWrapper']) {
    2325
    24                         notify_server(0)
    25 
    2626                        Settings = prepare_build()
    2727
     
    3434                                checkout()
    3535
    36                                 notify_server(0)
    37 
    3836                                build()
    3937
     
    5048                        BuildDir  = pwd tmp: true
    5149                        SrcDir    = pwd tmp: false
    52 
    53                         notify_server(45)
    5450                }
    5551        }
     
    7268        finally {
    7369                //Send email with final results if this is not a full build
    74                 if( Settings && !Settings.Silent ) {
    75                         email(log_needed, Settings.IsSandbox)
    76                 }
     70                email(log_needed)
    7771
    7872                echo 'Build Completed'
     
    116110                        //Also specify the compiler by hand
    117111                        targets=""
    118                         if( Settings.RunAllTests ) {
     112                        if( Settings.RunAllTests || Settings.RunBenchmark ) {
    119113                                targets="--with-target-hosts='host:debug,host:nodebug'"
    120114                        } else {
     
    153147                dir (BuildDir) {
    154148                        //Append bench results
    155                         sh "${SrcDir}/benchmark/jenkins.sh ${Settings.GitNewRef} ${Settings.Architecture} ${BuildDir}/bench.json"
     149                        sh "make --no-print-directory -C benchmark jenkins"
    156150                }
    157151        }
     
    176170        build_stage('Publish') {
    177171
    178                 if( !Settings.Publish ) return
     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)
    179176
    180177                //Then publish the results
    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'
     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')
    182182        }
    183183}
     
    196196
    197197        return """
     198<pre>
    198199The branch ${env.BRANCH_NAME} has been updated.
    199200${gitUpdate}
    200 
    201 Check console output at ${env.BUILD_URL} to view the results.
    202 
    203 - Status --------------------------------------------------------------
    204 
    205 BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}
    206 
    207 - Log -----------------------------------------------------------------
     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>
    208212${gitLog}
    209 -----------------------------------------------------------------------
     213</pre>
     214
     215<p>-----------------------------------------------------------------------</p>
     216<pre>
    210217Summary of changes:
    211218${gitDiff}
     219</pre>
    212220"""
    213221}
    214222
    215223//Standard build email notification
    216 def email(boolean log, boolean bIsSandbox) {
     224def email(boolean log) {
    217225        //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
    218226        //Configurations for email format
     
    221229        def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()
    222230        def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}"
    223         def email_body = """This is an automated email from the Jenkins build machine. It was
     231        def email_body = """<p>This is an automated email from the Jenkins build machine. It was
    224232generated because of a git hooks/post-receive script following
    225 a ref change which was pushed to the Cforall repository.
     233a ref change which was pushed to the C\u2200 repository.</p>
    226234""" + GitLogMessage()
    227235
    228         def email_to = "cforall@lists.uwaterloo.ca"
    229 
    230         if( Settings && !Settings.IsSandbox ) {
     236        def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"
     237
     238        if( Settings && !Settings.Silent ) {
    231239                //send email notification
    232240                emailext body: email_body, subject: email_subject, to: email_to, attachLog: log
     
    311319                }
    312320
     321                this.IsSandbox          = (branch == "jenkins-sandbox")
    313322                this.RunAllTests        = param.RunAllTests
    314323                this.RunBenchmark       = param.RunBenchmark
     
    316325                this.Publish            = param.Publish
    317326                this.Silent             = param.Silent
    318                 this.IsSandbox          = (branch == "jenkins-sandbox")
    319327
    320328                def full = param.RunAllTests ? " (Full)" : ""
     
    333341                this.GitNewRef = ''
    334342                this.GitOldRef = ''
     343        }
     344}
     345
     346class 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
    335355        }
    336356}
     
    398418}
    399419
    400 def 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 
    405420def make_doc() {
    406421        def err = null
     
    417432        }
    418433}
     434
     435def 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

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

    r6a9d4b4 r933f32f  
    250250distcleancheck_listfiles = find . -type f -print
    251251ACLOCAL = @ACLOCAL@
    252 ALLOCA = @ALLOCA@
    253252AMTAR = @AMTAR@
    254253AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    396395AUTOMAKE_OPTIONS = foreign    # do not require all the GNU file names
    397396ACLOCAL_AMFLAGS = -I automake
    398 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/*
     397MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* # order important
    399398SUBDIRS = driver src . @LIBCFA_TARGET_DIRS@
    400399noinst_DATA = @LIBCFA_TARGET_MAKEFILES@
     
    928927.PRECIOUS: Makefile
    929928
    930  # order important
    931929
    932930@LIBCFA_TARGET_MAKEFILES@ : Makefile $(srcdir)/libcfa/configure
  • automake/cfa.m4

    r6a9d4b4 r933f32f  
    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
     84AC_DEFUN([M4CFA_CHECK_COMPILE_FLAG],
     85[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
     86AS_VAR_PUSHDEF([CACHEVAR],[m4cfa_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
     87AC_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])
     94AS_VAR_IF(CACHEVAR,yes,
     95        [m4_default([$2], :)],
     96        [m4_default([$3], :)])
     97AS_VAR_POPDEF([CACHEVAR])dnl
     98])dnl M4CFA_CHECK_COMPILE_FLAGS
  • benchmark/Makefile.am

    r6a9d4b4 r933f32f  
    2121include $(top_srcdir)/src/cfa.make
    2222
    23 
    24 
    25 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread
    26 AM_CFAFLAGS = -quiet -in-tree -nodebug
    27 AM_UPPFLAGS = -quiet -nodebug -multi
     23AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread
     24AM_CFAFLAGS = -quiet -nodebug -in-tree
     25AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14
     26
     27BENCH_V_CC = $(__bench_v_CC_$(__quiet))
     28BENCH_V_CFA = $(__bench_v_CFA_$(__quiet))
     29BENCH_V_CXX = $(__bench_v_CXX_$(__quiet))
     30BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
     31BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
     32BENCH_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
    2849
    2950TOOLSDIR = ${abs_top_builddir}/tools/
     
    4667
    4768.NOTPARALLEL:
     69.PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv
    4870
    4971## =========================================================================================================
     
    6082
    6183%.runquiet :
    62         @+make $(basename $@) CFLAGS="-w"
     84        @+make $(basename $@) CFLAGS="-w" __quiet=quiet
    6385        @taskset -c 1 ./a.out
    6486        @rm -f a.out
     
    7395## =========================================================================================================
    7496
     97FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
     98
    7599jenkins$(EXEEXT):
    76         @echo "{"
    77         @echo -e '\t"githash": "'${githash}'",'
    78         @echo -e '\t"arch": "'   ${arch}   '",'
    79100@DOifskipcompile@
    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},'
     101        @+make compile.csv
    84102@DOendif@
    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 "}"
     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
     113compile.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
     125ctxswitch.csv:
     126        @echo "coroutine,thread" > $@
     127        @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
     128        @+make ctxswitch-cfa_thread.runquiet >> $@
     129        @$(srcdir)/fixcsv.sh $@
     130
     131mutex.csv:
     132        @echo "1-monitor,2-monitor" > $@
     133        @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
     134        @+make mutex-cfa2.runquiet >> $@
     135        @$(srcdir)/fixcsv.sh $@
     136
     137signal.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 $@
    109144
    110145## =========================================================================================================
    111146loop$(EXEEXT):
    112         $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
     147        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
    113148
    114149function$(EXEEXT):
    115         $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
     150        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
    116151
    117152fetch_add$(EXEEXT):
    118         $(AM_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
     153        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
     154
     155tls-fetch_add$(EXEEXT):
     156        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
    119157
    120158## =========================================================================================================
     
    123161        function.run                    \
    124162        fetch_add.run                   \
     163        tls-fetch_add.run                       \
    125164        ctxswitch-pthread.run           \
    126165        ctxswitch-cfa_coroutine.run     \
     
    139178
    140179ctxswitch-kos_fibre$(EXEEXT):
    141         $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
     180        $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
    142181
    143182ctxswitch-kos_fibre2$(EXEEXT):
    144         $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre
     183        $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre
    145184endif
    146185
     
    148187
    149188ctxswitch-pthread$(EXEEXT):
    150         $(AM_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
     189        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
    151190
    152191ctxswitch-cfa_coroutine$(EXEEXT):
    153         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
     192        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
    154193
    155194ctxswitch-cfa_thread$(EXEEXT):
    156         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
     195        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
    157196
    158197ctxswitch-cfa_thread2$(EXEEXT):
    159         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
     198        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
    160199
    161200ctxswitch-upp_coroutine$(EXEEXT):
    162         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
     201        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
    163202
    164203ctxswitch-upp_thread$(EXEEXT):
    165         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
     204        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
    166205
    167206ctxswitch-goroutine$(EXEEXT):
    168         $(AM_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
     207        $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
    169208
    170209ctxswitch-java_thread$(EXEEXT):
    171         $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
     210        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
    172211        @echo "#!/bin/sh" > a.out
    173212        @echo "java JavaThread" >> a.out
     
    187226
    188227mutex-pthread_lock$(EXEEXT):
    189         $(AM_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
     228        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
    190229
    191230mutex-upp$(EXEEXT):
    192         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
     231        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
    193232
    194233mutex-cfa1$(EXEEXT):
    195         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
     234        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
    196235
    197236mutex-cfa2$(EXEEXT):
    198         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
     237        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
    199238
    200239mutex-cfa4$(EXEEXT):
    201         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
     240        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
    202241
    203242mutex-java_thread$(EXEEXT):
    204         $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
     243        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
    205244        @echo "#!/bin/sh" > a.out
    206245        @echo "java JavaThread" >> a.out
     
    217256
    218257signal-pthread_cond$(EXEEXT):
    219         $(AM_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
     258        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
    220259
    221260signal-upp$(EXEEXT):
    222         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
     261        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
    223262
    224263signal-cfa1$(EXEEXT):
    225         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
     264        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
    226265
    227266signal-cfa2$(EXEEXT):
    228         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
     267        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
    229268
    230269signal-cfa4$(EXEEXT):
    231         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
     270        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
    232271
    233272signal-java_thread$(EXEEXT):
    234         $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
     273        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
    235274        @echo "#!/bin/sh" > a.out
    236275        @echo "java JavaThread" >> a.out
     
    246285
    247286waitfor-upp$(EXEEXT):
    248         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
     287        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
    249288
    250289waitfor-cfa1$(EXEEXT):
    251         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
     290        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
    252291
    253292waitfor-cfa2$(EXEEXT):
    254         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
     293        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
    255294
    256295waitfor-cfa4$(EXEEXT):
    257         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
     296        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
    258297
    259298## =========================================================================================================
     
    269308
    270309creation-cfa_coroutine$(EXEEXT):
    271         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
     310        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
    272311
    273312creation-cfa_coroutine_eager$(EXEEXT):
    274         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
     313        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
    275314
    276315creation-cfa_thread$(EXEEXT):
    277         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
     316        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
    278317
    279318creation-upp_coroutine$(EXEEXT):
    280         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
     319        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
    281320
    282321creation-upp_thread$(EXEEXT):
    283         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
     322        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
    284323
    285324creation-pthread$(EXEEXT):
    286         $(AM_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
     325        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
    287326
    288327creation-goroutine$(EXEEXT):
    289         $(AM_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
     328        $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
    290329
    291330creation-java_thread$(EXEEXT):
    292         $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
     331        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
    293332        @echo "#!/bin/sh" > a.out
    294333        @echo "java JavaThread" >> a.out
     
    311350
    312351compile-array$(EXEEXT):
    313         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
     352        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
    314353
    315354compile-attributes$(EXEEXT):
    316         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
     355        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
    317356
    318357compile-empty$(EXEEXT):
    319         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
     358        @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
    320359
    321360compile-expression$(EXEEXT):
    322         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
     361        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
    323362
    324363compile-io$(EXEEXT):
    325         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
     364        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
    326365
    327366compile-monitor$(EXEEXT):
    328         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     367        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
    329368
    330369compile-operators$(EXEEXT):
    331         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
     370        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
    332371
    333372compile-thread$(EXEEXT):
    334         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     373        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
    335374
    336375compile-typeof$(EXEEXT):
    337         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
    338 
     376        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
     377
  • benchmark/Makefile.in

    r6a9d4b4 r933f32f  
    200200DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    201201ACLOCAL = @ACLOCAL@
    202 ALLOCA = @ALLOCA@
    203202AMTAR = @AMTAR@
    204203AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    372371
    373372# applies to both programs
    374 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread
    375 AM_CFAFLAGS = -quiet -in-tree -nodebug
    376 AM_UPPFLAGS = -quiet -nodebug -multi
     373AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread
     374AM_CFAFLAGS = -quiet -nodebug -in-tree
     375AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14
     376BENCH_V_CC = $(__bench_v_CC_$(__quiet))
     377BENCH_V_CFA = $(__bench_v_CFA_$(__quiet))
     378BENCH_V_CXX = $(__bench_v_CXX_$(__quiet))
     379BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
     380BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
     381BENCH_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)
    377395TOOLSDIR = ${abs_top_builddir}/tools/
    378396REPEAT = ${abs_top_builddir}/tools/repeat
     
    383401PRINT_FORMAT = %20s: #Comments needed for spacing
    384402dummy_SOURCES = dummyC.c dummyCXX.cpp
     403FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
    385404CTXSWITCH_DEPEND = loop.run function.run fetch_add.run \
    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)
     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)
    391410testdir = $(top_srcdir)/tests
    392411all: all-am
     
    713732
    714733.NOTPARALLEL:
     734.PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv
    715735
    716736all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT)
     
    726746
    727747%.runquiet :
    728         @+make $(basename $@) CFLAGS="-w"
     748        @+make $(basename $@) CFLAGS="-w" __quiet=quiet
    729749        @taskset -c 1 ./a.out
    730750        @rm -f a.out
     
    738758
    739759jenkins$(EXEEXT):
    740         @echo "{"
    741         @echo -e '\t"githash": "'${githash}'",'
    742         @echo -e '\t"arch": "'   ${arch}   '",'
    743760@DOifskipcompile@
    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},'
     761        @+make compile.csv
    748762@DOendif@
    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 "}"
     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
     773compile.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
     785ctxswitch.csv:
     786        @echo "coroutine,thread" > $@
     787        @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
     788        @+make ctxswitch-cfa_thread.runquiet >> $@
     789        @$(srcdir)/fixcsv.sh $@
     790
     791mutex.csv:
     792        @echo "1-monitor,2-monitor" > $@
     793        @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
     794        @+make mutex-cfa2.runquiet >> $@
     795        @$(srcdir)/fixcsv.sh $@
     796
     797signal.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 $@
    773804
    774805loop$(EXEEXT):
    775         $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
     806        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
    776807
    777808function$(EXEEXT):
    778         $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
     809        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
    779810
    780811fetch_add$(EXEEXT):
    781         $(AM_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
     812        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
     813
     814tls-fetch_add$(EXEEXT):
     815        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
    782816
    783817@WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre$(EXEEXT):
    784 @WITH_LIBFIBRE_TRUE@    $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
     818@WITH_LIBFIBRE_TRUE@    $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
    785819
    786820@WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre2$(EXEEXT):
    787 @WITH_LIBFIBRE_TRUE@    $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre
     821@WITH_LIBFIBRE_TRUE@    $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre
    788822
    789823ctxswitch$(EXEEXT): $(CTXSWITCH_DEPEND)
    790824
    791825ctxswitch-pthread$(EXEEXT):
    792         $(AM_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
     826        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
    793827
    794828ctxswitch-cfa_coroutine$(EXEEXT):
    795         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
     829        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
    796830
    797831ctxswitch-cfa_thread$(EXEEXT):
    798         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
     832        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
    799833
    800834ctxswitch-cfa_thread2$(EXEEXT):
    801         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
     835        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
    802836
    803837ctxswitch-upp_coroutine$(EXEEXT):
    804         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
     838        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
    805839
    806840ctxswitch-upp_thread$(EXEEXT):
    807         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
     841        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
    808842
    809843ctxswitch-goroutine$(EXEEXT):
    810         $(AM_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
     844        $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
    811845
    812846ctxswitch-java_thread$(EXEEXT):
    813         $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
     847        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
    814848        @echo "#!/bin/sh" > a.out
    815849        @echo "java JavaThread" >> a.out
     
    828862
    829863mutex-pthread_lock$(EXEEXT):
    830         $(AM_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
     864        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
    831865
    832866mutex-upp$(EXEEXT):
    833         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
     867        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
    834868
    835869mutex-cfa1$(EXEEXT):
    836         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
     870        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
    837871
    838872mutex-cfa2$(EXEEXT):
    839         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
     873        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
    840874
    841875mutex-cfa4$(EXEEXT):
    842         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
     876        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
    843877
    844878mutex-java_thread$(EXEEXT):
    845         $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
     879        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
    846880        @echo "#!/bin/sh" > a.out
    847881        @echo "java JavaThread" >> a.out
     
    857891
    858892signal-pthread_cond$(EXEEXT):
    859         $(AM_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
     893        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
    860894
    861895signal-upp$(EXEEXT):
    862         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
     896        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
    863897
    864898signal-cfa1$(EXEEXT):
    865         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
     899        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
    866900
    867901signal-cfa2$(EXEEXT):
    868         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
     902        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
    869903
    870904signal-cfa4$(EXEEXT):
    871         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
     905        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
    872906
    873907signal-java_thread$(EXEEXT):
    874         $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
     908        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
    875909        @echo "#!/bin/sh" > a.out
    876910        @echo "java JavaThread" >> a.out
     
    884918
    885919waitfor-upp$(EXEEXT):
    886         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
     920        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
    887921
    888922waitfor-cfa1$(EXEEXT):
    889         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
     923        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
    890924
    891925waitfor-cfa2$(EXEEXT):
    892         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
     926        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
    893927
    894928waitfor-cfa4$(EXEEXT):
    895         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
     929        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
    896930
    897931creation$(EXEEXT) :\
     
    906940
    907941creation-cfa_coroutine$(EXEEXT):
    908         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
     942        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
    909943
    910944creation-cfa_coroutine_eager$(EXEEXT):
    911         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
     945        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
    912946
    913947creation-cfa_thread$(EXEEXT):
    914         $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
     948        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
    915949
    916950creation-upp_coroutine$(EXEEXT):
    917         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
     951        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
    918952
    919953creation-upp_thread$(EXEEXT):
    920         $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
     954        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
    921955
    922956creation-pthread$(EXEEXT):
    923         $(AM_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
     957        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
    924958
    925959creation-goroutine$(EXEEXT):
    926         $(AM_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
     960        $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
    927961
    928962creation-java_thread$(EXEEXT):
    929         $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
     963        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
    930964        @echo "#!/bin/sh" > a.out
    931965        @echo "java JavaThread" >> a.out
     
    943977
    944978compile-array$(EXEEXT):
    945         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
     979        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
    946980
    947981compile-attributes$(EXEEXT):
    948         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
     982        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
    949983
    950984compile-empty$(EXEEXT):
    951         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
     985        @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
    952986
    953987compile-expression$(EXEEXT):
    954         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
     988        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
    955989
    956990compile-io$(EXEEXT):
    957         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
     991        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
    958992
    959993compile-monitor$(EXEEXT):
    960         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     994        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
    961995
    962996compile-operators$(EXEEXT):
    963         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
     997        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
    964998
    965999compile-thread$(EXEEXT):
    966         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     1000        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
    9671001
    9681002compile-typeof$(EXEEXT):
    969         $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
     1003        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
    9701004
    9711005# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • benchmark/ctxswitch/cfa_cor.cfa

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

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

    r6a9d4b4 r933f32f  
    637637LIBOBJS
    638638CFA_BACKEND_CC
    639 ALLOCA
     639WITH_LIBTCMALLOC_FALSE
     640WITH_LIBTCMALLOC_TRUE
     641WITH_LIBPROFILER_FALSE
     642WITH_LIBPROFILER_TRUE
    640643WITH_LIBFIBRE_FALSE
    641644WITH_LIBFIBRE_TRUE
     
    19611964} # ac_fn_cxx_try_link
    19621965
    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.
    1967 ac_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; }
    1972 if eval \${$3+:} false; then :
    1973   $as_echo_n "(cached) " >&6
    1974 else
    1975   eval "$3=no"
    1976   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    1977 /* end confdefs.h.  */
    1978 $4
    1979 int
    1980 main ()
    1981 {
    1982 if (sizeof ($2))
    1983          return 0;
    1984   ;
    1985   return 0;
    1986 }
    1987 _ACEOF
    1988 if ac_fn_c_try_compile "$LINENO"; then :
    1989   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    1990 /* end confdefs.h.  */
    1991 $4
    1992 int
    1993 main ()
    1994 {
    1995 if (sizeof (($2)))
    1996             return 0;
    1997   ;
    1998   return 0;
    1999 }
    2000 _ACEOF
    2001 if ac_fn_c_try_compile "$LINENO"; then :
    2002 
    2003 else
    2004   eval "$3=yes"
    2005 fi
    2006 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    2007 fi
    2008 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    2009 fi
    2010 eval 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 
    20171966# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
    20181967# -------------------------------------------------------
     
    21062055} # ac_fn_c_check_header_mongrel
    21072056
    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.
    2112 ac_fn_c_find_intX_t ()
     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.
     2061ac_fn_c_check_type ()
    21132062{
    21142063  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
    2115   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5
    2116 $as_echo_n "checking for int$2_t... " >&6; }
     2064  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
     2065$as_echo_n "checking for $2... " >&6; }
    21172066if eval \${$3+:} false; then :
    21182067  $as_echo_n "(cached) " >&6
    21192068else
    21202069  eval "$3=no"
    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
     2070  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    21262071/* end confdefs.h.  */
    2127 $ac_includes_default
    2128              enum { N = $2 / 2 - 1 };
     2072$4
    21292073int
    21302074main ()
    21312075{
    2132 static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))];
    2133 test_array [0] = 0;
    2134 return test_array [0];
    2135 
     2076if (sizeof ($2))
     2077         return 0;
    21362078  ;
    21372079  return 0;
     
    21412083  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    21422084/* end confdefs.h.  */
    2143 $ac_includes_default
    2144                 enum { N = $2 / 2 - 1 };
     2085$4
    21452086int
    21462087main ()
    21472088{
    2148 static 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))];
    2150 test_array [0] = 0;
    2151 return test_array [0];
    2152 
     2089if (sizeof (($2)))
     2090            return 0;
    21532091  ;
    21542092  return 0;
     
    21582096
    21592097else
    2160   case $ac_type in #(
    2161   int$2_t) :
    2162     eval "$3=yes" ;; #(
    2163   *) :
    2164     eval "$3=\$ac_type" ;;
    2165 esac
     2098  eval "$3=yes"
    21662099fi
    21672100rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    21682101fi
    21692102rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    2170        if eval test \"x\$"$3"\" = x"no"; then :
    2171 
    2172 else
    2173   break
    2174 fi
    2175      done
    21762103fi
    21772104eval ac_res=\$$3
     
    21802107  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
    21812108
    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.
    2188 ac_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; }
    2193 if eval \${$3+:} false; then :
    2194   $as_echo_n "(cached) " >&6
    2195 else
    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
    2204 int
    2205 main ()
    2206 {
    2207 static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)];
    2208 test_array [0] = 0;
    2209 return test_array [0];
    2210 
    2211   ;
    2212   return 0;
    2213 }
    2214 _ACEOF
    2215 if 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" ;;
    2221 esac
    2222 fi
    2223 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    2224        if eval test \"x\$"$3"\" = x"no"; then :
    2225 
    2226 else
    2227   break
    2228 fi
    2229      done
    2230 fi
    2231 eval 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
     2109} # ac_fn_c_check_type
    22372110cat >config.log <<_ACEOF
    22382111This file contains any messages produced by compilers while
     
    26672540
    26682541
     2542# http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m4
     2543
    26692544
    26702545# don't use the default CFLAGS as they unconditonnaly add -O2
     
    35273402                "debug") ;;
    35283403                "nolib") ;;
     3404                "profile") ;;
    35293405                *)
    35303406                        >&2 echo "Configuration must be 'debug', 'nodebug' or 'nolib'"
     
    51835059
    51845060
    5185         # deprecated
    51865061# These are often not installed and people miss seeing the "no", so stop the configure.
    51875062for ac_prog in 'bison -y' byacc
     
    1673416609
    1673516610
    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; }
    16738 set x ${MAKE-make}
    16739 ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
    16740 if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
    16741   $as_echo_n "(cached) " >&6
    16742 else
    16743   cat >conftest.make <<\_ACEOF
    16744 SHELL = /bin/sh
    16745 all:
    16746         @echo '@@@%%%=$(MAKE)=@@@%%%'
    16747 _ACEOF
    16748 # GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
    16749 case `${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;;
    16754 esac
    16755 rm -f conftest.make
    16756 fi
    16757 if 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=
    16761 else
    16762   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
    16763 $as_echo "no" >&6; }
    16764   SET_MAKE="MAKE=${MAKE-make}"
    16765 fi
    16766 
    1676716611
    1676816612# Checks for libraries.
     
    1681816662
    1681916663
    16820 # Checks for header files.
    16821 ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
    16822 if test "x$ac_cv_type_size_t" = xyes; then :
    16823 
    16824 else
    16825 
    16826 cat >>confdefs.h <<_ACEOF
    16827 #define size_t unsigned int
    16828 _ACEOF
    16829 
    16830 fi
    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; }
    16836 if ${ac_cv_working_alloca_h+:} false; then :
     16664{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ProfilingIsEnabledForAllThreads in -lprofiler" >&5
     16665$as_echo_n "checking for ProfilingIsEnabledForAllThreads in -lprofiler... " >&6; }
     16666if ${ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads+:} false; then :
    1683716667  $as_echo_n "(cached) " >&6
    1683816668else
    16839   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     16669  ac_check_lib_save_LIBS=$LIBS
     16670LIBS="-lprofiler  $LIBS"
     16671cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    1684016672/* end confdefs.h.  */
    16841 #include <alloca.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
     16678extern "C"
     16679#endif
     16680char ProfilingIsEnabledForAllThreads ();
    1684216681int
    1684316682main ()
    1684416683{
    16845 char *p = (char *) alloca (2 * sizeof (int));
    16846                           if (p) return 0;
     16684return ProfilingIsEnabledForAllThreads ();
    1684716685  ;
    1684816686  return 0;
     
    1685016688_ACEOF
    1685116689if ac_fn_c_try_link "$LINENO"; then :
    16852   ac_cv_working_alloca_h=yes
    16853 else
    16854   ac_cv_working_alloca_h=no
     16690  ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads=yes
     16691else
     16692  ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads=no
    1685516693fi
    1685616694rm -f core conftest.err conftest.$ac_objext \
    1685716695    conftest$ac_exeext conftest.$ac_ext
    16858 fi
    16859 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5
    16860 $as_echo "$ac_cv_working_alloca_h" >&6; }
    16861 if test $ac_cv_working_alloca_h = yes; then
    16862 
    16863 $as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h
    16864 
    16865 fi
    16866 
    16867 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5
    16868 $as_echo_n "checking for alloca... " >&6; }
    16869 if ${ac_cv_func_alloca_works+:} false; then :
     16696LIBS=$ac_check_lib_save_LIBS
     16697fi
     16698{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads" >&5
     16699$as_echo "$ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads" >&6; }
     16700if test "x$ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads" = xyes; then :
     16701  HAVE_LIBPROFILER=1
     16702else
     16703  HAVE_LIBPROFILER=0
     16704fi
     16705
     16706 if test "$HAVE_LIBPROFILER" -eq 1; then
     16707  WITH_LIBPROFILER_TRUE=
     16708  WITH_LIBPROFILER_FALSE='#'
     16709else
     16710  WITH_LIBPROFILER_TRUE='#'
     16711  WITH_LIBPROFILER_FALSE=
     16712fi
     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; }
     16717if ${ac_cv_lib_tcmalloc_malloc+:} false; then :
    1687016718  $as_echo_n "(cached) " >&6
    1687116719else
    16872   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     16720  ac_check_lib_save_LIBS=$LIBS
     16721LIBS="-ltcmalloc  $LIBS"
     16722cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    1687316723/* end confdefs.h.  */
    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 */
    16888 void *alloca (size_t);
    16889 #    endif
    16890 #   endif
    16891 #  endif
    16892 # endif
     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
     16729extern "C"
    1689316730#endif
    16894 
     16731char malloc ();
    1689516732int
    1689616733main ()
    1689716734{
    16898 char *p = (char *) alloca (1);
    16899                                     if (p) return 0;
     16735return malloc ();
    1690016736  ;
    1690116737  return 0;
     
    1690316739_ACEOF
    1690416740if ac_fn_c_try_link "$LINENO"; then :
    16905   ac_cv_func_alloca_works=yes
    16906 else
    16907   ac_cv_func_alloca_works=no
     16741  ac_cv_lib_tcmalloc_malloc=yes
     16742else
     16743  ac_cv_lib_tcmalloc_malloc=no
    1690816744fi
    1690916745rm -f core conftest.err conftest.$ac_objext \
    1691016746    conftest$ac_exeext conftest.$ac_ext
    16911 fi
    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 
    16915 if test $ac_cv_func_alloca_works = yes; then
    16916 
    16917 $as_echo "#define HAVE_ALLOCA 1" >>confdefs.h
    16918 
    16919 else
    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 
    16925 ALLOCA=\${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; }
    16932 if ${ac_cv_os_cray+:} false; then :
    16933   $as_echo_n "(cached) " >&6
    16934 else
    16935   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    16936 /* end confdefs.h.  */
    16937 #if defined CRAY && ! defined CRAY2
    16938 webecray
    16939 #else
    16940 wenotbecray
    16941 #endif
    16942 
    16943 _ACEOF
    16944 if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
    16945   $EGREP "webecray" >/dev/null 2>&1; then :
    16946   ac_cv_os_cray=yes
    16947 else
    16948   ac_cv_os_cray=no
    16949 fi
    16950 rm -f conftest*
    16951 
    16952 fi
    16953 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5
    16954 $as_echo "$ac_cv_os_cray" >&6; }
    16955 if 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`
    16958 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
    16959 if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
    16960 
    16961 cat >>confdefs.h <<_ACEOF
    16962 #define CRAY_STACKSEG_END $ac_func
    16963 _ACEOF
    16964 
    16965     break
    16966 fi
    16967 
    16968   done
    16969 fi
    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; }
    16973 if ${ac_cv_c_stack_direction+:} false; then :
    16974   $as_echo_n "(cached) " >&6
    16975 else
    16976   if test "$cross_compiling" = yes; then :
    16977   ac_cv_c_stack_direction=0
    16978 else
    16979   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    16980 /* end confdefs.h.  */
    16981 $ac_includes_default
    16982 int
    16983 find_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 
    16993 int
    16994 main (int argc, char **argv)
    16995 {
    16996   return find_stack_direction (0, argc + !argv + 20) < 0;
    16997 }
    16998 _ACEOF
    16999 if ac_fn_c_try_run "$LINENO"; then :
    17000   ac_cv_c_stack_direction=1
    17001 else
    17002   ac_cv_c_stack_direction=-1
    17003 fi
    17004 rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
    17005   conftest.$ac_objext conftest.beam conftest.$ac_ext
    17006 fi
    17007 
    17008 fi
    17009 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5
    17010 $as_echo "$ac_cv_c_stack_direction" >&6; }
    17011 cat >>confdefs.h <<_ACEOF
    17012 #define STACK_DIRECTION $ac_cv_c_stack_direction
    17013 _ACEOF
    17014 
    17015 
    17016 fi
    17017 
    17018 for ac_header in fenv.h float.h inttypes.h libintl.h limits.h malloc.h stddef.h stdlib.h string.h unistd.h
     16747LIBS=$ac_check_lib_save_LIBS
     16748fi
     16749{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tcmalloc_malloc" >&5
     16750$as_echo "$ac_cv_lib_tcmalloc_malloc" >&6; }
     16751if test "x$ac_cv_lib_tcmalloc_malloc" = xyes; then :
     16752  HAVE_LIBTCMALLOC=1
     16753else
     16754  HAVE_LIBTCMALLOC=0
     16755fi
     16756
     16757 if test "$HAVE_LIBTCMALLOC" -eq 1; then
     16758  WITH_LIBTCMALLOC_TRUE=
     16759  WITH_LIBTCMALLOC_FALSE='#'
     16760else
     16761  WITH_LIBTCMALLOC_TRUE='#'
     16762  WITH_LIBTCMALLOC_FALSE=
     16763fi
     16764
     16765
     16766# Checks for header files.
     16767for ac_header in libintl.h malloc.h unistd.h
    1701916768do :
    1702016769  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
     
    1702516774_ACEOF
    1702616775
     16776else
     16777  echo "Error: Missing required header"; exit 1
    1702716778fi
    1702816779
     
    1703116782
    1703216783# Checks for typedefs, structures, and compiler characteristics.
    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; }
    17035 if ${ac_cv_header_stdbool_h+:} false; then :
     16784ac_fn_c_check_type "$LINENO" "_Float32" "ac_cv_type__Float32" "
     16785"
     16786if test "x$ac_cv_type__Float32" = xyes; then :
     16787
     16788cat >>confdefs.h <<_ACEOF
     16789#define HAVE__FLOAT32 1
     16790_ACEOF
     16791
     16792
     16793$as_echo "#define HAVE_KEYWORDS_FLOATXX /**/" >>confdefs.h
     16794
     16795fi
     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; }
     16801if ${m4cfa_cv_check_cflags___Wcast_function_type+:} false; then :
    1703616802  $as_echo_n "(cached) " >&6
    1703716803else
    17038   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     16804
     16805        m4cfa_check_save_flags=$CFLAGS
     16806        CFLAGS="$CFLAGS  -Wcast-function-type"
     16807        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    1703916808/* 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;
    1708416809
    1708516810int
    1708616811main ()
    1708716812{
    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);
    1709516813
    1709616814  ;
     
    1709916817_ACEOF
    1710016818if ac_fn_c_try_compile "$LINENO"; then :
    17101   ac_cv_header_stdbool_h=yes
    17102 else
    17103   ac_cv_header_stdbool_h=no
     16819  m4cfa_cv_check_cflags___Wcast_function_type=yes
     16820else
     16821  m4cfa_cv_check_cflags___Wcast_function_type=no
    1710416822fi
    1710516823rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    17106 fi
    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"
    17110 if test "x$ac_cv_type__Bool" = xyes; then :
    17111 
    17112 cat >>confdefs.h <<_ACEOF
    17113 #define HAVE__BOOL 1
    17114 _ACEOF
    17115 
    17116 
    17117 fi
    17118 
    17119 
    17120 if test $ac_cv_header_stdbool_h = yes; then
    17121 
    17122 $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h
    17123 
    17124 fi
    17125 
    17126 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
    17127 $as_echo_n "checking for inline... " >&6; }
    17128 if ${ac_cv_c_inline+:} false; then :
    17129   $as_echo_n "(cached) " >&6
    17130 else
    17131   ac_cv_c_inline=no
    17132 for ac_kw in inline __inline__ __inline; do
    17133   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
    17134 /* end confdefs.h.  */
    17135 #ifndef __cplusplus
    17136 typedef int foo_t;
    17137 static $ac_kw foo_t static_foo () {return 0; }
    17138 $ac_kw foo_t foo () {return 0; }
    17139 #endif
    17140 
    17141 _ACEOF
    17142 if ac_fn_c_try_compile "$LINENO"; then :
    17143   ac_cv_c_inline=$ac_kw
    17144 fi
    17145 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    17146   test "$ac_cv_c_inline" != no && break
    17147 done
    17148 
    17149 fi
    17150 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
    17151 $as_echo "$ac_cv_c_inline" >&6; }
    17152 
    17153 case $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     ;;
    17166 esac
    17167 
    17168 ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t"
    17169 case $ac_cv_c_int16_t in #(
    17170   no|yes) ;; #(
    17171   *)
    17172 
    17173 cat >>confdefs.h <<_ACEOF
    17174 #define int16_t $ac_cv_c_int16_t
    17175 _ACEOF
    17176 ;;
    17177 esac
    17178 
    17179 ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t"
    17180 case $ac_cv_c_int32_t in #(
    17181   no|yes) ;; #(
    17182   *)
    17183 
    17184 cat >>confdefs.h <<_ACEOF
    17185 #define int32_t $ac_cv_c_int32_t
    17186 _ACEOF
    17187 ;;
    17188 esac
    17189 
    17190 ac_fn_c_find_intX_t "$LINENO" "8" "ac_cv_c_int8_t"
    17191 case $ac_cv_c_int8_t in #(
    17192   no|yes) ;; #(
    17193   *)
    17194 
    17195 cat >>confdefs.h <<_ACEOF
    17196 #define int8_t $ac_cv_c_int8_t
    17197 _ACEOF
    17198 ;;
    17199 esac
    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; }
    17203 if ${ac_cv_c_restrict+:} false; then :
    17204   $as_echo_n "(cached) " >&6
    17205 else
    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.  */
    17211 typedef int * int_ptr;
    17212         int foo (int_ptr $ac_kw ip) {
    17213         return ip[0];
    17214        }
    17215 int
    17216 main ()
    17217 {
    17218 int s[1];
    17219         int * $ac_kw t = s;
    17220         t[0] = 0;
    17221         return foo(t)
    17222   ;
    17223   return 0;
    17224 }
    17225 _ACEOF
    17226 if ac_fn_c_try_compile "$LINENO"; then :
    17227   ac_cv_c_restrict=$ac_kw
    17228 fi
    17229 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    17230      test "$ac_cv_c_restrict" != no && break
    17231    done
    17232 
    17233 fi
    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 
    17247 ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
    17248 if test "x$ac_cv_type_size_t" = xyes; then :
    17249 
    17250 else
    17251 
    17252 cat >>confdefs.h <<_ACEOF
    17253 #define size_t unsigned int
    17254 _ACEOF
    17255 
    17256 fi
    17257 
    17258 ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t"
    17259 case $ac_cv_c_uint16_t in #(
    17260   no|yes) ;; #(
    17261   *)
    17262 
    17263 
    17264 cat >>confdefs.h <<_ACEOF
    17265 #define uint16_t $ac_cv_c_uint16_t
    17266 _ACEOF
    17267 ;;
    17268   esac
    17269 
    17270 ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t"
    17271 case $ac_cv_c_uint32_t in #(
    17272   no|yes) ;; #(
    17273   *)
    17274 
    17275 $as_echo "#define _UINT32_T 1" >>confdefs.h
    17276 
    17277 
    17278 cat >>confdefs.h <<_ACEOF
    17279 #define uint32_t $ac_cv_c_uint32_t
    17280 _ACEOF
    17281 ;;
    17282   esac
    17283 
    17284 ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t"
    17285 case $ac_cv_c_uint8_t in #(
    17286   no|yes) ;; #(
    17287   *)
    17288 
    17289 $as_echo "#define _UINT8_T 1" >>confdefs.h
    17290 
    17291 
    17292 cat >>confdefs.h <<_ACEOF
    17293 #define uint8_t $ac_cv_c_uint8_t
    17294 _ACEOF
    17295 ;;
    17296   esac
    17297 
    17298 
    17299 # Checks for library functions.
    17300 for ac_func in memset putenv strchr strtol
    17301 do :
    17302   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
    17303 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
    17304 if 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 
    17309 fi
    17310 done
     16824        CFLAGS=$m4cfa_check_save_flags
     16825fi
     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; }
     16828if test "x$m4cfa_cv_check_cflags___Wcast_function_type" = xyes; then :
     16829
     16830$as_echo "#define HAVE_CAST_FUNCTION_TYPE /**/" >>confdefs.h
     16831
     16832else
     16833  :
     16834fi
    1731116835
    1731216836
     
    1732116845
    1732216846#==============================================================================
    17323 ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile tests/preempt_longrun/Makefile tools/Makefile tools/prettyprinter/Makefile"
     16847ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile longrun_tests/Makefile tools/Makefile tools/prettyprinter/Makefile"
    1732416848
    1732516849
     
    1747216996if test -z "${WITH_LIBFIBRE_TRUE}" && test -z "${WITH_LIBFIBRE_FALSE}"; then
    1747316997  as_fn_error $? "conditional \"WITH_LIBFIBRE\" was never defined.
     16998Usually this means the macro was only invoked conditionally." "$LINENO" 5
     16999fi
     17000if test -z "${WITH_LIBPROFILER_TRUE}" && test -z "${WITH_LIBPROFILER_FALSE}"; then
     17001  as_fn_error $? "conditional \"WITH_LIBPROFILER\" was never defined.
     17002Usually this means the macro was only invoked conditionally." "$LINENO" 5
     17003fi
     17004if test -z "${WITH_LIBTCMALLOC_TRUE}" && test -z "${WITH_LIBTCMALLOC_FALSE}"; then
     17005  as_fn_error $? "conditional \"WITH_LIBTCMALLOC\" was never defined.
    1747417006Usually this means the macro was only invoked conditionally." "$LINENO" 5
    1747517007fi
     
    1845917991    "benchmark/Makefile") CONFIG_FILES="$CONFIG_FILES benchmark/Makefile" ;;
    1846017992    "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
    18461     "tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES tests/preempt_longrun/Makefile" ;;
     17993    "longrun_tests/Makefile") CONFIG_FILES="$CONFIG_FILES longrun_tests/Makefile" ;;
    1846217994    "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
    1846317995    "tools/prettyprinter/Makefile") CONFIG_FILES="$CONFIG_FILES tools/prettyprinter/Makefile" ;;
  • configure.ac

    r6a9d4b4 r933f32f  
    139139                "debug") ;;
    140140                "nolib") ;;
     141                "profile") ;;
    141142                *)
    142143                        >&2 echo "Configuration must be 'debug', 'nodebug' or 'nolib'"
     
    178179AC_PROG_CC
    179180AM_PROG_AS
    180 AM_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
    188 AC_PROG_MAKE_SET
    189188
    190189# Checks for libraries.
     
    192191AM_CONDITIONAL([WITH_LIBFIBRE], [test "$HAVE_LIBFIBRE" -eq 1])
    193192
     193AC_CHECK_LIB([profiler], [ProfilingIsEnabledForAllThreads], [HAVE_LIBPROFILER=1], [HAVE_LIBPROFILER=0])
     194AM_CONDITIONAL([WITH_LIBPROFILER], [test "$HAVE_LIBPROFILER" -eq 1])
     195
     196AC_CHECK_LIB([tcmalloc], [malloc], [HAVE_LIBTCMALLOC=1], [HAVE_LIBTCMALLOC=0])
     197AM_CONDITIONAL([WITH_LIBTCMALLOC], [test "$HAVE_LIBTCMALLOC" -eq 1])
     198
    194199# Checks for header files.
    195 AC_FUNC_ALLOCA
    196 AC_CHECK_HEADERS([fenv.h float.h inttypes.h libintl.h limits.h malloc.h stddef.h stdlib.h string.h unistd.h])
     200AC_CHECK_HEADERS([libintl.h malloc.h unistd.h], [], [echo "Error: Missing required header"; exit 1])
    197201
    198202# Checks for typedefs, structures, and compiler characteristics.
    199 AC_HEADER_STDBOOL
    200 AC_C_INLINE
    201 AC_TYPE_INT16_T
    202 AC_TYPE_INT32_T
    203 AC_TYPE_INT8_T
    204 AC_C_RESTRICT
    205 AC_TYPE_SIZE_T
    206 AC_TYPE_UINT16_T
    207 AC_TYPE_UINT32_T
    208 AC_TYPE_UINT8_T
    209 
    210 # Checks for library functions.
    211 AC_CHECK_FUNCS([memset putenv strchr strtol])
     203AC_CHECK_TYPES([_Float32], AC_DEFINE([HAVE_KEYWORDS_FLOATXX], [], [Have keywords _FloatXX.]), [], [[]])
     204
     205# Checks for compiler flags.
     206M4CFA_CHECK_COMPILE_FLAG([-Wcast-function-type], AC_DEFINE([HAVE_CAST_FUNCTION_TYPE], [], [Have compiler warning cast-function-type.]))
    212207
    213208#==============================================================================
     
    223218        benchmark/Makefile
    224219        tests/Makefile
    225         tests/preempt_longrun/Makefile
     220        longrun_tests/Makefile
    226221        tools/Makefile
    227222        tools/prettyprinter/Makefile
  • doc/LaTeXmacros/lstlang.sty

    r6a9d4b4 r933f32f  
    88%% Created On       : Sat May 13 16:34:42 2017
    99%% Last Modified By : Peter A. Buhr
    10 %% Last Modified On : Fri Apr  6 23:44:50 2018
    11 %% Update Count     : 20
     10%% Last Modified On : Tue Jan  8 14:40:33 2019
     11%% Update Count     : 21
    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, __extension__, exception, fallthrough, fallthru, finally,
     116                coroutine, disable, dtype, enable, exception, __extension__, 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

    r6a9d4b4 r933f32f  
    330330    contributer = {pabuhr@plg},
    331331    author      = {Nissim Francez},
    332     title       = {Another Advantage of Key word Notation for Parameter Communication with Subprograms},
     332    title       = {Another Advantage of Keyword 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     optnote     = {Accessed: 2016-09},
     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}},
    835844}
    836845
     
    939948    author      = {{\textsf{C}{$\mathbf{\forall}$} Features}},
    940949    howpublished= {\href{https://plg.uwaterloo.ca/~cforall/features}{https://\-plg.uwaterloo.ca/\-$\sim$cforall/\-features}},
    941     optnote     = {Accessed: 2018-01-01},
    942950}
    943951
     
    959967    year        = 2018,
    960968    howpublished= {\href{https://cforall.uwaterloo.ca/CFAStackEvaluation.zip}{https://cforall.uwaterloo.ca/\-CFAStackEvaluation.zip}},
    961     optnote     = {[Accessed May 2018]},
    962969}
    963970
     
    966973    contributer = {pabuhr@plg},
    967974    author      = {Aaron Moss and Robert Schluntz and Peter A. Buhr},
    968     title       = {\textsf{C}$\mathbf{\forall}$ : Adding Modern Programming Language Features to C},
     975    title       = {\textsf{C}$\mathbf{\forall}$ : Adding Modern Programming Language Features to {C}},
    969976    journal     = spe,
    970977    volume      = 48,
     
    10861093}
    10871094
     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
    10881104@article{Buhr85,
    10891105    keywords    = {goto, multi-exit loop},
     
    11321148    year        = 1998,
    11331149    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/}}
    11341177}
    11351178
     
    12341277}
    12351278
     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
    12361298@book{sml:commentary,
    12371299    author      = {Robin Milner and Mads Tofte},
     
    12941356    journal     = sigplan,
    12951357    year        = 1986,
    1296     month       = oct, volume = 21, number = 10, pages = {19-28},
     1358    month       = oct,
     1359    volume      = 21,
     1360    number      = 10,
     1361    pages       = {19-28},
    12971362    note        = {Object Oriented Programming Workshop}
    12981363}
     
    14591524    title       = {concurrent-locking},
    14601525    howpublished= {\href{https://github.com/pabuhr/concurrent-locking}{https://\-github.com/\-pabuhr/\-concurrent-locking}},
    1461     optnote     = {[Accessed April 2017]},
    14621526}
    14631527
     
    16211685}
    16221686
     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
    16231700@article{Buhr05a,
    16241701    keywords    = {concurrency, myths},
     
    17471824    howpublished= {\href{https://www.airs.com/blog/archives/428}
    17481825                  {https://www.airs.com/\-blog/\-archives/\-428}},
    1749     optnote     = {Accessed: 2018-05},
    17501826}
    17511827
     
    18431919    year        = 1965,
    18441920    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}},
    18451931}
    18461932
     
    22712357}
    22722358
     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
    22732375@article{design,
    22742376    keywords    = {Smalltalk, designing classes},
     
    22782380    journal     = joop,
    22792381    year        = 1988,
    2280     volume      = 1, number = 2, pages = {22-35},
     2382    volume      = 1,
     2383    number      = 2,
     2384    pages       = {22-35},
    22812385    comment     = {
    22822386        Abstract classes represent standard protocols.  ``It is better to
     
    23632467    year        = 1990,
    23642468    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}
    23652478}
    23662479
     
    24702583    pages       = {325-361},
    24712584}
     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}
    24722606
    24732607@book{Eiffel,
     
    29063040    year        = 2014,
    29073041    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},
    29093042}
    29103043
     
    29903123}
    29913124
     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
    29923135@inproceedings{F-bound,
    29933136    keywords    = {},
     
    30373180}
    30383181
     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
    30393213@manual{Fortran95,
    30403214    keywords    = {Fortran 95},
     
    30573231    address     = {\href{https://www.iso.org/standard/50459.html}{https://\-www.iso.org/\-standard/\-50459.html}},
    30583232    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,
    30593244}
    30603245
     
    33063491    year        = 2014,
    33073492    howpublished= {https://developer.gnome.org/gobject/stable/},
    3308     optnote     = {Accessed: 2017-04},
    33093493}
    33103494
     
    36213805    year        = {1964},
    36223806    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},
    36233831}
    36243832
     
    39274135}
    39284136
     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
    39294150% J
    39304151                 
     
    39484169    year        = 2015,
    39494170    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,
    39504192}
    39514193
     
    41294371}
    41304372
     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
    41314384@book{Weissman67,
    41324385    keywords    = {lisp},
     
    41384391}
    41394392
     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
    41404415@article{Sundell08,
    41414416    keywords    = {lock free, deque},
     
    41484423    year        = 2008,
    41494424    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},
    41504437}
    41514438
     
    41644451}
    41654452
     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
    41664462% M
    41674463
     
    41734469    publisher   = {Motorola},
    41744470    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},
    41754484}
    41764485
     
    44914800}
    44924801%    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}
    44934816
    44944817@manual{MPI,
     
    49175240    year        = 2014,
    49185241    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}
    49205242}
    49215243
     
    49275249    year        = 2015,
    49285250    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}
    49305251}
    49315252
     
    50625383    note        = {\href{https://www.openmp.org/wp-content/uploads/openmp-4.5.pdf}{https://\-www.openmp.org/\-wp-content/\-uploads/\-openmp-4.5.pdf}},
    50635384}
     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}
    50645404
    50655405@book{Deitel04,
     
    54405780    year        = 2012,
    54415781    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}
    54435782}
    54445783
     
    57646103    address     = {\href{https://www.iso.org/standard/64029.html}{https://\-www.iso.org/\-standard/\-64029.html}},
    57656104    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,
    57666116}
    57676117
     
    59176267    institution = {Carnegie Mellon University},
    59186268    year        = 1991,
    5919     month       = feb, number = "CMU-CS-91-106",
     6269    month       = feb,
     6270    number      = {CMU-CS-91-106},
    59206271    annote      = {
    59216272        Discusses a typed lambda calculus with
     
    59746325    journal     = sigplan,
    59756326    year        = 1988,
    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},
     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},
    59796332    abstract    = {
    59806333        This paper deals with the integration of an efficient asynchronous
     
    60266379}
    60276380
     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
    60286392@manual{Python,
    60296393    keywords    = {Python},
    60306394    contributer = {pabuhr@plg},
    6031     title       = {Python Reference Manual, Release 2.5},
    6032     author      = {Guido van Rossum},
     6395    author      = {Python},
     6396    title       = {Python Language Reference, Release 3.7.2},
    60336397    organization= {Python Software Foundation},
    6034     month       = sep,
    6035     year        = 2006,
    6036     note        = {Fred L. Drake, Jr., editor},
     6398    address     = {\href{https://docs.python.org/3/reference/index.html}{https://\-docs.python.org/\-3/\-reference/\-index.html}},
     6399    year        = 2018,
    60376400}
    60386401
    60396402% 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}
    60406414
    60416415@article{Grossman06,
     
    60746448}
    60756449
     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
    60766460% R
    60776461
     
    61876571    number      = 10,
    61886572    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},
    61896584}
    61906585
     
    63256720}
    63266721
     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
    63276732% S
    63286733
     
    70617466}
    70627467
     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
    70637478% T
    70647479
     
    71157530    author      = {{TIOBE Index}},
    71167531    howpublished= {\href{http://www.tiobe.com/tiobe_index}{http://\-www.tiobe.com/\-tiobe\_index}},
    7117     optnote     = {Accessed: 2018-09},
     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)}},
    71187540}
    71197541
     
    72777699}
    72787700
     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
    72797708@article{Cormack90,
    72807709    keywords    = {polymorphism},
     
    74477876    year        = 2017,
    74487877    howpublished= {\url{https://wiki.gnome.org/Projects/Vala/Manual}},
    7449     optnote     = {Accessed: 2017-04}
    74507878}
    74517879
     
    76218049% Y
    76228050
     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
    76238066% Z
    76248067
  • doc/papers/concurrency/Paper.tex

    r6a9d4b4 r933f32f  
    215215{}
    216216\lstnewenvironment{Go}[1][]
    217 {\lstset{#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}}
    218221{}
    219222
     
    228231}
    229232
    230 \title{\texorpdfstring{Concurrency in \protect\CFA}{Concurrency in Cforall}}
     233\title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}}
    231234
    232235\author[1]{Thierry Delisle}
     
    238241\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}}
    239242
    240 \fundingInfo{Natural Sciences and Engineering Research Council of Canada}
     243% \fundingInfo{Natural Sciences and Engineering Research Council of Canada}
    241244
    242245\abstract[Summary]{
    243 \CFA is a modern, polymorphic, \emph{non-object-oriented} extension of the C programming language.
    244 This paper discusses the design of the concurrency and parallelism features in \CFA, and its concurrent runtime-system.
    245 These features are created from scratch as ISO C lacks concurrency, relying largely on the pthreads library for concurrency.
    246 Coroutines and lightweight (user) threads are introduced into \CFA;
    247 as well, monitors are added as a high-level mechanism for mutual exclusion and synchronization.
    248 A unique contribution of this work is allowing multiple monitors to be safely acquired \emph{simultaneously}.
    249 All features respect the expectations of C programmers, while being fully integrate with the \CFA polymorphic type-system and other language features.
     246\CFA is a polymorphic, non-object-oriented, concurrent, backwards-compatible extension of the C programming language.
     247This paper discusses the design philosophy and implementation of its advanced control-flow and concurrent/parallel features, along with the supporting runtime.
     248These 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.
     250Library extension for executors, futures, and actors are built on these basic mechanisms.
     251The runtime provides significant programmer simplification and safety by eliminating spurious wakeup and reducing monitor barging.
     252The runtime also ensures multiple monitors can be safely acquired \emph{simultaneously} (deadlock free), and this feature is fully integrated with all monitor synchronization mechanisms.
     253All language features integrate with the \CFA polymorphic type-system and exception handling, while respecting the expectations and style of C programmers.
    250254Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming-languages.
    251255}%
    252256
    253 \keywords{concurrency, parallelism, coroutines, threads, monitors, runtime, C, Cforall}
     257\keywords{coroutines, concurrency, parallelism, threads, monitors, runtime, C, \CFA (Cforall)}
    254258
    255259
     
    262266\section{Introduction}
    263267
     268This 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.
     271However, 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.},
     272backwards-compatible extension of the C programming language.
     273Within the \CFA framework, new control-flow features are created from scratch.
     274ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}.
     275However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}.
     276Furthermore, \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;
     277no high-level language concurrency features are defined.
     278Interestingly, 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.
     279Finally, 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
     281In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages.
     282As multi-core hardware became available in the 1980/90s, both user and kernel threading were examined.
     283Kernel 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}.
     284Libraries like pthreads were developed for C, and the Solaris operating-system switched from user (JDK 1.1~\cite{JDK1.1}) to kernel threads.
     285As 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.
     286From 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}.
     287The 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}.
     288As well, user-threading facilitates a simpler concurrency approach using thread objects that leverage sequential patterns versus events with call-backs~\cite{vonBehren03}.
     289Finally, 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
     291A 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}.
     292The 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.
     293One solution is low-level qualifiers and functions (e.g., @volatile@ and atomics) allowing \emph{programmers} to explicitly write safe (race-free~\cite{Boehm12}) programs.
     294A safer solution is high-level language constructs so the \emph{compiler} knows the optimization boundaries, and hence, provides implicit safety.
     295This 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.
     297The 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.
     299Finally, solutions in the language allows matching constructs with language paradigm, i.e., imperative and functional languages have different presentations of the same concept.
     300
     301Finally, it is important for a language to provide safety over performance \emph{as the default}, allowing careful reduction of safety for performance when necessary.
     302Two 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.
     303If you believe spurious wakeup is a foundational concurrency property, than unblocking (signalling) a thread is always a hint.
     304If you \emph{do not} believe spurious wakeup is foundational, than signalling-as-hints is a performance decision.
     305Most importantly, removing spurious wakeup and signals-as-hints makes concurrent programming significantly safer because it removes local non-determinism.
     306Clawing back performance where the local non-determinism is unimportant, should be an option not the default.
     307
     308\begin{comment}
     309For 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++}.
     310It 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.
     311As well, user threading is often a complementary feature, allowing light-weight threading to match with low-cost objects, while hiding the application/kernel boundary.
     312User 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{
     313All implicit concurrency models have explicit threading in their implementation, and hence, can be build from explicit threading;
     314however, 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.}
     315Finally, 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.
     318The 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
     321Most 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.
     322As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten.
     323While \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.
     324Hence, 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.
     329We 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.
     330The main contributions of this work are:
     331\begin{itemize}
     332\item
     333expressive language-level coroutines and user-level threading, which respect the expectations of C programmers.
     334\item
     335monitor synchronization without barging.
     336\item
     337safely acquiring multiple monitors \emph{simultaneously} (deadlock free), while seamlessly integrating this capability with all monitor synchronization mechanisms.
     338\item
     339providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features.
     340\item
     341library extensions for executors, futures, and actors built on the basic mechanisms.
     342\item
     343a runtime system with no spurious wakeup.
     344\item
     345experimental results showing comparable performance of the new features with similar mechanisms in other concurrent programming-languages.
     346\end{itemize}
     347
     348\begin{comment}
    264349This paper provides a minimal concurrency \newterm{Application Program Interface} (API) that is simple, efficient and can be used to build other concurrency features.
    265350While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master.
     
    281366The proposed concurrency API is implemented in a dialect of C, called \CFA (pronounced C-for-all).
    282367The 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.
    283 
    284 
     368\end{comment}
     369
     370
     371\begin{comment}
    285372\section{\CFA Overview}
    286373
     
    551638\end{cfa}
    552639where the return type supplies the type/size of the allocation, which is impossible in most type systems.
    553 
    554 
    555 \section{Concurrency}
    556 \label{s:Concurrency}
    557 
    558 At its core, concurrency is based on multiple call-stacks and scheduling threads executing on these stacks.
    559 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}.
    560 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.
    561 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;
    562 a \newterm{stackful} coroutine executes on its own stack, allowing full generality.
    563 Only stackful coroutines are a stepping stone to concurrency.
    564 
    565 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}.
    566 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.
    567 The resulting execution system now follows a cooperative threading-model, called \newterm{non-preemptive scheduling}.
    568 
    569 Because the scheduler is special, it can either be a stackless or stackful coroutine.
    570 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.
    571 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.
    572 A stackful scheduler is often used for simplicity and security.
    573 
    574 Regardless of the approach used, a subset of concurrency related challenges start to appear.
    575 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}.
    576 While a scheduler introduces uncertainty in the order of execution, preemption introduces uncertainty about where context switches occur.
    577 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.
    578 The reason is that only the runtime has complete knowledge about resources and how to best utilized them.
    579 However, the introduction of unrestricted non-determinism results in the need for \newterm{mutual exclusion} and \newterm{synchronization} to restrict non-determinism for correctness;
    580 otherwise, it is impossible to write meaningful programs.
    581 Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows.
    582 
    583 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.
    584 As such, library support for threading is far from widespread.
    585 At the time of writing the paper, neither \protect\lstinline@gcc@ nor \protect\lstinline@clang@ support \protect\lstinline@threads.h@ in their standard libraries.}.
    586 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.
    587 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.
    588 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.
    589 Hence, 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 
    594 While 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).
     640\end{comment}
     641
     642
     643\section{Coroutines: Stepping Stone}
     644\label{coroutine}
     645
    595646Coroutines are generalized routines allowing execution to be temporarily suspended and later resumed.
    596647Hence, 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.
     
    616667\centering
    617668\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}
    618689\begin{lrbox}{\myboxA}
    619690\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    620 `int f1, f2, state = 1;`   // single global variables
    621 int 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 }
     691#define FIB_INIT { 0, 1 }
     692typedef struct { int fn1, fn; } Fib;
     693int fib( Fib * f ) {
     694
     695        int ret = f->fn1;
     696        f->fn1 = f->fn;
     697        f->fn = ret + f->fn;
     698        return ret;
     699}
     700
     701
     702
    630703int main() {
    631 
     704        Fib f1 = FIB_INIT, f2 = FIB_INIT;
    632705        for ( int i = 0; i < 10; i += 1 ) {
    633                 printf( "%d\n", fib() );
     706                printf( "%d %d\n",
     707                                fib( &f1 ), fib( &f2 ) );
    634708        }
    635709}
     
    640714\begin{lrbox}{\myboxB}
    641715\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    642 #define FIB_INIT `{ 0, 1 }`
    643 typedef struct { int f2, f1; } Fib;
    644 int fib( Fib * f ) {
    645 
    646         int ret = f->f2;
    647         int fn = f->f1 + f->f2;
    648         f->f2 = f->f1; f->f1 = fn;
    649 
    650         return ret;
    651 }
    652 int main() {
    653         Fib f1 = FIB_INIT, f2 = FIB_INIT;
    654         for ( int i = 0; i < 10; i += 1 ) {
    655                 printf( "%d %d\n", fib( &f1 ), fib( &f2 ) );
     716`coroutine` Fib { int fn1; };
     717void main( Fib & fib ) with( fib ) {
     718        int fn;
     719        [fn1, fn] = [0, 1];
     720        for () {
     721                `suspend();`
     722                [fn1, fn] = [fn, fn1 + fn];
    656723        }
    657724}
    658 \end{cfa}
    659 \end{lrbox}
    660 
    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; };
    673 void 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 }
    681 int next( Fib & fib ) with( fib ) {
    682         `resume( fib );`
    683         return fn;
     725int ?()( Fib & fib ) with( fib ) {
     726        `resume( fib );`  return fn1;
    684727}
    685728int main() {
    686729        Fib f1, f2;
    687         for ( int i = 1; i <= 10; i += 1 ) {
    688                 sout | next( f1 ) | next( f2 );
    689         }
    690 }
     730        for ( 10 ) {
     731                sout | f1() | f2();
     732}
     733
     734
    691735\end{cfa}
    692736\end{lrbox}
    693 \newbox\myboxB
    694 \begin{lrbox}{\myboxB}
    695 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    696 `coroutine` Fib { int ret; };
    697 void 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();`
    703         }
    704 }
    705 int next( Fib & fib ) with( fib ) {
    706         `resume( fib );`
    707         return ret;
    708 }
    709 
    710 
    711 
    712 
    713 
    714 
    715 \end{cfa}
     737
     738\newbox\myboxC
     739\begin{lrbox}{\myboxC}
     740\begin{python}[aboveskip=0pt,belowskip=0pt]
     741
     742def 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
     753f1 = Fib()
     754f2 = Fib()
     755for i in range( 10 ):
     756        print( next( f1 ), next( f2 ) )
     757
     758
     759
     760\end{python}
    716761\end{lrbox}
    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}
     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}
    722818\end{figure}
    723819
     
    759855\begin{lrbox}{\myboxA}
    760856\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    761 `coroutine` Format {
    762         char ch;   // used for communication
    763         int g, b;  // global because used in destructor
     857`coroutine` Fmt {
     858        char ch;   // communication variables
     859        int g, b;   // needed in destructor
    764860};
    765 void 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
     861void 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
    769865                                `suspend();`
    770                                 sout | ch;              // separator
    771                         }
    772                         sout | "  ";               // separator
    773                 }
    774                 sout | nl;
    775         }
    776 }
    777 void ?{}( Format & fmt ) { `resume( fmt );` }
    778 void ^?{}( Format & fmt ) with( fmt ) {
    779         if ( g != 0 || b != 0 ) sout | nl;
    780 }
    781 void format( Format & fmt ) {
    782         `resume( fmt );`
    783 }
     866                                sout | ch; } // print character
     867                        sout | "  "; } // block separator
     868                sout | nl; }  // group separator
     869}
     870void ?{}( Fmt & fmt ) { `resume( fmt );` } // prime
     871void ^?{}( Fmt & fmt ) with( fmt ) { // destructor
     872        if ( g != 0 || b != 0 ) // special case
     873                sout | nl; }
     874void send( Fmt & fmt, char c ) { fmt.ch = c; `resume( fmt )`; }
    784875int main() {
    785         Format fmt;
    786         eof: for ( ;; ) {
    787                 sin | fmt.ch;
    788           if ( eof( sin ) ) break eof;
    789                 format( fmt );
    790         }
     876        Fmt fmt;
     877        sout | nlOff;   // turn off auto newline
     878        for ( 41 )
     879                send( fmt, 'a' );
    791880}
    792881\end{cfa}
     
    795884\newbox\myboxB
    796885\begin{lrbox}{\myboxB}
    797 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    798 struct Format {
    799         char ch;
    800         int g, b;
    801 };
    802 void 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 }
    819 int 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}
     886\begin{python}[aboveskip=0pt,belowskip=0pt]
     887
     888
     889
     890def 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
     906fmt = Fmt()
     907`next( fmt )`                    # prime
     908for i in range( 41 ):
     909        `fmt.send( 'a' );`      # send to yield
     910
     911\end{python}
    830912\end{lrbox}
    831 \subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}
     913\subfloat[\CFA]{\label{f:CFAFmt}\usebox\myboxA}
    832914\qquad
    833 \subfloat[C Linearized]{\label{f:CFmt}\usebox\myboxB}
    834 \caption{Formatting text into lines of 5 blocks of 4 characters.}
     915\subfloat[Python]{\label{f:CFmt}\usebox\myboxB}
     916\caption{Output formatting text}
    835917\label{f:fmt-line}
    836918\end{figure}
     
    853935void main( Prod & prod ) with( prod ) {
    854936        // 1st resume starts here
    855         for ( int i = 0; i < N; i += 1 ) {
     937        for ( i; N ) {
    856938                int p1 = random( 100 ), p2 = random( 100 );
    857939                sout | p1 | " " | p2;
     
    869951}
    870952void start( Prod & prod, int N, Cons &c ) {
    871         &prod.c = &c;
     953        &prod.c = &c; // reassignable reference
    872954        prod.[N, receipt] = [N, 0];
    873955        `resume( prod );`
     
    884966        Prod & p;
    885967        int p1, p2, status;
    886         _Bool done;
     968        bool done;
    887969};
    888970void ?{}( Cons & cons, Prod & p ) {
    889         &cons.p = &p;
     971        &cons.p = &p; // reassignable reference
    890972        cons.[status, done ] = [0, false];
    891973}
     
    9451027@start@ returns and the program main terminates.
    9461028
     1029One \emph{killer} application for a coroutine is device drivers, which at one time caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}.
     1030Many 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}
     1035where a network message begins with the control character STX and ends with an ETX, followed by a 2-byte cyclic-redundancy check.
     1036Control characters may appear in a message if preceded by an ESC.
     1037Because 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}
     1041enum Status { CONT, MSG, ESTX, ELNTH, ECRC };
     1042`coroutine` Driver {
     1043        Status status;
     1044        char * msg, byte;
     1045};
     1046void ?{}( Driver & d, char * m ) { d.msg = m; }         $\C[3.0in]{// constructor}$
     1047Status next( Driver & d, char b ) with( d ) {           $\C{// 'with' opens scope}$
     1048        byte = b; `resume( d );` return status;
     1049}
     1050void 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
    9471084
    9481085\subsection{Coroutine Implementation}
     
    10601197\end{cquote}
    10611198The 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
     1204At its core, concurrency is based on multiple call-stacks and scheduling threads executing on these stacks.
     1205Multiple 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}.
     1206In 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.
     1207A \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;
     1208a \newterm{stackful} coroutine executes on its own stack, allowing full generality.
     1209Only stackful coroutines are a stepping stone to concurrency.
     1210
     1211The 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}.
     1212Therefore, a minimal concurrency system is possible using coroutines (see Section \ref{coroutine}) in conjunction with a scheduler to decide where to context switch next.
     1213The resulting execution system now follows a cooperative threading-model, called \newterm{non-preemptive scheduling}.
     1214
     1215Because the scheduler is special, it can either be a stackless or stackful coroutine.
     1216For 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.
     1217For 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.
     1218A stackful scheduler is often used for simplicity and security.
     1219
     1220Regardless of the approach used, a subset of concurrency related challenges start to appear.
     1221For 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}.
     1222While a scheduler introduces uncertainty in the order of execution, preemption introduces uncertainty about where context switches occur.
     1223Interestingly, uncertainty is necessary for the runtime (operating) system to give the illusion of parallelism on a single processor and increase performance on multiple processors.
     1224The reason is that only the runtime has complete knowledge about resources and how to best utilized them.
     1225However, the introduction of unrestricted non-determinism results in the need for \newterm{mutual exclusion} and \newterm{synchronization} to restrict non-determinism for correctness;
     1226otherwise, it is impossible to write meaningful programs.
     1227Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows.
     1228
     1229An 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.
     1230As such, library support for threading is far from widespread.
     1231At the time of writing the paper, neither \protect\lstinline@gcc@ nor \protect\lstinline@clang@ support \protect\lstinline@threads.h@ in their standard libraries.}.
     1232In 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.
     1233As 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.
     1234Furthermore, because C is a system-level language, programmers expect to choose precisely which features they need and which cost they are willing to pay.
     1235Hence, concurrent programs should be written using high-level mechanisms, and only step down to lower-level mechanisms when performance bottlenecks are encountered.
    10621236
    10631237
  • doc/papers/concurrency/mail

    r6a9d4b4 r933f32f  
    2727
    2828Software: Practice and Experience Editorial Office
     29
     30
     31
     32Date: Wed, 3 Oct 2018 21:25:28 +0000
     33From: Richard Jones <onbehalfof@manuscriptcentral.com>
     34Reply-To: R.E.Jones@kent.ac.uk
     35To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
     36Subject: Software: Practice and Experience - Decision on Manuscript ID
     37 SPE-18-0205
     38
     3903-Oct-2018
     40
     41Dear Dr Buhr,
     42
     43Many thanks for submitting SPE-18-0205 entitled "Concurrency in C∀" to Software: Practice and Experience.
     44
     45In 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
     47Thank 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
     49Yours sincerely,
     50
     51
     52Prof. Richard Jones
     53Editor, Software: Practice and Experience
     54R.E.Jones@kent.ac.uk
     55
     56Referee(s)' Comments to Author:
     57
     58Reviewing: 1
     59
     60Comments 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
     63Section 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
     65Section 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
     67Sections 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
     69Section 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
     71Section 4 briefly touches on a collection of well known synchronisation primitives. Again, this discussion does not materially contribute to the paper.
     72
     73Section 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
     75Section 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
     77Section 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
     79Section 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
     81Section 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
     83The 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
     85It 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
     88Reviewing: 2
     89
     90Comments to the Author
     91This article presents the design and rationale behind the concurrency
     92features of C-forall, a new low-level programming language.  After an
     93introduction that defines a selection of standard terminology, section
     942 gives crucial background on the design of the C-forall language.
     95Section 3 then starts the core of the article, discussing the
     96language's support for "concurrency" which in this case means
     97coroutines and threads; a very brief Section 4 builds on section 3
     98with a discussion of lower level synchronizations.  Section 5 the
     99presents the main features of concurrency control in C-forall:
     100monitors and mutexes. Section 6 then extends monitors with condition
     101variables to to support scheduling, and a very brief section 7
     102discusses preemption and pooling. Section 8 discusses the runtime
     103conceptual model, section 9 gives implementation detail, and section
     10410 briefly evaluates C-forall's performance via five concurrent
     105micro benchmarks. Finally section 11 concludes the article, and then
     106section 12 presents some future work. 
     107
     108
     109At 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,
     112which requires concurrency". The doomsayers trumpeting the death of
     113Moore's law have been proved correct at last, with CPUs sequential
     114performance increasing much more slowly than the number of cores
     115within each die. This means programmers --- especially low-level,
     116systems programmers --- must somehow manage the essential complexity
     117of writing concurrent programs to run in parallel in multiple threads
     118across multiple cores. Unfortunately, the most venerable widely used
     119systems programming language, C, supports parallelism only via an
     120e.g. the threads library.  This article aims to integrate concurrent
     121programming mechanisms more closely into a novel low-level C-based
     122programming language, C-forall. The article gives an outline of much of
     123C-forall, presents a series of concurrency mechanisms, and finally
     124some microbenchmark results.  The article is detailed, comprehensive,
     125and generally well written in understandable English.
     126
     127My main concern about the article are indicated by the fact that the
     128best summary of the problem the design of concurrent C-forall sets
     129out to solve is buried more than halfway through the article in section
     1307, as above, and then the best overview of the proposed solution is
     131given 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
     142That is, in my reading of the article, it proceeds bottom up rather
     143than top down, and so my main recommendation is to essentially reverse
     144the order of the article, proceeding from the problem to be solved,
     145the high level architecture of the proposed solutions, and then going
     146down to the low-level mechanisms.  My biggest problem reading the
     147article was for explanations of why a particular decision was taken,
     148or why a particular mechanism may be used --- often this description
     149is actually later in the article, but at that point it's too late for
     150the reader.  I have tried to point out most of these places in the
     151detailed comments below.
     152
     153My second concern is that the article makes several claims that are
     154not really justified by the design or implementation in the article.
     155These include claims that this approach meets the expectations of C
     156programmers, is minimal, is implemented in itself, etc.  The article
     157doesn't generally offer evidence to support these assertions (for many
     158of them, that would require empirical studies of programmers, or at
     159least corpus studies). The solution here is to talk about motivations
     160for the design choices "we made these decisions hoping that C
     161programmers would be comfortable" rather than claims of fact "C
     162programmers 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
     377To encourage accountability, I'm signing my reviews in 2018. For the record, I am James Noble, kjx@ecs.vuw.ac.nz.
     378
     379Reviewing: 3
     380
     381Comments to the Author
     382This 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
     384It 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
     386Overall the impression I gained is that this is a substantial system into which have gone much thought and effort.
     387
     388However, 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
     390The 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
     392The 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
     394Certain 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
     396Similarly, 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
     398I 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
     400The empirical data presented is a reasonable start at characterising the implementation's performance. However, it currently suffers certain flaws.
     401
     402Firstly, 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
     404It 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
     406It 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
     408In 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
     410The 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
     412The 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
     414One 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
     416I 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
     418Minor comments:
     419
     420The 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

    r6a9d4b4 r933f32f  
    22==================================
    33
    4 This is an adaptation of the earlier virtual proposal, updating it with new
    5 ideas, re-framing it and laying out more design decisions. It should
    6 eventually replace the earlier proposal, but not all features and syntax have
    7 been converted to the new design.
    8 
    94The basic concept of a virtual table (vtable) is the same here as in most
    10 other languages. They will mostly contain function pointers although they
    11 should be able to store anything that goes into a trait.
     5other languages that use them. They will mostly contain function pointers
     6although they should be able to store anything that goes into a trait.
     7
     8I also include notes on a sample implementation, which primarily exists to show
     9there is a reasonable implementation. The code samples for that are in a slight
     10pseudo-code to help avoid name mangling and keeps some CFA features while they
     11would actually be written in C.
    1212
    1313Trait Instances
     
    1515
    1616Currently traits are completely abstract. Data types might implement a trait
    17 but traits are not themselves data types. This will change that and allow
    18 instances of traits to be created from instances of data types that implement
    19 the trait.
     17but traits are not themselves data types. Which is to say you cannot have an
     18instance of a trait. This proposal will change that and allow instances of
     19traits to be created from instances of data types that implement the trait.
     20
     21For example:
    2022
    2123    trait combiner(otype T) {
    22                 void combine(T&, int);
    23         };
     24        void combine(T&, int);
     25    };
    2426
    2527    struct summation {
    26                 int sum;
    27         };
    28 
    29         void ?{}( struct summation & this ) {
    30                 this.sum = 0;
    31         }
     28        int sum;
     29    };
     30
     31    void ?{}( struct summation & this ) {
     32        this.sum = 0;
     33    }
    3234
    3335    void combine( struct summation & this, int num ) {
    34                 this.sum = this.sum + num;
    35         }
    36 
    37         trait combiner obj = struct summation{};
    38         combine(obj, 5);
     36        this.sum = this.sum + num;
     37    }
     38
     39    trait combiner obj = struct summation{};
     40    combine(obj, 5);
    3941
    4042As with `struct` (and `union` and `enum`), `trait` might be optional when
     
    4244before.
    4345
    44 Internally a trait object is a pair of pointers. One to an underlying object
    45 and the other to the vtable. All calls on an trait are implemented by looking
    46 up the matching function pointer and passing the underlying object and the
    47 remaining arguments to it.
    48 
    49 Trait objects can be moved by moving the pointers. Almost all other operations
    50 require some functions to be implemented on the underlying type. Depending on
    51 what is in the virtual table a trait type could be a dtype or otype.
     46For traits to be used this way they should meet two requirements. First they
     47should only have a single polymorphic type and each assertion should use that
     48type once as a parameter. Extensions may later loosen these requirements.
     49
     50Also 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
     60In this example `bar` may be used as a type but `foo` may not.
     61
     62When a trait is used as a type it creates a generic object which combines
     63the base structure (an instance of `summation` in this case) and the vtable,
     64which is currently created and provided by a hidden mechanism.
     65
     66The generic object type for each trait also implements that trait. This is
     67actually the only means by which it can be used. The type of these functions
     68look something like this:
     69
     70    void combine(trait combiner & this, int num);
     71
     72The main use case for trait objects is that they can be stored. They can be
     73passed 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
     91With a more complete widget trait you could, for example, construct a UI tool
     92kit that can declare containers that hold widgets without knowing about the
     93widget types. Making it reasonable to extend the tool kit.
     94
     95The trait types can also be used in the types of assertions on traits as well.
     96In this usage they passed as the underlying object and vtable pair as they
     97are stored. The trait types can also be used in that trait's definition, which
     98means you can pass two instances of a trait to a single function. However the
     99look-up of the one that is not used to look up any functions, until another
     100function 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
     108The two restrictions on traits that can be used as trait objects are:
     109
     1101.  Only one generic parameter may be defined in the trait's header.
     1112.  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
     114Elsewhere in this proposal I suggest ways to broaden these requirements.
     115A simple example would be if a trait meets requirement 1 but not 2, then
     116the assertions that do not satisfy the exactly one parameter requirement can
     117be ignored.
     118
     119However I would like to talk about why these two rules are in place in the
     120first place and the problems that any exceptions to these rules must avoid.
     121
     122The problems appear when the dispatcher function which operates on the
     123generic object.
     124
     125    trait combiner(otype T, otype U) {
     126        void combine(T&, U);
     127    }
     128
     129This one is so strange I don't have proper syntax for it but let us say that
     130the concrete dispatcher would be typed as
     131`void combine(combiner(T) &, combiner(U));`. Does the function that combine
     132the two underlying types exist to dispatch too?
     133
     134Maybe not. If `combiner(T)` works with ints and `combiner(U)` is a char then
     135they could not be. It would have to enforce that all pairs of any types
     136that are wrapped in this way. Which would pretty much destroy any chance of
     137separate compilation.
     138
     139Even then it would be more expensive as the wrappers would have to carry ids
     140that you use to look up on an <number of types>+1 dimensional table.
     141
     142The second restriction has a similar issue but makes a bit more sense to
     143write out.
     144
     145    trait Series(otype T) {
     146        ... size, iterators, getters ...
     147        T join(T const &, T const &);
     148    }
     149
     150With the dispatcher typed as:
     151
     152    Series join(Series const &, Series const &);
     153
     154Because these instances are generic and hide the underlying implementation we
     155do not know what that implementation is. Unfortunately this also means the
     156implementation for the two parameters might not be the same. Once we have
     157two different types involved this devolves into the first case.
     158
     159We could check at run-time that the have the same underlying type, but this
     160would likely time and space overhead and there is no clear recovery path.
     161
     162#### Sample Implementation
     163A simple way to implement trait objects is by a pair of pointers. One to the
     164underlying 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
     176The functions that run on the trait object would generally be generated using
     177the following pattern:
     178
     179    void draw(Surface & surface, drawable & traitObj) {
     180        return traitObj.vtable->draw(surface, traitObj.object);
     181    }
     182
     183There may have to be special cases for things like copy construction, that
     184might require a more significant wrapper. On the other hand moving could be
     185implemented by moving the pointers without any need to refer to the base
     186object.
     187
     188### Extension: Multiple Trait Parameters
     189The base proposal in effect creates another use for the trait syntax that is
     190related to the ones currently in the language but is also separate from them.
     191The current uses generic functions and generic types, this new use could be
     192described as generic objects.
     193
     194A generic object is of a concrete type and has concrete functions that work on
     195it. It is generic in that it is a wrapper for an unknown type. Traits serve
     196a similar role here as in generic functions as they limit what the function
     197can be generic over.
     198
     199This combines the use allowing to have a generic type that is a generic
     200object. All but one of the trait's parameters is given a concrete type,
     201conceptually currying the trait to create a trait with on generic parameter
     202that fits the original restrictions. The resulting concrete generic object
     203type is different with each set of provided parameters and their values.
     204
     205Then it just becomes a question of where this is done. Again both examples use
     206a 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
     215The first option is to do it at the definition of the trait. One parameter
     216is selected (here with the `virtual` keyword, but other rules like "the first"
     217could also be used) and when an instance of the trait is created all the
     218other 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
     227The second option is to skip a parameter as part of the type instance
     228definition. One parameter is explicitly skipped (again with the `virtual`
     229keyword) and the others have concrete types. The skipped one is the one we
     230are generic on.
     231
     232Incidentally in both examples `container_of_ints` may itself be a generic
     233object and `begin` returns a generic iterator with unknown implementation.
     234
     235These options are not exclusive. Defining a default on the trait allows for
     236an object to be created as in the first example. However, whether the
     237default is provided or not, the second syntax can be used to pick a
     238parameter on instantiation.
    52239
    53240Hierarchy
    54241---------
    55242
    56 Virtual tables by them selves are not quite enough to implement the planned
    57 hierarchy system. An addition of type ids, implemented as pointers which
    58 point to your parent's type id, is required to actually create the shape of
    59 the hierarchy. However vtables would allow behaviour to be carried with the
    60 tree.
    61 
    62 The hierarchy would be a tree of types, of traits and structs. Currently we do
    63 not support structural extension, so traits form the internal nodes and
    64 structures the leaf nodes.
    65 
    66 The syntax is undecided but it will include a clause like `virtual (PARENT)`
    67 on trait and struct definitions. It marks out all types in a hierarchy.
    68 PARENT may be omitted, if it is this type is the root of a hierarchy. Otherwise
    69 it is the name of the type that is this type's parent in the hierarchy.
    70 
    71 Traits define a trait instance type that implements all assertions in this
    72 trait and its parents up until the root of the hierarchy. Each trait then
    73 defines a vtable type. Structures will also have a vtable type but it should
    74 be the same as their parent's.
    75 
    76 Trait objects within the tree can be statically cast to a parent type. Casts
    77 from a parent type to a child type are conditional, they check to make sure
    78 the underlying instance is an instance of the child type, or an instance of
    79 one of its children. The type then is recoverable at run-time.
    80 
    81 As with regular trait objects, calling a function on a trait object will cause
    82 a look-up on the the virtual table. The casting rules make sure anything that
    83 can be cast to a trait type will have all the function implementations for
    84 that trait.
    85 
    86 Converting from a concrete type (structures at the edge of the hierarchy) to
    87 an abstract type works the same as with normal trait objects, the underlying
    88 object is packaged with a virtual table pointer. Converting back to an abstract
    89 type requires confirming the underlying type matches, but then simply extracts
    90 the pointer to it.
    91 
    92 ### Inline vtables
     243We would also like to implement hierarchical relations between types.
     244
     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
     255
     256Virtual tables by themselves are not quite enough to implement this system.
     257A vtable is just a list of functions and there is no way to check at run-time
     258what these functions, we carry that knowledge with the table.
     259
     260This proposal adds type ids to check for position in the hierarchy and an
     261explicate syntax for establishing a hierarchical relation between traits and
     262their implementing types. The ids should uniquely identify each type and
     263allow retrieval of the type's parent if one exists. By recursion this allows
     264the ancestor relation between any two hierarchical types can be checked.
     265
     266The hierarchy is created with traits as the internal nodes and structures
     267as the leaf nodes. The structures may be used normally and the traits can
     268be used to create generic objects as in the first section (the same
     269restrictions apply). However these type objects store their type id which can
     270be recovered to figure out which type they are or at least check to see if
     271they fall into a given sub-tree at run-time.
     272
     273Here is an example of part of a hierarchy. The `virtual(PARENT)` syntax is
     274just an example. But when used it give the name of the parent type or if
     275empty it shows that this type is the root of its hierarchy.
     276(Also I'm not sure where I got these casing rules.)
     277
     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    }
     283
     284    trait expression_node(otype T) virtual(ast_node) {
     285        Type eval_type(T const & this);
     286    }
     287
     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
     317This system does not support multiple inheritance. The system could be
     318extended to support it or a limited form (ex. you may have multiple parents
     319but they may not have a common ancestor). However this proposal focuses just
     320on using hierachy as organization. Other uses for reusable/genaric code or
     321shared interfaces is left for other features of the language.
     322
     323### Extension: Structural Inheritance
     324An extension would be allow structures to be used as internal nodes on the
     325inheritance tree. Its child types would have to implement the same fields.
     326
     327The 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
     329T. Offset unknown and passed in/stored with function pointers.)
     330A concrete child would have to declare the same set of fields with the same
     331types. This is of a more functional style.
     332
     333The stronger restriction is that the fields of the parent are a prefix of the
     334child's fields. Possibly automatically inserted. This the imperative view and
     335may also have less overhead.
     336
     337### Extension: Unions and Enumerations
     338Currently there is no reason unions and enumerations, in the cases they
     339do implement the trait, could not be in the hierarchy as leaf nodes.
     340
     341It does not work with structural induction, but that could just be a compile
     342time check that all ancestors are traits or do not add field assertions.
     343
     344#### Sample Implementation
     345The type id may be as little as:
     346
     347    struct typeid {
     348        struct typeid const * const parent;
     349    };
     350
     351Some linker magic would have to be used to ensure exactly one copy of each
     352structure for each type exists in memory. There seem to be special once
     353sections that support this and it should be easier than generating unique
     354ids across compilation units.
     355
     356The structure could be extended to contain any additional type information.
     357
     358There are two general designs for vtables with type ids. The first is to put
     359the type id at the top of the vtable, this is the most compact and efficient
     360solution but only works if we have exactly 1 vtable for each type. The second
     361is to put a pointer to the type id in each vtable. This has more overhead but
     362allows 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
     376One important restriction is that only one instance of each typeid in memory.
     377There is a ".gnu.linkonce" feature in the linker that might solve the issue.
     378
     379### Virtual Casts
     380The generic objects may be cast up and down the hierarchy.
     381
     382Casting to an ancestor type always succeeds. From one generic type to another
     383is just a reinterpretation and could be implicate. Wrapping and unwrapping
     384a concrete type will probably use the same syntax as in the first section.
     385
     386Casting from an ancestor to a descendent requires a check. The underlying
     387type may or may not belong to the sub-tree headed by that descendent. For this
     388we introduce a new cast operator, which returns the pointer unchanged if the
     389check succeeds and null otherwise.
     390
     391    trait SubType * new_value = (virtual trait SubType *)super_type;
     392
     393For 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
     425This is a small extension, even in the example above `io_error *` is repeated
     426in the cast and the variable being assigned to. Using return type inference
     427would allow the second type to be skipped in cases it is clear what type is
     428being checked against.
     429
     430The line then becomes:
     431
     432    io_error * error = (virtual)exc;
     433
     434#### Sample Implementation
     435This cast implementation assumes a type id layout similar to the one given
     436above. Also this code is definitely in the underlying C. Functions that give
     437this functionality could exist in the standard library but these are meant to
     438be 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
     454The virtual cast function might have to be wrapped with some casts to make it
     455compile without warning.
     456
     457For the implicate target type we may be able to lean on the type resolution
     458system that already exists. If the casting to ancestor type is built into
     459the resolution then the impicate target could be decided by picking an
     460overload, generated for each hierarchial type (here io_error and its root
     461type exception).
     462
     463    io_error * virtual_cast(exception * value) {
     464        return virtual_cast(io_error_typeid, value);
     465    }
     466
     467### Extension: Inline vtables
    93468Since the structures here are usually made to be turned into trait objects
    94 it might be worth it to have fields on them to store the virtual table
    95 pointer. This would have to be declared on the trait as an assertion, but if
    96 it is the trait object could be a single pointer.
    97 
    98 It is trivial to do if the field with the virtual table pointer is fixed.
    99 Otherwise some trickery with pointing to the field and storing the offset in
    100 the virtual table to recover the main object would have to be used.
     469it might be worth it to have fields in them to store the virtual table
     470pointer. 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
     472pointer.
     473
     474There are also three options for where the pointer to the vtable. It could be
     475anywhere, a fixed location for each trait or always at the front. For the per-
     476trait solution an extension to specify what it is (example `vtable[0];`) which
     477could also be used to combine it with others. So these options can be combined
     478to allow access to all three options.
     479
     480The pointer to virtual table field on structures might implicately added (the
     481types have to declare they are a child here) or created with a declaration,
     482possibly like the one used to create the assertion.
    101483
    102484### Virtual Tables as Types
    103 Here we consider encoding plus the implementation of functions on it. Which
    104 is to say in the type hierarchy structures aren't concrete types anymore,
    105 instead they are parent types to vtables, which combine the encoding and
    106 implementation.
     485Here we consider encoding plus the implementation of functions on it to be a
     486type. Which is to say in the type hierarchy structures aren't concrete types
     487anymore, instead they are parent types to vtables, which combine the encoding
     488and implementation.
     489
     490### Question: Wrapping Structures
     491One issue is what to do with concrete types at the base of the type tree.
     492When we are working with the concrete type generally it would like them to be
     493regular structures with direct calls. On the other hand for interactions with
     494other types in the hierarchy it is more convenent for the type already to be
     495cast.
     496
     497Which of these two should we use? Should we support both and if so how do we
     498choose which one is being used at any given time.
     499
     500On a related note I have been using pointers two trait types here, as that
     501is how many existing languages handle it. However the generic objects might
     502be only one or two pointers wide passing the objects as a whole would not
     503be very expensive and all operations on the generic objects probably have
     504to be defined anyways.
    107505
    108506Resolution Scope
     
    120518the type declaration, including the functions that satisfy the trait, are
    121519all defined. Currently there are many points where this can happen, not all
    122 of them will have the same definitions and no way to select one over the
    123 other.
    124 
    125 Some syntax would have to be added. All resolutions can be found at compile
    126 time and a single vtable created for each type at compilation time.
     520of them have the same definitions and no way to select one over the other.
     521
     522Some syntax would have to be added to specify the resolution point. To ensure
     523a single instance there may have to be two variants, one forward declaration
     524and one to create the instance. With some compiler magic the forward
     525declaration maybe enough.
     526
     527    extern trait combiner(struct summation) vtable;
     528    trait combiner(struct summation) vtable;
     529
     530Or (with the same variants):
     531
     532    vtable combiner(struct summation);
     533
     534The extern variant promises that the vtable will exist while the normal one
     535is where the resolution actually happens.
    127536
    128537### Explicit Resolution Points:
     
    141550vtable.
    142551
     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
     558The extern difference is the same before. The name (sum in the samples) is
     559used at the binding site to say which one is picked. The default keyword can
     560be 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.)
     566The object being bound is required. The name of the vtable is optional if
     567there is exactly one vtable name marked with default.
     568
     569These could also be placed inside functions. In which case both the name and
     570the default keyword might be optional. If the name is omitted in an assignment
     571the closest vtable is chosen (returning to the global default rule if no
     572appropriate local vtable is in scope).
     573
    143574### Site Based Resolution:
    144575Every place in code where the binding of a vtable to an object occurs has
     
    165596Stack allocated functions interact badly with this because they are not
    166597static. There are several ways to try to resolve this, however without a
    167 general solution most can only buy time.
     598general solution most can keep vtables from making the existing thunk problem
     599worse, they don't do anything to solve it.
    168600
    169601Filling in some fields of a static vtable could cause issues on a recursive
     
    180612shortest lifetime of a function assigned to it. However this still limits the
    181613lifetime "implicitly" and returns to the original problem with thunks.
     614
     615Odds And Ends
     616-------------
     617
     618In addition to the main design there are a few extras that should be
     619considered. They are not part of the core design but make the new uses fully
     620featured.
     621
     622### Extension: Parent-Child Assertion
     623For hierarchy types in regular traits, generic functions or generic structures
     624we may want to be able to check parent-child relationships between two types
     625given. For this we might have to add another primitive assertion. It would
     626have the following form if declared in code:
     627
     628    trait is_parent_child(dtype Parent, dtype Child) { <built-in magic> }
     629
     630This assertion is satified if Parent is an ancestor of Child in a hierarchy.
     631In other words Child can be statically cast to Parent. The cast from Parent
     632to child would be dynamically checked as usual.
     633
     634However in this form there are two concerns. The first that Parent will
     635usually be consistent for a given use, it will not be a variable. Second is
     636that we may also need the assertion functions. To do any casting/conversions
     637anyways.
     638TODO: Talk about when we wrap a concrete type and how that leads to "may".
     639
     640To this end it may be better that the parent trait combines the usual
     641assertions plus this new primitive assertion. There may or may not be use
     642cases for accessing just one half and providing easy access to them may be
     643required depending on how that turns out.
     644
     645    trait Parent(dtype T | interface(T)) virtual(<grand-parent?>) { }
     646
     647### Extension: sizeof Compatablity
     648Trait types are always sized, it may even be a fixed size like how pointers
     649have the same size regardless of what they point at. However their contents
     650may or may not be of a known size (if the `sized(...)` assertion is used).
     651
     652Currently there is no way to access this information. If it is needed a
     653special syntax would have to be added. Here a special case of `sizeof` is
     654used.
     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
     662As usual `y`, size of the type, is the size of the local storage used to put
     663the value into. The other case `x` checks the saved stored value in the
     664virtual table and returns that.
  • doc/theses/aaron_moss_PhD/phd/Makefile

    r6a9d4b4 r933f32f  
    22BIBDIR = ../../../bibliography
    33EVALDIR = evaluation
     4FIGDIR = figures
    45TEXLIB = .:${BUILD}:${BIBDIR}:
    56
     
    89BIBTEX = BIBINPUTS=${TEXLIB} && export BIBINPUTS && bibtex
    910
    10 VPATH = ${EVALDIR}
     11VPATH = ${EVALDIR} ${FIGDIR}
    1112
    1213BASE = thesis
     
    2223background \
    2324generic-types \
     25resolution-heuristics \
    2426type-environment \
    25 resolution-heuristics \
     27experiments \
    2628conclusion \
     29generic-bench \
     30}
     31
     32FIGURES = ${addsuffix .eps, \
     33safe-conv-graph \
     34resolution-dag \
     35union-find-with-classes \
     36persistent-union-find \
    2737}
    2838
    2939GRAPHS = ${addsuffix .tex, \
    3040generic-timing \
     41tests-completed \
     42per-prob-histo \
     43per-prob-depth \
     44cfa-time \
    3145}
    3246
     
    4761        dvips ${BUILD}/$< -o ${BUILD}/$@
    4862
    49 ${BASE}.dvi : Makefile ${SOURCES} ${GRAPHS} ${BIBFILE} ${BUILD}
     63${BASE}.dvi : Makefile ${SOURCES} ${GRAPHS} ${FIGURES} ${BIBFILE} ${BUILD}
    5064        ${LATEX} ${BASE}
    5165        ${BIBTEX} ${BUILD}/${BASE}
     
    5367        ${LATEX} ${BASE}
    5468
    55 ${GRAPHS} : generic-timing.gp generic-timing.dat ${BUILD}
     69generic-timing.tex : generic-timing.gp generic-timing.dat ${BUILD}
    5670        gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/generic-timing.gp
     71       
     72tests-completed.tex : algo-summary.gp algo-summary.dat bu-summary.dat ${BUILD}
     73        gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/algo-summary.gp
     74
     75per-prob-histo.tex : per-prob.gp per-prob.tsv ${BUILD}
     76        gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/per-prob.gp
     77
     78per-prob-depth.tex : per-prob-scatter.gp ${BUILD}
     79        gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/per-prob-scatter.gp
     80
     81cfa-time.tex : cfa-plots.gp cfa-time.tsv cfa-mem.tsv ${BUILD}
     82        gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/cfa-plots.gp
    5783
    5884${BUILD}:
  • doc/theses/aaron_moss_PhD/phd/background.tex

    r6a9d4b4 r933f32f  
    11\chapter{\CFA{}}
     2\label{cfa-chap}
    23
    34\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.
    45To 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.
    56
    6 The 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.
    7 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.
    8 This 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 
    10 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{} have been under active development continuously since.
    11 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.
    12 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}.
    13 
    14 \section{\CFA{} Features}
    15 
    16 The selection of features presented in this chapter are chosen to elucidate the design constraints of the work presented in this thesis.
    17 In 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}
     7Glen 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.
     8Building 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.
     9This 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
     11The \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.
     12As 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.
     13Notable 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
     15This 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.
     16In C, no simultaneously-visible declarations share identifiers, hence expression resolution in C is not difficult.
     17In \CFA{}, multiple added features make the resolution process significantly more complex.
     18Due 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
     20The features presented in this chapter are chosen to elucidate the design constraints of the work presented in this thesis.
     21In 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}
    2024
    2125It is important to note that \CFA{} is not an object-oriented language.
    22 This is a deliberate choice intended to maintain the applicability of the mental model and language idioms already possessed by C programmers.
    23 This 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.
     26This is a deliberate choice intended to maintain the applicability of the programming model and language idioms already possessed by C programmers.
     27This 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
    2629Particularly, \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.
    27 The 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.
     30While \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.
     31The 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.
    2832
    2933Another 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{}.
    30 This 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 
    34 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\cit{}.}, and variable or function declarations in inner scopes with the same name as a declaration in an outer scope hide the outer declaration.
    35 This 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.
     34As such, any language feature that requires code to be exposed in header files (\eg{} \CC{} templates) also eliminates encapsulation in \CFA{}.
     35Given 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
     39In 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.
     40This 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.
    3641\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:
    3742
     
    5055\end{cfa}
    5156
    52 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 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.
    53 However, 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}
     57The 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
     59While 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.
     60However, 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}
    5663
    5764C does allow name overloading in one context: operator overloading.
    5865From 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.
    59 For 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}}:
     66For 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.
     67This 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}}:
    6068
    6169\begin{cfa}
     
    7179\end{cfa}
    7280
    73 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''\cit{}, so as to present user programmers with only a single set of overloading rules.
    74 
    75 \subsubsection{Special Literal Types}
     81Together, \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}
    7684
    7785Literal !0! is also used polymorphically in C; it may be either integer zero or the null value of any pointer type.
    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 
    80 According 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.
    81 By 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.
     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
     88According 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.
     89By 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.
    8392
    8493\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.
    8594The 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.
    8695
    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!.
    88 As 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.
    89 As 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 
    93 The most significant feature \CFA{} adds is parametric-polymorphic functions.
     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!.
     97While 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.
     98As 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
     102The most significant type-system feature \CFA{} adds is parametric-polymorphic functions.
    94103Such functions are written using a !forall! clause (which gives the language its name):
    95104
     
    102111The 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.
    103112\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.
    104 Types which do not have one or more of these operators visible cannot be bound to !otype! parameters.
    105 In 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}
     113Types 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.
     114In 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}
    106116
    107117One benefit of this design is that it allows polymorphic functions to be separately compiled.
     
    109119The 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.
    110120
    111 \subsubsection{Type Assertions}
    112 
    113 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:
     121\subsection{Type Assertions}
     122
     123Since 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.}:
    114124
    115125\begin{cfa}
    116126forall(otype T `| { T twice(T); }`)
    117127T four_times(T x) { return twice( twice(x) ); }
    118 double twice(double d) { return d * 2.0; }  $\C[2.75in]{// (1)}$
     128double twice$\(_1\)$(double d) { return d * 2.0; }
    119129
    120130double ans = four_times( 10.5 );  $\C[2.75in]{// T bound to double, ans == 42.0}$
     
    129139\begin{cfa}
    130140forall(otype S | { S ?+?(S, S); })
    131 S twice(S x) { return x + x; }  $\C[2.75in]{// (2)}
    132 \end{cfa}
    133 
    134 This 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 
    137 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.
     141S twice$\(_2\)$(S x) { return x + x; }
     142\end{cfa}
     143
     144Specializing 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}}.
     146However, !twice!$_2$ also works for any type !S! that has an addition operator defined for it.
     147
     148Finding 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.}.
    138149If 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.
    139 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 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 
    144 Particular type combinations can be exempted from matching a given polymorphic function through use of a \emph{deleted function declaration}:
    145 
    146 \begin{cfa}
    147 int somefn(char) = void;
    148 \end{cfa}
    149 
    150 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. 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.}.
    151 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.
    152 If 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}.}:
     150To 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}.}:
    157155
    158156\begin{cfa}
     
    171169
    172170Semantically, 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.
    173 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 a structural inheritance, similar to interface implementation in Go, as opposed to the nominal inheritance model of Java and \CC{}.
     171Unlike 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{}.
    174172Nominal inheritance can be simulated in \CFA{} using marker variables in traits:
    175173
     
    186184
    187185Traits, 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.
    188 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.
     186Secondly, 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.}.
    189187Finally, 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}.}:
    190188
     
    206204\end{cfa}
    207205
    208 In 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.
     206In 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.
    209207Given 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!).
    210 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, few such systems could model both relationships simultaneously.
     208While 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,
     209I am unaware of any nominal-inheritance system that can model both relationships simultaneously.
     210Further comparison of \CFA{} polymorphism with other languages can be found in Section~\ref{generic-related-sec}.
    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 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 
    217 In 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.
    218 As 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.
     213The 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
     217Particular type combinations can be exempted from matching a given polymorphic function through the use of a \emph{deleted function declaration}:
     218
     219\begin{cfa}
     220int somefn(char) = void;
     221\end{cfa}
     222
     223This 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.}.
     224Deleted 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.
     225If 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
     229In 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.
     230As 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.
    219231\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!.
    220 One 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 
    222 The 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.
    223 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 which have either no interpretation or multiple ambiguous minimal-cost interpretations.
     232One 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
     234In 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.
     235While 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.
    224236Note that which subexpression interpretation is minimal-cost may require contextual information to disambiguate.
    225237For 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.
    226 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.}.
     238While 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}}.
    227239These 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.
    228240
    229 \subsection{Type Features} \label{type-features-sec}
    230 
    231 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 which have a smaller effect but are useful for code examples.
     241\section{Type Features} \label{type-features-sec}
     242
     243The 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.
    232244These features are described here.
    233245
    234 \subsubsection{Reference Types}
    235 
    236 One of the key ergonomic improvements in \CFA{} is reference types, designed and implemented by Robert Schluntz\cite{Schluntz17}.
     246\subsection{Reference Types}
     247
     248One of the key ergonomic improvements in \CFA{} is reference types, designed and implemented by Robert Schluntz \cite{Schluntz17}.
    237249Given some type !T!, a !T&! (``reference to !T!'') is essentially an automatically dereferenced pointer.
    238 These 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.
    239 A 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 
    241 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.
    242 In \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!)
    244 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 fresh compiler-generated temporary variable and passing a reference to that temporary.
    245 To 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:
     250These 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.
     251The addition of reference types also eliminated two syntactic special-cases present in previous versions of \CFA{}.
     252Consider the a call !a += b! to a compound assignment operator.
     253The previous declaration for that operator is !lvalue int ?+=?(int*, int)!.
     254To 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.
     255With references, this declaration is re-written as !int& ?+=?(int&, int)!.
     256The 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
     258The 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.
     259In \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!).
     261To 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.
     262To mitigate the ``!const! hell'' problem present in \CC{}, there is also a qualifier-dropping lvalue-to-lvalue conversion implemented by copying into a temporary:
    246263
    247264\begin{cfa}
    248265const int magic = 42;
    249 
    250266void inc_print( int& x ) { printf("%d\n", ++x); }
    251267
    252 print_inc( magic ); $\C{// legal; implicitly generated code in red below:}$
     268inc_print( magic ); $\C{// legal; implicitly generated code in red below:}$
    253269
    254270`int tmp = magic;` $\C{// to safely strip const-qualifier}$
    255 `print_inc( tmp );` $\C{// tmp is incremented, magic is unchanged}$
     271`inc_print( tmp );` $\C{// tmp is incremented, magic is unchanged}$
    256272\end{cfa}
    257273
     
    259275The 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.
    260276This 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.
    261 \CFA{} supports all of these use cases \TODO{test array} without further added syntax.
     277\CFA{} supports all of these use cases without further added syntax.
    262278The key to this syntax-free feature support is an observation made by the author that the address of a reference is a lvalue.
    263 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, and pointers to references by repeating the address-of operator:
     279In 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:
    264280
    265281\begin{cfa}
     
    270286\end{cfa}
    271287
    272 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 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}.
     288For 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}.
    277293This 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.
    278294A wide variety of conceptual resources may be conveniently managed by this scheme, including heap memory, file handles, and software locks.
     
    325341\end{cfa}
    326342
    327 \subsubsection{Tuple Types}
     343\subsection{Tuple Types}
    328344
    329345\CFA{} adds \emph{tuple types} to C, a syntactic facility for referring to lists of values anonymously or with a single identifier.
    330346An identifier may name a tuple, a function may return one, and a tuple may be implicitly \emph{destructured} into its component values.
    331347The 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.
    332 This allows tuples to take advantage of the same runtime optimizations available to generic types, while reducing code bloat.
    333 An 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}$
    337 int x = 2; $\C{// (2)}$
     348This reuse allows tuples to take advantage of the same runtime optimizations available to generic types, while reducing code bloat.
     349An 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}$
     353int x$\(_2\)$ = 2;
    338354
    339355forall(otype T)
    340 [T, T] swap( T a, T b ) { $\C{// (3)}$
     356[T, T] swap$\(_1\)$( T a, T b ) {
    341357        return [b, a]; $\C{// one-line swap syntax}$
    342358}
    343359
    344 x = swap( x ); $\C{// destructure [char, char] x into two elements}$
    345 $\C{// cannot use int x, not enough arguments}$
    346 
    347 void swap( int, char, char ); $\C{// (4)}$
    348 
    349 swap( x, x ); $\C{// (4) on (2), (1)}$
    350 $\C{// not (3) on (2), (2) due to polymorphism cost}$
     360x = swap( x ); $\C{// destructure x\(_1\) into two elements}$
     361$\C{// cannot use x\(_2\), not enough arguments}$
     362
     363void swap$\(_2\)$( int, char, char );
     364
     365swap( x, x ); $\C{// swap\(_2\)( x\(_2\), x\(_1\) )}$
     366$\C{// not swap\(_1\)( x\(_2\), x\(_2\) ) due to polymorphism cost}$
    351367\end{cfa}
    352368
    353369Tuple destructuring breaks the one-to-one relationship between identifiers and values.
    354 This precludes some argument-parameter matching strategies for expression resolution, as well as cheap interpretation filters based on comparing number of parameters and arguments.
    355 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!, depending which interpretation of !x! was chosen for the first argument.
     370Hence, some argument-parameter matching strategies for expression resolution are precluded, as well as cheap interpretation filters based on comparing number of parameters and arguments.
     371As 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.
     376This flexibility does incur significant added compilation costs, however, the mitigation of which are the primary concern of this thesis.
  • doc/theses/aaron_moss_PhD/phd/conclusion.tex

    r6a9d4b4 r933f32f  
    11\chapter{Conclusion}
    22
    3 Wrap it up --- Done, done done.
     3Decades after its first standardization, the C language remains a widely-used tool and a vital part of the software development landscape.
     4The \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.
     5This 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}).
     6Based 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}).
     7The combination of these practical improvements and added features significantly improve the viability of \CFA{} as a practical programming language.
     8
     9Further improvements to the \CFA{} type system are still possible, however.
     10One 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.
     11Another 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{}.
     12The 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.
     13An 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
     15More generally, the algorithmic techniques described in this thesis may be useful to implementors of other programming languages.
     16In 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.
     17The \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.
  • doc/theses/aaron_moss_PhD/phd/evaluation/generic-timing.dat

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

    r6a9d4b4 r933f32f  
    6262        \bigskip
    6363       
    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
     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
    7172       
    7273        \noindent
     
    7475  Internal-External Member: \=  \kill % using longest text to define tab length
    7576  Supervisor: \> Peter Buhr \\
    76   \> Professor, School of Computer Science, University of Waterloo \\
     77  \> Associate Professor, School of Computer Science, \\
     78  \> University of Waterloo \\
    7779  \end{tabbing}
    7880        \bigskip
     
    8183  \begin{tabbing}
    8284  Internal-External Member: \=  \kill % using longest text to define tab length
    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 \\
     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 \\
    8792  \end{tabbing}
    88 %       \bigskip
    89        
    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
     93        \bigskip
     94       
     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
    97103       
    98104%       \noindent
     
    124130\begin{center}\textbf{Abstract}\end{center}
    125131
    126 This is the abstract.
     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.
    127145
    128146\cleardoublepage
     
    131149% -------------------------------
    132150
    133 % \begin{center}\textbf{Acknowledgements}\end{center}
    134 
    135 % I would like to thank all the little people who made this thesis possible.
    136 % \cleardoublepage
     151\begin{center}\textbf{Acknowledgements}\end{center}
     152
     153Though a doctoral thesis is an individual project, I could not have completed it without the help and support of many members of my community.
     154This 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
     156My 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.
     157I gratefully acknowledge the financial support of the National Science and Engineering Council of Canada and Huawei Ltd.\ for this project.
     158I 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.
     159I am indebted to Peter van Beek and Ian Munro for their algorithmic expertise and willingness to share their time with me.
     160I 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
     162Finally, 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
    137165
    138166% D E D I C A T I O N
     
    141169% \begin{center}\textbf{Dedication}\end{center}
    142170
    143 % This is dedicated to the one I love.
     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
    144173% \cleardoublepage
    145174
  • doc/theses/aaron_moss_PhD/phd/generic-types.tex

    r6a9d4b4 r933f32f  
    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 not needed.
     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 unnecessary.
    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
    1619                struct int_list { int value; struct int_list* next; };
    1720
     
    2427                int int_list_head( const struct int_list* ls ) { return ls->value; }
    2528
    26                 $\C[\textwidth]{// all code must be duplicated for every generic instantiation}$
     29                // all code must be duplicated for every generic instantiation
    2730
    2831                struct string_list { const char* value; struct string_list* next; };
     
    3740                        { return ls->value; }
    3841
    39                 $\C[\textwidth]{// use is efficient and idiomatic}$
     42                // use is efficient and idiomatic
    4043
    4144                int main() {
     
    5558\begin{figure}
    5659        \begin{cfa}
     60                #include <stdlib.h> $\C{// for malloc}$
     61                #include <stdio.h>  $\C{// for printf}$
     62
    5763                // single code implementation
    5864
    5965                struct list { void* value; struct list* next; };
    6066
    61                 $\C[\textwidth]{// internal memory management requires helper functions}$
     67                // internal memory management requires helper functions
    6268
    6369                void list_insert( struct list** ls, void* x, void* (*copy)(void*) ) {
     
    6975                void* list_head( const struct list* ls ) { return ls->value; }
    7076
    71                 $\C[\textwidth]{// helpers duplicated per type}$
     77                // helpers duplicated per type
    7278
    7379                void* int_copy(void* x) {
     
    96102\begin{figure}
    97103        \begin{cfa}
    98                 $\C[\textwidth]{// code is nested in macros}$
     104                #include <stdlib.h> $\C{// for malloc}$
     105                #include <stdio.h>  $\C{// for printf}$
     106
     107                // code is nested in macros
    99108
    100109                #define list(N) N ## _list
     
    118127                define_list(string, const char*); $\C[3in]{// defines string\_list}$
    119128
    120                 $\C[\textwidth]{// use is efficient, but syntactically idiosyncratic}$
     129                // use is efficient, but syntactically idiosyncratic
    121130
    122131                int main() {
     
    134143\end{figure}
    135144
    136 \CC{}, Java, and other languages use \emph{generic types} to produce type-safe abstract data types.
    137 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 from which this chapter is closely based.
     145\CC{}, Java, and other languages use \emph{generic types} (or \emph{parameterized types}) to produce type-safe abstract data types.
     146Design 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.
    138147\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.
    139148A 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.
    140 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} \TODO{test this code}.
     149An 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}.
    141150
    142151\begin{figure}
    143152        \begin{cfa}
     153                #include <stdlib.hfa> $\C{// for alloc}$
     154                #include <stdio.h>  $\C{// for printf}$
     155
    144156                forall(otype T) struct list { T value; list(T)* next; };
    145157
    146                 $\C[\textwidth]{// single polymorphic implementation of each function}$
    147                 $\C[\textwidth]{// overloading reduces need for namespace prefixes}$
     158                // single polymorphic implementation of each function
     159                // overloading reduces need for namespace prefixes
    148160
    149161                forall(otype T) void insert( list(T)** ls, T x ) {
     
    155167                forall(otype T) T head( const list(T)* ls ) { return ls->value; }
    156168
    157                 $\C[\textwidth]{// use is clear and efficient}$
     169                // use is clear and efficient
    158170
    159171                int main() {
     
    173185\section{Design}
    174186
    175 Though 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.
    176 The guiding principle was to maintain an unsurprising language model for C programmers without compromising runtime efficiency.
    177 A 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 
    181 One approach to the design of generic types is that taken by \CC{} templates\cite{C++}.
     187Though 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.
     188The guiding principle is to maintain an unsurprising language model for C programmers without compromising runtime efficiency.
     189A 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
     193One approach to the design of generic types is that taken by \CC{} templates \cite{C++}.
    182194The 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.
    183195Template expansion has the benefit of generating code with near-optimal runtime efficiency, as distinct optimizations can be applied for each instantiation of the template.
    184 On 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.
     196On 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.
    185197The most significant restriction of the \CC{} template model is that it breaks separate compilation and C's translation-unit-based encapsulation mechanisms.
    186 Because 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.
    187 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{}.
    188 C 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 
    190 Java\cite{Java8} has another prominent implementation for generic types, introduced in Java~5 and based on a significantly different approach than \CC{}.
     198Because 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.
     199Furthermore, \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{}.
     200C 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
     202Java \cite{Java8} has another prominent implementation for generic types, introduced in Java~5 and based on a significantly different approach than \CC{}.
    191203The 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.
    192 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 and garbage collector.
     204This process of \emph{type erasure} has the benefit of allowing a single instantiation of polymorphic code, but relies heavily on Java's object model.
    193205To 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.
    194206
    195 Cyclone\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.
     207Cyclone \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.
    196208Cyclone 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.
    197209Furthermore, 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!.
     
    200212
    201213Many other languages include some form of generic types.
    202 As 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.
    203 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{}.
    204 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 it's garbage-collected, message-passing object-oriented model is a radical departure from C.
    205 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.
    206 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 paramters.
     214As 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.
     215Haskell \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{}.
     216Objective-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.
     217Go \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.
     218Go 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.
    207219Go does not, however, allow user code to define generic types, restricting Go programmers to the small set of generic types defined by the compiler.
    208 Rust 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.
     220Rust 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.
    209221On 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.
    210222
    211223\subsection{\CFA{} Generics}
    212224
    213 The generic types design in \CFA{} draws inspiration from both \CC{} and Java generics, capturing the better aspects of each.
    214 Like \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.
     225The generic types design in \CFA{} draws inspiration from both \CC{} and Java generics, capturing useful aspects of each.
     226Like \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.
    215227The 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.
    216 As an example, consider the following generic type and function \TODO{test this}:
    217 
     228As an example, consider the following generic type and function:
     229
     230% TODO whatever the bug is with initializer-expressions not working, it affects this
    218231\begin{cfa}
    219232forall( otype R, otype S ) struct pair { R first; S second; };
    220233
    221234pair(const char*, int) with_len( const char* s ) {
    222         return (pair(const char*), int){ s, strlen(s) };
     235        return (pair(const char*, int)){ s, strlen(s) };
    223236}
    224237\end{cfa}
    225238
    226239In 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!.
    227 If 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.
    230 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{Moss18}) and can be re-used for a wide variety of !pair! instantiations.
    231 Since the parameters to this polymorphic constructor call are all statically known, compiler inlining can eliminate any runtime overhead of this polymorphic call.
     240If 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.
     243However, 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.
     244Since the parameters to this polymorphic constructor call are all statically known, compiler inlining can in principle eliminate any runtime overhead of this polymorphic call.
    232245
    233246\CFA{} deliberately does not support \CC{}-style partial specializations of generic types.
    234 A 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.
     247A 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.
    235248Complications 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.
    236 Rather 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.
    237 Of 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.
     249Rather 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.
     250Of 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.
    238251
    239252Since \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.
    240 As an example, the !with_len! function above could be an optimization of the following more general function:
     253As 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{}:
    241254
    242255\begin{cfa}
     
    247260\end{cfa}
    248261
    249 \CFA{} generic types also support the type constraints from !forall! functions.
     262\CFA{} generic types also support type constraints, as in !forall! functions.
    250263For example, the following declaration of a sorted set type ensures that the set key implements equality and relational comparison:
    251264
     
    254267\end{cfa}
    255268
    256 These constraints are implemented by applying equivalent constraints to the compiler-generated constructors for this type.
     269These constraints are enforced by applying equivalent constraints to the compiler-generated constructors for this type.
    257270
    258271\section{Implementation} \label{generic-impl-sec}
    259272
    260 The 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.
    261 While \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.
    262 Instead, 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.
     273The ability to use generic types in polymorphic contexts means that the \CFA{} implementation must support a mechanism for accessing fields of generic types dynamically.
     274While \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.
     275Instead, 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
    263277A \emph{dtype-static} type has polymorphic parameters but is still concrete.
    264 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.
    265 In 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.
     278Polymorphic 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.
     279In 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.
    266280More 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.
    267 To illustrate, the following code using the !pair! type from above \TODO{test this} has each use of !pair! commented with its class:
    268 
     281To 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
    269284\begin{cfa}
    270285//dynamic, layout varies based on T
    271 forall(otype T) T value( pair(const char*, T) p ) { return p.second; }
     286forall(otype T) T value$\(_1\)$( pair(const char*, T) p ) { return p.second; }
    272287
    273288// dtype-static, F* and T* are concrete but recursively polymorphic
    274 forall(dtype F, otype T) T value( pair(F*, T*) ) { return *p.second; }
     289forall(dtype F, otype T) T value$\(_2\)$( pair(F*, T*) ) { return *p.second; }
    275290
    276291pair(const char*, int) p = {"magic", 42}; $\C[2.5in]{// concrete}$
    277292int i = value(p);
    278 pair(void*, int*) q = {0, &p.second}; $\C[2.5in]{// concrete}$
     293pair(void*, int*) q = {0, &i}; $\C[2.5in]{// concrete}$
    279294i = value(q);
    280295double d = 1.0;
     
    285300\subsection{Concrete Generic Types}
    286301
    287 The \CFACC{} translator template expands concrete generic types into new structure types, affording maximal inlining.
     302The \CFACC{} translator template-expands concrete generic types into new structure types, affording maximal inlining.
    288303To 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.
    289304In 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.
    290305A 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.
    291 As 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}}
     306As an example, the concrete instantiation for !pair(const char*, int)! is\footnote{Field name mangling for overloading purposes is omitted.\label{mangle-foot}}:
    292307
    293308\begin{cfa}
     
    296311
    297312A concrete generic type with dtype-static parameters is also expanded to a structure type, but this type is used for all matching instantiations.
    298 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.
     313In 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:
    299314
    300315\begin{cfa}
     
    308323The design for generic types presented here adds an \emph{offset array} containing structure-member offsets for dynamic generic !struct! types.
    309324A dynamic generic !union! needs no such offset array, as all members are at offset 0, but size and alignment are still necessary.
    310 Access 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 
    312 the offset arrays are statically generated where possible.
     325Access 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
     327The offset arrays are statically generated where possible.
    313328If 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.
    314 As an example, the body of the second !value! function above is implemented as
     329As an example, the body of !value!$_2$ above is implemented as:
    315330
    316331\begin{cfa}
     
    318333\end{cfa}
    319334
    320 Here, !_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
     335Here, !_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:
    322337
    323338\begin{cfa}
     
    330345For 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.
    331346\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.
    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.
     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.
    333348These 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.
    334 Un!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.
    335 Similarly, 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 
    337 The 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{}.
     349Un-!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.
     350Similarly, 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
     352The 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.
    338353This 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.
    339354Since \CFACC{} generates a distinct layout function for each type, constant-folding and loop unrolling are applied.
     
    342357forall(dtype T1, dtype T2, ... | sized(T1) | sized(T2) | ...)
    343358void layout(size_t* size, size_t* align, size_t* offsets) {
    344         // initialize values
    345359        *size = 0; *align = 1;
    346360        // set up members
     
    360374\end{cfa}
    361375
    362 Results of layout function calls are cached so that they are only computed once per type per function.
    363 Layout 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.
     376Results of layout-function calls are cached so that they are only computed once per type per function.
     377Layout 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.
    364378For 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.
    365379This 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.
    366380
    367 Whether a type is concrete, dtype-static, or dynamic is decided solely on the basis of the type arguments and !forall! clause type paramters.
    368 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 to use.
    369 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.
    370 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 we judged preserving separate compilation (and the associated C compatibility) in the implemented design to be an acceptable trade-off.
     381Whether a type is concrete, dtype-static, or dynamic is decided solely on the basis of the type arguments and !forall! clause type parameters.
     382This 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.
     383In 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.
     384However, 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.
    371385
    372386\subsection{Applications of Dtype-static Types} \label{dtype-static-sec}
     
    387401Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \emph{tag structures}.
    388402Sometimes, information is only used for type checking and can be omitted at runtime.
    389 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 !?+?!.
     403In 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 !?+?!.
    390404These implementations may even be separately compiled, unlike \CC{} template functions.
    391405However, the \CFA{} type checker ensures matching types are used by all calls to !?+?!, preventing nonsensical computations like adding a length to a volume.
     
    408422\section{Performance Experiments} \label{generic-performance-sec}
    409423
    410 To 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}.
    411 Since 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.
     424To 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}.
     425Since 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.
    412426A more illustrative comparison measures the costs of idiomatic usage of each language's features.
    413 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 other languages.
    414 The 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}
     427The 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}.
     428The 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
    417432int main() {
    418433        int max = 0, val = 42;
     
    435450\end{cfa}
    436451
    437 The 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{}.
    438 The \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.
     452The 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{}.
     453The \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.
    439454The 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.
    440455Note 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.
     
    449464\centering
    450465\input{generic-timing}
    451 \caption{Benchmark timing results (smaller is better)} \label{generic-eval-fig}
     466\caption[Benchmark timing results]{Benchmark timing results (smaller is better)} \label{generic-eval-fig}
    452467\end{figure}
    453468
     
    466481
    467482The 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.
    468 By 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.
     483By 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.
    469484\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.
    470485The gcc compiler is unable to optimize some dead code and condense nested calls; a compiler designed for \CFA{} could more easily perform these optimizations.
    471 Finally, the binary size for \CFA{} is larger because of static linking with \CFA{} libraries.
     486Finally, 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.
    472487
    473488\CFA{} is also competitive in terms of source code size, measured as a proxy for programmer effort.
     
    475490Use 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.
    476491The 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.
    477 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 reimplementation of such collection types by C programmers.
     492On 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.
    478493\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.
    479494I 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.
     
    481496Line 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.
    482497Such 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.
    483 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 respecified, either as a format specifier, explicit downcast, type-specific function, or by name in a !sizeof!, !struct! literal, or !new! expression.
     498To 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.
    484499The \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.
    485500The \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.
     
    487502\section{Future Work}
    488503
    489 The generic types design presented here is already sufficiently expressive to implement a variety of useful library types.
     504The generic types presented here are already sufficiently expressive to implement a variety of useful library types.
    490505However, some other features based on this design could further improve \CFA{}.
    491506
    492507The most pressing addition is the ability to have non-type generic parameters.
    493 C 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.
    494 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.
    495 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.
    496 
    497 The implementation mechanisms behind this generic types design can also be used to add new features to \CFA{}.
    498 One such potential feature would be to add \emph{field assertions} to the existing function and variable assertions on polymorphic type variables.
     508C 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
     512The implementation mechanisms behind generic types can also be used to add new features to \CFA{}.
     513One such potential feature is \emph{field assertions}, an addition to the existing function and variable assertions on polymorphic type variables.
     514These assertions could be specified using this proposed syntax:
     515
     516\begin{cfa}
     517trait 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
    499523Implementation of these field assertions would be based on the same code that supports member access by dynamic offset calculation for dynamic generic types.
    500524Simulating 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.
    501 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 we have deferred a decision on field assertions until we have more experience using \CFA{}.
    502 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.
    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.
     525Of 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
     527If 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}
     530struct point { int x, y; };  $\C{// traitof(point) is equivalent to hasXY above}$
     531struct coloured_point { int x, y; enum { RED, BLACK } colour };
     532
     533// works for both point and coloured_point
     534forall(dtype T | traitof(point)(T) )
     535double 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.
    504539
    505540With 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.
    506 However, 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.
    507 Two 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.
    508 These approaches are not mutually exclusive and allow performance optimizations to be applied only when necessary, without suffering global code bloat.
    509 In 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.
     541However, 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.
     542Two 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.
     543These approaches are complementary and allow performance optimizations to be applied only when necessary, without suffering global code bloat.
  • doc/theses/aaron_moss_PhD/phd/introduction.tex

    r6a9d4b4 r933f32f  
    11\chapter{Introduction}
    22
    3 The C programming language 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 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:
     3The C programming language~\cite{C11} 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 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:
    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 procedural control structures.
    21 \CC{} is even a largely backwards-compatible extension of C, with development dating back nearly as far as C itself.
    22 Though 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.
     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 control structures.
     21\CC{}~\cite{C++} is even a largely backwards-compatible extension of C.
     22Though 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.
    2323
    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.
     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.
    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 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.
     27Unlike other popular C extensions like \CC{} and Objective-C, \CFA{} adds modern features to C without imposing an object-oriented paradigm to use them.
     28However, 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.
    2829
    2930This 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.
    30 Particular contributions of this work include design and implementation of
    31 parametric-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}).
    32 This 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.
     31Particular 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}
    3338
    34 Though 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.
    35 In 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.
    36 Type 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.
     39The prototype system, which implements the algorithmic contributions of this thesis, is the first performant type-checker implementation for a \CFA{}-style type system.
     40As 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
     42Though 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.
     43In 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.
     44Much 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.
     45As an example in \CC{}:
     46\begin{C++}
     47template<typename T> T* zero() { return new T( 0 ); }
     48
     49int* z = zero<int>();  $\C{// must specify int twice}$
     50\end{C++}
     51
     52\CFA{} allows !int* z = zero()!, which elides the second !int!.
     53While 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{}.
     54By 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.
     55Type 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
     57One area of inquiry that is outside the scope of this thesis is formalization of the \CFA{} type system.
     58Ditchfield~\cite{Ditchfield92} defined the $F_\omega^\ni$ polymorphic lambda calculus, which is the theoretical basis for the \CFA{} type system.
     59Ditchfield did not, however, prove any soundness or completeness properties for $F_\omega^\ni$; such proofs remain future work.
     60A number of formalisms other than $F_\omega^\ni$ could potentially be adapted to model \CFA{}.
     61One 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.
     62These 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}.
  • doc/theses/aaron_moss_PhD/phd/macros.tex

    r6a9d4b4 r933f32f  
    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.}}
     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.}\@}
    2122
    2223\newcommand{\myset}[1]{\left\{#1\right\}}
  • doc/theses/aaron_moss_PhD/phd/resolution-heuristics.tex

    r6a9d4b4 r933f32f  
    1 \chapter{Resolution Heuristics}
     1\chapter{Resolution Algorithms}
    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 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.
    6 I 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.
    7 To 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.
    8 
    9 \section{Conversion Cost}
    10 
    11 
    12 
    13 % Discuss changes to cost model, as promised in Ch. 2
    14 
    15 % Mention relevance of work to C++20 concepts
     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 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.
     6A 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.
     7To choose among valid interpretations, a \emph{conversion cost} is used to rank interpretations.
     8This conversion cost is summed over all subexpression interpretations in the interpretation of a top-level expression.
     9Hence, the expression resolution problem is to find the unique minimal-cost interpretation for an expression, reporting an error if no such unique interpretation exists.
     10
     11\section{Expression Resolution}
     12
     13The 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.
     14Once 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.
     15
     16The expression resolution problem in \CFA{} is more difficult than the analogous problems in C or \CC{}.
     17As mentioned above, the lack of name overloading in C (except for built-in operators) makes its resolution problem substantially easier.
     18A comparison of the richer type systems in \CFA{} and \CC{} highlights some of the challenges in \CFA{} expression resolution.
     19The 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.
     20One 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:
     21
     22\begin{cfa}
     23forall(dtype T) T& deref(T*); $\C{// dereferences pointer}$
     24forall(otype T) T* def(); $\C{// new heap-allocated default-initialized value}$
     25
     26int& i = deref( def() );
     27\end{cfa}
     28
     29In 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>() )!.
     30Similarly, 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.
     31Because 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.}.
     32Additionally, 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.
     33The precise definition of \CFA{} expression resolution in this section further expands on the challenges of this problem.
     34
     35\subsection{Type Unification}
     36
     37The polymorphism features of \CFA{} require binding of concrete types to polymorphic type variables.
     38Briefly, \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.
     39A \emph{unification} algorithm is used to simultaneously check two types for equivalence with respect to the substitutions in an environment and update that environment.
     40Essentially, 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.
     41Ditchfield~\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.
     46Both 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.
     47C 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.
     48The 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.
     49Since 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
     57Beginning 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.
     58Loosely defined, the conversion cost counts the implicit conversions utilized by an interpretation.
     59With more specificity, the cost is a lexicographically-ordered tuple, where each element corresponds to a particular kind of conversion.
     60In 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.
     61Degree 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}.
     62The 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}$.
     63The 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}
     66void f$\(_1\)$(char, long); $\C{// (1,0,1)}$
     67void f$\(_2\)$(short, long); $\C{// (1,0,1)}$
     68forall(otype T) void f$\(_3\)$(T, long); $\C{// (0,1,1)}$
     69void f$\(_4\)$(long, long); $\C{// (0,0,2)}$
     70void f$\(_5\)$(int, unsigned long); $\C{// (0,0,2)}$
     71void f$\(_6\)$(int, long); $\C{// (0,0,1)}$
     72\end{cfa}
     73
     74Note 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).
     75These 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
     91As 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
     93I also refined the \CFA{} cost model as part of this thesis work.
     94Bilson'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}
     97forall(dtype T | { T& ++?(T&); }) T& advance$\(_1\)$(T& i, int n);
     98forall(dtype T | { T& ++?(T&); T& ?+=?(T&, int)}) T& advance$\(_2\)$(T& i, int n);
     99\end{cfa}
     100
     101In resolving a call to !advance!, the binding to the !T&! parameter in the assertions is added to the $poly$ cost in Bilson's model.
     102However, type assertions actually make a function \emph{less} polymorphic, and as such functions with more type assertions should be preferred in type resolution.
     103In 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.
     104Accordingly, a $specialization$ element is now included in the \CFA{} cost tuple, the values of which are always negative.
     105Each 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.
     106A 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
     108I also incorporated an unimplemented aspect of Ditchfield's earlier cost model.
     109In 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}
     112forall(otype T, otype U) void f$\(_1\)$(T, U);  $\C[3.125in]{// polymorphic}$
     113forall(otype T) void f$\(_2\)$(T, T);  $\C[3.125in]{// less polymorphic}$
     114forall(otype T) void f$\(_3\)$(T, int);  $\C[3.125in]{// even less polymorphic}$
     115forall(otype T) void f$\(_4\)$(T*, int); $\C[3.125in]{// least polymorphic}$
     116\end{cfa}
     117
     118The 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.
     119In the example above, !f!$_1$ has $var = 2$, while the others have $var = 1$.
     120
     121The 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.
     122In 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.
     123Thus, 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$.
     124This process is recursive, such that !T**! has $specialization = -2$.
     125This calculation works similarly for generic types, \eg{} !box(T)! also has specialization cost $-1$.
     126For 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!).
     127Specialization 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.
     128User 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.
     129Since 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
     131A final refinement I have made to the \CFA{} cost model is with regard to choosing among arithmetic conversions.
     132The 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.
     133Bilson's \CFACC{} uses conversion costs based off Figure~\ref{bilson-conv-fig}.
     134However, 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.
     135In 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$.
     136This 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.
     137This refined conversion graph is shown in Figure~\ref{extended-conv-fig}.
     138
     139With 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
     147The 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.
     148Nonetheless, some salient details are repeated here for the sake of completeness.
     149
     150On a theoretical level, the resolver treats most expressions as if they were function calls.
     151Operators in \CFA{} (both those existing in C and added features like constructors) are all modelled as function calls.
     152In 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.
     153Similarly, an aggregate member expression !a.m! can be modelled as a unary function !m! that takes one argument of the aggregate type.
     154Literals 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
     156Since most expressions can be treated as function calls, nested function calls are the primary component of complexity in expression resolution.
     157Each function call has an \emph{identifier} that must match the name of the corresponding declaration, and a possibly-empty list of \emph{arguments}.
     158These 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.
     159A 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.
     160The 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.
     162The 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}
     165void f(int);
     166double g$\(_1\)$(int);
     167int g$\(_2\)$(long);
     168
     169f( g(42) );
     170\end{cfa}
     171
     172Considered 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.
     173However, 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) )!.
     174If !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.
     175Due 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
     177If there are no valid interpretations of the top-level expression, expression resolution fails and must produce an appropriate error message.
     178If any subexpression has no valid interpretations, the process can be short-circuited and the error produced at that time.
     179If there are multiple valid interpretations of a top-level expression, ties are broken based on the conversion cost, calculated as above.
     180If 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.
     181Multiple 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
     183The \CFA{} resolver uses type assertions to filter out otherwise-valid subexpression interpretations.
     184An 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.
     185Type assertion satisfaction is tested by performing type unification on the type of the assertion and the type of the declaration satisfying the assertion.
     186That 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.
     187Assertion-satisfying declarations may be polymorphic functions with assertions of their own that must be satisfied recursively.
     188This 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
     190Cast expressions must be treated somewhat differently than functions for backwards compatibility purposes with C.
     191In 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.
     192C 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.
     193The 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.
     194However, 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.
     195This is demonstrated in the following example, adapted from the C standard library:
     196
     197\begin{cfa}
     198unsigned long long x;
     199(unsigned)(x >> 32);
     200\end{cfa}
     201
     202In 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)$.
     203If 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)$.
     204However, 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.
     205For 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.
     206Thus, 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}.
     211While 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}.
     213Secondly, 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.
     214Programmers 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.
     215If 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
     219Expression 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
     221If 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.
     222In 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
     230To 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!.
     231Accordingly, 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.
     232This 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}).
     233Since 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
     235Implicit 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)$.
     236Polymorphism 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.
     238An 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
     240Considering the recursive traversal of the expression tree, polymorphism again greatly expands the worst-case runtime.
     241Let $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.
     242Ambiguous 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.
     243One 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.
     244As 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$).
     245With 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.
     246Calculated recursively, the bound on the total number of candidate interpretations is $O(i^{p^d})$, each with a distinct type.
     247
     248Given 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 )$.
     249Since 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 )$.
     250Since the size of the expression is $O(p^d)$, letting $n = p^d$ this simplifies to $O(i^n \cdot n^2)$
     251
     252This 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)$.
     254If 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.
     255However, 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)$.
     256Now, $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.
     257It 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
     259It 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.
     260It 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.
     261However, the worst-case bound for assertion satisfaction is based on recursive assertion satisfaction calls exceeding the limit, which is an error case.
     262In 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
     264Similarly, 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.
     265This 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.
     266Type 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
     270Pruning 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.
     271One 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.
     272For 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.
     273All 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
     293Note 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
     295Overload 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.
     296Baker's algorithm~\cite{Baker82} takes a single pass from the leaves of the expression tree up, pre-computing argument candidates at each step.
     297For each candidate function, Baker attempts to match argument types to parameter types in sequence, failing if any parameter cannot be matched.
     298
     299Bilson~\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.
     300These argument combinations are matched to the parameter types of the candidate function as a unit rather than individual arguments.
     301Bilson'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
     303Unlike 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.
     304As presented, this algorithm requires the parameter to have a known type, which is a poor fit for polymorphic type parameters in \CFA{}.
     305Cormack'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
     307Ganzinger 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.
     308Persch~\etal{}~\cite{PW:overload} developed a similar two-pass approach where the bottom-up pass is followed by the top-down pass.
     309These 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.
     310This approach of filtering out invalid types is unsuited to \CFA{} expression resolution, however, due to the presence of polymorphic functions and implicit conversions.
     311
     312Some 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.
     314This 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++}
     317template<typename T> T* malloc() { /* ... */ }
     318
     319int* 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}
     325forall(dtype T | sized(T)) T* malloc();
     326
     327int* p = malloc(); $\C{// Infers T = int from left-hand side}$
     328\end{cfa}
     329
     330Baker~\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.
     331This 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
     335The assertion satisfaction algorithm designed by Bilson~\cite{Bilson03} for the original \CFACC{} is the most-relevant prior work to this project.
     336Before 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}).
     337If this subexpression interpretation ends up not being used in the final resolution, then the (sometimes substantial) work of checking its assertions ends up wasted.
     338Bilson'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}
     341List(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
     365One 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.
     366Satisfying 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.
     367Nonetheless, 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
     369Another 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.
     370Monomorphic 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.
     371Thus, 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.
     372More 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.
     373As 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.
     374This 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
     376Making the conversion cost of an interpretation independent of the cost of satisfying its assertions has further benefits.
     377Bilson'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.
     378If 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.
     379In 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.
     380The experimental results in Chapter~\ref{expr-chap} indicate that this is a worthwhile trade-off.
     381
     382Optimizing 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}
     385sout | "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
     389The 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.
     390Secondly, 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}
     393forall( dtype ostype | ostream( ostype ) )
     394ostype& ?|? ( ostype&, int );
     395\end{cfa}
     396
     397Note 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.
     398On 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
     400To solve this problem, I have developed a \emph{cached} variant of assertion checking.
     401During the course of checking the assertions of a single top-level expression, the results are cached for each assertion checked.
     402The 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.
     403This adjusted assertion declaration is then run through the \CFA{} name-mangling algorithm to produce an equivalent string-type key.
     404
     405One superficially-promising optimization, which I did not pursue, is caching assertion-satisfaction judgments among top-level expressions.
     406This 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.
     407New 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.
     408Furthermore, 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.
     409Given 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
     411The 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.
     412For instance, Matsakis~\cite{Matsakis17} and the Rust team have developed a PROLOG-based engine to check satisfaction of Rust traits.
     413The 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.
     414Expressing 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.)
     416On the other hand, the deeply-recursive nature of the satisfiability problem makes it difficult to adapt to optimizing solver approaches such as linear programming.
     417To 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.
     418As 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
     422As 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.
     423This 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
     425I 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.
     426This approach is more flexible than type unification, allowing for conversions to be applied to functions to satisfy assertions.
     427Anecdotally, 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.
     428Practically, 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.
     429The 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
     431One \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.
     432An 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.}.
     433This would allow ascription casts to the desired return type to be used for overload selection:
     434
     435\begin{cfa}
     436int f$\(_1\)$(int);
     437int f$\(_2\)$(double);
     438int g$\(_1\)$(int);
     439double g$\(_2\)$(long);
     440
     441f((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
     446Though performance of the existing resolution algorithms is promising, some further optimizations do present themselves.
     447The 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.
     448Integer or vector operations on a more-packed representation may prove effective, though dealing with the negative-valued $specialization$ field may require some effort.
     449
     450Parallelization of various phases of expression resolution may also be useful.
     451The 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.
     452While the checks for mutual compatibility are naturally more serial, there may be some benefit to parallel resolution of the subproblem instances.
     453
     454The 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.
  • doc/theses/aaron_moss_PhD/phd/thesis.tex

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

    r6a9d4b4 r933f32f  
    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 being able 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 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.
     6Furthermore, 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.
     7In 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.
     8Chapter~\ref{expr-chap} contains empirical comparisons of the performance of these data structures when integrated into the resolution algorithm.
    89
    910\section{Definitions} \label{env-defn-sec}
    1011
    1112For purposes of this chapter, a \emph{type environment} $T$ is a set of \emph{type classes} $\myset{T_1, T_2, \cdots, T_{|T|}}$.
    12 Each 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.
    13 Each 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).
     13Each type class $T_i$ contains a set of \emph{type variables} $\myset{v_{i,1}, v_{i,2}, \cdots, v_{i,|T_i|}}$.
     14Since 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}.
     15Each 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
     17The following example demonstrates the use of a type environment for unification:
     18
     19\begin{cfa}
     20forall(otype F) F f(F, F);
     21forall(otype G) G g(G);
     22
     23f( g(10), g(20) );
     24\end{cfa}
     25
     26Expression resolution starts from an empty type environment; from this empty environment, the calls to !g! can be independently resolved.
     27These 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!).
     28To 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!.
     29To 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.
     30Since 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!$\}$.
    1431
    1532\begin{table}
     
    1835\centering
    1936\begin{tabular}{r@{\hskip 0.25em}ll}
    20         $find(T, v_{i,j})$ & $\rightarrow T_i | \bot$           & Locate class for variable             \\
     37        \hline
     38        $find(T, v_{i,j})$ & $\rightarrow T_i~|~\mathsf{fail}$          & Locate class for variable             \\
    2139        $report(T_i)$ & $\rightarrow \{ v_{i,j} \cdots \}$      & List variables for class              \\
    22         $bound(T_i)$ & $\rightarrow b_i | \bot$                         & Get bound for class                   \\
    23         $insert(v_{i,1})$ &                                                                     & New single-variable class             \\
     40        $bound(T_i)$ & $\rightarrow b_i~|~\mathsf{fail}$                                & Get bound for class                   \\
     41        $insert(T, v_{i,1})$ &                                                          & New single-variable class             \\
    2442        $add(T_i, v_{i,j})$ &                                                           & Add variable to class                 \\
    2543        $bind(T_i, b_i)$ &                                                                      & Set or update class bound             \\
    26         $unify(T, T_i, T_j)$ & $\rightarrow \top | \bot$        & Combine two type classes              \\
     44        \hline
     45        $unify(T, T_i, T_j)$ & $\rightarrow \mathsf{pass}~|~\mathsf{fail}$      & Combine two type classes              \\
    2746        $split(T, T_i)$ & $\rightarrow T'$                                      & Revert the last $unify$ operation on $T_i$            \\
    28         $combine(T, T')$ & $\rightarrow \top | \bot$            & Merge two environments                \\
     47        $combine(T, T')$ & $\rightarrow \mathsf{pass}~|~\mathsf{fail}$          & Merge two environments                \\
    2948        $save(T)$ & $\rightarrow H$                                                     & Get handle for current state  \\
    30         $backtrack(T, H)$ &                                                                     & Return to handle state
     49        $backtrack(T, H)$ &                                                                     & Return to handle state                \\
     50        \hline
    3151\end{tabular}
    3252\end{table}
    3353
    34 Given this basic structure, type environments in \CFACC{} need to support eleven basic operations, summarized in Table~\ref{env-op-table}.
    35 The first seven operations are straightforward queries and updates on these data structures:
    36 The 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.
     54Type environments in \CFACC{} need to support eleven basic operations, summarized in Table~\ref{env-op-table}.
     55The first six operations are straightforward queries and updates on these data structures:
     56The 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.
    3757The 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.
    3858
    39 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}$ cannot belong to any other type class in $T$.
     59The 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$.
    4060The $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$.
    4161$bind(T_i, b_i)$ mutates the bound for a type class, setting or updating the current bound.
    4262
    43 The $unify$ operation is the fundamental non-trivial operation a type environment data structure must support.
     63The $unify$ operation is the fundamental non-trivial operation a type-environment data-structure must support.
    4464$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.
    4565It 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.
    46 $unify$ depends on an internal $unifyBound$ operation which may fail.
    47 In \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.
     66$unify$ depends on an internal $unifyBound$ operation, which may fail.
     67In \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.
    4868If 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.
    49 For 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!.
     69For 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!.
    5070As 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.
    5171For more information on \CFA{} unification, see \cite{Bilson03}.
    52 The 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$.
    53 If 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 
    55 Given the nature of the expression resolution problem as backtracking search, caching and concurrency are both useful tools to decrease runtime.
     72The 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$.
     73If 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
     75Given the nature of the expression resolution problem as a backtracking search, caching and concurrency are both useful tools to decrease runtime.
    5676However, both of these approaches may produce multiple distinct descendants of the same initial type environment, which have possibly been mutated in incompatible ways.
    57 As 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.
    59 The 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.
     77As 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.
     79The invalid state of $T$ on failure is not important, given that a combination failure results in the resolution algorithm backtracking to a different environment.
    6080$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'$.
    6181Like $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.
     
    6484The 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$.
    6585As 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.
    66 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.
    67 
    68 \section{Approaches}
    69 
    70 \subsection{Na\"{\i}ve}
    71 
    72 The 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.
     86These 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
     92The 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.
    7393This 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.
    74 Some 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.
     94Some 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.
    7595These improvements do not change the fundamental issues with this data structure, however.
    7696
    77 \subsection{Incremental Inheritance}
    78 
    79 One 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.
     97\subsection{Incremental Inheritance} \label{inc-env-sec}
     98
     99One 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.
    80100This 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.
    81 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.
    82 
    83 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.
    84 Any 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.
     101Since 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
     103For 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.
     104Any 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.
    85105However, 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.
    86106
    87 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 diff, but is correct as long as the ``null parent'' base case is properly handled.
     107This 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.
    88108The 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.
    89 These 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.
     109These 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.
    90110
    91111\subsection{Union-Find} \label{env-union-find-approach}
    92112
    93 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}.
     113Given 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}.
    94114Union-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.
    95115The 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.
    96116$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.
    97117$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.
    98 If 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$.
     118If 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}.
    99119
    100120The 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.
    101 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.
    102 This issue can be solved by including a side map from class representatives to the type class bound.
    103 If 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.
     121In 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.
     122This issue can be solved by including a side map from class representatives to the type-class bound.
     123If 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.
    104124
    105125\subsection{Union-Find with Classes} \label{env-union-find-classes-approach}
     
    107127Another 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.
    108128Since 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.
    109 The 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.
    110 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.
    111 
    112 \TODO{port figure from slideshow}
     129The 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.
     130Unfortunately, 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.
    113131
    114132The 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.
     
    117135In my version, the list data structure does not affect the layout of the union-find tree, maintaining the same asymptotic bounds as union-find.
    118136In 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.
    119 When two classes are unified, the !next! pointers of the representatives of those classes are swapped, splicing the two circularly-linked lists together.
     137When 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}.
    120138Importantly, 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.
    121139The 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}
    122147
    123148If 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.
     
    127152
    128153\begin{theorem} \label{env-reverse-thm}
    129 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.
     154The !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.
    130155\end{theorem}
    131156
     
    133158        By induction on the height of the tree. \\
    134159        \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. \\
    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.
     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.
    136161\end{proof}
    137162
     
    139164
    140165\subsection{Persistent Union-Find}
    141 
    142 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 between environments are both assets to performance.
     166\label{env-persistent-union-find}
     167
     168Given 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.
    143169Conchon and Filli\^{a}tre~\cite{Conchon07} present a persistent union-find data structure based on the persistent array of Baker~\cite{Baker78,Baker91}.
    144170
    145 \TODO{port figure from slideshow}
    146 
    147 In 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.
    148 In this manner, a tree of edits is formed, rooted at the actual array.
    149 Read from the actual array at the root can be performed in constant time, as with a non-persistent array.
     171In 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.
     172By construction, these array references always point to a node more like the actual array, forming a tree of edits rooted at the actual array.
     173Reads from the actual array at the root can be performed in constant time, as with a non-persistent array.
    150174The 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. 
    151 The mutation algorithm at the root is in some sense a special case of the key operation on persistent arrays, $reroot$.
    152 
     175
     176The mutation algorithm at the root is a special case of the key operation on persistent arrays, $reroot$.
    153177A rerooting operation takes any array reference and makes it the root node of the array.
    154 This 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.
     178This 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.
    155179In 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.
    156 While $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.
     180While $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.
    157181Also, 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.
    158182Since 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.
    159183
    160184While 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.
    161 In particular, an arbitrary number of type variables must be added to the environment.
    162 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.
    163 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, and !Edit! mutates an existing key-value pair.
    164 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.
     185In particular, an arbitrary number of type variables may be added to the environment.
     186As 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.
     187Besides 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.
     188In 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.
    165189The 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.
    166 Making !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.
    167 The 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 
    169 Maintaining 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.
     190Figure~\ref{persistent-union-find-fig} demonstrates the structure of a simple example.
     191Making !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
     201This added semantic information on $union$ operations in the persistent union-find edit tree exposes a new option for combining type environments.
    170202If 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.
    171 This 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.
     203This 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.
     204However, 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.
    172205
    173206The procedure for $combine(T, T')$ based on edit paths is as follows:
    174207The 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.
    175208By 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.
    176 This procedure is repeated for both the class edit tree and the binding edit tree.
    177 When the list of net changes to the environment has been produced, the additive changes are applied to $T$.
    178 For 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.
    179 The 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''$.
    180 Where $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 
    184 In this section I present asymptotic analyses of the various approaches to a type environment data structure discussed in the previous section.
     209This procedure is repeated for both the class edit-tree and the binding edit-tree.
     210When the list of net changes to the environment is produced, the additive changes are applied to $T$.
     211For 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.
     212A 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
     217In this section, I present asymptotic analyses of the various approaches to the type environment data structure discussed in the previous section.
     218My 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.
    185220
    186221\begin{table}
     
    190225\begin{tabular}{rllll}
    191226        \hline
    192                                 & \textbf{Na\"{\i}ve}   & \textbf{Incremental}  & \textbf{Union-Find}           & \textbf{U-F with Classes}             \\
    193         \hline
    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)$                                                \\
     227                                & \textbf{Na\"{\i}ve} & \textbf{Incremental} & \textbf{Union-Find} & \textbf{Persistent U-F} \\
     228        \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)$                        \\
    205241        \hline
    206242\end{tabular}
    207243\end{table}
    208244
    209 % Future work: design multi-threaded version of C&F persistent map --- core idea is some sort of thread-boundary edit node
     245\subsection{Na\"{\i}ve and Incremental}
     246\label{naive-incremental-analysis}
     247
     248The 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.
     249As a result, every class's index must be consulted for a $find$ operation, at an overall cost of $O(n)$.
     250The 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)$.
     251It should be noted that subsequent queries for the same variable execute in constant time.
     252
     253Since 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)$.
     254Since the type classes store their bounds, $bound$ and $bind$ are both $O(1)$ given a type class.
     255Once 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)$.
     256Adding 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
     258The 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$.
     259The 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.
     260Since 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))$.
     261The 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))$.
     262Neither variant supports the $split$ operation to undo a $unify$.
     263
     264The 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)$.
     265The 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
     270The 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.
     271For 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)$.
     272Basic 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))$.
     273Persistent 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
     275All 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.
     277Since $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
     279Union-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$.
     280Basic 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.
     282Persistent union-find uses a different approach for $combine$, discussed in Section~\ref{env-persistent-union-find}.
     283Discounting 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))$.
     284Each 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
     286In terms of backtracking operations, the basic union-find data structure only supports deep copies, for $O(nm)$ cost for both $save$ and $backtrack$.
     287Persistent 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
     291This 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.
     292Chapter~\ref{expr-chap} provides experimental performance results for a representative set of these approaches.
     293One 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.
     294This 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}.
     295This 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
     297This 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.
     298However, 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.
     299This 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.
     300Alternatively, the concurrent hash trie of Prokopec \etal{} \cite{Prokopec11,Prokopec12} may be a useful hash-table replacement.
  • doc/user/user.tex

    r6a9d4b4 r933f32f  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Tue Dec 11 23:19:26 2018
    14 %% Update Count     : 3400
     13%% Last Modified On : Sun May  5 18:24:50 2019
     14%% Update Count     : 3489
    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
    195196
    196197\subsection{Background}
     
    432433which conditionally includes the correct header file, if the program is compiled using \Indexc{gcc} or \Indexc{cfa}.
    433434
     435The \CFA translator has multiple steps.
     436The following flags control how the tranlator works, the stages run, and printing within a stage.
     437The 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
    434507
    435508\section{Backquote Identifiers}
     
    508581
    509582As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
    510 Unsigned 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).
    511 Signed 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$.
    512 Hence, 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.
    513 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the base cannot be negative.
    514 \begin{cfa}
    515 sout | 2 ®\® 8u | 4 ®\® 3u | -4 ®\® 3u | 4 ®\® -3 | -4 ®\® -3 | 4.0 ®\® 2.1 | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
    516 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
    517 \end{cfa}
     583Integral 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).
     584Overflow from large exponents or negative exponents return zero.
     585Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
     586\begin{cfa}
     587sout | 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);
     5891 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
     590\end{cfa}
     591Note, ©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.
    518592Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©.
    519 The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation versions are available.
    520 For returning an integral value, the user type ©T© must define multiplication, ©*©, and one, ©1©;
    521 for returning a floating value, an additional divide of type ©T© into a ©double© returning a ©double© (©double ?/?( double, T )©) is necessary for negative exponents.
     593The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation version is available.
     594\begin{cfa}
     595forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } )
     596OT ?®\®?( OT ep, unsigned int y );
     597forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } )
     598OT ?®\®?( OT ep, unsigned long int y );
     599\end{cfa}
     600The user type ©T© must define multiplication, one, ©1©, and, ©*©.
    522601
    523602
     
    549628\subsection{Loop Control}
    550629
    551 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges.
     630The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
     631\begin{itemize}
     632\item
    552633An empty conditional implies ©1©.
    553 The up-to range ©~©\index{~@©~©} means exclusive range [M,N);
    554 the up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N].
    555 The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M);
    556 the down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M].
     634\item
     635The up-to range ©~©\index{~@©~©} means exclusive range [M,N).
     636\item
     637The up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N].
     638\item
     639The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M).
     640\item
     641The down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M].
     642\item
     643©@© means put nothing in this field.
     644\item
    557645©0© is the implicit start value;
     646\item
    558647©1© is the implicit increment value.
     648\item
    559649The up-to range uses ©+=© for increment;
    560 the down-to range uses ©-=© for decrement.
     650\item
     651The down-to range uses ©-=© for decrement.
     652\item
    561653The 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}
    562657\begin{cquote}
    563 \begin{tabular}{@{}ll|l@{}}
    564 \multicolumn{2}{c|}{loop control} & \multicolumn{1}{c}{output} \\
     658\begin{tabular}{@{}l|l@{}}
     659\multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\
    565660\hline
    566661\begin{cfa}
    567 while ®()® { sout | "empty"; break; }
    568 do { sout | "empty"; break; } while ®()®;
    569 for ®()® { sout | "empty"; break; }
    570 for ( ®0® ) { sout | "A"; }
    571 for ( ®1® ) { sout | "A"; }
    572 for ( ®10® ) { sout | "A"; }
    573 for ( ®1 ~= 10 ~ 2® ) { sout | "B"; }
    574 for ( ®10 -~= 1 ~ 2® ) { sout | "C"; }
    575 for ( ®0.5 ~ 5.5® ) { sout | "D"; }
    576 for ( ®5.5 -~ 0.5® ) { sout | "E"; }
    577 for ( ®i; 10® ) { sout | i; }
    578 for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; }
    579 for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; }
    580 for ( ®i; 0.5 ~ 5.5® ) { sout | i; }
    581 for ( ®i; 5.5 -~ 0.5® ) { sout | i; }
    582 for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; }
    583 for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; }
     662sout | nlOff;
     663while ®()® { sout | "empty"; break; } sout | nl;
     664do { sout | "empty"; break; } while ®()®; sout | nl;
     665for ®()® { sout | "empty"; break; } sout | nl;
     666for ( ®0® ) { sout | "A"; } sout | "zero" | nl;
     667for ( ®1® ) { sout | "A"; } sout | nl;
     668for ( ®10® ) { sout | "A"; } sout | nl;
     669for ( ®1 ~= 10 ~ 2® ) { sout | "B"; } sout | nl;
     670for ( ®10 -~= 1 ~ 2® ) { sout | "C"; } sout | nl;
     671for ( ®0.5 ~ 5.5® ) { sout | "D"; } sout | nl;
     672for ( ®5.5 -~ 0.5® ) { sout | "E"; } sout | nl;
     673for ( ®i; 10® ) { sout | i; } sout | nl;
     674for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; } sout | nl;
     675for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; } sout | nl;
     676for ( ®i; 0.5 ~ 5.5® ) { sout | i; } sout | nl;
     677for ( ®i; 5.5 -~ 0.5® ) { sout | i; } sout | nl;
     678for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; } sout | nl;
     679for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; } sout | nl;
    584680enum { N = 10 };
    585 for ( ®N® ) { sout | "N"; }
    586 for ( ®i; N® ) { sout | i; }
    587 for ( ®i; N -~ 0® ) { sout | i; }
     681for ( ®N® ) { sout | "N"; } sout | nl;
     682for ( ®i; N® ) { sout | i; } sout | nl;
     683for ( ®i; N -~ 0® ) { sout | i; } sout | nl;
    588684const int start = 3, comp = 10, inc = 2;
    589 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; }
     685for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } sout | nl;
     686for ( ®i; 1 ~ @® ) { if ( i > 10 ) break;
     687        sout | i; } sout | nl;
     688for ( ®i; 10 -~ @® ) { if ( i < 0 ) break;
     689        sout | i; } sout | nl;
     690for ( ®i; 2 ~ @ ~ 2® ) { if ( i > 10 ) break;
     691        sout | i; } sout | nl;
     692for ( ®i; 2.1 ~ @ ~ @® ) { if ( i > 10.5 ) break;
     693        sout | i; i += 1.7; } sout | nl;
     694for ( ®i; 10 -~ @ ~ 2® ) { if ( i < 0 ) break;
     695        sout | i; } sout | nl;
     696for ( ®i; 12.1 ~ @ ~ @® ) { if ( i < 2.5 ) break;
     697        sout | i; i -= 1.7; } sout | nl;
     698for ( ®i; 5 : j; -5 ~ @® ) { sout | i | j; } sout | nl;
     699for ( ®i; 5 : j; -5 -~ @® ) { sout | i | j; } sout | nl;
     700for ( ®i; 5 : j; -5 ~ @ ~ 2® ) { sout | i | j; } sout | nl;
     701for ( ®i; 5 : j; -5 -~ @ ~ 2® ) { sout | i | j; } sout | nl;
     702for ( ®j; -5 ~ @ : i; 5® ) { sout | i | j; } sout | nl;
     703for ( ®j; -5 -~ @ : i; 5® ) { sout | i | j; } sout | nl;
     704for ( ®j; -5 ~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl;
     705for ( ®j; -5 -~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl;
     706for ( ®j; -5 -~ @ ~ 2 : i; 5 : k; 1.5 ~ @® ) {
     707        sout | i | j | k; } sout | nl;
     708for ( ®j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 5® ) {
     709        sout | i | j | k; } sout | nl;
     710for ( ®k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 5® ) {
     711        sout | i | j | k; } sout | nl;
    590712\end{cfa}
    591713&
    592714\begin{cfa}
    593 sout | nl;
    594 sout | nl;
    595 sout | nl;
    596 sout | "zero" | nl;
    597 sout | nl;
    598 sout | nl;
    599 sout | nl;
    600 sout | nl;
    601 sout | nl;
    602 sout | nl;
    603 sout | nl;
    604 sout | nl;
    605 sout | nl;
    606 sout | nl;
    607 sout | nl;
    608 sout | nl;
    609 sout | nl | nl;
    610 
    611 sout | nl;
    612 sout | nl;
    613 sout | nl | nl;
    614 
    615 sout | nl;
    616 \end{cfa}
    617 &
    618 \begin{cfa}
     715
    619716empty
    620717empty
     
    640737
    6417383 6 9
     739
     7401 2 3 4 5 6 7 8 9 10
     741
     74210 9 8 7 6 5 4 3 2 1 0
     743
     7442 4 6 8 10
     745
     7462.1 3.8 5.5 7.2 8.9
     747
     74810 8 6 4 2 0
     749
     75012.1 10.4 8.7 7 5.3 3.6
     7510 -5 1 -4 2 -3 3 -2 4 -1
     7520 -5 1 -6 2 -7 3 -8 4 -9
     7530 -5 1 -3 2 -1 3 1 4 3
     7540 -5 1 -7 2 -9 3 -11 4 -13
     7550 -5 1 -4 2 -3 3 -2 4 -1
     7560 -5 1 -6 2 -7 3 -8 4 -9
     7570 -5 1 -3 2 -1 3 1 4 3
     7580 -5 1 -7 2 -9 3 -11 4 -13
     759
     7600 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     761
     7620 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     763
     7640 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    642765\end{cfa}
    643766\end{tabular}
    644767\end{cquote}
     768\caption{Loop Control Examples}
     769\label{f:LoopControlExamples}
     770\end{figure}
    645771
    646772
     
    13201446\end{cfa}
    13211447Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
    1322 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice.
     1448While 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}
     1450In 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}
    13231452
    13241453\CFA provides its own type, variable and routine declarations, using a different syntax.
  • driver/Makefile.am

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

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jan 15 20:56:03 2019
    13 // Update Count     : 280
     12// Last Modified On : Sun Feb 10 08:28:09 2019
     13// Update Count     : 281
    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 help = false;                                                                      // -help 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
    112113        bool CFA_flag = false;                                                          // -CFA flag
    113114        bool cpp_flag = false;                                                          // -E or -M flag, preprocessor only
     
    162163                                debug = true;                                                   // strip the debug flag
    163164                        } else if ( arg == "-nodebug" ) {
    164                                 debug = false;                                                  // strip the nodebug flag
     165                                debug = false;                                                  // strip the debug flag
     166                        } else if ( arg == "-nolib" ) {
     167                                nolib = true;                                                   // strip the nodebug flag
    165168                        } else if ( arg == "-quiet" ) {
    166169                                quiet = true;                                                   // strip the quiet flag
     
    366369                }  // if
    367370        } // if
    368         const char * config = debug ? "debug": "nodebug";
     371        const char * config = nolib ? "nolib" : (debug ? "debug": "nodebug");
    369372        string libdir = libbase + arch + "-" + config;
    370373
    371         if ( ! dirExists( libdir ) ) {
     374        if ( ! nolib && ! dirExists( libdir ) ) {
    372375                cerr << argv[0] << " internal error, configuration " << config << " not installed." << endl;
    373376                cerr << "Was looking for " << libdir << endl;
     
    495498                args[nargs] = "-Wno-deprecated";
    496499                nargs += 1;
     500#ifdef HAVE_CAST_FUNCTION_TYPE
     501                args[nargs] = "-Wno-cast-function-type";
     502                nargs += 1;
     503#endif // HAVE_CAST_FUNCTION_TYPE
    497504                if ( ! std_flag ) {                                                             // default c11, if none specified
    498505                        args[nargs] = "-std=gnu11";
  • libcfa/configure

    r6a9d4b4 r933f32f  
    23822382
    23832383
     2384# http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m4
     2385
    23842386
    23852387am__api_version='1.15'
     
    29572959case $CONFIGURATION in
    29582960        "debug"   )
    2959                 CONFIG_CFLAGS="-O0 -g"
     2961                CONFIG_CFLAGS="-Og -g"
    29602962                CONFIG_CFAFLAGS="-debug"
    29612963                CONFIG_BUILDLIB="yes"
    29622964        ;;
    29632965        "nodebug" )
    2964                 CONFIG_CFLAGS="-O2 -s"
     2966                CONFIG_CFLAGS="-O3 -s"
    29652967                CONFIG_CFAFLAGS="-nodebug"
    29662968                CONFIG_BUILDLIB="yes"
    29672969        ;;
    29682970        "nolib"   )
    2969                 CONFIG_CFLAGS="-O2 -s"
     2971                CONFIG_CFLAGS="-O3 -s"
     2972                CONFIG_CFAFLAGS="-nolib"
     2973                CONFIG_BUILDLIB="no"
     2974        ;;
     2975        "profile" )
     2976                CONFIG_CFLAGS="-O3 -g -fno-omit-frame-pointer"
    29702977                CONFIG_CFAFLAGS="-nodebug"
    2971                 CONFIG_BUILDLIB="no"
     2978                CONFIG_BUILDLIB="yes"
    29722979        ;;
    29732980        *)
     
    29752982        ;;
    29762983esac
     2984
     2985CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}"
    29772986
    29782987
  • libcfa/configure.ac

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Fri Jul 21 16:21:03 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Aug  5 21:40:38 2018
    13 // Update Count     : 20
     12// Last Modified On : Tue Mar 26 23:10:36 2019
     13// Update Count     : 95
    1414//
    1515
     
    4242typedef unsigned long long __cfaabi_abi_exception_type_t;
    4343
     44#include <limits.h>                                                                             // CHAR_BIT
    4445#include "../src/virtual.h"
    4546#include "../src/exception.h"
     
    5051// increment/decrement unification
    5152
    52 static inline forall( dtype T | { T& ?+=?( T&, one_t ); } )
    53 T& ++? ( T& x ) { return x += 1; }
     53static inline {
     54        forall( dtype DT | { DT & ?+=?( DT &, one_t ); } )
     55        DT & ++?( DT & x ) { return x += 1; }
    5456
    55 static inline forall( dtype T | sized(T) | { void ?{}( T&, T ); void ^?{}( T& ); T& ?+=?( T&, one_t ); } )
    56 T& ?++ ( T& x ) { T tmp = x; x += 1; return tmp; }
     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; }
    5759
    58 static inline forall( dtype T | { T& ?-=?( T&, one_t ); } )
    59 T& --? ( T& x ) { return x -= 1; }
     60        forall( dtype DT | { DT & ?-=?( DT &, one_t ); } )
     61        DT & --?( DT & x ) { return x -= 1; }
    6062
    61 static inline forall( dtype T | sized(T) | { void ?{}( T&, T ); void ^?{}( T& ); T& ?-=?( T&, one_t ); } )
    62 T& ?-- ( T& x ) { T tmp = x; x -= 1; return tmp; }
     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.
     69static inline forall( dtype DT | sized(DT) ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }
    6370
    6471// exponentiation operator implementation
     
    7380} // extern "C"
    7481
    75 static inline float ?\?( float x, float y ) { return powf( x, y ); }
    76 static inline double ?\?( double x, double y ) { return pow( x, y ); }
    77 static inline long double ?\?( long double x, long double y ) { return powl( x, y ); }
    78 static inline float _Complex ?\?( float _Complex x, _Complex float y ) { return cpowf(x, y ); }
    79 static inline double _Complex ?\?( double _Complex x, _Complex double y ) { return cpow( x, y ); }
    80 static inline long double _Complex ?\?( long double _Complex x, _Complex long double y ) { return cpowl( x, y ); }
     82static 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
    8190
    82 static 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 } // ?\?
     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
    9294
    93 static inline forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } )
    94 T ?\?( 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 } // ?\?
     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
    103106
    104 // unsigned computation may be faster and larger
    105 static 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 } // ?\?
     107static 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
    115114
    116 static 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 } // ?\?
     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__()
    120121
    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.
     122static 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
    125126
    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 // } // ?\?
     127#undef __CFA_BASE_COMP_1__
     128#undef __CFA_BASE_COMP_2__
     129#undef __CFA_EXP_OVERFLOW__
    131130
    132 static inline long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
    133 static inline unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
    134 static inline int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; }
    135 static inline unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
     131static 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
    136137
    137138// Local Variables: //
  • libcfa/prelude/extras.c

    r6a9d4b4 r933f32f  
    1 #include <stddef.h>                                     // size_t, ptrdiff_t
     1#include <stddef.h>                                     // size_t, ptrdiff_t, intptr_t, uintptr_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

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

    r6a9d4b4 r933f32f  
     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
    116#include <algorithm>
    217#include <array>
     
    1126        bool hasComparison;
    1227} basicTypes[] = {
    13         // { "char"                  , false, true , },
    14         // { "signed char"           , false, true , },
    15         // { "unsigned char"         , false, true , },
     28        { "char"                  , false, true , },
     29        { "signed char"           , false, true , },
     30        { "unsigned char"         , false, true , },
    1631        { "signed short"          , false, true , },
    1732        { "unsigned short"        , false, true , },
     
    3449#if defined(__i386__) || defined(__ia64__) || defined(__x86_64__)
    3550        { "__float80"             , true , true , },
    36         { "_Float128"             , true , true , },
     51        { "__float128"            , true , true , },
    3752#endif
    3853};
     
    103118        { "?!=?", false, "signed int", Normal, "" },
    104119        { "?=?", true, "", Normal, "" }, // void * LHS, zero_t RHS ???
    105         { "*?", false, "&", Normal, " | sized(DT)" }, // & ???
     120//      { "*?", false, "&", Normal, " | sized(DT)" }, // & ???
     121        { "*?", false, "&", Normal, "" }, // & ???
    106122
    107123        { "?-?", false, "ptrdiff_t", Normal, " | sized(DT)" },
     
    150166        cout << endl;
    151167
    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;
     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;
    156172
    157173        for (auto op : arithmeticOperators) {
     
    188204        cout << "// Arithmetic Constructors //" << endl;
    189205        cout << "/////////////////////////////" << endl;
     206        cout << endl;
     207
    190208        auto otype = [](const std::string & type, bool do_volatile = false) {
    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 << " )";
     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 << ")";
    196214                }
    197215                cout << ";" << endl;
    198                 cout << "void \t^?{}( " << type << " & );" << endl;
     216                cout << "void ^?{}( " << type << " & );" << endl;
    199217        };
    200218
    201219        otype("zero_t");
     220        cout << endl;
    202221        otype("one_t");
     222        cout << endl;
    203223        otype("_Bool", true);
    204         otype("char", true);
    205         otype("signed char", true);
    206         otype("unsigned char", true);
     224        cout << endl;
    207225
    208226        for (auto type : basicTypes) {
    209                 cout << "void  ?{}(" << type.name << " &);" << endl;
    210                 cout << "void  ?{}(" << type.name << " &, " << type.name << ");" << endl;
     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;
    211231                cout << "void ^?{}(" << type.name << " &);" << endl;
    212232                cout << endl;
     
    217237        cout << "// Pointer Constructors //" << endl;
    218238        cout << "//////////////////////////" << endl;
    219         cout << "forall(ftype FT) void  ?{}( FT *&, FT * );" << endl;
    220         cout << "forall(ftype FT) void  ?{}( FT * volatile &, FT * );" << endl;
     239        cout << endl;
     240
     241        cout << "forall(ftype FT) void ?{}( FT *&, FT * );" << endl;
     242        cout << "forall(ftype FT) void ?{}( FT * volatile &, FT * );" << endl;
    221243
    222244        // generate qualifiers
     
    242264                for (auto cvq : qualifiersPair) {
    243265                        for (auto is_vol : { "        ", "volatile" }) {
    244                                 cout << "forall(dtype DT) void  ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl;
     266                                cout << "forall(dtype DT) void ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl;
    245267                        }
    246268                }
    247269                for (auto cvq : qualifiersSingle) {
    248270                        for (auto is_vol : { "        ", "volatile" }) {
    249                                 cout << "forall(dtype DT) void  ?{}(" << cvq << type << " * " << is_vol << " &);" << endl;
     271                                cout << "forall(dtype DT) void ?{}(" << cvq << type << " * " << is_vol << " &);" << endl;
    250272                        }
    251273                        for (auto is_vol : { "        ", "volatile" }) {
     
    269291        cout << "forall(ftype FT) FT *                  ?=?( FT *          &, zero_t );" << endl;
    270292        cout << "forall(ftype FT) FT *                  ?=?( FT * volatile &, zero_t );" << endl;
    271         cout << "forall( ftype FT ) void        ?{}( FT *          & );" << endl;
    272         cout << "forall( ftype FT ) void        ^?{}( FT *         & );" << endl;
     293        cout << "forall(ftype FT) void  ?{}( FT *          & );" << endl;
     294        cout << "forall(ftype FT) void  ^?{}( FT *         & );" << endl;
    273295        cout << endl;
    274296
     
    277299        cout << "///////////////////////" << endl;
    278300
    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 
     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;
    286307
    287308        for (auto op : pointerOperators) {
     
    387408}
    388409
     410// Local Variables: //
     411// tab-width: 4 //
     412// End: //
  • libcfa/prelude/sync-builtins.cf

    r6a9d4b4 r933f32f  
    323323_Bool __sync_bool_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    324324#endif
     325forall(dtype T) _Bool __sync_bool_compare_and_swap(T * volatile *, T *, T*, ...);
    325326
    326327char __sync_val_compare_and_swap(volatile char *, char, char,...);
     
    348349unsigned __int128 __sync_val_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    349350#endif
     351forall(dtype T) T * __sync_val_compare_and_swap(T * volatile *, T *, T*,...);
    350352
    351353char __sync_lock_test_and_set(volatile char *, char,...);
     
    434436#endif
    435437
    436 char __atomic_exchange_n(volatile char *, volatile char *, int);
     438char __atomic_exchange_n(volatile char *, char, int);
    437439char __atomic_exchange_1(volatile char *, char, int);
    438440void __atomic_exchange(volatile char *, volatile char *, volatile char *, int);
    439 signed char __atomic_exchange_n(volatile signed char *, volatile signed char *, int);
     441signed char __atomic_exchange_n(volatile signed char *, signed char, int);
    440442signed char __atomic_exchange_1(volatile signed char *, signed char, int);
    441443void __atomic_exchange(volatile signed char *, volatile signed char *, volatile signed char *, int);
    442 unsigned char __atomic_exchange_n(volatile unsigned char *, volatile unsigned char *, int);
     444unsigned char __atomic_exchange_n(volatile unsigned char *, unsigned char, int);
    443445unsigned char __atomic_exchange_1(volatile unsigned char *, unsigned char, int);
    444446void __atomic_exchange(volatile unsigned char *, volatile unsigned char *, volatile unsigned char *, int);
    445 signed short __atomic_exchange_n(volatile signed short *, volatile signed short *, int);
     447signed short __atomic_exchange_n(volatile signed short *, signed short, int);
    446448signed short __atomic_exchange_2(volatile signed short *, signed short, int);
    447449void __atomic_exchange(volatile signed short *, volatile signed short *, volatile signed short *, int);
    448 unsigned short __atomic_exchange_n(volatile unsigned short *, volatile unsigned short *, int);
     450unsigned short __atomic_exchange_n(volatile unsigned short *, unsigned short, int);
    449451unsigned short __atomic_exchange_2(volatile unsigned short *, unsigned short, int);
    450452void __atomic_exchange(volatile unsigned short *, volatile unsigned short *, volatile unsigned short *, int);
    451 signed int __atomic_exchange_n(volatile signed int *, volatile signed int *, int);
     453signed int __atomic_exchange_n(volatile signed int *, signed int, int);
    452454signed int __atomic_exchange_4(volatile signed int *, signed int, int);
    453455void __atomic_exchange(volatile signed int *, volatile signed int *, volatile signed int *, int);
    454 unsigned int __atomic_exchange_n(volatile unsigned int *, volatile unsigned int *, int);
     456unsigned int __atomic_exchange_n(volatile unsigned int *, unsigned int, int);
    455457unsigned int __atomic_exchange_4(volatile unsigned int *, unsigned int, int);
    456458void __atomic_exchange(volatile unsigned int *, volatile unsigned int *, volatile unsigned int *, int);
    457 signed long long int __atomic_exchange_n(volatile signed long long int *, volatile signed long long int *, int);
     459signed long long int __atomic_exchange_n(volatile signed long long int *, signed long long int, int);
    458460signed long long int __atomic_exchange_8(volatile signed long long int *, signed long long int, int);
    459461void __atomic_exchange(volatile signed long long int *, volatile signed long long int *, volatile signed long long int *, int);
    460 unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, volatile unsigned long long int *, int);
     462unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, unsigned long long int, int);
    461463unsigned long long int __atomic_exchange_8(volatile unsigned long long int *, unsigned long long int, int);
    462464void __atomic_exchange(volatile unsigned long long int *, volatile unsigned long long int *, volatile unsigned long long int *, int);
    463465#if defined(__SIZEOF_INT128__)
    464 signed __int128 __atomic_exchange_n(volatile signed __int128 *, volatile signed __int128 *, int);
     466signed __int128 __atomic_exchange_n(volatile signed __int128 *, signed __int128, int);
    465467signed __int128 __atomic_exchange_16(volatile signed __int128 *, signed __int128, int);
    466468void __atomic_exchange(volatile signed __int128 *, volatile signed __int128 *, volatile signed __int128 *, int);
    467 unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, volatile unsigned __int128 *, int);
     469unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, unsigned __int128, int);
    468470unsigned __int128 __atomic_exchange_16(volatile unsigned __int128 *, unsigned __int128, int);
    469471void __atomic_exchange(volatile unsigned __int128 *, volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    470472#endif
     473forall(dtype T) T * __atomic_exchange_n(T * volatile *, T *, int);
     474forall(dtype T) void __atomic_exchange(T * volatile *, T * volatile *, T * volatile *, int);
    471475
    472476_Bool __atomic_load_n(const volatile _Bool *, int);
     
    507511void __atomic_load(const volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    508512#endif
     513forall(dtype T) T * __atomic_load_n(T * const volatile *, int);
     514forall(dtype T) void __atomic_load(T * const volatile *, T **, int);
    509515
    510516_Bool __atomic_compare_exchange_n(volatile char *, char *, char, _Bool, int, int);
     
    543549_Bool __atomic_compare_exchange   (volatile unsigned __int128 *, unsigned __int128 *, unsigned __int128 *, _Bool, int, int);
    544550#endif
     551forall(dtype T) _Bool __atomic_compare_exchange_n (T * volatile *, T **, T*, _Bool, int, int);
     552forall(dtype T) _Bool __atomic_compare_exchange   (T * volatile *, T **, T**, _Bool, int, int);
    545553
    546554void __atomic_store_n(volatile _Bool *, _Bool, int);
     
    581589void __atomic_store(volatile unsigned __int128 *, unsigned __int128 *, int);
    582590#endif
     591forall(dtype T) void __atomic_store_n(T * volatile *, T *, int);
     592forall(dtype T) void __atomic_store(T * volatile *, T **, int);
    583593
    584594char __atomic_add_fetch  (volatile char *, char, int);
  • libcfa/src/Makefile.am

    r6a9d4b4 r933f32f  
    7474
    7575prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    76         ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
     76        ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -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         @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
     80        $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
    8181
    8282
  • libcfa/src/Makefile.in

    r6a9d4b4 r933f32f  
    926926
    927927prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    928         ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
     928        ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -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         @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
     932        $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
    933933
    934934#----------------------------------------------------------------------------------------------------------------
  • libcfa/src/bits/containers.hfa

    r6a9d4b4 r933f32f  
    186186
    187187        forall(dtype T | is_node(T))
    188         static inline bool ?!=?( __queue(T) & this, zero_t zero ) {
     188        static inline bool ?!=?( __queue(T) & this, __attribute__((unused)) zero_t zero ) {
    189189                return this.head != 0;
    190190        }
     
    196196//-----------------------------------------------------------------------------
    197197#ifdef __cforall
    198         forall(dtype TYPE | sized(TYPE))
     198        forall(dtype 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, zero_t zero ) {
     270        static inline bool ?!=?( __dllist(T) & this, __attribute__((unused)) zero_t zero ) {
    271271                return this.head != 0;
    272272        }
  • libcfa/src/concurrency/CtxSwitch-i386.S

    r6a9d4b4 r933f32f  
    4141#define PC_OFFSET       ( 2 * PTR_BYTE )
    4242
    43 .text
     43        .text
    4444        .align 2
    45 .globl  CtxSwitch
     45        .globl CtxSwitch
     46        .type  CtxSwitch, @function
    4647CtxSwitch:
    4748
     
    5051
    5152        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
    5853
    5954        // Save volatile registers on the stack.
     
    6762        movl %esp,SP_OFFSET(%eax)
    6863        movl %ebp,FP_OFFSET(%eax)
    69 //      movl 4(%ebp),%ebx       // save previous eip for debugger
    70 //      movl %ebx,PC_OFFSET(%eax)
    7164
    7265        // Copy the "to" context argument from the stack to register eax
     
    7467        // argument is now at 8 + 12 = 20(%esp)
    7568
    76         movl 28(%esp),%eax
     69        movl 20(%esp),%eax
    7770
    7871        // Load new context from the "to" area.
     
    8780        popl %ebx
    8881
    89         // Load floating & SSE control words from the stack.
    90 
    91         fldcw   4(%esp)
    92         ldmxcsr 0(%esp)
    93         add    $8,%esp
    94 
    9582        // Return to thread.
    9683
    9784        ret
     85        .size  CtxSwitch, .-CtxSwitch
    9886
    9987// Local Variables: //
  • libcfa/src/concurrency/CtxSwitch-x86_64.S

    r6a9d4b4 r933f32f  
    3939#define SP_OFFSET       ( 0 * PTR_BYTE )
    4040#define FP_OFFSET       ( 1 * PTR_BYTE )
    41 #define PC_OFFSET       ( 2 * PTR_BYTE )
    4241
    43 .text
     42//-----------------------------------------------------------------------------
     43// Regular context switch routine which enables switching from one context to anouther
     44        .text
    4445        .align 2
    45 .globl  CtxSwitch
     46        .globl CtxSwitch
     47        .type  CtxSwitch, @function
    4648CtxSwitch:
    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
    5349
    5450        // Save volatile registers on the stack.
     
    7874        popq %r15
    7975
    80         // Load floating & SSE control words from the stack.
    81 
    82         fldcw   4(%rsp)
    83         ldmxcsr 0(%rsp)
    84         addq   $8,%rsp
    85 
    8676        // Return to thread.
    8777
    8878        ret
     79        .size  CtxSwitch, .-CtxSwitch
    8980
    90 .text
     81//-----------------------------------------------------------------------------
     82// Stub used to create new stacks which are ready to be context switched to
     83        .text
    9184        .align 2
    92 .globl  CtxInvokeStub
     85        .globl CtxInvokeStub
     86        .type    CtxInvokeStub, @function
    9387CtxInvokeStub:
    9488        movq %rbx, %rdi
    9589        jmp *%r12
     90        .size  CtxInvokeStub, .-CtxInvokeStub
    9691
    9792// Local Variables: //
  • libcfa/src/concurrency/coroutine.cfa

    r6a9d4b4 r933f32f  
    3535
    3636extern "C" {
    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       }
     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__));
    4244}
    4345
     
    4749// minimum feasible stack size in bytes
    4850#define MinStackSize 1000
    49 static size_t pageSize = 0;                             // architecture pagesize HACK, should go in proper runtime singleton
     51extern size_t __page_size;                              // architecture pagesize HACK, should go in proper runtime singleton
     52
     53void __stack_prepare( __stack_info_t * this, size_t create_size );
    5054
    5155//-----------------------------------------------------------------------------
    5256// Coroutine ctors and dtors
    53 void ?{}( 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 
    63 void ^?{}(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       }
     57void ?{}( __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
     71void ^?{}(__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        }
    7287}
    7388
    7489void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) {
    75       (this.stack){storage, storageSize};
    76       this.name = name;
    77       errno_ = 0;
    78       state = Start;
    79       starter = NULL;
    80       last = NULL;
    81       cancellation = NULL;
     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;
    8297}
    8398
    8499void ^?{}(coroutine_desc& this) {
    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       }
     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        }
    102117}
    103118
     
    106121forall(dtype T | is_coroutine(T))
    107122void prime(T& cor) {
    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
    116 void 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 
    144 void 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;
     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
     156void __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;
    190182}
    191183
     
    193185// is not inline (We can't inline Cforall in C)
    194186extern "C" {
    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       }
     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        }
    216207}
    217208
  • libcfa/src/concurrency/coroutine.hfa

    r6a9d4b4 r933f32f  
    4646//-----------------------------------------------------------------------------
    4747// Public coroutine API
    48 static inline void suspend();
     48static inline void suspend(void);
    4949
    5050forall(dtype T | is_coroutine(T))
    51 static inline void resume(T & cor);
     51static inline T & 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");
    6670}
    6771
    6872// Private wrappers for context switch and stack creation
    69 extern void CoroutineCtxSwitch(coroutine_desc * src, coroutine_desc * dst);
    70 extern void create_stack( coStack_t * this, unsigned int storageSize );
     73// Wrapper for co
     74static 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
     94extern void __stack_prepare   ( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
    7195
    7296// Suspend implementation inlined for performance
    73 static inline void suspend() {
     97static inline void suspend(void) {
    7498        // optimization : read TLS once and reuse it
    7599        // Safety note: this is preemption safe since if
     
    77101        // will also migrate which means this value will
    78102        // stay in syn with the TLS
    79         coroutine_desc * src = TL_GET( this_coroutine );
     103        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    80104
    81105        assertf( src->last != 0,
     
    93117// Resume implementation inlined for performance
    94118forall(dtype T | is_coroutine(T))
    95 static inline void resume(T & cor) {
     119static inline T & resume(T & cor) {
    96120        // optimization : read TLS once and reuse it
    97121        // Safety note: this is preemption safe since if
     
    99123        // will also migrate which means this value will
    100124        // stay in syn with the TLS
    101         coroutine_desc * src = TL_GET( this_coroutine );
     125        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    102126        coroutine_desc * dst = get_coroutine(cor);
    103127
    104         if( unlikely(!dst->stack.base) ) {
    105                 create_stack(&dst->stack, dst->stack.size);
     128        if( unlikely(dst->context.SP == NULL) ) {
     129                __stack_prepare(&dst->stack, 65000);
    106130                CtxStart(&cor, CtxInvokeCoroutine);
    107131        }
     
    121145        // always done for performance testing
    122146        CoroutineCtxSwitch( src, dst );
     147
     148        return cor;
    123149}
    124150
     
    129155        // will also migrate which means this value will
    130156        // stay in syn with the TLS
    131         coroutine_desc * src = TL_GET( this_coroutine );
     157        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    132158
    133159        // not resuming self ?
  • libcfa/src/concurrency/invoke.c

    r6a9d4b4 r933f32f  
    2828
    2929extern void __suspend_internal(void);
    30 extern void __leave_coroutine(void);
    31 extern void __finish_creation(void);
     30extern void __leave_coroutine( struct coroutine_desc * );
     31extern void __finish_creation( struct thread_desc * );
    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 
    5149        main( this );
    5250
    5351        //Final suspend, should never return
    54         __leave_coroutine();
     52        __leave_coroutine( cor );
    5553        __cabi_abort( "Resumed dead coroutine" );
    5654}
     
    6260        __attribute((__unused__)) struct _Unwind_Exception * unwind_exception,
    6361        __attribute((__unused__)) struct _Unwind_Context * context,
    64         __attribute((__unused__)) void * param
     62        void * param
    6563) {
    6664        if( actions & _UA_END_OF_STACK  ) {
    6765                // We finished unwinding the coroutine,
    6866                // leave it
    69                 __leave_coroutine();
     67                __leave_coroutine( param );
    7068                __cabi_abort( "Resumed dead coroutine" );
    7169        }
     
    7573}
    7674
    77 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) __attribute__ ((__noreturn__));
    78 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) {
    79         _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, NULL );
     75void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) __attribute__ ((__noreturn__));
     76void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) {
     77        _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, cor );
    8078        printf("UNWIND ERROR %d after force unwind\n", ret);
    8179        abort();
     
    8886        void *this
    8987) {
     88        // Fetch the thread handle from the user defined thread structure
     89        struct thread_desc* thrd = get_thread( this );
     90
    9091        // First suspend, once the thread arrives here,
    9192        // the function pointer to main can be invalidated without risk
    92         __finish_creation();
    93 
    94         // Fetch the thread handle from the user defined thread structure
    95         struct thread_desc* thrd = get_thread( this );
    96         thrd->self_cor.last = NULL;
     93        __finish_creation( thrd );
    9794
    9895        // Officially start the thread by enabling preemption
     
    120117        void (*invoke)(void *)
    121118) {
    122         struct coStack_t* stack = &get_coroutine( this )->stack;
     119        struct coroutine_desc * cor = get_coroutine( this );
     120        struct __stack_t * stack = cor->stack.storage;
    123121
    124122#if defined( __i386 )
    125123
    126124        struct FakeStack {
    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)
     125            void *fixedRegisters[3];              // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant)
    130126            void *rturn;                          // where to go on return from uSwitch
    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
     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
    134130        };
    135131
    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
     132        cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );
     133        cor->context.FP = NULL;         // terminate stack with NULL fp
    138134
    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
     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;
    144140
    145141#elif defined( __x86_64 )
     
    147143        struct FakeStack {
    148144                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)
    151145                void *rturn;                        // where to go on return from uSwitch
    152146                void *dummyReturn;                  // NULL return address to provide proper alignment
    153147        };
    154148
    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
     149        cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );
     150        cor->context.FP = NULL;         // terminate stack with NULL fp
    157151
    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
     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;
    164158
    165159#elif defined( __ARM_ARCH )
     
    171165        };
    172166
    173         ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );
    174         ((struct machine_context_t *)stack->context)->FP = NULL;
     167        cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );
     168        cor->context.FP = NULL;
    175169
    176         struct FakeStack *fs = (struct FakeStack *)((struct machine_context_t *)stack->context)->SP;
     170        struct FakeStack *fs = (struct FakeStack *)cor->context.SP;
    177171
    178172        fs->intRegs[8] = CtxInvokeStub;
  • libcfa/src/concurrency/invoke.h

    r6a9d4b4 r933f32f  
    5050
    5151                extern thread_local struct KernelThreadData {
    52                         struct coroutine_desc * volatile this_coroutine;
    5352                        struct thread_desc    * volatile this_thread;
    5453                        struct processor      * volatile this_processor;
     
    6160                } kernelTLS __attribute__ ((tls_model ( "initial-exec" )));
    6261        }
    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
    6762        #endif
    6863
    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
     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;
    7793        };
    7894
     
    8096
    8197        struct coroutine_desc {
     98                // context that is switch during a CtxSwitch
     99                struct __stack_context_t context;
     100
    82101                // stack information of the coroutine
    83                 struct coStack_t stack;
    84 
    85                 // textual name for coroutine/task, initialized by uC++ generated code
     102                struct __stack_info_t stack;
     103
     104                // textual name for coroutine/task
    86105                const char * name;
    87 
    88                 // copy of global UNIX variable errno
    89                 int errno_;
    90106
    91107                // current execution status for coroutine
    92108                enum coroutine_state state;
     109
    93110                // first coroutine to resume this one
    94111                struct coroutine_desc * starter;
     
    144161        struct thread_desc {
    145162                // 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
    146171                // coroutine body used to store context
    147172                struct coroutine_desc  self_cor;
     
    170195                        struct thread_desc * prev;
    171196                } node;
    172      };
    173 
    174      #ifdef __cforall
    175      extern "Cforall" {
     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
    176205                static inline thread_desc * & get_next( thread_desc & this ) {
    177206                        return this.next;
     
    231260        // assembler routines that performs the context switch
    232261        extern void CtxInvokeStub( void );
    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
     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");
    253265
    254266#endif //_INVOKE_PRIVATE_H_
  • libcfa/src/concurrency/kernel.cfa

    r6a9d4b4 r933f32f  
    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//-----------------------------------------------------------------------------
    38107//Start and stop routine for the kernel, declared first to make sure they run first
    39108static void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
     
    42111//-----------------------------------------------------------------------------
    43112// Kernel storage
    44 KERNEL_STORAGE(cluster,           mainCluster);
    45 KERNEL_STORAGE(processor,         mainProcessor);
    46 KERNEL_STORAGE(thread_desc,       mainThread);
    47 KERNEL_STORAGE(machine_context_t, mainThreadCtx);
     113KERNEL_STORAGE(cluster,         mainCluster);
     114KERNEL_STORAGE(processor,       mainProcessor);
     115KERNEL_STORAGE(thread_desc,     mainThread);
     116KERNEL_STORAGE(__stack_t,       mainThreadCtx);
    48117
    49118cluster     * mainCluster;
     
    54123struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
    55124}
     125
     126size_t __page_size = 0;
    56127
    57128//-----------------------------------------------------------------------------
     
    60131        NULL,
    61132        NULL,
    62         NULL,
    63133        { 1, false, false }
    64134};
     
    67137// Struct to steal stack
    68138struct current_stack_info_t {
    69         machine_context_t ctx;
    70         unsigned int size;              // size of stack
     139        __stack_t * storage;            // pointer to stack object
    71140        void *base;                             // base of stack
    72         void *storage;                  // pointer to stack
    73141        void *limit;                    // stack grows towards stack limit
    74142        void *context;                  // address of cfa_context_t
    75         void *top;                              // address of top of storage
    76143};
    77144
    78145void ?{}( current_stack_info_t & this ) {
    79         CtxGet( this.ctx );
    80         this.base = this.ctx.FP;
    81         this.storage = this.ctx.SP;
     146        __stack_context_t ctx;
     147        CtxGet( ctx );
     148        this.base = ctx.FP;
    82149
    83150        rlimit r;
    84151        getrlimit( RLIMIT_STACK, &r);
    85         this.size = r.rlim_cur;
    86 
    87         this.limit = (void *)(((intptr_t)this.base) - this.size);
     152        size_t size = r.rlim_cur;
     153
     154        this.limit = (void *)(((intptr_t)this.base) - size);
    88155        this.context = &storage_mainThreadCtx;
    89         this.top = this.base;
    90156}
    91157
    92158//-----------------------------------------------------------------------------
    93159// Main thread construction
    94 void ?{}( 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 }
    103160
    104161void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) {
    105         stack{ info };
     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;
    106169        name = "Main Thread";
    107         errno_ = 0;
    108170        state = Start;
    109171        starter = NULL;
     172        last = NULL;
     173        cancellation = NULL;
    110174}
    111175
    112176void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) {
     177        state = Start;
    113178        self_cor{ info };
    114179        curr_cor = &self_cor;
     
    241306}
    242307
     308static int * __volatile_errno() __attribute__((noinline));
     309static int * __volatile_errno() { asm(""); return &errno; }
     310
    243311// KERNEL ONLY
    244312// runThread runs a thread by context switching
    245313// from the processor coroutine to the target thread
    246 static void runThread(processor * this, thread_desc * dst) {
    247         assert(dst->curr_cor);
     314static void runThread(processor * this, thread_desc * thrd_dst) {
    248315        coroutine_desc * proc_cor = get_coroutine(this->runner);
    249         coroutine_desc * thrd_cor = dst->curr_cor;
    250316
    251317        // Reset the terminating actions here
     
    253319
    254320        // Update global state
    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
     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;
    260335}
    261336
     
    263338static void returnToKernel() {
    264339        coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
    265         coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine;
    266         ThreadCtxSwitch(thrd_cor, proc_cor);
     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;
    267363}
    268364
     
    307403        processor * proc = (processor *) arg;
    308404        kernelTLS.this_processor = proc;
    309         kernelTLS.this_coroutine = NULL;
    310405        kernelTLS.this_thread    = NULL;
    311406        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
     
    314409        // to waste the perfectly valid stack create by pthread.
    315410        current_stack_info_t info;
    316         machine_context_t ctx;
    317         info.context = &ctx;
     411        __stack_t ctx;
     412        info.storage = &ctx;
    318413        (proc->runner){ proc, &info };
    319414
    320         __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.base);
     415        __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
    321416
    322417        //Set global state
    323         kernelTLS.this_coroutine = get_coroutine(proc->runner);
    324418        kernelTLS.this_thread    = NULL;
    325419
     
    350444
    351445// KERNEL_ONLY
    352 void kernel_first_resume(processor * this) {
    353         coroutine_desc * src = kernelTLS.this_coroutine;
     446void kernel_first_resume( processor * this ) {
     447        thread_desc * src = mainThread;
    354448        coroutine_desc * dst = get_coroutine(this->runner);
    355449
    356450        verify( ! kernelTLS.preemption_state.enabled );
    357451
    358         create_stack(&dst->stack, dst->stack.size);
     452        __stack_prepare( &dst->stack, 65000 );
    359453        CtxStart(&this->runner, CtxInvokeCoroutine);
    360454
    361455        verify( ! kernelTLS.preemption_state.enabled );
    362456
    363         dst->last = src;
    364         dst->starter = dst->starter ? dst->starter : src;
     457        dst->last = &src->self_cor;
     458        dst->starter = dst->starter ? dst->starter : &src->self_cor;
    365459
    366460        // set state of current coroutine to inactive
    367461        src->state = src->state == Halted ? Halted : Inactive;
    368462
    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 
    379463        // context switch to specified coroutine
    380         assert( src->stack.context );
    381         CtxSwitch( src->stack.context, dst->stack.context );
     464        verify( dst->context.SP );
     465        CtxSwitch( &src->context, &dst->context );
    382466        // when CtxSwitch returns we are back in the src coroutine
    383467
     
    386470
    387471        verify( ! kernelTLS.preemption_state.enabled );
     472}
     473
     474// KERNEL_ONLY
     475void 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 );
    388485}
    389486
     
    394491void ScheduleThread( thread_desc * thrd ) {
    395492        verify( thrd );
    396         verify( thrd->self_cor.state != Halted );
     493        verify( thrd->state != Halted );
    397494
    398495        verify( ! kernelTLS.preemption_state.enabled );
     
    551648        __cfaabi_dbg_print_safe("Kernel : Starting\n");
    552649
     650        __page_size = sysconf( _SC_PAGESIZE );
     651
    553652        __cfa_dbg_global_clusters.list{ __get };
    554653        __cfa_dbg_global_clusters.lock{};
     
    565664        mainThread = (thread_desc *)&storage_mainThread;
    566665        current_stack_info_t info;
     666        info.storage = (__stack_t*)&storage_mainThreadCtx;
    567667        (*mainThread){ &info };
    568668
     
    599699        kernelTLS.this_processor = mainProcessor;
    600700        kernelTLS.this_thread    = mainThread;
    601         kernelTLS.this_coroutine = &mainThread->self_cor;
    602701
    603702        // Enable preemption
     
    634733        // which is currently here
    635734        __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);
    636         returnToKernel();
     735        kernel_last_resume( kernelTLS.this_processor );
    637736        mainThread->self_cor.state = Halted;
    638737
     
    720819                __cfaabi_dbg_bits_write( abort_text, len );
    721820
    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 );
     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 );
    724823                        __cfaabi_dbg_bits_write( abort_text, len );
    725824                }
  • libcfa/src/concurrency/thread.cfa

    r6a9d4b4 r933f32f  
    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 };
    3334        self_cor{ name, storage, storageSize };
    34         verify(&self_cor);
     35        state = Start;
    3536        curr_cor = &self_cor;
    3637        self_mon.owner = &this;
     
    7374forall( dtype T | is_thread(T) )
    7475void __thrd_start( T& this ) {
    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);
     76        thread_desc * this_thrd = get_thread(this);
     77        thread_desc * curr_thrd = TL_GET( this_thread );
    8078
    8179        disable_interrupts();
    82         create_stack(&thrd_c->stack, thrd_c->stack.size);
    83         kernelTLS.this_coroutine = thrd_c;
    8480        CtxStart(&this, CtxInvokeThread);
    85         assert( thrd_c->last->stack.context );
    86         CtxSwitch( thrd_c->last->stack.context, thrd_c->stack.context );
     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 );
    8784
    88         ScheduleThread(thrd_h);
     85        ScheduleThread(this_thrd);
    8986        enable_interrupts( __cfaabi_dbg_ctx );
    9087}
     
    9289extern "C" {
    9390        // KERNEL ONLY
    94         void __finish_creation(void) {
    95                 coroutine_desc* thrd_c = kernelTLS.this_coroutine;
    96                 ThreadCtxSwitch( thrd_c, thrd_c->last );
     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 );
    9797        }
    9898}
     
    112112}
    113113
    114 // KERNEL ONLY
    115 void 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 
    132114// Local Variables: //
    133115// mode: c //
  • libcfa/src/concurrency/thread.hfa

    r6a9d4b4 r933f32f  
    6161void ^?{}(thread_desc & this);
    6262
    63 static inline void ?{}(thread_desc & this)                                                                  { this{ "Anonymous Thread", *mainCluster, NULL, 0 }; }
     63static inline void ?{}(thread_desc & this)                                                                  { this{ "Anonymous Thread", *mainCluster, NULL, 65000 }; }
    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, 0 }; }
    67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, 0, stackSize }; }
     66static inline void ?{}(thread_desc & this, struct cluster & cl )                                            { this{ "Anonymous Thread", cl, NULL, 65000 }; }
     67static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, NULL, 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, 0 }; }
    70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl )                   { this{ name, cl, NULL, 0 }; }
     69static inline void ?{}(thread_desc & this, const char * const name)                                         { this{ name, *mainCluster, NULL, 65000 }; }
     70static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl )                   { this{ name, cl, NULL, 65000 }; }
    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

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed May 24 15:40:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 20 15:23:50 2017
    13 // Update Count     : 2
     12// Last Modified On : Sun Feb 17 11:22:03 2019
     13// Update Count     : 3
    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

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed May 24 15:40:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 20 15:23:58 2017
    13 // Update Count     : 2
     12// Last Modified On : Sun Feb 17 11:24:04 2019
     13// Update Count     : 3
    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

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 24 18:33:38 2018
    13 // Update Count     : 304
     12// Last Modified On : Thu May 16 08:33:28 2019
     13// Update Count     : 328
    1414//
    1515
     
    2323#include <complex.h>                                                                    // creal, cimag
    2424#include <assert.h>
     25#include <errno.h>                                                                              // errno
    2526
    2627#define IO_MSG "I/O error: "
    2728
    28 void ?{}( ofstream & os, void * file, bool sepDefault, bool sepOnOff, bool nlOnOff, bool prt, const char * separator, const char * tupleSeparator ) {
     29void ?{}( ofstream & os, void * file ) {
    2930        os.file = file;
    30         os.sepDefault = sepDefault;
    31         os.sepOnOff = sepOnOff;
    32         os.nlOnOff = nlOnOff;
    33         os.prt = prt;
    34         sepSet( os, separator );
     31        os.sepDefault = true;
     32        os.sepOnOff = false;
     33        os.nlOnOff = true;
     34        os.prt = false;
     35        os.sawNL = false;
     36        sepSet( os, " " );
    3537        sepSetCur( os, sepGet( os ) );
    36         sepSetTuple( os, tupleSeparator );
     38        sepSetTuple( os, ", " );
    3739}
    3840
     
    102104
    103105void open( ofstream & os, const char * name, const char * mode ) {
    104         FILE *file = fopen( name, mode );
     106        FILE * file = fopen( name, mode );
    105107        #ifdef __CFA_DEBUG__
    106108        if ( file == 0 ) {
    107                 fprintf( stderr, IO_MSG "open output file \"%s\", ", name );
    108                 perror( 0 );
    109                 exit( EXIT_FAILURE );
     109                abort( IO_MSG "open output file \"%s\", %s", name, strerror( errno ) );
    110110        } // if
    111111        #endif // __CFA_DEBUG__
    112         (os){ file, true, false, true, false, " ", ", " };
     112        (os){ file };
    113113} // open
    114114
     
    121121
    122122        if ( fclose( (FILE *)(os.file) ) == EOF ) {
    123                 perror( IO_MSG "close output" );
     123                abort( IO_MSG "close output %s", strerror( errno ) );
    124124        } // if
    125125} // close
     
    127127ofstream & write( ofstream & os, const char * data, size_t size ) {
    128128        if ( fail( os ) ) {
    129                 fprintf( stderr, "attempt write I/O on failed stream\n" );
    130                 exit( EXIT_FAILURE );
     129                abort( "attempt write I/O on failed stream\n" );
    131130        } // if
    132131
    133132        if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) {
    134                 perror( IO_MSG "write" );
    135                 exit( EXIT_FAILURE );
     133                abort( IO_MSG "write %s", strerror( errno ) );
    136134        } // if
    137135        return os;
     
    144142        if ( len == EOF ) {
    145143                if ( ferror( (FILE *)(os.file) ) ) {
    146                         fprintf( stderr, "invalid write\n" );
    147                         exit( EXIT_FAILURE );
     144                        abort( "invalid write\n" );
    148145                } // if
    149146        } // if
     
    155152} // fmt
    156153
    157 static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_), true, false, true, false, " ", ", " };
     154static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_) };
    158155ofstream & sout = soutFile;
    159 static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_), true, false, true, false, " ", ", " };
     156static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_) };
    160157ofstream & serr = serrFile;
    161158
     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
     164void nl( ofstream & os ) {
     165        if ( getANL( os ) ) (ofstream &)(nl( os ));                     // implementation only
     166        else setPrt( os, false );                                                       // turn off
     167}
    162168
    163169//---------------------------------------
     
    166172void ?{}( ifstream & is, void * file ) {
    167173        is.file = file;
     174        is.nlOnOff = false;
    168175}
    169176
     
    177184        open( is, name, "r" );
    178185}
     186
     187void nlOn( ifstream & os ) { os.nlOnOff = true; }
     188void nlOff( ifstream & os ) { os.nlOnOff = false; }
     189bool getANL( ifstream & os ) { return os.nlOnOff; }
    179190
    180191int fail( ifstream & is ) {
     
    187198
    188199void open( ifstream & is, const char * name, const char * mode ) {
    189         FILE *file = fopen( name, mode );
     200        FILE * file = fopen( name, mode );
    190201        #ifdef __CFA_DEBUG__
    191202        if ( file == 0 ) {
    192                 fprintf( stderr, IO_MSG "open input file \"%s\", ", name );
    193                 perror( 0 );
    194                 exit( EXIT_FAILURE );
     203                abort( IO_MSG "open input file \"%s\", %s\n", name, strerror( errno ) );
    195204        } // if
    196205        #endif // __CFA_DEBUG__
     
    206215
    207216        if ( fclose( (FILE *)(is.file) ) == EOF ) {
    208                 perror( IO_MSG "close input" );
     217                abort( IO_MSG "close input %s", strerror( errno ) );
    209218        } // if
    210219} // close
     
    212221ifstream & read( ifstream & is, char * data, size_t size ) {
    213222        if ( fail( is ) ) {
    214                 fprintf( stderr, "attempt read I/O on failed stream\n" );
    215                 exit( EXIT_FAILURE );
     223                abort( "attempt read I/O on failed stream\n" );
    216224        } // if
    217225
    218226        if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) {
    219                 perror( IO_MSG "read" );
    220                 exit( EXIT_FAILURE );
     227                abort( IO_MSG "read %s", strerror( errno ) );
    221228        } // if
    222229        return is;
     
    225232ifstream &ungetc( ifstream & is, char c ) {
    226233        if ( fail( is ) ) {
    227                 fprintf( stderr, "attempt ungetc I/O on failed stream\n" );
    228                 exit( EXIT_FAILURE );
     234                abort( "attempt ungetc I/O on failed stream\n" );
    229235        } // if
    230236
    231237        if ( ungetc( c, (FILE *)(is.file) ) == EOF ) {
    232                 perror( IO_MSG "ungetc" );
    233                 exit( EXIT_FAILURE );
     238                abort( IO_MSG "ungetc %s", strerror( errno ) );
    234239        } // if
    235240        return is;
     
    243248        if ( len == EOF ) {
    244249                if ( ferror( (FILE *)(is.file) ) ) {
    245                         fprintf( stderr, "invalid read\n" );
    246                         exit( EXIT_FAILURE );
     250                        abort( "invalid read\n" );
    247251                } // if
    248252        } // if
  • libcfa/src/fstream.hfa

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

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Sep  6 09:01:30 2018
    13 // Update Count     : 513
     12// Last Modified On : Thu May  9 16:29:12 2019
     13// Update Count     : 516
    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
    236237static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; }
     238
    237239// 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;
     535        HeapManager.Storage * block;                                            // pointer to new block of storage
    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                 char helpText[64];
     658                enum { BufferSize = 64 };
     659                char helpText[BufferSize];
    659660                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    660661                __cfaabi_dbg_bits_write( helpText, len );
     
    853854                        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    854855                        if ( ! mapped )
    855                                 #endif // __CFA_DEBUG__
     856                        #endif // __CFA_DEBUG__
    856857                                memset( (char *)area + usize, '\0', asize - ( (char *)area - (char *)header ) - usize ); // zero-fill back part
    857858                        header->kind.real.blockSize |= 2;                       // mark new request as zero fill
     
    10341035// Local Variables: //
    10351036// tab-width: 4 //
    1036 // compile-command: "cfa -nodebug -O2 heap.c" //
     1037// compile-command: "cfa -nodebug -O2 heap.cfa" //
    10371038// End: //
  • libcfa/src/iostream.cfa

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 24 18:33:40 2018
    13 // Update Count     : 589
     12// Last Modified On : Sun May 19 10:48:27 2019
     13// Update Count     : 654
    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
    2526#include <complex.h>                                                                    // creal, cimag
    2627}
    2728
    2829forall( 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
    2948        ostype & ?|?( ostype & os, bool b ) {
    3049                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     
    135154        } // ?|?
    136155
     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
    137163        ostype & ?|?( ostype & os, float f ) {
    138164                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    139                 fmt( os, "%g", f );
     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
    140169                return os;
    141170        } // ?|?
     
    146175        ostype & ?|?( ostype & os, double d ) {
    147176                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    148                 fmt( os, "%.*lg", DBL_DIG, d );
     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
    149181                return os;
    150182        } // ?|?
     
    155187        ostype & ?|?( ostype & os, long double ld ) {
    156188                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    157                 fmt( os, "%.*Lg", LDBL_DIG, ld );
     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
    158193                return os;
    159194        } // ?|?
     
    164199        ostype & ?|?( ostype & os, float _Complex fc ) {
    165200                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    166                 fmt( os, "%g%+gi", crealf( fc ), cimagf( fc ) );
     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" );
    167212                return os;
    168213        } // ?|?
     
    173218        ostype & ?|?( ostype & os, double _Complex dc ) {
    174219                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    175                 fmt( os, "%.*lg%+.*lgi", DBL_DIG, creal( dc ), DBL_DIG, cimag( dc ) );
     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" );
    176231                return os;
    177232        } // ?|?
     
    182237        ostype & ?|?( ostype & os, long double _Complex ldc ) {
    183238                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    184                 fmt( os, "%.*Lg%+.*Lgi", LDBL_DIG, creall( ldc ), LDBL_DIG, cimagl( ldc ) );
     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" );
    185250                return os;
    186251        } // ?|?
     
    378443
    379444        istype & ?|?( istype & is, char & c ) {
    380                 fmt( is, "%c", &c );                                                    // must pass pointer through varg to fmt
     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
    381452                return is;
    382453        } // ?|?
     
    470541        } // ?|?
    471542
    472 
    473543        // manipulators
    474544        istype & ?|?( istype & is, istype & (* manip)( istype & ) ) {
     
    477547
    478548        istype & nl( istype & is ) {
    479                 fmt( is, "%*[ \t\f\n\r\v]" );                                   // ignore whitespace
     549                fmt( is, "%*[^\n]" );                                                   // ignore characters to newline
    480550                return is;
    481551        } // 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
    482562} // distribution
    483563
  • libcfa/src/iostream.hfa

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 24 18:33:40 2018
    13 // Update Count     : 220
     12// Last Modified On : Sat May 11 10:31:27 2019
     13// Update Count     : 232
    1414//
    1515
     
    4848        void close( ostype & os );
    4949        ostype & write( ostype &, const char *, size_t );
    50         int fmt( ostype &, const char format[], ... );
     50        int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
    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
    6469        ostype & ?|?( ostype &, bool );
    6570        void ?|?( ostype &, bool );
     
    144149
    145150trait istream( dtype istype ) {
     151        void nlOn( istype & );                                                          // read newline
     152        void nlOff( istype & );                                                         // scan newline
     153        bool getANL( istype & );                                                        // get scan newline (on/off)
    146154        int fail( istype & );
    147155        int eof( istype & );
     
    150158        istype & read( istype &, char *, size_t );
    151159        istype & ungetc( istype &, char );
    152         int fmt( istype &, const char format[], ... );
     160        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    153161}; // istream
    154162
     
    184192        istype & ?|?( istype &, istype & (*)( istype & ) );
    185193        istype & nl( istype & is );
     194        istype & nlOn( istype & );
     195        istype & nlOff( istype & );
    186196} // distribution
    187197
     
    205215
    206216// Local Variables: //
    207 // mode: c //
    208217// tab-width: 4 //
    209218// End: //
  • libcfa/src/rational.cfa

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed Apr  6 17:54:28 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 23 22:56:49 2018
    13 // Update Count     : 170
     12// Last Modified On : Thu Mar 28 17:33:03 2019
     13// Update Count     : 181
    1414//
    1515
     
    3535        static RationalImpl simplify( RationalImpl & n, RationalImpl & d ) {
    3636                if ( d == (RationalImpl){0} ) {
    37                         serr | "Invalid rational number construction: denominator cannot be equal to 0.";
    38                         exit( EXIT_FAILURE );
     37                        abort( "Invalid rational number construction: denominator cannot be equal to 0.\n" );
    3938                } // exit
    4039                if ( d < (RationalImpl){0} ) { d = -d; n = -n; } // move sign to numerator
     
    5453        void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ) {
    5554                RationalImpl t = simplify( n, d );                              // simplify
    56                 r.numerator = n / t;
    57                 r.denominator = d / t;
     55                r.[numerator, denominator] = [n / t, d / t];
    5856        } // rational
    5957
     
    7876                RationalImpl prev = r.numerator;
    7977                RationalImpl t = gcd( abs( n ), r.denominator ); // simplify
    80                 r.numerator = n / t;
    81                 r.denominator = r.denominator / t;
     78                r.[numerator, denominator] = [n / t, r.denominator / t];
    8279                return prev;
    8380        } // numerator
     
    8683                RationalImpl prev = r.denominator;
    8784                RationalImpl t = simplify( r.numerator, d );    // simplify
    88                 r.numerator = r.numerator / t;
    89                 r.denominator = d / t;
     85                r.[numerator, denominator] = [r.numerator / t, d / t];
    9086                return prev;
    9187        } // denominator
     
    120116
    121117        Rational(RationalImpl) +?( Rational(RationalImpl) r ) {
    122                 Rational(RationalImpl) t = { r.numerator, r.denominator };
    123                 return t;
     118                return (Rational(RationalImpl)){ r.numerator, r.denominator };
    124119        } // +?
    125120
    126121        Rational(RationalImpl) -?( Rational(RationalImpl) r ) {
    127                 Rational(RationalImpl) t = { -r.numerator, r.denominator };
    128                 return t;
     122                return (Rational(RationalImpl)){ -r.numerator, r.denominator };
    129123        } // -?
    130124
    131125        Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    132126                if ( l.denominator == r.denominator ) {                 // special case
    133                         Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator };
    134                         return t;
     127                        return (Rational(RationalImpl)){ l.numerator + r.numerator, l.denominator };
    135128                } else {
    136                         Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
    137                         return t;
     129                        return (Rational(RationalImpl)){ l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
    138130                } // if
    139131        } // ?+?
     
    141133        Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    142134                if ( l.denominator == r.denominator ) {                 // special case
    143                         Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator };
    144                         return t;
     135                        return (Rational(RationalImpl)){ l.numerator - r.numerator, l.denominator };
    145136                } else {
    146                         Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
    147                         return t;
     137                        return (Rational(RationalImpl)){ l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
    148138                } // if
    149139        } // ?-?
    150140
    151141        Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    152                 Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator };
    153                 return t;
     142                return (Rational(RationalImpl)){ l.numerator * r.numerator, l.denominator * r.denominator };
    154143        } // ?*?
    155144
    156145        Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    157146                if ( r.numerator < (RationalImpl){0} ) {
    158                         r.numerator = -r.numerator;
    159                         r.denominator = -r.denominator;
     147                        r.[numerator, denominator] = [-r.numerator, -r.denominator];
    160148                } // if
    161                 Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator };
    162                 return t;
     149                return (Rational(RationalImpl)){ l.numerator * r.denominator, l.denominator * r.numerator };
    163150        } // ?/?
    164151
     
    167154        forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )
    168155        istype & ?|?( istype & is, Rational(RationalImpl) & r ) {
    169                 RationalImpl t;
    170156                is | r.numerator | r.denominator;
    171                 t = simplify( r.numerator, r.denominator );
     157                RationalImpl t = simplify( r.numerator, r.denominator );
    172158                r.numerator /= t;
    173159                r.denominator /= t;
     
    185171        } // distribution
    186172} // distribution
     173
     174forall( otype RationalImpl | arithmetic( RationalImpl ) | { RationalImpl ?\?( RationalImpl, unsigned long ); } )
     175Rational(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}
    187182
    188183// conversion
  • libcfa/src/rational.hfa

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jul  5 20:39:51 2016
    13 // Update Count     : 12
     12// Last Modified On : Mon Mar 25 08:00:08 2019
     13// Update Count     : 15
    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
    1829} // extern "C"
    1930
  • libcfa/src/stdlib.hfa

    r6a9d4b4 r933f32f  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 17 15:37:45 2018
    13 // Update Count     : 346
     12// Last Modified On : Wed Apr 24 17:35:43 2019
     13// Update Count     : 352
    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 
    4942        T * calloc( size_t dim ) {
    5043                return (T *)(void *)calloc( dim, sizeof(T) );   // C calloc
     
    7669        T * alloc( char fill ) {
    7770                T * ptr = (T *)(void *)malloc( (size_t)sizeof(T) );     // C malloc
    78                 return (T *)memset( ptr, (int)fill, sizeof(T) );        // initial with fill value
     71                return (T *)memset( ptr, (int)fill, sizeof(T) ); // initialize with fill value
    7972        } // alloc
    8073
     
    8477
    8578        T * alloc( size_t dim, char fill ) {
    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
     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
    8881        } // alloc
    8982
  • libcfa/src/time.hfa

    r6a9d4b4 r933f32f  
    3030
    3131static inline {
    32         Duration ?=?( Duration & dur, zero_t ) { return dur{ 0 }; }
     32        Duration ?=?( Duration & dur, __attribute__((unused)) 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, 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; }
     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; }
    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, zero_t ) { t{ 0, 0 }; }
    104 
    105         timeval ?=?( timeval & t, zero_t ) { return t{ 0 }; }
     103        void ?{}( timeval & t, __attribute__((unused)) zero_t ) { t{ 0, 0 }; }
     104
     105        timeval ?=?( timeval & t, __attribute__((unused)) 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, zero_t ) { t{ 0, 0 }; }
    119 
    120         timespec ?=?( timespec & t, zero_t ) { return t{ 0 }; }
     118        void ?{}( timespec & t, __attribute__((unused)) zero_t ) { t{ 0, 0 }; }
     119
     120        timespec ?=?( timespec & t, __attribute__((unused)) 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, zero_t ) { return time{ 0 }; }
     147        Time ?=?( Time & time, __attribute__((unused)) 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

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

    r6a9d4b4 r933f32f  
    9191build_triplet = @build@
    9292host_triplet = @host@
    93 subdir = tests/preempt_longrun
     93subdir = longrun_tests
    9494ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
    9595am__aclocal_m4_deps = $(top_srcdir)/automake/libtool.m4 \
     
    331331        $(TEST_LOG_FLAGS)
    332332am__DIST_COMMON = $(srcdir)/Makefile.in \
    333         $(top_srcdir)/automake/test-driver
     333        $(top_srcdir)/automake/test-driver $(top_srcdir)/src/cfa.make
    334334DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    335335ACLOCAL = @ACLOCAL@
    336 ALLOCA = @ALLOCA@
    337336AMTAR = @AMTAR@
    338337AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    343342AWK = @AWK@
    344343BUILD_IN_TREE_FLAGS = @BUILD_IN_TREE_FLAGS@
    345 CC = @CFACC@
     344CC = @CC@
    346345CCAS = @CCAS@
    347346CCASDEPMODE = @CCASDEPMODE@
     
    357356CFA_NAME = @CFA_NAME@
    358357CFA_PREFIX = @CFA_PREFIX@
    359 CFLAGS = ${BUILD_FLAGS}
     358CFLAGS = @CFLAGS@
    360359CPP = @CPP@
    361360CPPFLAGS = @CPPFLAGS@
     
    480479AUTOMAKE_OPTIONS = foreign    # do not require all the GNU file names
    481480ACLOCAL_AMFLAGS = -I automake
     481CFACOMPILE = $(CFACC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) $(AM_CFLAGS) $(CFLAGS)
     482LTCFACOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
     483        $(LIBTOOLFLAGS) --mode=compile $(CFACC) $(DEFS) \
     484        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) \
     485        $(AM_CFLAGS) $(CFLAGS)
     486
     487AM_V_CFA = $(am__v_CFA_@AM_V@)
     488am__v_CFA_ = $(am__v_CFA_@AM_DEFAULT_V@)
     489am__v_CFA_0 = @echo "  CFA     " $@;
     490am__v_CFA_1 =
     491AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     492am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     493am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     494am__v_JAVAC_1 =
     495AM_V_GOC = $(am__v_GOC_@AM_V@)
     496am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
     497am__v_GOC_0 = @echo "  GOC     " $@;
     498am__v_GOC_1 =
     499UPPCC = u++
     500UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     501AM_V_UPP = $(am__v_UPP_@AM_V@)
     502am__v_UPP_ = $(am__v_UPP_@AM_DEFAULT_V@)
     503am__v_UPP_0 = @echo "  UPP     " $@;
     504am__v_UPP_1 =
    482505repeats = 10
    483506max_time = 600
     
    485508debug = -debug
    486509type = LONG
    487 REPEAT = ${abs_top_srcdir}/tools/repeat
    488 WATCHDOG = ${abs_top_srcdir}/tools/watchdog
     510REPEAT = $(abs_top_builddir)/tools/repeat
     511WATCHDOG = $(abs_top_builddir)/tools/watchdog
    489512TIME = /usr/bin/time -f "%E"
    490 
    491 # $(shell ./update-type $(type))
    492 # ./update-type $(type)
    493 UPDATED_TYPE = $(shell ./update-type $(type))
    494 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -I.. -I. -DTEST_$(shell cat .type | tr a-z A-Z)
     513UPDATED_TYPE = $(shell $(srcdir)/update-type $(type))
     514BUILD_FLAGS =
     515AM_CFAFLAGS = \
     516        -g \
     517        -Wall \
     518        -Wno-unused-function \
     519        -quiet \
     520        -O2 \
     521        -DPREEMPTION_RATE=$(preempt) \
     522        -I$(abs_top_srcdir)/tests \
     523        -I$(srcdir) \
     524        -DTEST_$(shell cat .type | tr a-z A-Z) \
     525        -in-tree
     526
    495527TESTS = block coroutine create disjoint enter enter3 processor stack wait yield
    496528all: all-am
    497529
    498530.SUFFIXES:
    499 .SUFFIXES: .log .test .test$(EXEEXT) .trs
    500 $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(am__configure_deps)
     531.SUFFIXES: .cfa .lo .log .o .test .test$(EXEEXT) .trs
     532$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/src/cfa.make $(am__configure_deps)
    501533        @for dep in $?; do \
    502534          case '$(am__configure_deps)' in \
     
    507539          esac; \
    508540        done; \
    509         echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/preempt_longrun/Makefile'; \
     541        echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign longrun_tests/Makefile'; \
    510542        $(am__cd) $(top_srcdir) && \
    511           $(AUTOMAKE) --foreign tests/preempt_longrun/Makefile
     543          $(AUTOMAKE) --foreign longrun_tests/Makefile
    512544Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
    513545        @case '$?' in \
     
    518550            cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
    519551        esac;
     552$(top_srcdir)/src/cfa.make $(am__empty):
    520553
    521554$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
     
    918951
    919952
    920 # .INTERMEDIATE: ${TESTS}
    921 
    922 all-local: ${TESTS:=.run}
    923 
    924 runall : ${TESTS:=.run}
     953.cfa.o:
     954        $(AM_V_CFA)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
     955        $(CFACOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
     956        $(am__mv) $$depbase.Tpo $$depbase.Po
     957
     958.cfa.lo:
     959        $(AM_V_CFA)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
     960        $(LTCFACOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
     961        $(am__mv) $$depbase.Tpo $$depbase.Plo
     962
     963# .INTERMEDIATE: $(TESTS)
     964
     965all-local: $(TESTS:=.run)
     966
     967runall : $(TESTS:=.run)
    925968        @ echo "All programs terminated normally"
    926969
    927 watchall : ${TESTS:=.watch}
     970watchall : $(TESTS:=.watch)
    928971        @ echo "All programs terminated normally"
    929972
    930 compileall : ${TESTS}
     973compileall : $(TESTS)
    931974        @ echo "Compiled"
    932975
    933976clean-local:
    934         rm -f ${TESTS} core* out.log .type
    935 
    936 % : %.c ${CC} ${UPDATED_TYPE}
    937         ${AM_V_GEN}${CC} ${CFLAGS} ${<} $(debug) -o ${@}
    938 
    939 %.run : % ${REPEAT}
    940         @ time ${REPEAT} -r out.log -i -s $(repeats) timeout ${max_time} ./${<}
    941         @ rm ${<}
    942         @ echo -e "${<}: SUCCESS\n"
    943 
    944 %.watch : % ${WATCHDOG}
    945         @ time ${WATCHDOG} ./${<}
    946         @ rm ${<}
    947         @ echo -e "${<}: SUCCESS\n"
    948 
    949 %.time : % ${REPEAT}
    950         @ ${REPEAT} -i -s -- $(repeats) $(TIME) -a -o times.log ./${<}
    951         @ rm ${<}
    952         @ echo -e "${<}: SUCCESS\n"
    953 
    954 ${REPEAT}: ${abs_top_srcdir}/tools/Makefile
    955         @+make -C ${abs_top_srcdir}/tools/
    956 
    957 ${WATCHDOG}: ${abs_top_srcdir}/tools/Makefile
    958         @+make -C ${abs_top_srcdir}/tools/
     977        rm -f $(TESTS) core* out.log .type
     978
     979% : %.cfa $(CFACC) $(UPDATED_TYPE)
     980        $(AM_V_CFA)$(CFACOMPILE) $(<) $(debug) -o $(@)
     981
     982%.run : % $(REPEAT)
     983        @ time $(REPEAT) -r out.log -i -s $(repeats) timeout $(max_time) ./$(<)
     984        @ rm $(<)
     985        @ echo -e "$(<): SUCCESS\n"
     986
     987%.watch : % $(WATCHDOG)
     988        @ time $(WATCHDOG} ./$(<)
     989        @ rm $(<)
     990        @ echo -e "$(<): SUCCESS\n"
     991
     992%.time : % $(REPEAT)
     993        @ $(REPEAT) -i -s -- $(repeats) $(TIME) -a -o times.log ./$(<)
     994        @ rm $(<)
     995        @ echo -e "$(<): SUCCESS\n"
     996
     997$(REPEAT): $(abs_top_builddir)/tools/Makefile
     998        @+make -C $(abs_top_builddir)/tools/
     999
     1000$(WATCHDOG): $(abs_top_builddir)/tools/Makefile
     1001        @+make -C $(abs_top_builddir)/tools/
    9591002
    9601003# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • longrun_tests/enter.cfa

    r6a9d4b4 r933f32f  
    55
    66#define __kick_rate 75000ul
    7 #include "long_tests.h"
     7#include "long_tests.hfa"
    88
    99#ifndef PREEMPTION_RATE
  • longrun_tests/stack.cfa

    r6a9d4b4 r933f32f  
    55
    66#define __kick_rate 5000000ul
    7 #include "long_tests.h"
     7#include "long_tests.hfa"
    88
    99#ifndef PREEMPTION_RATE
  • src/CodeGen/CodeGenerator.cc

    r6a9d4b4 r933f32f  
    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 : Sat May  5 09:08:32 2018
    13 // Update Count     : 494
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr May  2 10:47:00 2019
     13// Update Count     : 497
    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 ( !lineMarks || to.isUnset() ) return;
     85                if ( !options.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 ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ), printExprTypes( printExprTypes ), endl( *this ) {}
     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 ) {}
    119120
    120121        string CodeGenerator::mangleName( DeclarationWithType * decl ) {
    121122                // GCC builtins should always be printed unmangled
    122                 if ( pretty || decl->linkage.is_gcc_builtin ) return decl->name;
     123                if ( options.pretty || decl->linkage.is_gcc_builtin ) return decl->name;
    123124                if ( decl->mangleName != "" ) {
    124125                        // need to incorporate scope level in order to differentiate names for destructors
     
    164165                previsit( (BaseSyntaxNode *)node );
    165166                GuardAction( [this, node](){
    166                         if ( printExprTypes && node->result ) {
    167                                 output << " /* " << genType( node->result, "", pretty, genC ) << " */ ";
     167                        if ( options.printExprTypes && node->result ) {
     168                                output << " /* " << genType( node->result, "", options ) << " */ ";
    168169                        }
    169170                } );
     
    173174        void CodeGenerator::postvisit( FunctionDecl * functionDecl ) {
    174175                // deleted decls should never be used, so don't print them
    175                 if ( functionDecl->isDeleted && genC ) return;
     176                if ( functionDecl->isDeleted && options.genC ) return;
    176177                extension( functionDecl );
    177178                genAttributes( functionDecl->get_attributes() );
     
    180181                functionDecl->get_funcSpec().print( output );
    181182
    182                 output << genType( functionDecl->get_functionType(), mangleName( functionDecl ), pretty, genC );
     183                Options subOptions = options;
     184                subOptions.anonymousUnused = functionDecl->has_body();
     185                output << genType( functionDecl->get_functionType(), mangleName( functionDecl ), subOptions );
    183186
    184187                asmName( functionDecl );
     
    194197        void CodeGenerator::postvisit( ObjectDecl * objectDecl ) {
    195198                // deleted decls should never be used, so don't print them
    196                 if ( objectDecl->isDeleted && genC ) return;
    197                 if (objectDecl->get_name().empty() && genC ) {
     199                if ( objectDecl->isDeleted && options.genC ) return;
     200                if (objectDecl->get_name().empty() && options.genC ) {
    198201                        // only generate an anonymous name when generating C code, otherwise it clutters the output too much
    199202                        static UniqueName name = { "__anonymous_object" };
    200203                        objectDecl->set_name( name.newName() );
     204            // Stops unused parameter warnings.
     205            if ( options.anonymousUnused ) {
     206                objectDecl->attributes.push_back( new Attribute( "unused" ) );
     207            }
    201208                }
    202209
     
    205212
    206213                handleStorageClass( objectDecl );
    207                 output << genType( objectDecl->get_type(), mangleName( objectDecl ), pretty, genC );
     214                output << genType( objectDecl->get_type(), mangleName( objectDecl ), options.pretty, options.genC );
    208215
    209216                asmName( objectDecl );
     
    224231
    225232        void CodeGenerator::handleAggregate( AggregateDecl * aggDecl, const std::string & kind ) {
    226                 if( ! aggDecl->parameters.empty() && ! genC ) {
     233                if( ! aggDecl->parameters.empty() && ! options.genC ) {
    227234                        // assertf( ! genC, "Aggregate type parameters should not reach code generation." );
    228235                        output << "forall(";
     
    294301
    295302        void CodeGenerator::postvisit( TraitDecl * traitDecl ) {
    296                 assertf( ! genC, "TraitDecls should not reach code generation." );
     303                assertf( ! options.genC, "TraitDecls should not reach code generation." );
    297304                extension( traitDecl );
    298305                handleAggregate( traitDecl, "trait " );
     
    300307
    301308        void CodeGenerator::postvisit( TypedefDecl * typeDecl ) {
    302                 assertf( ! genC, "Typedefs are removed and substituted in earlier passes." );
     309                assertf( ! options.genC, "Typedefs are removed and substituted in earlier passes." );
    303310                output << "typedef ";
    304                 output << genType( typeDecl->get_base(), typeDecl->get_name(), pretty, genC ) << endl;
     311                output << genType( typeDecl->get_base(), typeDecl->get_name(), options ) << endl;
    305312        }
    306313
    307314        void CodeGenerator::postvisit( TypeDecl * typeDecl ) {
    308                 assertf( ! genC, "TypeDecls should not reach code generation." );
     315                assertf( ! options.genC, "TypeDecls should not reach code generation." );
    309316                output << typeDecl->genTypeString() << " " << typeDecl->name;
    310317                if ( typeDecl->sized ) {
     
    371378
    372379        void CodeGenerator::postvisit( ConstructorInit * init ){
    373                 assertf( ! genC, "ConstructorInit nodes should not reach code generation." );
     380                assertf( ! options.genC, "ConstructorInit nodes should not reach code generation." );
    374381                // pseudo-output for constructor/destructor pairs
    375382                output << "<ctorinit>{" << endl << ++indent << "ctor: ";
     
    507514                                        } else {
    508515                                                // no constructors with 0 or more than 2 parameters
    509                                                 assertf( ! genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );
     516                                                assertf( ! options.genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );
    510517                                                output << "(";
    511518                                                (*arg++)->accept( *visitor );
     
    604611                        // an lvalue cast, this has been taken out.
    605612                        output << "(";
    606                         output << genType( castExpr->get_result(), "", pretty, genC );
     613                        output << genType( castExpr->get_result(), "", options );
    607614                        output << ")";
    608615                } // if
     
    612619
    613620        void CodeGenerator::postvisit( KeywordCastExpr * castExpr ) {
    614                 assertf( ! genC, "KeywordCast should not reach code generation." );
     621                assertf( ! options.genC, "KeywordCast should not reach code generation." );
    615622                extension( castExpr );
    616623                output << "((" << castExpr->targetString() << " &)";
     
    620627
    621628        void CodeGenerator::postvisit( VirtualCastExpr * castExpr ) {
    622                 assertf( ! genC, "VirtualCastExpr should not reach code generation." );
     629                assertf( ! options.genC, "VirtualCastExpr should not reach code generation." );
    623630                extension( castExpr );
    624631                output << "(virtual ";
     
    628635
    629636        void CodeGenerator::postvisit( UntypedMemberExpr * memberExpr ) {
    630                 assertf( ! genC, "UntypedMemberExpr should not reach code generation." );
     637                assertf( ! options.genC, "UntypedMemberExpr should not reach code generation." );
    631638                extension( memberExpr );
    632639                memberExpr->get_aggregate()->accept( *visitor );
     
    661668                output << "sizeof(";
    662669                if ( sizeofExpr->get_isType() ) {
    663                         output << genType( sizeofExpr->get_type(), "", pretty, genC );
     670                        output << genType( sizeofExpr->get_type(), "", options );
    664671                } else {
    665672                        sizeofExpr->get_expr()->accept( *visitor );
     
    673680                output << "__alignof__(";
    674681                if ( alignofExpr->get_isType() ) {
    675                         output << genType( alignofExpr->get_type(), "", pretty, genC );
     682                        output << genType( alignofExpr->get_type(), "", options );
    676683                } else {
    677684                        alignofExpr->get_expr()->accept( *visitor );
     
    681688
    682689        void CodeGenerator::postvisit( UntypedOffsetofExpr * offsetofExpr ) {
    683                 assertf( ! genC, "UntypedOffsetofExpr should not reach code generation." );
     690                assertf( ! options.genC, "UntypedOffsetofExpr should not reach code generation." );
    684691                output << "offsetof(";
    685                 output << genType( offsetofExpr->get_type(), "", pretty, genC );
     692                output << genType( offsetofExpr->get_type(), "", options );
    686693                output << ", " << offsetofExpr->get_member();
    687694                output << ")";
     
    691698                // use GCC builtin
    692699                output << "__builtin_offsetof(";
    693                 output << genType( offsetofExpr->get_type(), "", pretty, genC );
     700                output << genType( offsetofExpr->get_type(), "", options );
    694701                output << ", " << mangleName( offsetofExpr->get_member() );
    695702                output << ")";
     
    697704
    698705        void CodeGenerator::postvisit( OffsetPackExpr * offsetPackExpr ) {
    699                 assertf( ! genC, "OffsetPackExpr should not reach code generation." );
    700                 output << "__CFA_offsetpack(" << genType( offsetPackExpr->get_type(), "", pretty, genC ) << ")";
     706                assertf( ! options.genC, "OffsetPackExpr should not reach code generation." );
     707                output << "__CFA_offsetpack(" << genType( offsetPackExpr->get_type(), "", options ) << ")";
    701708        }
    702709
     
    728735                extension( commaExpr );
    729736                output << "(";
    730                 if ( genC ) {
     737                if ( options.genC ) {
    731738                        // arg1 of a CommaExpr is never used, so it can be safely cast to void to reduce gcc warnings.
    732739                        commaExpr->set_arg1( new CastExpr( commaExpr->get_arg1() ) );
     
    739746
    740747        void CodeGenerator::postvisit( TupleAssignExpr * tupleExpr ) {
    741                 assertf( ! genC, "TupleAssignExpr should not reach code generation." );
     748                assertf( ! options.genC, "TupleAssignExpr should not reach code generation." );
    742749                tupleExpr->stmtExpr->accept( *visitor );
    743750        }
    744751
    745752        void CodeGenerator::postvisit( UntypedTupleExpr * tupleExpr ) {
    746                 assertf( ! genC, "UntypedTupleExpr should not reach code generation." );
     753                assertf( ! options.genC, "UntypedTupleExpr should not reach code generation." );
    747754                extension( tupleExpr );
    748755                output << "[";
     
    752759
    753760        void CodeGenerator::postvisit( TupleExpr * tupleExpr ) {
    754                 assertf( ! genC, "TupleExpr should not reach code generation." );
     761                assertf( ! options.genC, "TupleExpr should not reach code generation." );
    755762                extension( tupleExpr );
    756763                output << "[";
     
    760767
    761768        void CodeGenerator::postvisit( TupleIndexExpr * tupleExpr ) {
    762                 assertf( ! genC, "TupleIndexExpr should not reach code generation." );
     769                assertf( ! options.genC, "TupleIndexExpr should not reach code generation." );
    763770                extension( tupleExpr );
    764771                tupleExpr->get_tuple()->accept( *visitor );
     
    767774
    768775        void CodeGenerator::postvisit( TypeExpr * typeExpr ) {
    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 );
     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 );
    773780                }
    774781        }
     
    788795        void CodeGenerator::postvisit( CompoundLiteralExpr *compLitExpr ) {
    789796                assert( compLitExpr->get_result() && dynamic_cast< ListInit * > ( compLitExpr->get_initializer() ) );
    790                 output << "(" << genType( compLitExpr->get_result(), "", pretty, genC ) << ")";
     797                output << "(" << genType( compLitExpr->get_result(), "", options ) << ")";
    791798                compLitExpr->get_initializer()->accept( *visitor );
    792799        }
    793800
    794801        void CodeGenerator::postvisit( UniqueExpr * unqExpr ) {
    795                 assertf( ! genC, "Unique expressions should not reach code generation." );
     802                assertf( ! options.genC, "Unique expressions should not reach code generation." );
    796803                output << "unq<" << unqExpr->get_id() << ">{ ";
    797804                unqExpr->get_expr()->accept( *visitor );
     
    829836
    830837        void CodeGenerator::postvisit( ConstructorExpr * expr ) {
    831                 assertf( ! genC, "Unique expressions should not reach code generation." );
     838                assertf( ! options.genC, "Unique expressions should not reach code generation." );
    832839                expr->callExpr->accept( *visitor );
    833840        }
    834841
    835842        void CodeGenerator::postvisit( DeletedExpr * expr ) {
    836                 assertf( ! genC, "Deleted expressions should not reach code generation." );
     843                assertf( ! options.genC, "Deleted expressions should not reach code generation." );
    837844                expr->expr->accept( *visitor );
    838845        }
    839846
    840847        void CodeGenerator::postvisit( DefaultArgExpr * arg ) {
    841                 assertf( ! genC, "Default argument expressions should not reach code generation." );
     848                assertf( ! options.genC, "Default argument expressions should not reach code generation." );
    842849                arg->expr->accept( *visitor );
    843850        }
    844851
    845852        void CodeGenerator::postvisit( GenericExpr * expr ) {
    846                 assertf( ! genC, "C11 _Generic expressions should not reach code generation." );
     853                assertf( ! options.genC, "C11 _Generic expressions should not reach code generation." );
    847854                output << "_Generic(";
    848855                expr->control->accept( *visitor );
     
    854861                                output << "default: ";
    855862                        } else {
    856                                 output << genType( assoc.type, "", pretty, genC ) << ": ";
     863                                output << genType( assoc.type, "", options ) << ": ";
    857864                        }
    858865                        assoc.expr->accept( *visitor );
     
    889896        void CodeGenerator::postvisit( ExprStmt * exprStmt ) {
    890897                assert( exprStmt );
    891                 if ( genC ) {
     898                if ( options.genC ) {
    892899                        // cast the top-level expression to void to reduce gcc warnings.
    893900                        exprStmt->set_expr( new CastExpr( exprStmt->get_expr() ) );
     
    9991006                  case BranchStmt::FallThrough:
    10001007                  case BranchStmt::FallThroughDefault:
    1001                         assertf( ! genC, "fallthru should not reach code generation." );
     1008                        assertf( ! options.genC, "fallthru should not reach code generation." );
    10021009                  output << "fallthru";
    10031010                        break;
    10041011                } // switch
    10051012                // print branch target for labelled break/continue/fallthru in debug mode
    1006                 if ( ! genC && branchStmt->get_type() != BranchStmt::Goto ) {
     1013                if ( ! options.genC && branchStmt->get_type() != BranchStmt::Goto ) {
    10071014                        if ( ! branchStmt->get_target().empty() ) {
    10081015                                output << " " << branchStmt->get_target();
     
    10211028
    10221029        void CodeGenerator::postvisit( ThrowStmt * throwStmt ) {
    1023                 assertf( ! genC, "Throw statements should not reach code generation." );
     1030                assertf( ! options.genC, "Throw statements should not reach code generation." );
    10241031
    10251032                output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ?
     
    10361043        }
    10371044        void CodeGenerator::postvisit( CatchStmt * stmt ) {
    1038                 assertf( ! genC, "Catch statements should not reach code generation." );
     1045                assertf( ! options.genC, "Catch statements should not reach code generation." );
    10391046
    10401047                output << ((stmt->get_kind() == CatchStmt::Terminate) ?
     
    10531060
    10541061        void CodeGenerator::postvisit( WaitForStmt * stmt ) {
    1055                 assertf( ! genC, "Waitfor statements should not reach code generation." );
     1062                assertf( ! options.genC, "Waitfor statements should not reach code generation." );
    10561063
    10571064                bool first = true;
     
    10991106
    11001107        void CodeGenerator::postvisit( WithStmt * with ) {
    1101                 if ( ! genC ) {
     1108                if ( ! options.genC ) {
    11021109                        output << "with ( ";
    11031110                        genCommaList( with->exprs.begin(), with->exprs.end() );
     
    11651172
    11661173        void CodeGenerator::postvisit( ImplicitCtorDtorStmt * stmt ) {
    1167                 assertf( ! genC, "ImplicitCtorDtorStmts should not reach code generation." );
     1174                assertf( ! options.genC, "ImplicitCtorDtorStmts should not reach code generation." );
    11681175                stmt->callStmt->accept( *visitor );
    11691176        }
  • src/CodeGen/CodeGenerator.h

    r6a9d4b4 r933f32f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Aug 18 15:40:00 2017
    13 // Update Count     : 56
     12// Last Modified On : Tue Apr 30 12:01:00 2019
     13// Update Count     : 57
    1414//
    1515
     
    2020#include <string>                 // for string
    2121
     22#include "CodeGen/Options.h"      // for Options
    2223#include "Common/Indenter.h"      // for Indenter
    2324#include "Common/PassVisitor.h"   // for PassVisitor
     
    3132
    3233                CodeGenerator( std::ostream &os, bool pretty = false, bool genC = false, bool lineMarks = false, bool printExprTypes = false );
     34                CodeGenerator( std::ostream &os, const Options &options );
    3335
    3436                //*** Turn off visit_children for all nodes
     
    144146                std::ostream & output;
    145147                LabelPrinter printLabels;
    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;
     148                Options options;
    150149        public:
    151150                LineEnder endl;
  • src/CodeGen/GenType.cc

    r6a9d4b4 r933f32f  
    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 : Fri Mar 17 09:02:28 2017
    13 // Update Count     : 22
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed May  1 15:24:00 2019
     13// Update Count     : 23
    1414//
    1515#include "GenType.h"
     
    2828        struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
    2929                std::string typeString;
    30                 GenType( const std::string &typeString, bool pretty, bool genC, bool lineMarks );
     30                GenType( const std::string &typeString, const Options &options );
    3131
    3232                void previsit( BaseSyntaxNode * );
     
    5757                void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
    5858
    59                 bool pretty = false;    // pretty print
    60                 bool genC = false;      // generating C code?
    61                 bool lineMarks = false; // lineMarks on for CodeGenerator?
     59                Options options;
    6260        };
    6361
    64         std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {
    65                 PassVisitor<GenType> gt( baseString, pretty, genC, lineMarks );
     62        std::string genType( Type *type, const std::string &baseString, const Options &options ) {
     63                PassVisitor<GenType> gt( baseString, options );
    6664                std::ostringstream os;
    6765
    6866                if ( ! type->get_attributes().empty() ) {
    69                         PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
     67                        PassVisitor<CodeGenerator> cg( os, options );
    7068                        cg.pass.genAttributes( type->get_attributes() );
    7169                } // if
     
    7573        }
    7674
    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 ) {}
     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 ) {}
    8284
    8385        // *** BaseSyntaxNode
     
    133135                } // if
    134136                if ( dimension != 0 ) {
    135                         PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
     137                        PassVisitor<CodeGenerator> cg( os, options );
    136138                        dimension->accept( cg );
    137139                } else if ( isVarLen ) {
     
    167169        void GenType::postvisit( ReferenceType * refType ) {
    168170                assert( refType->base != 0);
    169                 assertf( ! genC, "Reference types should not reach code generation." );
     171                assertf( ! options.genC, "Reference types should not reach code generation." );
    170172                handleQualifiers( refType );
    171173                typeString = "&" + typeString;
     
    195197                        } // if
    196198                } else {
    197                         PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
     199                        PassVisitor<CodeGenerator> cg( os, options );
    198200                        os << "(" ;
    199201
     
    215217
    216218                // add forall
    217                 if( ! funcType->forall.empty() && ! genC ) {
     219                if( ! funcType->forall.empty() && ! options.genC ) {
    218220                        // assertf( ! genC, "Aggregate type parameters should not reach code generation." );
    219221                        std::ostringstream os;
    220                         PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
     222                        PassVisitor<CodeGenerator> cg( os, options );
    221223                        os << "forall(";
    222224                        cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );
     
    229231                if ( ! refType->parameters.empty() ) {
    230232                        std::ostringstream os;
    231                         PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
     233                        PassVisitor<CodeGenerator> cg( os, options );
    232234                        os << "(";
    233235                        cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
     
    240242        void GenType::postvisit( StructInstType * structInst )  {
    241243                typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;
    242                 if ( genC ) typeString = "struct " + typeString;
     244                if ( options.genC ) typeString = "struct " + typeString;
    243245                handleQualifiers( structInst );
    244246        }
     
    246248        void GenType::postvisit( UnionInstType * unionInst ) {
    247249                typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;
    248                 if ( genC ) typeString = "union " + typeString;
     250                if ( options.genC ) typeString = "union " + typeString;
    249251                handleQualifiers( unionInst );
    250252        }
     
    252254        void GenType::postvisit( EnumInstType * enumInst ) {
    253255                typeString = enumInst->name + " " + typeString;
    254                 if ( genC ) typeString = "enum " + typeString;
     256                if ( options.genC ) typeString = "enum " + typeString;
    255257                handleQualifiers( enumInst );
    256258        }
     
    262264
    263265        void GenType::postvisit( TupleType * tupleType ) {
    264                 assertf( ! genC, "Tuple types should not reach code generation." );
     266                assertf( ! options.genC, "Tuple types should not reach code generation." );
    265267                unsigned int i = 0;
    266268                std::ostringstream os;
     
    268270                for ( Type * t : *tupleType ) {
    269271                        i++;
    270                         os << genType( t, "", pretty, genC, lineMarks ) << (i == tupleType->size() ? "" : ", ");
     272                        os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", ");
    271273                }
    272274                os << "] ";
     
    281283        void GenType::postvisit( ZeroType * zeroType ) {
    282284                // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    283                 typeString = (pretty ? "zero_t " : "long int ") + typeString;
     285                typeString = (options.pretty ? "zero_t " : "long int ") + typeString;
    284286                handleQualifiers( zeroType );
    285287        }
     
    287289        void GenType::postvisit( OneType * oneType ) {
    288290                // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    289                 typeString = (pretty ? "one_t " : "long int ") + typeString;
     291                typeString = (options.pretty ? "one_t " : "long int ") + typeString;
    290292                handleQualifiers( oneType );
    291293        }
    292294
    293295        void GenType::postvisit( GlobalScopeType * globalType ) {
    294                 assertf( ! genC, "Global scope type should not reach code generation." );
     296                assertf( ! options.genC, "Global scope type should not reach code generation." );
    295297                handleQualifiers( globalType );
    296298        }
    297299
    298300        void GenType::postvisit( TraitInstType * inst ) {
    299                 assertf( ! genC, "Trait types should not reach code generation." );
     301                assertf( ! options.genC, "Trait types should not reach code generation." );
    300302                typeString = inst->name + " " + typeString;
    301303                handleQualifiers( inst );
     
    304306        void GenType::postvisit( TypeofType * typeof ) {
    305307                std::ostringstream os;
    306                 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
     308                PassVisitor<CodeGenerator> cg( os, options );
    307309                os << "typeof(";
    308310                typeof->expr->accept( cg );
     
    313315
    314316        void GenType::postvisit( QualifiedType * qualType ) {
    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;
     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;
    318320                typeString = os.str();
    319321                handleQualifiers( qualType );
     
    333335                        typeString = "_Atomic " + typeString;
    334336                } // if
    335                 if ( type->get_lvalue() && ! genC ) {
     337                if ( type->get_lvalue() && ! options.genC ) {
    336338                        // when not generating C code, print lvalue for debugging.
    337339                        typeString = "lvalue " + typeString;
  • src/CodeGen/GenType.h

    r6a9d4b4 r933f32f  
    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 : Fri Jul 21 22:17:23 2017
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr 30 11:47:00 2019
     13// Update Count     : 3
    1414//
    1515
     
    1818#include <string>  // for string
    1919
     20#include "CodeGen/Options.h" // for Options
     21
    2022class Type;
    2123
    2224namespace CodeGen {
     25        std::string genType( Type *type, const std::string &baseString, const Options &options );
    2326        std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false );
    2427  std::string genPrettyType( Type * type, const std::string & baseString );
  • src/CodeGen/module.mk

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

    r6a9d4b4 r933f32f  
    3939}
    4040
     41void abort(const char *fmt, ... ) noexcept __attribute__((noreturn, format(printf, 1, 2)));
     42void 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
    4151// Local Variables: //
    4252// tab-width: 4 //
  • src/Common/PassVisitor.h

    r6a9d4b4 r933f32f  
    44
    55#include <stack>
    6 
     6#include <type_traits>
     7
     8#include "Common/Stats.h"
    79#include "Common/utility.h"
    810
     
    153155        virtual void visit( ConstructorInit * ctorInit ) override final;
    154156
    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 
    259257        virtual Constant * mutate( Constant * constant ) override final;
    260258
     
    300298
    301299
    302         TypeSubstitution **             get_env_ptr    () { return env_impl             ( pass, 0); }
     300        auto                                    get_env_ptr    () -> decltype(env_impl( pass, 0)) { return env_impl( pass, 0); }
    303301        std::list< Statement* > *       get_beforeStmts() { return stmtsToAddBefore_impl( pass, 0); }
    304302        std::list< Statement* > *       get_afterStmts () { return stmtsToAddAfter_impl ( pass, 0); }
     
    347345};
    348346
     347class WithConstTypeSubstitution {
     348protected:
     349        WithConstTypeSubstitution() = default;
     350        ~WithConstTypeSubstitution() = default;
     351
     352public:
     353        const TypeSubstitution * env = nullptr;
     354};
     355
    349356class WithStmtsToAdd {
    350357protected:
     
    426433};
    427434
     435#include "Common/Stats.h"
     436
     437extern 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
    428443#include "SynTree/TypeSubstitution.h"
    429444#include "PassVisitor.impl.h"
  • src/Common/PassVisitor.impl.h

    r6a9d4b4 r933f32f  
    2020
    2121#define MUTATE_END( type, node )                \
    22         return call_postmutate< type * >( node ); \
     22        auto __return = call_postmutate< type * >( node ); \
     23        assert( __return ); \
     24        return __return;
    2325
    2426
     
    6769        SemanticErrorException errors;
    6870
     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);
    6974        for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) {
     75
     76
    7077                // splice in new declarations after previous decl
    7178                if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); }
     
    8390                if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); }
    8491        }
     92        pass_visitor_stats.depth--;
    8593        if ( ! errors.isEmpty() ) {
    8694                throw errors;
     
    94102        SemanticErrorException errors;
    95103
     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);
    96107        for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) {
    97108                // splice in new declarations after previous decl
     
    109120                if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); }
    110121        }
     122        pass_visitor_stats.depth--;
    111123        if ( ! errors.isEmpty() ) {
    112124                throw errors;
     
    126138        if ( ! visitor.get_visit_children() ) return;
    127139        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);
    128144        for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) {
    129145                try {
     
    135151                }
    136152        }
     153        pass_visitor_stats.depth--;
    137154        if ( ! errors.isEmpty() ) {
    138155                throw errors;
     
    151168template< typename Container, typename pass_type >
    152169inline void maybeMutate_impl( Container & container, PassVisitor< pass_type > & mutator ) {
     170
    153171        if ( ! mutator.get_visit_children() ) return;
    154172        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);
    155177        for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) {
    156178                try {
     
    163185                } // try
    164186        } // for
     187        pass_visitor_stats.depth--;
    165188        if ( ! errors.isEmpty() ) {
    166189                throw errors;
     
    185208        DeclList_t* afterDecls  = get_afterDecls();
    186209
     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);
    187213        for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) {
    188214
     
    192218                try {
    193219                        func( *i );
     220                        assert( *i );
    194221                        assert(( empty( beforeStmts ) && empty( afterStmts ))
    195222                            || ( empty( beforeDecls ) && empty( afterDecls )) );
     
    202229                if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); }
    203230        }
     231        pass_visitor_stats.depth--;
    204232
    205233        if ( !empty( afterDecls ) ) { splice( std::back_inserter( statements ), afterDecls); }
     
    229257
    230258        // don't want statements from outer CompoundStmts to be added to this CompoundStmt
    231         ValueGuardPtr< TypeSubstitution * >  oldEnv        ( get_env_ptr    () );
     259        ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type >  oldEnv( get_env_ptr() );
    232260        ValueGuardPtr< DeclList_t >          oldBeforeDecls( get_beforeDecls() );
    233261        ValueGuardPtr< DeclList_t >          oldAfterDecls ( get_afterDecls () );
     
    19651993
    19661994        // don't want statements from outer CompoundStmts to be added to this StmtExpr
    1967         ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
     1995        ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type >  oldEnv( get_env_ptr() );
    19681996        ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
    19691997        ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );
     
    19822010
    19832011        // don't want statements from outer CompoundStmts to be added to this StmtExpr
    1984         ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
     2012        ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type >  oldEnv( get_env_ptr() );
    19852013        ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
    19862014        ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );
     
    26782706
    26792707//--------------------------------------------------------------------------
    2680 // Subrange
    2681 template< typename pass_type >
    2682 void PassVisitor< pass_type >::visit( Subrange * node ) {
    2683         VISIT_START( node );
    2684 
    2685         VISIT_END( node );
    2686 }
    2687 
    2688 template< typename pass_type >
    2689 Subrange * PassVisitor< pass_type >::mutate( Subrange * node  )  {
    2690         MUTATE_START( node );
    2691 
    2692         MUTATE_END( Subrange, node );
    2693 }
    2694 
    2695 //--------------------------------------------------------------------------
    26962708// Attribute
    26972709template< typename pass_type >
  • src/Common/PassVisitor.proto.h

    r6a9d4b4 r933f32f  
    165165static inline type * name##_impl( __attribute__((unused)) pass_type& pass, __attribute__((unused)) long unused ) { return nullptr;}    \
    166166
    167 FIELD_PTR( TypeSubstitution *, env )
     167FIELD_PTR( const 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
    176178//---------------------------------------------------------
    177179// Indexer
     
    220222INDEXER_FUNC2( addWith   , std::list< Expression * > &, BaseSyntaxNode * );
    221223
     224#undef INDEXER_FUNC1
     225#undef INDEXER_FUNC2
    222226
    223227template<typename pass_type>
  • src/Common/SemanticError.h

    r6a9d4b4 r933f32f  
    1717
    1818#include "ErrorObjects.h"
     19#include "AST/Node.hpp"
    1920#include <cstring>
    2021
  • src/Common/Stats/Heap.h

    r6a9d4b4 r933f32f  
    1616#pragma once
    1717
    18 namespace HeapStats {
    19         void newPass( const char * const name );
    20         void printStats();
     18namespace Stats {
     19        namespace Heap {
     20                void newPass( const char * const name );
     21                void print();
     22        }
    2123}
  • src/Common/module.mk

    r6a9d4b4 r933f32f  
    1515###############################################################################
    1616
    17 SRC += Common/SemanticError.cc \
    18        Common/UniqueName.cc \
    19        Common/DebugMalloc.cc \
    20        Common/Assert.cc \
    21        Common/Heap.cc \
    22        Common/Eval.cc
     17SRC_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
     28SRC += $(SRC_COMMON) Common/DebugMalloc.cc
     29SRCDEMANGLE += $(SRC_COMMON)
  • src/Common/utility.h

    r6a9d4b4 r933f32f  
    463463std::pair<long long int, bool> eval(Expression * expr);
    464464
    465 // -----------------------------------------------------------------------------
    466 /// Reorders the input range in-place so that the minimal-value elements according to the
    467 /// comparator are in front;
     465namespace ast {
     466        class Expr;
     467}
     468
     469std::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;
    468474/// returns the iterator after the last minimal-value element.
    469475template<typename Iter, typename Compare>
    470476Iter sort_mins( Iter begin, Iter end, Compare& lt ) {
    471477        if ( begin == end ) return end;
    472        
     478
    473479        Iter min_pos = begin;
    474480        for ( Iter i = begin + 1; i != end; ++i ) {
  • src/CompilationState.cc

    r6a9d4b4 r933f32f  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon Ju1 30 10:47:01 2018
    11 // Last Modified By : Rob Schluntz
    12 // Last Modified On : Mon Ju1 30 10:46:25 2018
    13 // Update Count     : 2
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri May  3 13:45:23 2019
     13// Update Count     : 4
    1414//
    1515
    16 bool
     16int
    1717        astp = false,
    1818        bresolvep = false,
     
    2626        libcfap = false,
    2727        nopreludep = false,
    28         noprotop = false,
     28        genproto = false,
    2929        nomainp = false,
    3030        parsep = false,
  • src/CompilationState.h

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

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

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

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

    r6a9d4b4 r933f32f  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Aug 18 10:22:00 2017
    13 // Update Count     : 12
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Mar 11 22:26:52 2019
     13// Update Count     : 14
    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

    r6a9d4b4 r933f32f  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Rob Schluntz
    12 // Last Modified On : Tue Jul 28 13:32:43 2015
    13 // Update Count     : 156
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Mar 11 22:26:02 2019
     13// Update Count     : 159
    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
    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 ) {
     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 ) {
    8080                assert( definition != 0 );
    8181                assert( llabel.size() > 0 );
     
    100100                } // for
    101101
    102                 // produce one of the labels attached to this statement to be
    103                 // temporarily used as the canonical label
     102                // produce one of the labels attached to this statement to be temporarily used as the canonical label
    104103                return labelTable[ llabel.front() ]->get_label();
    105104        }
     
    117116
    118117        // Builds a table that maps a label to its defining statement.
    119         std::map<Label, Statement * > *LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
     118        std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
    120119                std::map< Label, Statement * > *ret = new std::map< Label, Statement * >();
    121120                for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) {
  • src/ControlStruct/LabelGenerator.cc

    r6a9d4b4 r933f32f  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Aug 14 14:14:00 2015
    13 // Update Count     : 14
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Mar 11 22:23:20 2019
     13// Update Count     : 15
    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 
    3231                return labelGenerator;
    3332        }
     
    3837                if ( stmt && ! stmt->get_labels().empty() ) {
    3938                        os << "_" << stmt->get_labels().front() << "__";
    40                 }
     39                } // if
    4140                std::string ret = os.str();
    4241                Label l( ret );
  • src/ControlStruct/module.mk

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

    r6a9d4b4 r933f32f  
    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 WithTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting {
     78                class Pass1 final : public BoxPass, public WithConstTypeSubstitution, 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 WithTypeSubstitution {
     152                class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithConstTypeSubstitution {
    153153                public:
    154154                        PolyGenericCalculator();
  • src/GenPoly/GenPoly.cc

    r6a9d4b4 r933f32f  
    440440        }
    441441
    442         bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, TypeSubstitution * env ) {
     442        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const 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, TypeSubstitution * env ) {
     452        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const 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

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

    r6a9d4b4 r933f32f  
    168168
    169169        /// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately
    170         struct GenericInstantiator final : public WithTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards {
     170        struct GenericInstantiator final : public WithConstTypeSubstitution, 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

    r6a9d4b4 r933f32f  
    4242
    4343namespace GenPoly {
    44         struct Specialize final : public WithTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {
     44        struct Specialize final : public WithConstTypeSubstitution, 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, TypeSubstitution *env ) {
     56        bool needsPolySpecialization( Type *formalType, Type *actualType, const TypeSubstitution *env ) {
    5757                if ( env ) {
    5858                        using namespace ResolvExpr;
     
    145145        }
    146146
    147         bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
     147        bool needsSpecialization( Type *formalType, Type *actualType, const TypeSubstitution *env ) {
    148148                return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType );
    149149        }
  • src/GenPoly/module.mk

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 21 17:35:05 2017
    13 // Update Count     : 74
     12// Last Modified On : Wed Feb 13 18:15:56 2019
     13// Update Count     : 76
    1414//
    1515#include "FixInit.h"
     
    7272                };
    7373
    74                 struct InsertImplicitCalls : public WithTypeSubstitution {
     74                struct InsertImplicitCalls : public WithConstTypeSubstitution {
    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

    r6a9d4b4 r933f32f  
    55#include <memory>                  // for __shared_ptr
    66
     7#include "AST/Expr.hpp"
     8#include "AST/Stmt.hpp"
     9#include "AST/Type.hpp"
    710#include "Common/PassVisitor.h"
    811#include "Common/SemanticError.h"  // for SemanticError
     
    2629#include "Tuples/Tuples.h"         // for Tuples::isTtype
    2730
    28 class UntypedValofExpr;
    29 
    3031namespace InitTweak {
    3132        namespace {
     
    432433                        assert( false );
    433434                }
     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                // }
    434448        }
    435449
     
    451465                        assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );
    452466                }
     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                // }
    453490        }
    454491
     
    513550                }
    514551        }
     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        }
    515564
    516565        Type * isPointerType( Type * type ) {
  • src/InitTweak/InitTweak.h

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

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

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

    r6a9d4b4 r933f32f  
    1010## Author           : Peter A. Buhr
    1111## Created On       : Sun May 31 08:51:46 2015
    12 ## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tus Jul 25 10:34:00 2017
    14 ## Update Count     : 76
     12## Last Modified By : Peter A. Buhr
     13## Last Modified On : Fri Feb 15 09:44:09 2019
     14## Update Count     : 97
    1515###############################################################################
    1616
     
    2020
    2121SRC = main.cc \
    22                         MakeLibCfa.cc \
    23                         CompilationState.cc
     22      MakeLibCfa.cc \
     23      CompilationState.cc
     24
     25SRCDEMANGLE = CompilationState.cc
    2426
    2527MAINTAINERCLEANFILES =
    26 MOSTLYCLEANFILES = Parser/gcc-flags.h
     28MOSTLYCLEANFILES =
    2729
    28 Parser/gcc-flags.h :
    29         ${AM_V_GEN}$(CC) -dM -E - < /dev/null | sed 's/define /define __GCC__/' > $(@)
     30if WITH_LIBPROFILER
     31LIBPROFILER = -lprofiler
     32endif
    3033
    31 Parser/lex.ll : Parser/gcc-flags.h
     34if WITH_LIBTCMALLOC
     35LIBTCMALLOC = -ltcmalloc
     36TCMALLOCFLAG = -DTCMALLOC
     37endif
    3238
    3339include CodeGen/module.mk
     
    4652include Virtual/module.mk
    4753
     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
    4861# put into lib for now
    4962cfa_cpplibdir = $(CFA_LIBDIR)
    5063cfa_cpplib_PROGRAMS = ../driver/cfa-cpp demangler
    5164___driver_cfa_cpp_SOURCES = $(SRC)
    52 ___driver_cfa_cpp_LDADD = -ldl                  # yywrap
     65___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC)
    5366
    54 AM_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
     67AM_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)
    5568AM_LDFLAGS  = @HOST_FLAGS@ -Xlinker -export-dynamic
    5669ARFLAGS     = cr
     
    5871demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete
    5972
    60 demangler_LDADD = libdemangle.a     # yywrap
     73demangler_LDADD = libdemangle.a -ldl                    # yywrap
    6174
    6275noinst_LIBRARIES = libdemangle.a
    63 libdemangle_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 
     76libdemangle_a_SOURCES = $(SRCDEMANGLE)
    15277
    15378MAINTAINERCLEANFILES += ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}}
  • src/Makefile.in

    r6a9d4b4 r933f32f  
    162162libdemangle_a_LIBADD =
    163163am__dirstamp = $(am__leading_dot)dirstamp
    164 am_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) \
     164am__objects_1 = CodeGen/CodeGenerator.$(OBJEXT) \
     165        CodeGen/FixMain.$(OBJEXT) CodeGen/GenType.$(OBJEXT) \
     166        CodeGen/OperatorTable.$(OBJEXT)
     167am__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)
     172am__objects_3 = ControlStruct/ForExprMutator.$(OBJEXT) \
    191173        ControlStruct/LabelFixer.$(OBJEXT) \
    192174        ControlStruct/LabelGenerator.$(OBJEXT) \
    193175        ControlStruct/MLEMutator.$(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) \
     176        ControlStruct/Mutate.$(OBJEXT)
     177am__objects_4 = ResolvExpr/AdjustExprType.$(OBJEXT) \
    198178        ResolvExpr/Alternative.$(OBJEXT) \
    199179        ResolvExpr/AlternativeFinder.$(OBJEXT) \
    200         ResolvExpr/ExplodedActual.$(OBJEXT) \
    201180        ResolvExpr/CastCost.$(OBJEXT) ResolvExpr/CommonType.$(OBJEXT) \
    202181        ResolvExpr/ConversionCost.$(OBJEXT) \
    203182        ResolvExpr/CurrentObject.$(OBJEXT) \
     183        ResolvExpr/ExplodedActual.$(OBJEXT) \
    204184        ResolvExpr/FindOpenVars.$(OBJEXT) ResolvExpr/Occurs.$(OBJEXT) \
    205185        ResolvExpr/PolyCost.$(OBJEXT) \
     
    212192        ResolvExpr/SpecCost.$(OBJEXT) \
    213193        ResolvExpr/TypeEnvironment.$(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)
    221 libdemangle_a_OBJECTS = $(am_libdemangle_a_OBJECTS)
    222 am__installdirs = "$(DESTDIR)$(cfa_cpplibdir)"
    223 PROGRAMS = $(cfa_cpplib_PROGRAMS)
    224 am__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) \
     194        ResolvExpr/Unify.$(OBJEXT)
     195am__objects_5 = SymTab/Autogen.$(OBJEXT) SymTab/FixFunction.$(OBJEXT) \
    271196        SymTab/Indexer.$(OBJEXT) SymTab/Mangler.$(OBJEXT) \
    272         SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT) \
    273         SymTab/FixFunction.$(OBJEXT) SymTab/Autogen.$(OBJEXT) \
    274         SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \
     197        SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT)
     198am__objects_6 = SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \
    275199        SynTree/BasicType.$(OBJEXT) SynTree/PointerType.$(OBJEXT) \
    276200        SynTree/ArrayType.$(OBJEXT) SynTree/ReferenceType.$(OBJEXT) \
     
    291215        SynTree/Initializer.$(OBJEXT) \
    292216        SynTree/TypeSubstitution.$(OBJEXT) SynTree/Attribute.$(OBJEXT) \
    293         SynTree/DeclReplacer.$(OBJEXT) \
     217        SynTree/DeclReplacer.$(OBJEXT)
     218am__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)
     228am_libdemangle_a_OBJECTS = $(am__objects_7)
     229libdemangle_a_OBJECTS = $(am_libdemangle_a_OBJECTS)
     230am__installdirs = "$(DESTDIR)$(cfa_cpplibdir)"
     231PROGRAMS = $(cfa_cpplib_PROGRAMS)
     232am__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) \
    294255        Tuples/TupleAssignment.$(OBJEXT) \
    295256        Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
     
    297258        Validate/FindSpecialDecls.$(OBJEXT) \
    298259        Virtual/ExpandCasts.$(OBJEXT)
    299 am____driver_cfa_cpp_OBJECTS = $(am__objects_1)
     260am____driver_cfa_cpp_OBJECTS = $(am__objects_8)
    300261___driver_cfa_cpp_OBJECTS = $(am____driver_cfa_cpp_OBJECTS)
    301 ___driver_cfa_cpp_DEPENDENCIES =
     262am__DEPENDENCIES_1 =
     263___driver_cfa_cpp_DEPENDENCIES = $(am__DEPENDENCIES_1) \
     264        $(am__DEPENDENCIES_1)
    302265AM_V_lt = $(am__v_lt_@AM_V@)
    303266am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
     
    418381DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    419382ACLOCAL = @ACLOCAL@
    420 ALLOCA = @ALLOCA@
    421383AMTAR = @AMTAR@
    422384AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    566528AUTOMAKE_OPTIONS = foreign subdir-objects
    567529ACLOCAL_AMFLAGS = -I automake
    568 SRC = 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 \
     530SRC = main.cc MakeLibCfa.cc CompilationState.cc $(SRC_CODEGEN) \
     531        CodeGen/Generate.cc CodeGen/FixNames.cc CodeTools/DeclStats.cc \
    572532        CodeTools/ResolvProtoDump.cc CodeTools/TrackLoc.cc \
    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 \
     533        Concurrency/Keywords.cc Concurrency/Waitfor.cc $(SRC_COMMON) \
     534        Common/DebugMalloc.cc $(SRC_CONTROLSTRUCT) \
    579535        ControlStruct/ExceptTranslate.cc GenPoly/Box.cc \
    580536        GenPoly/GenPoly.cc GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc \
     
    587543        Parser/StatementNode.cc Parser/InitializerNode.cc \
    588544        Parser/TypeData.cc Parser/LinkageSpec.cc \
    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 \
     545        Parser/parserutility.cc $(SRC_RESOLVEXPR) \
     546        ResolvExpr/AlternativePrinter.cc $(SRC_SYMTAB) $(SRC_SYNTREE) \
    618547        Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
    619548        Tuples/Explode.cc Validate/HandleAttributes.cc \
    620549        Validate/FindSpecialDecls.cc Virtual/ExpandCasts.cc
     550SRCDEMANGLE = 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
    621558MAINTAINERCLEANFILES = ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}}
    622 MOSTLYCLEANFILES = Parser/gcc-flags.h Parser/lex.cc Parser/parser.cc \
    623         Parser/parser.hh Parser/parser.output
    624 BUILT_SOURCES = Parser/parser.hh
    625 AM_YFLAGS = -d -t -v
    626 
    627 # put into lib for now
    628 cfa_cpplibdir = $(CFA_LIBDIR)
    629 ___driver_cfa_cpp_SOURCES = $(SRC)
    630 ___driver_cfa_cpp_LDADD = -ldl                  # yywrap
    631 AM_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
    632 AM_LDFLAGS = @HOST_FLAGS@ -Xlinker -export-dynamic
    633 ARFLAGS = cr
    634 demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete
    635 demangler_LDADD = libdemangle.a     # yywrap
    636 noinst_LIBRARIES = libdemangle.a
    637 libdemangle_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 \
     559MOSTLYCLEANFILES = 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
     564SRC_CODEGEN = \
    675565        CodeGen/CodeGenerator.cc \
    676566        CodeGen/FixMain.cc \
    677         CodeGen/Generate.cc \
    678567        CodeGen/GenType.cc \
    679         CodeGen/OperatorTable.cc \
    680         Common/Assert.cc \
    681         Common/Eval.cc \
    682         Common/SemanticError.cc \
    683         Common/UniqueName.cc \
    684         Concurrency/Keywords.cc \
     568        CodeGen/OperatorTable.cc
     569
     570SRC_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
     581SRC_CONTROLSTRUCT = \
    685582        ControlStruct/ForExprMutator.cc \
    686583        ControlStruct/LabelFixer.cc \
    687584        ControlStruct/LabelGenerator.cc \
    688585        ControlStruct/MLEMutator.cc \
    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 
     586        ControlStruct/Mutate.cc
     587
     588BUILT_SOURCES = Parser/parser.hh
     589AM_YFLAGS = -d -t -v
     590SRC_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
     612SRC_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
     620SRC_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
     658cfa_cpplibdir = $(CFA_LIBDIR)
     659___driver_cfa_cpp_SOURCES = $(SRC)
     660___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC)
     661AM_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)
     662AM_LDFLAGS = @HOST_FLAGS@ -Xlinker -export-dynamic
     663ARFLAGS = cr
     664demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete
     665demangler_LDADD = libdemangle.a -ldl                    # yywrap
     666noinst_LIBRARIES = libdemangle.a
     667libdemangle_a_SOURCES = $(SRCDEMANGLE)
    726668all: $(BUILT_SOURCES)
    727669        $(MAKE) $(AM_MAKEFLAGS) all-am
     
    762704clean-noinstLIBRARIES:
    763705        -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
    764 SymTab/$(am__dirstamp):
    765         @$(MKDIR_P) SymTab
    766         @: > SymTab/$(am__dirstamp)
    767 SymTab/$(DEPDIR)/$(am__dirstamp):
    768         @$(MKDIR_P) SymTab/$(DEPDIR)
    769         @: > SymTab/$(DEPDIR)/$(am__dirstamp)
    770 SymTab/Demangle.$(OBJEXT): SymTab/$(am__dirstamp) \
    771         SymTab/$(DEPDIR)/$(am__dirstamp)
    772 SymTab/ManglerCommon.$(OBJEXT): SymTab/$(am__dirstamp) \
    773         SymTab/$(DEPDIR)/$(am__dirstamp)
    774 SynTree/$(am__dirstamp):
    775         @$(MKDIR_P) SynTree
    776         @: > SynTree/$(am__dirstamp)
    777 SynTree/$(DEPDIR)/$(am__dirstamp):
    778         @$(MKDIR_P) SynTree/$(DEPDIR)
    779         @: > SynTree/$(DEPDIR)/$(am__dirstamp)
    780 SynTree/Type.$(OBJEXT): SynTree/$(am__dirstamp) \
    781         SynTree/$(DEPDIR)/$(am__dirstamp)
    782 SynTree/VoidType.$(OBJEXT): SynTree/$(am__dirstamp) \
    783         SynTree/$(DEPDIR)/$(am__dirstamp)
    784 SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \
    785         SynTree/$(DEPDIR)/$(am__dirstamp)
    786 SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \
    787         SynTree/$(DEPDIR)/$(am__dirstamp)
    788 SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \
    789         SynTree/$(DEPDIR)/$(am__dirstamp)
    790 SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \
    791         SynTree/$(DEPDIR)/$(am__dirstamp)
    792 SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \
    793         SynTree/$(DEPDIR)/$(am__dirstamp)
    794 SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \
    795         SynTree/$(DEPDIR)/$(am__dirstamp)
    796 SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \
    797         SynTree/$(DEPDIR)/$(am__dirstamp)
    798 SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \
    799         SynTree/$(DEPDIR)/$(am__dirstamp)
    800 SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \
    801         SynTree/$(DEPDIR)/$(am__dirstamp)
    802 SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \
    803         SynTree/$(DEPDIR)/$(am__dirstamp)
    804 SynTree/ZeroOneType.$(OBJEXT): SynTree/$(am__dirstamp) \
    805         SynTree/$(DEPDIR)/$(am__dirstamp)
    806 SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \
    807         SynTree/$(DEPDIR)/$(am__dirstamp)
    808 SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \
    809         SynTree/$(DEPDIR)/$(am__dirstamp)
    810 SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    811         SynTree/$(DEPDIR)/$(am__dirstamp)
    812 SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    813         SynTree/$(DEPDIR)/$(am__dirstamp)
    814 SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    815         SynTree/$(DEPDIR)/$(am__dirstamp)
    816 SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    817         SynTree/$(DEPDIR)/$(am__dirstamp)
    818 SynTree/AddressExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    819         SynTree/$(DEPDIR)/$(am__dirstamp)
    820 SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \
    821         SynTree/$(DEPDIR)/$(am__dirstamp)
    822 SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
    823         SynTree/$(DEPDIR)/$(am__dirstamp)
    824 SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
    825         SynTree/$(DEPDIR)/$(am__dirstamp)
    826 SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \
    827         SynTree/$(DEPDIR)/$(am__dirstamp)
    828 SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \
    829         SynTree/$(DEPDIR)/$(am__dirstamp)
    830 SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    831         SynTree/$(DEPDIR)/$(am__dirstamp)
    832 SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    833         SynTree/$(DEPDIR)/$(am__dirstamp)
    834 SynTree/AggregateDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    835         SynTree/$(DEPDIR)/$(am__dirstamp)
    836 SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    837         SynTree/$(DEPDIR)/$(am__dirstamp)
    838 SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    839         SynTree/$(DEPDIR)/$(am__dirstamp)
    840 SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \
    841         SynTree/$(DEPDIR)/$(am__dirstamp)
    842 SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \
    843         SynTree/$(DEPDIR)/$(am__dirstamp)
    844 SynTree/Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \
    845         SynTree/$(DEPDIR)/$(am__dirstamp)
    846 SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \
    847         SynTree/$(DEPDIR)/$(am__dirstamp)
    848706CodeGen/$(am__dirstamp):
    849707        @$(MKDIR_P) CodeGen
     
    856714CodeGen/FixMain.$(OBJEXT): CodeGen/$(am__dirstamp) \
    857715        CodeGen/$(DEPDIR)/$(am__dirstamp)
    858 CodeGen/Generate.$(OBJEXT): CodeGen/$(am__dirstamp) \
    859         CodeGen/$(DEPDIR)/$(am__dirstamp)
    860716CodeGen/GenType.$(OBJEXT): CodeGen/$(am__dirstamp) \
    861717        CodeGen/$(DEPDIR)/$(am__dirstamp)
    862718CodeGen/OperatorTable.$(OBJEXT): CodeGen/$(am__dirstamp) \
    863719        CodeGen/$(DEPDIR)/$(am__dirstamp)
     720Concurrency/$(am__dirstamp):
     721        @$(MKDIR_P) Concurrency
     722        @: > Concurrency/$(am__dirstamp)
     723Concurrency/$(DEPDIR)/$(am__dirstamp):
     724        @$(MKDIR_P) Concurrency/$(DEPDIR)
     725        @: > Concurrency/$(DEPDIR)/$(am__dirstamp)
     726Concurrency/Keywords.$(OBJEXT): Concurrency/$(am__dirstamp) \
     727        Concurrency/$(DEPDIR)/$(am__dirstamp)
    864728Common/$(am__dirstamp):
    865729        @$(MKDIR_P) Common
     
    872736Common/Eval.$(OBJEXT): Common/$(am__dirstamp) \
    873737        Common/$(DEPDIR)/$(am__dirstamp)
     738Common/PassVisitor.$(OBJEXT): Common/$(am__dirstamp) \
     739        Common/$(DEPDIR)/$(am__dirstamp)
    874740Common/SemanticError.$(OBJEXT): Common/$(am__dirstamp) \
    875741        Common/$(DEPDIR)/$(am__dirstamp)
     742Common/Stats/$(am__dirstamp):
     743        @$(MKDIR_P) Common/Stats
     744        @: > Common/Stats/$(am__dirstamp)
     745Common/Stats/$(DEPDIR)/$(am__dirstamp):
     746        @$(MKDIR_P) Common/Stats/$(DEPDIR)
     747        @: > Common/Stats/$(DEPDIR)/$(am__dirstamp)
     748Common/Stats/Counter.$(OBJEXT): Common/Stats/$(am__dirstamp) \
     749        Common/Stats/$(DEPDIR)/$(am__dirstamp)
     750Common/Stats/Heap.$(OBJEXT): Common/Stats/$(am__dirstamp) \
     751        Common/Stats/$(DEPDIR)/$(am__dirstamp)
     752Common/Stats/Stats.$(OBJEXT): Common/Stats/$(am__dirstamp) \
     753        Common/Stats/$(DEPDIR)/$(am__dirstamp)
     754Common/Stats/Time.$(OBJEXT): Common/Stats/$(am__dirstamp) \
     755        Common/Stats/$(DEPDIR)/$(am__dirstamp)
    876756Common/UniqueName.$(OBJEXT): Common/$(am__dirstamp) \
    877757        Common/$(DEPDIR)/$(am__dirstamp)
    878 Concurrency/$(am__dirstamp):
    879         @$(MKDIR_P) Concurrency
    880         @: > Concurrency/$(am__dirstamp)
    881 Concurrency/$(DEPDIR)/$(am__dirstamp):
    882         @$(MKDIR_P) Concurrency/$(DEPDIR)
    883         @: > Concurrency/$(DEPDIR)/$(am__dirstamp)
    884 Concurrency/Keywords.$(OBJEXT): Concurrency/$(am__dirstamp) \
    885         Concurrency/$(DEPDIR)/$(am__dirstamp)
    886758ControlStruct/$(am__dirstamp):
    887759        @$(MKDIR_P) ControlStruct
     
    940812ResolvExpr/AlternativeFinder.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    941813        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     814ResolvExpr/CastCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
     815        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     816ResolvExpr/CommonType.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
     817        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     818ResolvExpr/ConversionCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
     819        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     820ResolvExpr/CurrentObject.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
     821        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    942822ResolvExpr/ExplodedActual.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    943823        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    944 ResolvExpr/CastCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    945         ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    946 ResolvExpr/CommonType.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    947         ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    948 ResolvExpr/ConversionCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    949         ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    950 ResolvExpr/CurrentObject.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    951         ResolvExpr/$(DEPDIR)/$(am__dirstamp)
    952824ResolvExpr/FindOpenVars.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    953825        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     
    974846ResolvExpr/Unify.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
    975847        ResolvExpr/$(DEPDIR)/$(am__dirstamp)
     848SymTab/$(am__dirstamp):
     849        @$(MKDIR_P) SymTab
     850        @: > SymTab/$(am__dirstamp)
     851SymTab/$(DEPDIR)/$(am__dirstamp):
     852        @$(MKDIR_P) SymTab/$(DEPDIR)
     853        @: > SymTab/$(DEPDIR)/$(am__dirstamp)
    976854SymTab/Autogen.$(OBJEXT): SymTab/$(am__dirstamp) \
    977855        SymTab/$(DEPDIR)/$(am__dirstamp)
     
    982860SymTab/Mangler.$(OBJEXT): SymTab/$(am__dirstamp) \
    983861        SymTab/$(DEPDIR)/$(am__dirstamp)
     862SymTab/ManglerCommon.$(OBJEXT): SymTab/$(am__dirstamp) \
     863        SymTab/$(DEPDIR)/$(am__dirstamp)
    984864SymTab/Validate.$(OBJEXT): SymTab/$(am__dirstamp) \
    985865        SymTab/$(DEPDIR)/$(am__dirstamp)
     866SymTab/Demangle.$(OBJEXT): SymTab/$(am__dirstamp) \
     867        SymTab/$(DEPDIR)/$(am__dirstamp)
     868SynTree/$(am__dirstamp):
     869        @$(MKDIR_P) SynTree
     870        @: > SynTree/$(am__dirstamp)
     871SynTree/$(DEPDIR)/$(am__dirstamp):
     872        @$(MKDIR_P) SynTree/$(DEPDIR)
     873        @: > SynTree/$(DEPDIR)/$(am__dirstamp)
     874SynTree/Type.$(OBJEXT): SynTree/$(am__dirstamp) \
     875        SynTree/$(DEPDIR)/$(am__dirstamp)
     876SynTree/VoidType.$(OBJEXT): SynTree/$(am__dirstamp) \
     877        SynTree/$(DEPDIR)/$(am__dirstamp)
     878SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \
     879        SynTree/$(DEPDIR)/$(am__dirstamp)
     880SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \
     881        SynTree/$(DEPDIR)/$(am__dirstamp)
     882SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \
     883        SynTree/$(DEPDIR)/$(am__dirstamp)
     884SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \
     885        SynTree/$(DEPDIR)/$(am__dirstamp)
     886SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \
     887        SynTree/$(DEPDIR)/$(am__dirstamp)
     888SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \
     889        SynTree/$(DEPDIR)/$(am__dirstamp)
     890SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \
     891        SynTree/$(DEPDIR)/$(am__dirstamp)
     892SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \
     893        SynTree/$(DEPDIR)/$(am__dirstamp)
     894SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \
     895        SynTree/$(DEPDIR)/$(am__dirstamp)
     896SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \
     897        SynTree/$(DEPDIR)/$(am__dirstamp)
     898SynTree/ZeroOneType.$(OBJEXT): SynTree/$(am__dirstamp) \
     899        SynTree/$(DEPDIR)/$(am__dirstamp)
     900SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \
     901        SynTree/$(DEPDIR)/$(am__dirstamp)
     902SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \
     903        SynTree/$(DEPDIR)/$(am__dirstamp)
     904SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     905        SynTree/$(DEPDIR)/$(am__dirstamp)
     906SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     907        SynTree/$(DEPDIR)/$(am__dirstamp)
     908SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     909        SynTree/$(DEPDIR)/$(am__dirstamp)
     910SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     911        SynTree/$(DEPDIR)/$(am__dirstamp)
     912SynTree/AddressExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     913        SynTree/$(DEPDIR)/$(am__dirstamp)
     914SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \
     915        SynTree/$(DEPDIR)/$(am__dirstamp)
     916SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
     917        SynTree/$(DEPDIR)/$(am__dirstamp)
     918SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
     919        SynTree/$(DEPDIR)/$(am__dirstamp)
     920SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \
     921        SynTree/$(DEPDIR)/$(am__dirstamp)
     922SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \
     923        SynTree/$(DEPDIR)/$(am__dirstamp)
     924SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     925        SynTree/$(DEPDIR)/$(am__dirstamp)
     926SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     927        SynTree/$(DEPDIR)/$(am__dirstamp)
     928SynTree/AggregateDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     929        SynTree/$(DEPDIR)/$(am__dirstamp)
     930SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     931        SynTree/$(DEPDIR)/$(am__dirstamp)
     932SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     933        SynTree/$(DEPDIR)/$(am__dirstamp)
     934SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \
     935        SynTree/$(DEPDIR)/$(am__dirstamp)
     936SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \
     937        SynTree/$(DEPDIR)/$(am__dirstamp)
     938SynTree/Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \
     939        SynTree/$(DEPDIR)/$(am__dirstamp)
     940SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \
     941        SynTree/$(DEPDIR)/$(am__dirstamp)
    986942Tuples/$(am__dirstamp):
    987943        @$(MKDIR_P) Tuples
     
    990946        @$(MKDIR_P) Tuples/$(DEPDIR)
    991947        @: > Tuples/$(DEPDIR)/$(am__dirstamp)
    992 Tuples/Explode.$(OBJEXT): Tuples/$(am__dirstamp) \
    993         Tuples/$(DEPDIR)/$(am__dirstamp)
    994948Tuples/TupleAssignment.$(OBJEXT): Tuples/$(am__dirstamp) \
    995949        Tuples/$(DEPDIR)/$(am__dirstamp)
    996950Tuples/TupleExpansion.$(OBJEXT): Tuples/$(am__dirstamp) \
     951        Tuples/$(DEPDIR)/$(am__dirstamp)
     952Tuples/Explode.$(OBJEXT): Tuples/$(am__dirstamp) \
    997953        Tuples/$(DEPDIR)/$(am__dirstamp)
    998954Validate/$(am__dirstamp):
     
    10601016        echo " rm -f" $$list; \
    10611017        rm -f $$list
     1018CodeGen/Generate.$(OBJEXT): CodeGen/$(am__dirstamp) \
     1019        CodeGen/$(DEPDIR)/$(am__dirstamp)
    10621020CodeGen/FixNames.$(OBJEXT): CodeGen/$(am__dirstamp) \
    10631021        CodeGen/$(DEPDIR)/$(am__dirstamp)
     
    10771035        Concurrency/$(DEPDIR)/$(am__dirstamp)
    10781036Common/DebugMalloc.$(OBJEXT): Common/$(am__dirstamp) \
    1079         Common/$(DEPDIR)/$(am__dirstamp)
    1080 Common/Heap.$(OBJEXT): Common/$(am__dirstamp) \
    10811037        Common/$(DEPDIR)/$(am__dirstamp)
    10821038ControlStruct/ExceptTranslate.$(OBJEXT):  \
     
    11491105        -rm -f CodeTools/*.$(OBJEXT)
    11501106        -rm -f Common/*.$(OBJEXT)
     1107        -rm -f Common/Stats/*.$(OBJEXT)
    11511108        -rm -f Concurrency/*.$(OBJEXT)
    11521109        -rm -f ControlStruct/*.$(OBJEXT)
     
    11791136@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/DebugMalloc.Po@am__quote@
    11801137@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/Eval.Po@am__quote@
    1181 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/Heap.Po@am__quote@
     1138@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/PassVisitor.Po@am__quote@
    11821139@AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/SemanticError.Po@am__quote@
    11831140@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@
    11841145@AMDEP_TRUE@@am__include@ @am__quote@Concurrency/$(DEPDIR)/Keywords.Po@am__quote@
    11851146@AMDEP_TRUE@@am__include@ @am__quote@Concurrency/$(DEPDIR)/Waitfor.Po@am__quote@
     
    14441405        -rm -f Common/$(DEPDIR)/$(am__dirstamp)
    14451406        -rm -f Common/$(am__dirstamp)
     1407        -rm -f Common/Stats/$(DEPDIR)/$(am__dirstamp)
     1408        -rm -f Common/Stats/$(am__dirstamp)
    14461409        -rm -f Concurrency/$(DEPDIR)/$(am__dirstamp)
    14471410        -rm -f Concurrency/$(am__dirstamp)
     
    14811444
    14821445distclean: distclean-am
    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)
     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)
    14841447        -rm -f Makefile
    14851448distclean-am: clean-am distclean-compile distclean-generic \
     
    15271490
    15281491maintainer-clean: maintainer-clean-am
    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)
     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)
    15301493        -rm -f Makefile
    15311494maintainer-clean-am: distclean-am maintainer-clean-generic
     
    15671530
    15681531
    1569 Parser/gcc-flags.h :
    1570         ${AM_V_GEN}$(CC) -dM -E - < /dev/null | sed 's/define /define __GCC__/' > $(@)
    1571 
    1572 Parser/lex.ll : Parser/gcc-flags.h
     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
    15731538
    15741539# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • src/Parser/DeclarationNode.cc

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Sat May 16 13:17:07 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jun  4 21:24:45 2018
    13 // Update Count     : 802
     12// Last Modified On : Sun Mar 10 16:10:32 2019
     13// Update Count     : 976
    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 checkL( char c ) { return c == 'l' || c == 'L'; }
    55 static inline bool checkZ( char c ) { return c == 'z' || c == 'Z'; }
    56 static inline bool checkU( char c ) { return c == 'u' || c == 'U'; }
     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'; }
    5756static inline bool checkF( char c ) { return c == 'f' || c == 'F'; }
    5857static inline bool checkD( char c ) { return c == 'd' || c == 'D'; }
     58static inline bool checkF80( char c ) { return c == 'w' || c == 'W'; }
     59static inline bool checkF128( char c ) { return c == 'q' || c == 'Q'; }
     60static inline bool checkL( char c ) { return c == 'l' || c == 'L'; }
    5961static inline bool checkI( char c ) { return c == 'i' || c == 'I'; }
    6062static inline bool checkB( char c ) { return c == 'b' || c == 'B'; }
    6163static inline bool checkX( char c ) { return c == 'x' || c == 'X'; }
    62 
    63 static 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 
    68 static 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;
     64// static inline bool checkN( char c ) { return c == 'n' || c == 'N'; }
     65
     66void 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;
    7982                } else {                                                                                // 128
    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
     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
     90void 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
    95109
    96110Expression * build_constantInteger( string & str ) {
    97         static const BasicType::Kind kind[2][6] = {
    98                 // short (h) must be before char (hh)
     111        static const BasicType::Kind kind[2][7] = {
     112                // short (h) must be before char (hh) because shorter type has the longer suffix
    99113                { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, BasicType::SignedInt128, },
    100114                { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::UnsignedInt128, },
    101115        };
    102116
    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
     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
    106121
    107122        unsigned long long int v;                                                       // converted integral value
    108123        size_t last = str.length() - 1;                                         // last subscript of constant
    109124        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
    110130
    111131        // special constants
     
    119139        } // if
    120140
    121         // Cannot be "0"
     141        // Cannot be just "0"/"1"; sscanf stops at the suffix, if any; value goes over the wall => always generate
    122142
    123143        if ( str[0] == '0' ) {                                                          // radix character ?
     
    127147                        //printf( "%llx %llu\n", v, v );
    128148                } else if ( checkB( str[1] ) ) {                                // binary constant ?
    129                         v = 0;
    130                         for ( unsigned int i = 2;; i += 1 ) {           // compute value
     149                        v = 0;                                                                          // compute value
     150                        for ( unsigned int i = 2;; ) {                          // ignore prefix
    131151                                if ( str[i] == '1' ) v |= 1;
    132                           if ( i == last ) break;
     152                                i += 1;
     153                          if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
    133154                                v <<= 1;
    134155                        } // for
    135                         //printf( "%llx %llu\n", v, v );
     156                        //printf( "%#llx %llu\n", v, v );
    136157                } else {                                                                                // octal constant
    137158                        sscanf( (char *)str.c_str(), "%llo", &v );
    138                         //printf( "%llo %llu\n", v, v );
     159                        //printf( "%#llo %llu\n", v, v );
    139160                } // if
    140161        } else {                                                                                        // decimal constant ?
    141162                sscanf( (char *)str.c_str(), "%llu", &v );
    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;
     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
     209        // 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 ?
     212                // 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 ) );
    170221                        } // 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 );
    209         // Constant type is correct for overload resolving.
    210         ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[Unsigned][size] ), str, v ) );
    211         if ( Unsigned && size < 2 ) {                                           // hh or h, less than int ?
    212                 // 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][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 
     222                } // if
     223        } // if
     224
     225  CLEANUP: ;
    224226        delete &str;                                                                            // created by lex
    225227        return ret;
     
    227229
    228230
    229 static inline void checkLNFloat( string & str, int & lnth, int & size ) {
    230         string::size_type posn = str.find_first_of( "lL" ), start = posn;
     231static 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
    231240  if ( posn == string::npos ) return;
    232         size = 2;                                                                                       // assume largest size
    233         lnth = 0;
     241        explnth = true;
    234242        posn += 1;                                                                                      // advance to size
    235243        if ( str[posn] == '3' ) {                                                       // 32
    236                 size = 0;
     244                if ( str[last] != 'x' ) type = 6;
     245                else type = 7;
    237246        } else if ( str[posn] == '6' ) {                                        // 64
    238                 size = 1;
    239         } else if ( str[posn] == '8' || str[posn] == '1' ) { // 80, 128
    240                 size = 2;
    241                 if ( str[posn] == '1' ) posn += 1;
     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
    242258        } else {
    243259                assertf( false, "internal error, bad floating point length %s", str.c_str() );
    244260        } // if
    245         posn += 1;
    246         str.erase( start, posn - start + 1 );                           // remove length suffix
    247 } // checkLNFloat
     261} // checkFnxFloat
    248262
    249263
    250264Expression * build_constantFloat( string & str ) {
    251         static const BasicType::Kind kind[2][3] = {
    252                 { BasicType::Float, BasicType::Double, BasicType::LongDouble },
    253                 { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex },
     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 },
    254268        };
    255269
    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
     270        // floating-point constant has minimum of 2 characters 1. or .1
    260271        size_t last = str.length() - 1;
    261272        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
    262276
    263277        sscanf( str.c_str(), "%lg", &v );
     
    269283
    270284        if ( checkF( str[last] ) ) {                                            // float ?
    271                 size = 0;
     285                type = 0;
    272286        } else if ( checkD( str[last] ) ) {                                     // double ?
    273                 size = 1;
     287                type = 1;
    274288        } else if ( checkL( str[last] ) ) {                                     // long double ?
    275                 size = 2;
     289                type = 2;
     290        } else if ( checkF80( str[last] ) ) {                           // __float80 ?
     291                type = 3;
     292        } else if ( checkF128( str[last] ) ) {                          // __float128 ?
     293                type = 4;
    276294        } else {
    277                 size = 1;                                                                               // double (default)
    278                 checkLNFloat( str, lnth, size );
    279         } // if
     295                type = 1;                                                                               // double (default if no suffix)
     296                checkFnxFloat( str, last, explnth, type );
     297        } // if
     298
    280299        if ( ! complx && checkI( str[last - 1] ) ) {            // imaginary ?
    281300                complx = true;
    282301        } // if
    283302
    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 );
     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 );
    288307        } // if
    289308
  • src/Parser/ParseNode.h

    r6a9d4b4 r933f32f  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Nov  1 20:54:53 2018
    13 // Update Count     : 854
     12// Last Modified On : Mon Apr 15 14:22:39 2019
     13// Update Count     : 874
    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(); }
    135134        template<typename T>
    136135        bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); }
    137136
    138137        Expression * build() const { return const_cast<ExpressionNode *>(this)->expr.release(); }
     138
     139        std::unique_ptr<Expression> expr;                                       // public because of lifetime implications
    139140  private:
    140141        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.
    209         enum BasicType { Void, Bool, Char, Int, Float, Double, LongDouble, Int128, Float80, Float128, NoBasicType };
     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 };
    210212        static const char * basicTypeNames[];
    211         enum ComplexType { Complex, Imaginary, NoComplexType };
     213        enum ComplexType { Complex, NoComplexType, Imaginary }; // Imaginary unsupported => parse, but make invisible and print error message
    212214        static const char * complexTypeNames[];
    213215        enum Signedness { Signed, Unsigned, NoSignedness };
  • src/Parser/TypeData.cc

    r6a9d4b4 r933f32f  
    1010// Created On       : Sat May 16 15:12:51 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Nov  2 07:54:26 2018
    13 // Update Count     : 624
     12// Last Modified On : Wed Feb 13 18:16:23 2019
     13// Update Count     : 649
    1414//
    1515
     
    666666
    667667          case DeclarationNode::Float:
    668           case DeclarationNode::Float80:
    669           case DeclarationNode::Float128:
    670668          case DeclarationNode::Double:
    671669          case DeclarationNode::LongDouble:                                     // not set until below
    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 },
     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, },
    676682                };
    677683
     
    686692                        genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype );
    687693                } // 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
    688700                if ( td->length == DeclarationNode::Long ) {
    689701                        const_cast<TypeData *>(td)->basictype = DeclarationNode::LongDouble;
    690702                } // if
    691703
    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 
    701704                ret = floattype[ td->complextype ][ td->basictype - DeclarationNode::Float ];
     705                //printf( "XXXX %d %d %d %d\n", td->complextype, td->basictype, DeclarationNode::Float, ret );
    702706                break;
    703707
  • src/Parser/TypeData.h

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

    r6a9d4b4 r933f32f  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Thu Nov  1 20:57:35 2018
    13  * Update Count     : 687
     12 * Last Modified On : Wed May 15 21:25:27 2019
     13 * Update Count     : 708
    1414 */
    1515
     
    3939using namespace std;
    4040
     41#include "config.h"                                                                             // configure info
    4142#include "ParseNode.h"
    4243#include "TypedefTable.h"
     
    5960#define IDENTIFIER_RETURN()     RETURN_VAL( typedefTable.isKind( yytext ) )
    6061#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
    6168
    6269void rm_underscore() {
     
    9299hex_quad {hex}("_"?{hex}){3}
    93100size_opt (8|16|32|64|128)?
    94 length ("ll"|"LL"|[lL]{size_opt})|("hh"|"HH"|[hH])
    95 integer_suffix_opt ("_"?(([uU]({length}?[iI]?)|([iI]{length}))|([iI]({length}?[uU]?)|([uU]{length}))|({length}([iI]?[uU]?)|([uU][iI]))|[zZ]))?
     101                                // CFA: explicit l8/l16/l32/l64/l128, char 'hh', short 'h', int 'n'
     102length ("ll"|"LL"|[lL]{size_opt})|("hh"|"HH"|[hHnN])
     103                                // CFA: size_t 'z', pointer 'p', which define a sign and length
     104integer_suffix_opt ("_"?(([uU]({length}?[iI]?)|([iI]{length}))|([iI]({length}?[uU]?)|([uU]{length}))|({length}([iI]?[uU]?)|([uU][iI]))|[zZ]|[pP]))?
    96105
    97106octal_digits ({octal})|({octal}({octal}|"_")*{octal})
     
    112121                                // GCC: D (double) and iI (imaginary) suffixes, and DL (long double)
    113122exponent "_"?[eE]"_"?[+-]?{decimal_digits}
    114 floating_size 32|64|80|128
    115 floating_length ([fFdDlL]|[lL]{floating_size})
     123floating_size 16|32|32x|64|64x|80|128|128x
     124floating_length ([fFdDlLwWqQ]|[fF]{floating_size})
    116125floating_suffix ({floating_length}?[iI]?)|([iI]{floating_length})
    117126floating_suffix_opt ("_"?({floating_suffix}|"DL"))?
     
    217226char                    { KEYWORD_RETURN(CHAR); }
    218227choose                  { KEYWORD_RETURN(CHOOSE); }                             // CFA
     228coerce                  { KEYWORD_RETURN(COERCE); }                             // CFA
    219229_Complex                { KEYWORD_RETURN(COMPLEX); }                    // C99
    220230__complex               { KEYWORD_RETURN(COMPLEX); }                    // GCC
     
    240250finally                 { KEYWORD_RETURN(FINALLY); }                    // CFA
    241251float                   { KEYWORD_RETURN(FLOAT); }
    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
    247 float80                 { KEYWORD_RETURN(FLOAT80); }                    // GCC
    248 _Float128               { KEYWORD_RETURN(FLOAT128); }                   // GCC
    249 _Float128x              { KEYWORD_RETURN(FLOAT128); }                   // GCC
    250 __float128              { KEYWORD_RETURN(FLOAT128); }                   // GCC
    251 float128                { KEYWORD_RETURN(FLOAT128); }                   // GCC
     252__float80               { KEYWORD_RETURN(uuFLOAT80); }                  // GCC
     253float80                 { KEYWORD_RETURN(uuFLOAT80); }                  // GCC
     254__float128              { KEYWORD_RETURN(uuFLOAT128); }                 // GCC
     255float128                { 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
    252263for                             { KEYWORD_RETURN(FOR); }
    253264forall                  { KEYWORD_RETURN(FORALL); }                             // CFA
    254265fortran                 { KEYWORD_RETURN(FORTRAN); }
    255266ftype                   { KEYWORD_RETURN(FTYPE); }                              // CFA
     267generator               { KEYWORD_RETURN(GENERATOR); }                  // CFA
    256268_Generic                { KEYWORD_RETURN(GENERIC); }                    // C11
    257269goto                    { KEYWORD_RETURN(GOTO); }
  • src/Parser/module.mk

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Nov  8 18:08:23 2018
    13 // Update Count     : 4052
     12// Last Modified On : Wed May 15 21:25:27 2019
     13// Update Count     : 4296
    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         //cur->addType( specifier );
    102         for ( cur = dynamic_cast< DeclarationNode * >( cur->get_next() ); cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
     101        for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {
    103102                cl->cloneBaseType( cur );
    104103        } // for
    105104        declList->addType( cl );
    106 //      delete cl;
    107105        return declList;
    108106} // distAttr
     
    175173DeclarationNode * fieldDecl( DeclarationNode * typeSpec, DeclarationNode * fieldList ) {
    176174        if ( ! fieldList ) {                                                            // field declarator ?
    177                 if ( ! ( typeSpec->type && typeSpec->type->kind == TypeData::Aggregate ) ) {
     175                if ( ! ( typeSpec->type && (typeSpec->type->kind == TypeData::Aggregate || typeSpec->type->kind == TypeData::Enum) ) ) {
    178176                        stringstream ss;
    179177                        typeSpec->type->print( ss );
     
    187185
    188186ForCtrl * forCtrl( ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    189         ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->get_expr());
     187        ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->expr.get());
    190188        if ( constant && (constant->get_constant()->get_value() == "0" || constant->get_constant()->get_value() == "1") ) {
    191189        type = new ExpressionNode( new CastExpr( maybeMoveBuild< Expression >(type), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ) );
     
    193191        return new ForCtrl(
    194192                distAttr( DeclarationNode::newTypeof( type, true ), DeclarationNode::newName( index )->addInitializer( new InitializerNode( start ) ) ),
    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 ) ) );
     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 );
    198197} // forCtrl
    199198
    200199ForCtrl * forCtrl( ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    201         if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->get_expr()) ) {
     200        if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->expr.get()) ) {
    202201                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
    203208        } else {
    204209                SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr;
     
    260265%token RESTRICT                                                                                 // C99
    261266%token ATOMIC                                                                                   // C11
    262 %token FORALL MUTEX VIRTUAL                                                             // CFA
     267%token FORALL MUTEX VIRTUAL COERCE                                              // CFA
    263268%token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED
    264269%token BOOL COMPLEX IMAGINARY                                                   // C99
    265 %token INT128 FLOAT80 FLOAT128                                                  // GCC
     270%token INT128 uuFLOAT80 uuFLOAT128                                              // GCC
     271%token uFLOAT16 uFLOAT32 uFLOAT32X uFLOAT64 uFLOAT64X uFLOAT128 // GCC
    266272%token ZERO_T ONE_T                                                                             // CFA
    267273%token VALIST                                                                                   // GCC
     
    269275%token ENUM STRUCT UNION
    270276%token EXCEPTION                                                                                // CFA
    271 %token COROUTINE MONITOR THREAD                                                 // CFA
     277%token GENERATOR COROUTINE MONITOR THREAD                               // CFA
    272278%token OTYPE FTYPE DTYPE TTYPE TRAIT                                    // CFA
    273279%token SIZEOF OFFSETOF
     
    324330%type<en> argument_expression_list              argument_expression                     default_initialize_opt
    325331%type<ifctl> if_control_expression
    326 %type<fctl> for_control_expression
     332%type<fctl> for_control_expression              for_control_expression_list
    327333%type<compop> inclexcl
    328334%type<en> subrange
    329335%type<decl> asm_name_opt
    330 %type<en> asm_operands_opt asm_operands_list asm_operand
     336%type<en> asm_operands_opt                              asm_operands_list                       asm_operand
    331337%type<label> label_list
    332338%type<en> asm_clobbers_list_opt
    333339%type<flag> asm_volatile_opt
    334340%type<en> handler_predicate_opt
    335 %type<genexpr> generic_association generic_assoc_list
     341%type<genexpr> generic_association              generic_assoc_list
    336342
    337343// statements
     
    671677        // empty
    672678                { $$ = nullptr; }
    673         | '?'                                                                                           // CFA, default parameter
     679        | '@'                                                                                           // CFA, default parameter
    674680                { SemanticError( yylloc, "Default parameter for argument is currently unimplemented." ); $$ = nullptr; }
    675681                // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); }
     
    789795        | '(' type_no_function ')' cast_expression
    790796                { $$ = 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 ) ); }
    791800        | '(' COROUTINE '&' ')' cast_expression                         // CFA
    792801                { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }
     
    800809        | '(' VIRTUAL type_no_function ')' cast_expression      // CFA
    801810                { $$ = 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; }
    802817//      | '(' type_no_function ')' tuple
    803818//              { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
     819        ;
     820
     821qualifier_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
     828cast_modifier:
     829        '-'
     830        | '+'
    804831        ;
    805832
     
    9841011                // labels cannot be identifiers 0 or 1 or ATTR_IDENTIFIER
    9851012        identifier_or_type_name ':' attribute_list_opt statement
    986                 {
    987                         $$ = $4->add_label( $1, $3 );
    988                 }
     1013                { $$ = $4->add_label( $1, $3 ); }
    9891014        ;
    9901015
     
    10021027        statement_decl
    10031028        | statement_decl_list statement_decl
    1004                 { if ( $1 != 0 ) { $1->set_last( $2 ); $$ = $1; } }
     1029                { assert( $1 ); $1->set_last( $2 ); $$ = $1; }
    10051030        ;
    10061031
     
    10091034                { $$ = new StatementNode( $1 ); }
    10101035        | EXTENSION declaration                                                         // GCC
    1011                 {
    1012                         distExt( $2 );
    1013                         $$ = new StatementNode( $2 );
    1014                 }
     1036                { distExt( $2 ); $$ = new StatementNode( $2 ); }
    10151037        | function_definition
    10161038                { $$ = new StatementNode( $1 ); }
    10171039        | EXTENSION function_definition                                         // GCC
    1018                 {
    1019                         distExt( $2 );
    1020                         $$ = new StatementNode( $2 );
    1021                 }
     1040                { distExt( $2 ); $$ = new StatementNode( $2 ); }
    10221041        | statement
    10231042        ;
     
    10261045        statement
    10271046        | statement_list_nodecl statement
    1028                 { if ( $1 != 0 ) { $1->set_last( $2 ); $$ = $1; } }
     1047                { assert( $1 ); $1->set_last( $2 ); $$ = $1; }
    10291048        ;
    10301049
     
    11381157        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    11391158                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2 ) ); }
    1140         | FOR '(' push for_control_expression ')' statement pop
     1159        | FOR '(' push for_control_expression_list ')' statement pop
    11411160                { $$ = new StatementNode( build_for( $4, $6 ) ); }
    11421161        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
     
    11441163        ;
    11451164
     1165for_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
    11461188for_control_expression:
    1147         comma_expression                                                                        // CFA
     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
    11481197                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11491198                                                OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1150         | constant_expression inclexcl constant_expression      // CFA
     1199        | comma_expression inclexcl comma_expression            // CFA
    11511200                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1152         | constant_expression inclexcl constant_expression '~' constant_expression // CFA
     1201        | comma_expression inclexcl comma_expression '~' comma_expression // CFA
    11531202                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, $5 ); }
    11541203        | comma_expression ';' comma_expression                         // CFA
    11551204                { $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11561205                                                OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1157         | comma_expression ';' constant_expression inclexcl constant_expression // CFA
     1206        | comma_expression ';' comma_expression inclexcl comma_expression // CFA
    11581207                { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1159         | comma_expression ';' constant_expression inclexcl constant_expression '~' constant_expression // CFA
     1208        | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA
    11601209                { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); }
    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 ); }
     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 ); }
    11671222        ;
    11681223
     
    17711826        | FLOAT
    17721827                { $$ = DeclarationNode::newBasicType( DeclarationNode::Float ); }
    1773         | FLOAT80
    1774                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float80 ); }
    1775         | FLOAT128
    1776                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float128 ); }
    17771828        | DOUBLE
    17781829                { $$ = 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 ); }
    17791846        | COMPLEX                                                                                       // C99
    17801847                { $$ = DeclarationNode::newComplexType( DeclarationNode::Complex ); }
     
    19962063        | EXCEPTION
    19972064                { yyy = true; $$ = DeclarationNode::Exception; }
     2065        | GENERATOR
     2066                { yyy = true; $$ = DeclarationNode::Coroutine; }
    19982067        | COROUTINE
    19992068                { yyy = true; $$ = DeclarationNode::Coroutine; }
  • src/ResolvExpr/AlternativeFinder.cc

    r6a9d4b4 r933f32f  
    258258                        // - necessary pre-requisite to pruning
    259259                        AltList candidates;
     260                        std::list<std::string> errors;
    260261                        for ( unsigned i = 0; i < alternatives.size(); ++i ) {
    261                                 resolveAssertions( alternatives[i], indexer, candidates );
     262                                resolveAssertions( alternatives[i], indexer, candidates, errors );
    262263                        }
    263264                        // fail early if none such
    264265                        if ( mode.failFast && candidates.empty() ) {
    265266                                std::ostringstream stream;
    266                                 stream << "No resolvable alternatives for expression " << expr << "\n"
    267                                        << "Alternatives with failing assertions are:\n";
    268                                 printAlts( alternatives, stream, 1 );
     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                                }
    269273                                SemanticError( expr->location, stream.str() );
    270274                        }
  • src/ResolvExpr/CommonType.cc

    r6a9d4b4 r933f32f  
    1010// Created On       : Sun May 17 06:59:27 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Sep 25 15:18:17 2017
    13 // Update Count     : 9
     12// Last Modified On : Thu Feb 14 17:10:10 2019
     13// Update Count     : 24
    1414//
    1515
     
    176176        }
    177177
    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         };
     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
    207480        static_assert(
    208                 sizeof(combinedType)/sizeof(combinedType[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
     481                sizeof(commonTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
    209482                "Each basic type kind should have a corresponding row in the combined type matrix"
    210483        );
     
    218491        void CommonType::postvisit( BasicType *basicType ) {
    219492                if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
    220                         BasicType::Kind newType = combinedType[ basicType->get_kind() ][ otherBasic->get_kind() ];
     493                        BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ otherBasic->get_kind() ];
    221494                        if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= otherBasic->get_qualifiers() ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->get_qualifiers() <= otherBasic->get_qualifiers() ) || widenSecond ) ) {
    222495                                result = new BasicType( basicType->get_qualifiers() | otherBasic->get_qualifiers(), newType );
     
    224497                } else if ( dynamic_cast< EnumInstType * > ( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) {
    225498                        // use signed int in lieu of the enum/zero/one type
    226                         BasicType::Kind newType = combinedType[ basicType->get_kind() ][ BasicType::SignedInt ];
     499                        BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];
    227500                        if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= type2->get_qualifiers() ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->get_qualifiers() <= type2->get_qualifiers() ) || widenSecond ) ) {
    228501                                result = new BasicType( basicType->get_qualifiers() | type2->get_qualifiers(), newType );
  • src/ResolvExpr/ConversionCost.cc

    r6a9d4b4 r933f32f  
    1010// Created On       : Sun May 17 07:06:19 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Sep 25 15:43:34 2017
    13 // Update Count     : 10
     12// Last Modified On : Mon May  6 14:18:22 2019
     13// Update Count     : 25
    1414//
    1515
     
    2828
    2929namespace ResolvExpr {
    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 };
     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
    3841
    3942#if 0
     
    4245#define PRINT(x)
    4346#endif
     47
    4448        Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    4549                if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
     
    179183        }
    180184
    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         };
     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
    263253        static_assert(
    264254                sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
    265                 "Each basic type kind should have a corresponding row in the cost matrix"
     255                "Missing row in the cost matrix"
    266256        );
    267257
     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        );
    268304
    269305        void ConversionCost::postvisit( VoidType * ) {
     
    279315                                cost = Cost::zero;
    280316                                cost.incSafe( tableResult );
     317                                cost.incSign( signMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ] );
    281318                        } // if
    282319                } else if ( dynamic_cast< EnumInstType *>( dest ) ) {
     
    300337                                        // types are the same, except otherPointer has more qualifiers
    301338                                        cost = Cost::safe;
    302                                 }
     339                                } // if
    303340                        } else {
    304341                                int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );
     
    422459                                cost = Cost::zero;
    423460                                cost.incSafe( tableResult + 1 );
    424                         }
     461                                cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] );
     462                        } // if
    425463                } else if ( dynamic_cast< PointerType* >( dest ) ) {
    426                         cost = Cost::safe;
    427                 }
     464                        cost = Cost::zero;
     465                        cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation
     466                } // if
    428467        }
    429468
     
    439478                                cost = Cost::zero;
    440479                                cost.incSafe( tableResult + 1 );
    441                         }
    442                 }
     480                                cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] );
     481                        } // if
     482                } // if
    443483        }
    444484} // namespace ResolvExpr
  • src/ResolvExpr/Cost.h

    r6a9d4b4 r933f32f  
    77// Cost.h --
    88//
    9 // Author           : Richard C. Bilson
     9// Author           : Peter Buhr and Aaron Moss
    1010// Created On       : Sun May 17 09:39:50 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Fri Oct 05 14:32:00 2018
    13 // Update Count     : 7
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 29 18:33:44 2019
     13// Update Count     : 49
    1414//
    1515
     
    1717
    1818#include <iostream>
     19#include <cassert>
     20#include <climits>
    1921
    2022namespace ResolvExpr {
     23#if 0
     24
     25        //*************************** OLD ***************************
     26
    2127        class Cost {
    2228          private:
    23                 Cost( int unsafeCost, int polyCost, int safeCost, int varCost, int specCost,
    24                         int referenceCost );
    25 
     29                Cost( int unsafeCost, int polyCost, int safeCost, int signCost,
     30                          int varCost, int specCost, int referenceCost );
    2631          public:
    2732                Cost & incUnsafe( int inc = 1 );
    2833                Cost & incPoly( int inc = 1 );
    2934                Cost & incSafe( int inc = 1 );
     35                Cost & incSign( int inc = 1 );
    3036                Cost & incVar( int inc = 1 );
    3137                Cost & decSpec( int inc = 1 );
     
    3541                int get_polyCost() const { return polyCost; }
    3642                int get_safeCost() const { return safeCost; }
     43                int get_signCost() const { return signCost; }
    3744                int get_varCost() const { return varCost; }
    3845                int get_specCost() const { return specCost; }
     
    4047
    4148                Cost operator+( const Cost &other ) const;
    42                 Cost operator-( const Cost &other ) const;
    4349                Cost &operator+=( const Cost &other );
    4450                bool operator<( const Cost &other ) const;
     
    5561                static const Cost poly;
    5662                static const Cost safe;
     63                static const Cost sign;
    5764                static const Cost var;
    5865                static const Cost spec;
     
    6370                int polyCost;       ///< Count of parameters and return values bound to some poly type
    6471                int safeCost;       ///< Safe (widening) conversions
     72                int signCost;       ///< Count of safe sign conversions
    6573                int varCost;        ///< Count of polymorphic type variables
    6674                int specCost;       ///< Polymorphic type specializations (type assertions), negative cost
     
    6876        };
    6977
    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 ) {}
     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 ) {}
    7482
    7583        inline Cost & Cost::incUnsafe( int inc ) {
     
    8896                if ( *this == infinity ) return *this;
    8997                safeCost += inc;
     98                return *this;
     99        }
     100
     101        inline Cost & Cost::incSign( int inc ) {
     102                if ( *this == infinity ) return *this;
     103                signCost += inc;
    90104                return *this;
    91105        }
     
    111125        inline Cost Cost::operator+( const Cost &other ) const {
    112126                if ( *this == infinity || other == infinity ) return infinity;
    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 };
     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 };
    125131        }
    126132
     
    134140                polyCost += other.polyCost;
    135141                safeCost += other.safeCost;
     142                signCost += other.signCost;
    136143                varCost += other.varCost;
    137144                specCost += other.specCost;
     
    156163                } else if ( safeCost < other.safeCost ) {
    157164                        return true;
     165                } else if ( signCost > other.signCost ) {
     166                        return false;
     167                } else if ( signCost < other.signCost ) {
     168                        return true;
    158169                } else if ( varCost > other.varCost ) {
    159170                        return false;
     
    180191                c = polyCost - other.polyCost; if ( c ) return c;
    181192                c = safeCost - other.safeCost; if ( c ) return c;
     193                c = signCost - other.signCost; if ( c ) return c;
    182194                c = varCost - other.varCost; if ( c ) return c;
    183195                c = specCost - other.specCost; if ( c ) return c;
     
    189201                        && polyCost == other.polyCost
    190202                        && safeCost == other.safeCost
     203                        && signCost == other.signCost
    191204                        && varCost == other.varCost
    192205                        && specCost == other.specCost
     
    199212
    200213        inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {
    201                 return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", "
    202                           << cost.safeCost << ", " << cost.varCost << ", " << cost.specCost << ", "
     214                return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", "
     215                          << cost.safeCost << ", " << cost.signCost << ", "
     216                                  << cost.varCost << ", " << cost.specCost << ", "
    203217                          << cost.referenceCost << " )";
    204218        }
     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
    205374} // namespace ResolvExpr
    206375
  • src/ResolvExpr/RenameVars.cc

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

    r6a9d4b4 r933f32f  
    2020#include <list>                     // for list
    2121#include <memory>                   // for unique_ptr
    22 #include <string>
     22#include <sstream>                  // for ostringstream
     23#include <string>                   // for string
    2324#include <unordered_map>            // for unordered_map, unordered_multimap
    2425#include <utility>                  // for move
     
    2728#include "Alternative.h"            // for Alternative, AssertionItem, AssertionList
    2829#include "Common/FilterCombos.h"    // for filterCombos
     30#include "Common/Indenter.h"        // for Indenter
    2931#include "Common/utility.h"         // for sort_mins
    3032#include "ResolvExpr/RenameVars.h"  // for renameTyVars
     
    3335#include "SynTree/Expression.h"     // for InferredParams
    3436#include "TypeEnvironment.h"        // for TypeEnvironment, etc.
    35 #include "typeops.h"                // for adjustExprType
     37#include "typeops.h"                // for adjustExprType, specCost
    3638#include "Unify.h"                  // for unify
    3739
     
    5658        using CandidateList = std::vector<AssnCandidate>;
    5759
    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 
    7760        /// Reference to single deferred item
    7861        struct DeferRef {
    79                 const AssnCacheItem& item;
     62                const DeclarationWithType* decl;
     63                const AssertionSetValue& info;
    8064                const AssnCandidate& match;
    8165        };
     
    8468        /// Acts like indexed list of DeferRef
    8569        struct DeferItem {
    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; }
     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] }; }
    10582        };
    10683
     
    177154                                for ( const auto& assn : x.assns ) {
    178155                                        k += computeConversionCost(
    179                                                 assn.match.adjType, assn.item.deferIds[0].decl->get_type(), indexer,
    180                                                 x.env );
     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                                        }
    181171                                }
    182172                                it = cache.emplace_hint( it, &x, k );
     
    249239
    250240        /// Resolve a single assertion, in context
    251         bool resolveAssertion( AssertionItem& assn, ResnState& resn, AssnCache& cache ) {
     241        bool resolveAssertion( AssertionItem& assn, ResnState& resn ) {
    252242                // skip unused assertions
    253243                if ( ! assn.info.isUsed ) return true;
    254244
    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                                                 }
    288                                         }
    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                                 }
     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;
     271                                        }
     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;
    295278                        }
    296 
    297                         it = cache.emplace_hint( it, assnKey, AssnCacheItem{ std::move(matches) } );
    298                 }
    299 
    300                 CandidateList& matches = it->second.matches;
     279                }
    301280
    302281                // break if no suitable assertion
     
    305284                // defer if too many suitable assertions
    306285                if ( matches.size() > 1 ) {
    307                         it->second.deferIds.emplace_back( assn.decl, assn.info );
    308                         resn.deferred.emplace_back( cache, assnKey );
     286                        resn.deferred.emplace_back( assn.decl, assn.info, std::move(matches) );
    309287                        return true;
    310288                }
     
    314292                addToIndexer( match.have, resn.indexer );
    315293                resn.newNeed.insert( match.need.begin(), match.need.end() );
    316                 resn.alt.env = match.env;
    317                 resn.alt.openVars = match.openVars;
     294                resn.alt.env = std::move(match.env);
     295                resn.alt.openVars = std::move(match.openVars);
    318296
    319297                bindAssertion( assn.decl, assn.info, resn.alt, match, resn.inferred );
     
    364342        static const int recursionLimit = /* 10 */ 4;
    365343
    366         void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ) {
     344        void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out, std::list<std::string>& errors ) {
    367345                // finish early if no assertions to resolve
    368346                if ( alt.need.empty() ) {
     
    376354                ResnList resns{ ResnState{ alt, root_indexer } };
    377355                ResnList new_resns{};
    378                 AssnCache assnCache;
    379356
    380357                // resolve assertions in breadth-first-order up to a limited number of levels deep
     
    385362                                for ( auto& assn : resn.need ) {
    386363                                        // fail early if any assertion is not resolvable
    387                                         if ( ! resolveAssertion( assn, resn, assnCache ) ) goto nextResn;
     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                                        }
    388375                                }
    389376
     
    396383                                        }
    397384                                } 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() );
    402385                                        // resolve deferred assertions by mutual compatibility
    403386                                        std::vector<CandidateEnvMerger::OutType> compatible = filterCombos(
    404387                                                resn.deferred,
    405388                                                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                                        }
    406404                                        // sort by cost
    407405                                        CandidateCost coster{ resn.indexer };
     
    429427                                                        new_resn.newNeed.insert( match.need.begin(), match.need.end() );
    430428
    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                                                         }
     429                                                        bindAssertion( r.decl, r.info, new_resn.alt, match, new_resn.inferred );
    436430                                                }
    437431
  • src/ResolvExpr/ResolveAssertions.h

    r6a9d4b4 r933f32f  
    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 );
     26        void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out, std::list<std::string>& errors );
    2727} // namespace ResolvExpr
    2828
  • src/ResolvExpr/Resolver.cc

    r6a9d4b4 r933f32f  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:17:01 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Fri Oct 05 09:43:00 2018
    13 // Update Count     : 214
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Tue Feb 19 18:09:56 2019
     13// Update Count     : 240
    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                 static CastExpr untyped( nullptr ); // cast to void
    293                 untyped.location = expr->location;
     292                CastExpr * untyped = new CastExpr( expr ); // cast to void
     293                untyped->location = expr->location;
    294294
    295295                // set up and resolve expression cast to void
    296                 untyped.arg = expr;
    297296                Alternative choice;
    298                 findUnfinishedKindExpression( &untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
     297                findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
    299298                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

    r6a9d4b4 r933f32f  
    1010// Created On       : Sun May 17 12:18:34 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:36:57 2017
    13 // Update Count     : 3
     12// Last Modified On : Mon Feb 18 20:40:38 2019
     13// Update Count     : 4
    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

    r6a9d4b4 r933f32f  
    386386        }
    387387
    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 ) {
     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 ) {
    389391
    390392                auto class1 = internal_lookup( var1->get_name() );
     
    428430                                        class1->set_type( common );
    429431                                }
     432                                class1->data.isComplete |= data.isComplete;
    430433                                env.erase( class2 );
    431434                        } else return false;
     
    435438                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
    436439                                class1->allowWidening = widen1;
     440                                class1->data.isComplete |= data.isComplete;
    437441                                env.erase( class2 );
    438442                        } else {
    439443                                class2->vars.insert( class1->vars.begin(), class1->vars.end() );
    440444                                class2->allowWidening = widen2;
     445                                class2->data.isComplete |= data.isComplete;
    441446                                env.erase( class1 );
    442447                        } // if
     
    445450                        class1->vars.insert( var2->get_name() );
    446451                        class1->allowWidening = widen1;
     452                        class1->data.isComplete |= data.isComplete;
    447453                } else if ( class2 != env.end() ) {
    448454                        // var1 unbound, add to class2
    449455                        class2->vars.insert( var1->get_name() );
    450456                        class2->allowWidening = widen2;
     457                        class2->data.isComplete |= data.isComplete;
    451458                } else {
    452459                        // neither var bound, create new class
  • src/ResolvExpr/TypeEnvironment.h

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

    r6a9d4b4 r933f32f  
    2121#include <string>                 // for string, operator==, operator!=, bas...
    2222#include <utility>                // for pair, move
    23 
     23#include <vector>
     24
     25#include "AST/Node.hpp"
     26#include "AST/Type.hpp"
    2427#include "Common/PassVisitor.h"   // for PassVisitor
    2528#include "FindOpenVars.h"         // for findOpenVars
     
    172175                bool isopen2 = var2 && ( entry2 != openVars.end() );
    173176
    174                 if ( isopen1 && isopen2 && entry1->second == entry2->second ) {
    175                         result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
     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                        }
    176185                } else if ( isopen1 ) {
    177186                        result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
     
    624633        }
    625634
    626         // xxx - compute once and store in the FunctionType?
    627635        Type * extractResultType( FunctionType * function ) {
    628636                if ( function->get_returnVals().size() == 0 ) {
     
    638646                }
    639647        }
     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        }
    640660} // namespace ResolvExpr
    641661
  • src/ResolvExpr/module.mk

    r6a9d4b4 r933f32f  
    1515###############################################################################
    1616
    17 SRC += 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
     17SRC_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
     39SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc
     40SRCDEMANGLE += $(SRC_RESOLVEXPR)
  • src/ResolvExpr/typeops.h

    r6a9d4b4 r933f32f  
    1010// Created On       : Sun May 17 07:28:22 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:36:18 2017
    13 // Update Count     : 3
     12// Last Modified On : Fri Feb  8 09:30:34 2019
     13// Update Count     : 4
    1414//
    1515
     
    1818#include <vector>
    1919
     20#include "AST/Node.hpp"
     21#include "AST/Type.hpp"
    2022#include "SynTree/SynTree.h"
    2123#include "SynTree/Type.h"
     
    99101        /// creates the type represented by the list of returnVals in a FunctionType. The caller owns the return value.
    100102        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 );
    101105
    102106        // in CommonType.cc
    103         Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
     107        Type * commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
    104108
    105109        // in PolyCost.cc
  • src/SymTab/Indexer.cc

    r6a9d4b4 r933f32f  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:37:33 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 17 16:08:40 2017
    13 // Update Count     : 20
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Mar  8 13:55:00 2019
     13// Update Count     : 21
    1414//
    1515
     
    1717
    1818#include <cassert>                 // for assert, strict_dynamic_cast
    19 #include <iostream>                // for operator<<, basic_ostream, ostream
    2019#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
    2425
    2526#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
    2627#include "Common/SemanticError.h"  // for SemanticError
    2728#include "Common/utility.h"        // for cloneAll
    28 #include "GenPoly/GenPoly.h"
     29#include "Common/Stats/Counter.h"  // for counters
     30#include "GenPoly/GenPoly.h"       // for getFunctionType
    2931#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    3032#include "Mangler.h"               // for Mangler
     
    3840#include "SynTree/Type.h"          // for Type, StructInstType, UnionInstType
    3941
    40 #define debugPrint(x) if ( doDebug ) { std::cerr << x; }
    41 
    4242namespace SymTab {
    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;
     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)
    11471                        };
    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         }
     72                        return ret;
     73                }
     74        }
     75
     76        Indexer::Indexer()
     77        : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
     78          prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
    20679
    20780        Indexer::~Indexer() {
    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;
     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;
    231109        }
    232110
    233111        void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
    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 );
     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                }
    258122        }
    259123
    260124        NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
    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 );
     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;
    265130        }
    266131
    267132        StructDecl *Indexer::lookupStruct( const std::string &id ) const {
    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 );
     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;
     138        }
     139
     140        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;
     146        }
     147
     148        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;
     154        }
     155
     156        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;
    272172        }
    273173
    274174        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
    275                 return lookupTypeAtScope( id, 0 );
     175                return atScope( 0 )->lookupType( id );
    276176        }
    277177
    278178        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
    279                 return lookupStructAtScope( id, 0 );
     179                return atScope( 0 )->lookupStruct( id );
    280180        }
    281181
    282182        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
    283                 return lookupUnionAtScope( id, 0 );
     183                return atScope( 0 )->lookupUnion( id );
    284184        }
    285185
    286186        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
    287                 return lookupEnumAtScope( id, 0 );
    288         }
    289 
    290         EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
    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 );
    295         }
    296 
    297         UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
    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 );
    302         }
    303 
    304         TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
    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 );
     187                return atScope( 0 )->lookupEnum( id );
    405188        }
    406189
     
    424207        }
    425208
    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
     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
    428215                assert( (isObject( added ) && isObject( existing.id ) )
    429216                        || ( isFunction( added ) && isFunction( existing.id ) ) );
    430217
    431                 if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
     218                if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
    432219                        // new definition shadows the autogenerated one, even at the same scope
    433220                        return false;
    434                 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) {
     221                } else if ( LinkageSpec::isMangled( added->linkage )
     222                                || ResolvExpr::typesCompatible(
     223                                        added->get_type(), existing.id->get_type(), Indexer() ) ) {
    435224
    436225                        // it is a conflict if one declaration is deleted and the other is not
    437226                        if ( deleteStmt && ! existing.deleteStmt ) {
    438                                 return handleConflicts( existing, "deletion of defined identifier " );
     227                                if ( handleConflicts.mode == OnConflict::Error ) {
     228                                        SemanticError( added, "deletion of defined identifier " );
     229                                }
     230                                return true;
    439231                        } else if ( ! deleteStmt && existing.deleteStmt ) {
    440                                 return handleConflicts( existing, "definition of deleted identifier " );
     232                                if ( handleConflicts.mode == OnConflict::Error ) {
     233                                        SemanticError( added, "definition of deleted identifier " );
     234                                }
     235                                return true;
    441236                        }
    442237
    443238                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    444                                 if ( isFunction( added ) ) {
    445                                         return handleConflicts( existing, "duplicate function definition for " );
     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;
     246                        } // if
     247                } else {
     248                        if ( handleConflicts.mode == OnConflict::Error ) {
     249                                SemanticError( added, "duplicate definition for " );
     250                        }
     251                        return true;
     252                } // if
     253
     254                return true;
     255        }
     256
     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                                        }
    446358                                } else {
    447                                         return handleConflicts( existing, "duplicate object definition for " );
    448                                 } // if
    449                         } // if
    450                 } else {
    451                         return handleConflicts( existing, "duplicate definition for " );
    452                 } // if
    453 
     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
    454432                return true;
    455433        }
    456434
    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 
     435        void Indexer::addId(
     436                        DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr,
     437                        BaseSyntaxNode * deleteStmt ) {
     438                ++*stats().add_calls;
    462439                const std::string &name = decl->name;
     440                if ( name == "" ) return;
     441               
    463442                std::string mangleName;
    464443                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
    465                         // mangle the name without including the appropriate suffix, so overridable routines are placed into the
    466                         // same "bucket" as their user defined versions.
     444                        // mangle the name without including the appropriate suffix, so overridable routines
     445                        // are placed into the same "bucket" as their user defined versions.
    467446                        mangleName = Mangler::mangle( decl, false );
    468447                } else {
     
    470449                } // if
    471450
    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 ) ) {
     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 ) ) {
     454                        // Check that a Cforall declaration doesn't override any C declaration
     455                        if ( hasCompatibleCDecl( name, mangleName ) ) {
     456                                SemanticError( decl, "Cforall declaration hides C function " );
     457                        }
     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 ) ) {
    480462                                SemanticError( decl, "conflicting overload of C function " );
    481463                        }
    482                 } else {
    483                         // Check that a Cforall declaration doesn't override any C declaration
    484                         if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
    485                                 SemanticError( decl, "Cforall declaration hides C function " );
    486                         }
    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;
     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) ) );
    496508        }
    497509
    498510        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
    499511                // default handling of conflicts is to raise an error
    500                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );
     512                addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
    501513        }
    502514
    503515        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
    504516                // default handling of conflicts is to raise an error
    505                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
     517                addId( decl, OnConflict::error(), nullptr, deleteStmt );
    506518        }
    507519
     
    518530                        }
    519531                }
    520                 // does not need to be added to the table if both existing and added have a base that are the same
     532                // does not need to be added to the table if both existing and added have a base that are
     533                // the same
    521534                return true;
    522535        }
    523536
    524537        void Indexer::addType( NamedTypeDecl *decl ) {
    525                 debugPrint( "Adding type " << decl->name << std::endl );
    526                 makeWritable();
    527 
     538                ++*stats().add_calls;
    528539                const std::string &id = decl->name;
    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                 }
     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 } );
    541554        }
    542555
     
    551564
    552565        void Indexer::addStruct( const std::string &id ) {
    553                 debugPrint( "Adding fwd decl for struct " << id << std::endl );
    554566                addStruct( new StructDecl( id ) );
    555567        }
    556568
    557569        void Indexer::addStruct( StructDecl *decl ) {
    558                 debugPrint( "Adding struct " << decl->name << std::endl );
    559                 makeWritable();
    560 
     570                ++*stats().add_calls;
    561571                const std::string &id = decl->name;
    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                 }
     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 } );
    574586        }
    575587
    576588        void Indexer::addEnum( EnumDecl *decl ) {
    577                 debugPrint( "Adding enum " << decl->name << std::endl );
    578                 makeWritable();
    579 
     589                ++*stats().add_calls;
    580590                const std::string &id = decl->name;
    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                 }
     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 } );
    593605        }
    594606
    595607        void Indexer::addUnion( const std::string &id ) {
    596                 debugPrint( "Adding fwd decl for union " << id << std::endl );
    597608                addUnion( new UnionDecl( id ) );
    598609        }
    599610
    600611        void Indexer::addUnion( UnionDecl *decl ) {
    601                 debugPrint( "Adding union " << decl->name << std::endl );
    602                 makeWritable();
    603 
     612                ++*stats().add_calls;
    604613                const std::string &id = decl->name;
    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                 }
     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 } );
    617628        }
    618629
    619630        void Indexer::addTrait( TraitDecl *decl ) {
    620                 debugPrint( "Adding trait " << decl->name << std::endl );
    621                 makeWritable();
    622 
     631                ++*stats().add_calls;
    623632                const std::string &id = decl->name;
    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 ) {
     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 ) {
    639651                for ( Declaration * decl : aggr->members ) {
    640652                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     
    642654                                if ( dwt->name == "" ) {
    643655                                        Type * t = dwt->get_type()->stripReferences();
    644                                         if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
     656                                        if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {
    645657                                                Expression * base = expr->clone();
    646658                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
     
    659671                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
    660672
    661                                 addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
    662                                         // on conflict, delete the identifier
    663                                         existing.deleteStmt = withStmt;
    664                                         return true;
    665                                 });
     673                                addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
    666674                        }
    667675                }
     
    685693                addIds( ftype->returnVals );
    686694                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 
    747695        }
    748696
  • src/SymTab/Indexer.h

    r6a9d4b4 r933f32f  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:38:55 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 17 16:09:12 2017
    13 // Update Count     : 8
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Mar  8 13:55:00 2019
     13// Update Count     : 9
    1414//
    1515
    1616#pragma once
    1717
    18 #include <iosfwd>             // for ostream
    19 #include <list>               // for list
    20 #include <string>             // for string
    21 #include <functional>         // for function
     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
    2222
    23 #include "SynTree/Visitor.h"  // for Visitor
    24 #include "SynTree/SynTree.h"  // for AST nodes
     23#include "Common/PersistentMap.h"  // for PersistentMap
     24#include "SynTree/SynTree.h"       // for AST nodes
    2525
    2626namespace ResolvExpr {
    27 class Cost;
     27        class Cost;
    2828}
    2929
    3030namespace SymTab {
    31         class Indexer {
    32           public:
     31        class Indexer : public std::enable_shared_from_this<SymTab::Indexer> {
     32        public:
    3333                explicit Indexer();
     34                virtual ~Indexer();
    3435
    35                 Indexer( const Indexer &that );
    36                 Indexer( Indexer &&that );
    37                 virtual ~Indexer();
    38                 Indexer& operator= ( const Indexer &that );
    39                 Indexer& operator= ( Indexer &&that );
    40 
    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
     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
    4338                void enterScope();
    4439                void leaveScope();
     
    5045                        /// non-null if this declaration is deleted
    5146                        BaseSyntaxNode * deleteStmt = nullptr;
     47                        /// scope of identifier
     48                        unsigned long scope = 0;
    5249
    5350                        // NOTE: shouldn't need either of these constructors, but gcc-4 does not properly support initializer lists with default members.
    5451                        IdData() = default;
    55                         IdData( DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ) {}
     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 ) {}
    5658
    5759                        Expression * combine( ResolvExpr::Cost & cost ) const;
     
    8082                EnumDecl *globalLookupEnum( const std::string &id ) const;
    8183
    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 
    10084                void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr );
    10185                void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt );
     
    11296                void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt );
    11397
    114                 /// adds all of the members of the Aggregate (addWith helper)
    115                 void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction );
    116 
    11798                /// convenience function for adding a list of Ids to the indexer
    11899                void addIds( const std::list< DeclarationWithType * > & decls );
     
    124105                void addFunctionType( FunctionType * ftype );
    125106
    126                 bool doDebug = false; ///< Display debugging trace?
    127107          private:
    128                 struct Impl;
     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
    129113
    130                 Impl *tables;         ///< Copy-on-write instance of table data structure
    131                 unsigned long scope;  ///< Scope index of this pointer
     114                        Scoped(Decl* d, unsigned long s) : decl(d), scope(s) {}
     115                };
    132116
    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 );
     117                using Ptr = std::shared_ptr<const Indexer>;
    137118
    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;
     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> >;
    142126
    143                 /// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope)
    144                 void makeWritable();
     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 );
    145170
    146171                /// common code for addId, addDeletedId, etc.
    147                 void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
     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;
    148183        };
    149184} // namespace SymTab
  • src/SymTab/Mangler.cc

    r6a9d4b4 r933f32f  
    3838                        struct Mangler : public WithShortCircuiting, public WithVisitorRef<Mangler>, public WithGuards {
    3939                                Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
    40                                 Mangler( const ResolvExpr::TypeEnvironment& env );
    4140                                Mangler( const Mangler & ) = delete;
    4241
     
    6766                          private:
    6867                                std::ostringstream mangleName;  ///< Mangled name being constructed
    69                                 typedef std::map< std::string, std::pair< std::string, int > > VarMapType;
     68                                typedef std::map< std::string, std::pair< int, int > > VarMapType;
    7069                                VarMapType varNums;             ///< Map of type variables to indices
    7170                                int nextVarNum;                 ///< Next type variable index
    72                                 const ResolvExpr::TypeEnvironment* env;  ///< optional environment for substitutions
    7371                                bool isTopLevel;                ///< Is the Mangler at the top level
    7472                                bool mangleOverridable;         ///< Specially mangle overridable built-in methods
     
    8078                          public:
    8179                                Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    82                                         int nextVarNum, const ResolvExpr::TypeEnvironment* env,
    83                                         const VarMapType& varNums );
     80                                        int nextVarNum, const VarMapType& varNums );
    8481
    8582                          private:
     
    109106                }
    110107
    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 
    118108                namespace {
    119109                        Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams )
    120                                 : nextVarNum( 0 ), env(nullptr), isTopLevel( true ),
     110                                : nextVarNum( 0 ), isTopLevel( true ),
    121111                                mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    122112                                mangleGenericParams( mangleGenericParams ) {}
    123113                       
    124                         Mangler::Mangler( const ResolvExpr::TypeEnvironment& env )
    125                                 : nextVarNum( 0 ), env( &env ), isTopLevel( true ), mangleOverridable( false ),
    126                                 typeMode( false ), mangleGenericParams( true ) {}
    127                        
    128114                        Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    129                                 int nextVarNum, const ResolvExpr::TypeEnvironment* env,
    130                                 const VarMapType& varNums )
    131                                 : varNums( varNums ), nextVarNum( nextVarNum ), env( env ), isTopLevel( false ),
     115                                int nextVarNum, const VarMapType& varNums )
     116                                : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
    132117                                mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    133118                                mangleGenericParams( mangleGenericParams ) {}
     
    358343                                                        assert( false );
    359344                                                } // switch
    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() );
     345                                                varNums[ (*i)->name ] = std::make_pair( nextVarNum, (int)(*i)->get_kind() );
    377346                                                for ( std::list< DeclarationWithType* >::iterator assert = (*i)->assertions.begin(); assert != (*i)->assertions.end(); ++assert ) {
    378347                                                        PassVisitor<Mangler> sub_mangler(
    379                                                                 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, env,
    380                                                                 varNums );
     348                                                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    381349                                                        (*assert)->accept( sub_mangler );
    382350                                                        assertionNames.push_back( sub_mangler.pass.get_mangleName() );
  • src/SymTab/Mangler.h

    r6a9d4b4 r933f32f  
    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 );
    4946
    5047                namespace Encoding {
  • src/SymTab/ManglerCommon.cc

    r6a9d4b4 r933f32f  
    1010// Created On       : Sun May 17 21:44:03 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:45:30 2017
    13 // Update Count     : 15
     12// Last Modified On : Thu Feb 14 17:06:37 2019
     13// Update Count     : 26
    1414//
    1515
     
    2323                        const std::string manglePrefix = "_X";
    2424
    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                         };
     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
    6180                        static_assert(
    6281                                sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES,
  • src/SymTab/Validate.cc

    r6a9d4b4 r933f32f  
    4949#include "CodeGen/OperatorTable.h"     // for isCtorDtor, isCtorDtorAssign
    5050#include "ControlStruct/Mutate.h"      // for ForExprMutator
     51#include "Common/Stats.h"              // for Stats::Heap
    5152#include "Common/PassVisitor.h"        // for PassVisitor, WithDeclsToAdd
    5253#include "Common/ScopedMap.h"          // for ScopedMap
     
    298299                PassVisitor<FixQualifiedTypes> fixQual;
    299300
    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 );
     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                }
    325384        }
    326385
  • src/SymTab/module.mk

    r6a9d4b4 r933f32f  
    1515###############################################################################
    1616
    17 SRC += SymTab/Indexer.cc \
    18        SymTab/Mangler.cc \
    19        SymTab/ManglerCommon.cc \
    20        SymTab/Validate.cc \
    21        SymTab/FixFunction.cc \
    22        SymTab/Autogen.cc
     17SRC_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
     25SRC += $(SRC_SYMTAB)
     26SRCDEMANGLE += $(SRC_SYMTAB) SymTab/Demangle.cc
  • src/SynTree/AddressExpr.cc

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

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

    r6a9d4b4 r933f32f  
    1818#include "Common/CodeLocation.h"
    1919#include "Common/Indenter.h"
     20#include "Common/Stats.h"
     21
    2022class Visitor;
    2123class Mutator;
     
    2325class BaseSyntaxNode {
    2426  public:
     27  static Stats::Counters::SimpleCounter* new_nodes;
     28
    2529        CodeLocation location;
     30
     31  BaseSyntaxNode() { ++*new_nodes; }
     32  BaseSyntaxNode( const BaseSyntaxNode& o ) : location(o.location) { ++*new_nodes; }
    2633
    2734        virtual ~BaseSyntaxNode() {}
  • src/SynTree/BasicType.cc

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

    r6a9d4b4 r933f32f  
    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 : Fri Spt 28 14:49:00 2018
    13 // Update Count     : 30
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Feb 13 18:11:22 2019
     13// Update Count     : 32
    1414//
    1515
     
    2525Constant::Constant( Type * type, std::string rep, double val ) : type( type ), rep( rep ), val( val ) {}
    2626
    27 Constant::Constant( const Constant &other ) : rep( other.rep ), val( other.val ) {
     27Constant::Constant( const Constant &other ) : BaseSyntaxNode( other ), rep( other.rep ), val( other.val ) {
    2828        type = other.type->clone();
    2929}
  • src/SynTree/Declaration.cc

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

    r6a9d4b4 r933f32f  
    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 : Sun Sep  3 19:24:06 2017
    13 // Update Count     : 131
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr May  2 10:47:00 2019
     13// Update Count     : 135
    1414//
    1515
     
    1919#include <iosfwd>                // for ostream
    2020#include <list>                  // for list
     21#include <unordered_map>         // for unordered_map
    2122#include <string>                // for string, operator+, allocator, to_string
    2223
     
    7071        static Declaration *declFromId( UniqueId id );
    7172
    72   private:
     73        UniqueId uniqueId;
    7374        Type::StorageClasses storageClasses;
    74         UniqueId uniqueId;
     75  private:
    7576};
    7677
     
    166167        CompoundStmt *get_statements() const { return statements; }
    167168        void set_statements( CompoundStmt *newValue ) { statements = newValue; }
     169        bool has_body() const { return NULL != statements; }
    168170
    169171        static FunctionDecl * newFunction( const std::string & name, FunctionType * type, CompoundStmt * statements );
     
    211213                TypeDecl::Kind kind;
    212214                bool isComplete;
     215
    213216                Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {}
    214217                Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {}
    215218                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
    216222                bool operator==(const Data & other) const { return kind == other.kind && isComplete == other.isComplete; }
    217223                bool operator!=(const Data & other) const { return !(*this == other);}
     
    239245        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    240246
    241   private:
    242247        Kind kind;
    243248};
     
    300305        virtual void accept( Visitor &v ) override { v.visit( this ); }
    301306        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    302   private:
    303307        DeclarationNode::Aggregate kind;
     308  private:
    304309        virtual std::string typeString() const override;
    305310};
     
    330335        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    331336  private:
    332         std::map< std::string, long long int > enumValues;
     337        std::unordered_map< std::string, long long int > enumValues;
    333338        virtual std::string typeString() const override;
    334339};
  • src/SynTree/Expression.cc

    r6a9d4b4 r933f32f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jul 25 14:15:47 2017
    13 // Update Count     : 54
     12// Last Modified On : Tue Feb 19 18:10:55 2019
     13// Update Count     : 60
    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 ) : Expression(), arg(arg), isGenerated( isGenerated ) {
     280CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) {
    281281        set_result(toType);
    282282}
    283283
    284 CastExpr::CastExpr( Expression *arg, bool isGenerated ) : Expression(), arg(arg), isGenerated( isGenerated ) {
     284CastExpr::CastExpr( Expression * arg, bool isGenerated ) : 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 << "Cast of:" << std::endl << indent+1;
     295void CastExpr::print( std::ostream & os, Indenter indent ) const {
     296        os << (isGenerated ? "Generated " : "Explicit ") << "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

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

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

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar  8 14:53:02 2018
    13 // Update Count     : 78
     12// Last Modified On : Tue Mar 12 09:01:53 2019
     13// Update Count     : 83
    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,
    226                Statement *body, std::list<Statement *> & initialization, bool isDoWhile = false );
    227         WhileStmt( const WhileStmt &other );
     225        WhileStmt( Expression * condition, Statement * body, std::list<Statement *> & initialization, bool isDoWhile = false );
     226        WhileStmt( const WhileStmt & other );
    228227        virtual ~WhileStmt();
    229228
    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; }
     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; }
    234233        bool get_isDoWhile() { return isDoWhile; }
    235234        void set_isDoWhile( bool newValue ) { isDoWhile = newValue; }
    236235
    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;
     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;
    241240};
    242241
     
    244243  public:
    245244        std::list<Statement *> initialization;
    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 );
     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 );
    253251        virtual ~ForStmt();
    254252
    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;
     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;
    267265};
    268266
     
    274272        const Label originalTarget;
    275273        Label target;
    276         Expression *computedTarget;
     274        Expression * computedTarget;
    277275        Type type;
    278276
    279277        BranchStmt( Label target, Type ) throw (SemanticErrorException);
    280         BranchStmt( Expression *computedTarget, Type ) throw (SemanticErrorException);
     278        BranchStmt( Expression * computedTarget, Type ) throw (SemanticErrorException);
    281279
    282280        Label get_originalTarget() { return originalTarget; }
     
    284282        void set_target( Label newValue ) { target = newValue; }
    285283
    286         Expression *get_computedTarget() { return computedTarget; }
     284        Expression * get_computedTarget() { return computedTarget; }
    287285        void set_target( Expression * newValue ) { computedTarget = newValue; }
    288286
    289287        Type get_type() { return type; }
    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;
     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;
    296294  private:
    297         static const char *brType[];
     295        static const char * brType[];
    298296};
    299297
    300298class ReturnStmt : public Statement {
    301299  public:
    302         Expression *expr;
    303 
    304         ReturnStmt( Expression *expr );
    305         ReturnStmt( const ReturnStmt &other );
     300        Expression * expr;
     301
     302        ReturnStmt( Expression * expr );
     303        ReturnStmt( const ReturnStmt & other );
    306304        virtual ~ReturnStmt();
    307305
    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;
     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;
    315313};
    316314
     
    324322
    325323        ThrowStmt( Kind kind, Expression * expr, Expression * target = nullptr );
    326         ThrowStmt( const ThrowStmt &other );
     324        ThrowStmt( const ThrowStmt & other );
    327325        virtual ~ThrowStmt();
    328326
     
    333331        void set_target( Expression * newTarget ) { target = newTarget; }
    334332
    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;
     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;
    339337};
    340338
     
    345343        FinallyStmt * finallyBlock;
    346344
    347         TryStmt( CompoundStmt *tryBlock, std::list<CatchStmt *> &handlers, FinallyStmt *finallyBlock = 0 );
    348         TryStmt( const TryStmt &other );
     345        TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = 0 );
     346        TryStmt( const TryStmt & other );
    349347        virtual ~TryStmt();
    350348
    351         CompoundStmt *get_block() const { return block; }
    352         void set_block( CompoundStmt *newValue ) { block = newValue; }
     349        CompoundStmt * get_block() const { return block; }
     350        void set_block( CompoundStmt * newValue ) { block = newValue; }
    353351        std::list<CatchStmt *>& get_catchers() { return handlers; }
    354352
    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;
     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;
    362360};
    363361
     
    367365
    368366        const Kind kind;
    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 );
     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 );
    376374        virtual ~CatchStmt();
    377375
    378376        Kind get_kind() { return kind; }
    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;
     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;
    390388};
    391389
    392390class FinallyStmt : public Statement {
    393391  public:
    394         CompoundStmt *block;
    395 
    396         FinallyStmt( CompoundStmt *block );
    397         FinallyStmt( const FinallyStmt &other );
     392        CompoundStmt * block;
     393
     394        FinallyStmt( CompoundStmt * block );
     395        FinallyStmt( const FinallyStmt & other );
    398396        virtual ~FinallyStmt();
    399397
    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;
     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;
    407405};
    408406
     
    438436        } orelse;
    439437
    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;
     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;
    444442
    445443};
     
    464462class DeclStmt : public Statement {
    465463  public:
    466         Declaration *decl;
    467 
    468         DeclStmt( Declaration *decl );
    469         DeclStmt( const DeclStmt &other );
     464        Declaration * decl;
     465
     466        DeclStmt( Declaration * decl );
     467        DeclStmt( const DeclStmt & other );
    470468        virtual ~DeclStmt();
    471469
    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.
     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.
    485482class ImplicitCtorDtorStmt : public Statement {
    486483  public:
     
    492489        virtual ~ImplicitCtorDtorStmt();
    493490
    494         Statement *get_callStmt() const { return callStmt; }
     491        Statement * get_callStmt() const { return callStmt; }
    495492        void set_callStmt( Statement * newValue ) { callStmt = newValue; }
    496493
    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;
     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;
    501498};
    502499
  • src/SynTree/SynTree.h

    r6a9d4b4 r933f32f  
    3434class NamedTypeDecl;
    3535class TypeDecl;
    36 class FtypeDecl;
    37 class DtypeDecl;
    3836class TypedefDecl;
    3937class AsmDecl;
     
    9088class ConstructorExpr;
    9189class CompoundLiteralExpr;
    92 class UntypedValofExpr;
    9390class RangeExpr;
    9491class UntypedTupleExpr;
     
    132129class ConstructorInit;
    133130
    134 class Subrange;
    135 
    136131//template <class T>    // emulate a union with templates?
    137132class Constant;
  • src/SynTree/Type.cc

    r6a9d4b4 r933f32f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 22 10:17:19 2018
    13 // Update Count     : 39
     12// Last Modified On : Thu Jan 31 21:54:16 2019
     13// Update Count     : 43
    1414//
    1515#include "Type.h"
     
    2525
    2626const char *BasicType::typeNames[] = {
     27#if 0
    2728        "_Bool",
    2829        "char",
     
    4950        "unsigned __int128",
    5051        "__float80",
    51         "__float128"
     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",
    52107};
    53108static_assert(
  • src/SynTree/Type.h

    r6a9d4b4 r933f32f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Sep 25 14:14:01 2017
    13 // Update Count     : 154
     12// Last Modified On : Thu Feb 14 17:11:24 2019
     13// Update Count     : 169
    1414//
    1515
     
    207207class BasicType : public Type {
    208208  public:
     209        // GENERATED START, DO NOT EDIT
     210        // GENERATED BY BasicTypes-gen.cc
    209211        enum Kind {
    210212                Bool,
     
    220222                LongLongSignedInt,
    221223                LongLongUnsignedInt,
    222                 Float,
    223                 Double,
    224                 LongDouble,
    225                 FloatComplex,
    226                 DoubleComplex,
    227                 LongDoubleComplex,
    228                 FloatImaginary,
    229                 DoubleImaginary,
    230                 LongDoubleImaginary,
    231224                SignedInt128,
    232225                UnsignedInt128,
    233                 Float80,
    234                 Float128,
     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,
    235248                NUMBER_OF_BASIC_TYPES
    236249        } kind;
     250        // GENERATED END
    237251
    238252        static const char *typeNames[];                                         // string names for basic types, MUST MATCH with Kind
  • src/SynTree/TypeSubstitution.cc

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:52:24 2017
    13 // Update Count     : 3
     12// Last Modified On : Tue Apr 30 22:52:47 2019
     13// Update Count     : 9
    1414//
    1515
     
    1919#include <iosfwd>                  // for ostream
    2020#include <list>                    // for list<>::iterator, _List_iterator
    21 #include <map>                     // for _Rb_tree_iterator, map, map<>::val...
    22 #include <set>                     // for set
     21#include <unordered_map>
     22#include <unordered_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 );
    42         template< typename SynTreeClass > int applyFree( SynTreeClass *&input );
     41        template< typename SynTreeClass > int apply( SynTreeClass *&input ) const;
     42        template< typename SynTreeClass > int applyFree( SynTreeClass *&input ) const;
    4343
    4444        void add( std::string formalType, Type *actualType );
     
    4848        bool empty() const;
    4949
     50        void addVar( std::string formalExpr, Expression *actualExpr );
     51
    5052        template< typename FormalIterator, typename ActualIterator >
    5153        void add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
     
    5658
    5759        /// create a new TypeSubstitution using bindings from env containing all of the type variables in expr
    58         static TypeSubstitution * newFromExpr( Expression * expr, TypeSubstitution * env );
     60        static TypeSubstitution * newFromExpr( Expression * expr, const TypeSubstitution * env );
    5961
    6062        void normalize();
     
    7880        friend class PassVisitor;
    7981
    80         typedef std::map< std::string, Type* > TypeEnvType;
    81         typedef std::map< std::string, Expression* > VarEnvType;
     82        typedef std::unordered_map< std::string, Type * > TypeEnvType;
     83        typedef std::unordered_map< std::string, Expression * > VarEnvType;
    8284        TypeEnvType typeEnv;
    8385        VarEnvType varEnv;
     
    8991        auto begin() const -> decltype( typeEnv.begin() ) { return typeEnv.begin(); }
    9092        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(); }
    9198};
    9299
     
    98105        ActualIterator actualIt = actualBegin;
    99106        for ( ; formalIt != formalEnd; ++formalIt, ++actualIt ) {
    100                 if ( TypeDecl *formal = dynamic_cast< TypeDecl* >( *formalIt ) ) {
    101                         if ( TypeExpr *actual = dynamic_cast< TypeExpr* >( *actualIt ) ) {
     107                if ( TypeDecl *formal = dynamic_cast< TypeDecl * >( *formalIt ) ) {
     108                        if ( TypeExpr *actual = dynamic_cast< TypeExpr * >( *actualIt ) ) {
    102109                                if ( formal->get_name() != "" ) {
    103110                                        TypeEnvType::iterator i = typeEnv.find( formal->get_name() );
     
    130137// definitition must happen after PassVisitor is included so that WithGuards can be used
    131138struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
    132                 Substituter( TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
     139                Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
    133140
    134141                Type * postmutate( TypeInstType * aggregateUseType );
     
    143150                void premutate( UnionInstType * aggregateUseType );
    144151
    145                 TypeSubstitution & sub;
     152                const TypeSubstitution & sub;
    146153                int subCount = 0;
    147154                bool freeOnly;
    148                 typedef std::set< std::string > BoundVarsType;
     155                typedef std::unordered_set< std::string > BoundVarsType;
    149156                BoundVarsType boundVars;
    150157};
    151158
    152159template< typename SynTreeClass >
    153 int TypeSubstitution::apply( SynTreeClass *&input ) {
     160int TypeSubstitution::apply( SynTreeClass *&input ) const {
    154161        assert( input );
    155162        PassVisitor<Substituter> sub( *this, false );
     
    163170
    164171template< typename SynTreeClass >
    165 int TypeSubstitution::applyFree( SynTreeClass *&input ) {
     172int TypeSubstitution::applyFree( SynTreeClass *&input ) const {
    166173        assert( input );
    167174        PassVisitor<Substituter> sub( *this, true );
  • src/SynTree/Visitor.h

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

    r6a9d4b4 r933f32f  
    1515###############################################################################
    1616
    17 SRC += 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
     17SRC_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
    5152
     53SRC += $(SRC_SYNTREE)
     54SRCDEMANGLE += $(SRC_SYNTREE)
  • src/Tuples/TupleExpansion.cc

    r6a9d4b4 r933f32f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 21 17:35:04 2017
    13 // Update Count     : 19
     12// Last Modified On : Wed Feb 13 18:14:12 2019
     13// Update Count     : 21
    1414//
    1515
     
    1717#include <cassert>                // for assert
    1818#include <list>                   // for list
    19 
     19#include <vector>
     20
     21#include "AST/CVQualifiers.hpp"
     22#include "AST/Expr.hpp"
     23#include "AST/Node.hpp"
     24#include "AST/Type.hpp"
    2025#include "Common/PassVisitor.h"   // for PassVisitor, WithDeclsToAdd, WithGu...
    2126#include "Common/ScopedMap.h"     // for ScopedMap
     
    5863                };
    5964
    60                 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithTypeSubstitution {
     65                struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {
    6166                        Type * postmutate( TupleType * tupleType );
    6267
     
    314319                return new TupleType( qualifiers, types );
    315320        }
     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        }
    316345
    317346        TypeInstType * isTtype( Type * type ) {
  • src/Tuples/Tuples.h

    r6a9d4b4 r933f32f  
    1919#include <vector>
    2020
     21#include "AST/Fwd.hpp"
     22#include "AST/Node.hpp"
    2123#include "SynTree/Expression.h"
    2224#include "SynTree/Declaration.h"
     
    2729namespace Tuples {
    2830        // TupleAssignment.cc
    29         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 
     31        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
    3032                std::vector< ResolvExpr::AlternativeFinder >& args );
    31        
     33
    3234        // TupleExpansion.cc
    3335        /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
     
    4244        /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
    4345        Type * makeTupleType( const std::list< Expression * > & exprs );
     46        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
    4447
    4548        /// returns a TypeInstType if `type` is a ttype, nullptr otherwise
    4649        TypeInstType * isTtype( Type * type );
     50        const ast::TypeInstType * isTtype( const ast::Type * type );
    4751
    4852        /// returns true if the expression may contain side-effects.
  • src/Tuples/module.mk

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

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

    r6a9d4b4 r933f32f  
    5252#undef CFA_VERSION_SHORT
    5353
    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
     54/* Have compiler warning cast-function-type. */
     55#undef HAVE_CAST_FUNCTION_TYPE
    6856
    6957/* Define to 1 if you have the <dlfcn.h> header file. */
    7058#undef HAVE_DLFCN_H
    7159
    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 
    7860/* Define to 1 if you have the <inttypes.h> header file. */
    7961#undef HAVE_INTTYPES_H
    8062
     63/* Have keywords _FloatXX. */
     64#undef HAVE_KEYWORDS_FLOATXX
     65
    8166/* Define to 1 if you have the <libintl.h> header file. */
    8267#undef HAVE_LIBINTL_H
    83 
    84 /* Define to 1 if you have the <limits.h> header file. */
    85 #undef HAVE_LIMITS_H
    8668
    8769/* Define to 1 if you have the <malloc.h> header file. */
     
    9173#undef HAVE_MEMORY_H
    9274
    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 
    10575/* Define to 1 if you have the <stdint.h> header file. */
    10676#undef HAVE_STDINT_H
     
    10979#undef HAVE_STDLIB_H
    11080
    111 /* Define to 1 if you have the `strchr' function. */
    112 #undef HAVE_STRCHR
    113 
    11481/* Define to 1 if you have the <strings.h> header file. */
    11582#undef HAVE_STRINGS_H
     
    11784/* Define to 1 if you have the <string.h> header file. */
    11885#undef HAVE_STRING_H
    119 
    120 /* Define to 1 if you have the `strtol' function. */
    121 #undef HAVE_STRTOL
    12286
    12387/* Define to 1 if you have the <sys/stat.h> header file. */
     
    13094#undef HAVE_UNISTD_H
    13195
    132 /* Define to 1 if the system has the type `_Bool'. */
    133 #undef HAVE__BOOL
     96/* Define to 1 if the system has the type `_Float32'. */
     97#undef HAVE__FLOAT32
    13498
    13599/* Define to the sub-directory where libtool stores uninstalled libraries. */
     
    157121#undef PACKAGE_VERSION
    158122
    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
    166 
    167123/* Define to 1 if you have the ANSI C header files. */
    168124#undef STDC_HEADERS
     
    180136   `char[]'. */
    181137#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

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

    r6a9d4b4 r933f32f  
    77// main.cc --
    88//
    9 // Author           : Richard C. Bilson
     9// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 26 08:11:19 2018
    13 // Update Count     : 499
     12// Last Modified On : Fri May  3 16:10:52 2019
     13// Update Count     : 599
    1414//
    1515
     
    2424#include <fstream>                          // for ofstream
    2525#include <iostream>                         // for operator<<, basic_ostream
     26#include <iomanip>
    2627#include <iterator>                         // for back_inserter
    2728#include <list>                             // for list
     
    3738#include "CodeTools/TrackLoc.h"             // for fillLocations
    3839#include "Common/CompilerError.h"           // for CompilerError
    39 #include "Common/Heap.h"
     40#include "Common/Stats.h"
    4041#include "Common/PassVisitor.h"
     42// #include "AST/Pass.hpp"
    4143#include "Common/SemanticError.h"           // for SemanticError
    4244#include "Common/UnimplementedError.h"      // for UnimplementedError
     
    6567using namespace std;
    6668
    67 #define PASS(name, pass)                   \
     69static 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 )                  \
    6887        if ( errorp ) { cerr << name << endl; } \
    69         HeapStats::newPass(name);               \
    70         pass;
     88        NewPass(name);                          \
     89        Stats::Time::StartBlock(name);          \
     90        pass;                                   \
     91        Stats::Time::StopBlock();
    7192
    7293LinkageSpec::Spec linkage = LinkageSpec::Cforall;
     
    7495DeclarationNode * parseTree = nullptr;                                  // program parse tree
    7596
    76 std::string PreludeDirector = "";
     97static std::string PreludeDirector = "";
    7798
    7899static void parse_cmdline( int argc, char *argv[], const char *& filename );
     
    130151} // backtrace
    131152
    132 void sigSegvBusHandler( int sig_num ) {
     153static void sigSegvBusHandler( int sig_num ) {
    133154        cerr << "*CFA runtime error* program cfa-cpp terminated with "
    134155                 <<     (sig_num == SIGSEGV ? "segment fault" : "bus error")
     
    136157        backtrace( 2 );                                                                         // skip first 2 stack frames
    137158        //_exit( EXIT_FAILURE );
    138         abort();
     159        abort();                                                                                        // cause core dump for debugging
    139160} // sigSegvBusHandler
    140161
    141 void sigAbortHandler( __attribute__((unused)) int sig_num ) {
     162static void sigAbortHandler( __attribute__((unused)) int sig_num ) {
    142163        backtrace( 6 );                                                                         // skip first 6 stack frames
    143164        signal( SIGABRT, SIG_DFL);                                                      // reset default signal handler
    144     raise( SIGABRT );                                                                   // reraise SIGABRT
     165                raise( SIGABRT );                                                                       // reraise SIGABRT
    145166} // sigAbortHandler
    146167
     
    148169int main( int argc, char * argv[] ) {
    149170        FILE * input;                                                                           // use FILE rather than istream because yyin is FILE
    150         ostream *output = & cout;
    151         const char *filename = nullptr;
     171        ostream * output = & cout;
     172        const char * filename = nullptr;
    152173        list< Declaration * > translationUnit;
    153174
     
    181202                } // if
    182203
     204                Stats::Time::StartGlobal();
     205                NewPass("Parse");
     206                Stats::Time::StartBlock("Parse");
     207
    183208                // read in the builtins, extras, and the prelude
    184209                if ( ! nopreludep ) {                                                   // include gcc builtins
     
    215240                        parseTree->printList( cout );
    216241                        delete parseTree;
    217                         return 0;
     242                        return EXIT_SUCCESS;
    218243                } // if
    219244
     
    224249                if ( astp ) {
    225250                        dump( translationUnit );
    226                         return 0;
     251                        return EXIT_SUCCESS;
    227252                } // if
    228253
     
    231256                // works okay for now.
    232257                CodeTools::fillLocations( translationUnit );
     258                Stats::Time::StopBlock();
    233259
    234260                // add the assignment statement after the initialization of a type parameter
    235                 PASS( "validate", SymTab::validate( translationUnit, symtabp ) );
     261                PASS( "Validate", SymTab::validate( translationUnit, symtabp ) );
    236262                if ( symtabp ) {
    237263                        deleteAll( translationUnit );
    238                         return 0;
     264                        return EXIT_SUCCESS;
    239265                } // if
    240266
     
    242268                        PassVisitor<ResolvExpr::AlternativePrinter> printer( cout );
    243269                        acceptAll( translationUnit, printer );
    244                         return 0;
     270                        return EXIT_SUCCESS;
    245271                } // if
    246272
    247273                if ( validp ) {
    248274                        dump( 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 ) );
     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 ) );
    256282                if ( libcfap ) {
    257283                        // generate the bodies of cfa library functions
     
    262288                        CodeTools::printDeclStats( translationUnit );
    263289                        deleteAll( translationUnit );
    264                         return 0;
    265                 }
     290                        return EXIT_SUCCESS;
     291                } // if
    266292
    267293                if ( bresolvep ) {
    268294                        dump( translationUnit );
    269                         return 0;
     295                        return EXIT_SUCCESS;
    270296                } // if
    271297
     
    274300                if ( resolvprotop ) {
    275301                        CodeTools::dumpAsResolvProto( translationUnit );
    276                         return 0;
    277                 }
    278 
    279                 PASS( "resolve", ResolvExpr::resolve( translationUnit ) );
     302                        return EXIT_SUCCESS;
     303                } // if
     304
     305                PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
    280306                if ( exprp ) {
    281307                        dump( translationUnit );
    282                         return 0;
     308                        return EXIT_SUCCESS;
    283309                } // if
    284310
    285311                // fix ObjectDecl - replaces ConstructorInit nodes
    286                 PASS( "fixInit", InitTweak::fix( translationUnit, buildingLibrary() ) );
     312                PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
    287313                if ( ctorinitp ) {
    288314                        dump ( translationUnit );
    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?
     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?
    301327
    302328                if ( tuplep ) {
    303329                        dump( translationUnit );
    304                         return 0;
    305                 }
    306 
    307                 PASS( "virtual expandCasts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM
    308 
    309                 PASS( "instantiateGenerics", GenPoly::instantiateGeneric( 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 ) );
    310336                if ( genericsp ) {
    311337                        dump( translationUnit );
    312                         return 0;
    313                 }
    314                 PASS( "convertLvalue", GenPoly::convertLvalue( translationUnit ) );
     338                        return EXIT_SUCCESS;
     339                } // if
     340                PASS( "Convert L-Value", GenPoly::convertLvalue( translationUnit ) );
    315341
    316342
    317343                if ( bboxp ) {
    318344                        dump( translationUnit );
    319                         return 0;
    320                 } // if
    321                 PASS( "box", GenPoly::box( translationUnit ) );
     345                        return EXIT_SUCCESS;
     346                } // if
     347                PASS( "Box", GenPoly::box( translationUnit ) );
    322348
    323349                if ( bcodegenp ) {
    324350                        dump( translationUnit );
    325                         return 0;
    326                 }
     351                        return EXIT_SUCCESS;
     352                } // if
    327353
    328354                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    331357
    332358                CodeTools::fillLocations( translationUnit );
    333                 PASS( "codegen", CodeGen::generate( translationUnit, *output, ! noprotop, prettycodegenp, true, linemarks ) );
     359                PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
    334360
    335361                CodeGen::FixMain::fix( *output, (PreludeDirector + "/bootloader.c").c_str() );
     
    347373                        delete output;
    348374                } // if
    349                 return 1;
     375                return EXIT_FAILURE;
    350376        } catch ( UnimplementedError &e ) {
    351377                cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl;
     
    353379                        delete output;
    354380                } // if
    355                 return 1;
     381                return EXIT_FAILURE;
    356382        } catch ( CompilerError &e ) {
    357383                cerr << "Compiler Error: " << e.get_what() << endl;
     
    360386                        delete output;
    361387                } // if
    362                 return 1;
    363         } catch(...) {
     388                return EXIT_FAILURE;
     389        } catch ( ... ) {
    364390                std::exception_ptr eptr = std::current_exception();
    365391                try {
    366392                        if (eptr) {
    367393                                std::rethrow_exception(eptr);
    368                         }
    369                         else {
    370                                 std::cerr << "Exception Uncaught and Unkown" << std::endl;
    371                         }
     394                        } else {
     395                                std::cerr << "Exception Uncaught and Unknown" << std::endl;
     396                        } // if
    372397                } catch(const std::exception& e) {
    373398                        std::cerr << "Uncaught Exception \"" << e.what() << "\"\n";
    374                 }
    375                 return 1;
    376         }// try
     399                } // try
     400                return EXIT_FAILURE;
     401        } // try
    377402
    378403        deleteAll( translationUnit );
    379         if(!libcfap && !treep) HeapStats::printStats();
    380         return 0;
     404        Stats::print();
     405        return EXIT_SUCCESS;
    381406} // main
    382407
    383 void 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 
     408
     409static const char optstring[] = ":hlLmNn:pP:S:twW:D:F:";
     410
     411enum { PreludeDir = 128 };
     412static 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
     431static 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
     449static_assert( sizeof( long_opts ) / sizeof( long_opts[0] ) - 1 == sizeof( description ) / sizeof( description[0] ), "Long opts and description must match" );
     450
     451static 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};
     477enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) };
     478
     479static 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
     506static void parse_cmdline( int argc, char * argv[], const char *& filename ) {
    412507        opterr = 0;                                                                                     // (global) prevent getopt from printing error messages
    413508
    414509        bool Wsuppress = false, Werror = false;
    415510        int c;
    416         while ( (c = getopt_long( argc, argv, "abBcCdefgGlLmnNpqrRstTvwW:yzZD:F:", long_opts, &long_index )) != -1 ) {
     511        while ( (c = getopt_long( argc, argv, optstring, long_opts, nullptr )) != -1 ) {
    417512                switch ( c ) {
    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:
     513                  case 'h':                                                                             // help message
     514                        usage( argv );                                                          // no return
     515                        break;
    456516                  case 'l':                                                                             // generate libcfa.c
    457517                        libcfap = true;
    458518                        break;
    459                   case Linemarks:
    460                   case 'L':                                                                             // print lines marks
     519                  case 'L':                                                                             // generate line marks
    461520                        linemarks = true;
    462521                        break;
    463                   case Nopreamble:
    464                   case 'n':                                                                             // do not read preamble
     522                  case 'm':                                                                             // do not replace main
     523                        nomainp = true;
     524                        break;
     525                  case 'N':                                                                             // do not generate line marks
     526                        linemarks = false;
     527                        break;
     528                  case 'n':                                                                             // do not read prelude
    465529                        nopreludep = true;
    466530                        break;
    467                   case Nolinemarks:
    468                   case 'N':                                                                             // suppress line marks
    469                         linemarks = false;
    470                         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:
     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;
    497552                  case 't':                                                                             // build in tree
    498553                        treep = true;
    499554                        break;
    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':
     555                  case 'w':                                                                             // suppress all warnings, hidden
    508556                        Wsuppress = true;
    509557                        break;
    510                   case 'W':
     558                  case 'W':                                                                             // coordinate gcc -W with CFA, hidden
    511559                        if ( strcmp( optarg, "all" ) == 0 ) {
    512560                                SemanticWarning_EnableAll();
     
    525573                        } // if
    526574                        break;
    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
     575                  case 'D':                                                                             // ignore -Dxxx, forwarded by cpp, hidden
     576                        break;
     577                  case 'F':                                                                             // source file-name without suffix, hidden
    539578                        filename = optarg;
    540579                        break;
    541                   case '?':
     580                  case '?':                                                                             // unknown option
    542581                        if ( optopt ) {                                                         // short option ?
    543                                 assertf( false, "Unknown option: -%c\n", (char)optopt );
     582                                cout << "Unknown option -" << (char)optopt << endl;
    544583                        } else {
    545                                 assertf( false, "Unknown option: %s\n", argv[optind - 1] );
    546                         } // if
    547                         #if defined(__GNUC__) && __GNUC__ >= 7
    548                                 __attribute__((fallthrough));
    549                         #endif
     584                                cout << "Unknown option " << argv[optind - 1] << endl;
     585                        } // 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:
    550595                  default:
    551                         abort();
     596                        usage( argv );                                                          // no return
    552597                } // switch
    553598        } // while
     
    587632        list< Declaration * > decls;
    588633
    589         if ( noprotop ) {
     634        if ( genproto ) {
    590635                filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), notPrelude );
    591636        } else {
     
    595640        // depending on commandline options, either generate code or dump the AST
    596641        if ( codegenp ) {
    597                 CodeGen::generate( decls, out, ! noprotop, prettycodegenp );
     642                CodeGen::generate( decls, out, ! genproto, prettycodegenp );
    598643        } else {
    599644                printAll( decls, out );
    600         }
     645        } // if
    601646        deleteAll( translationUnit );
    602647} // dump
  • tests/.expect/KRfunctions.x64.txt

    r6a9d4b4 r933f32f  
    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))(signed int __anonymous_object0){
     64signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(__attribute__ ((unused)) 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_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)));
     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)));
    113108    }
    114109
  • tests/.expect/KRfunctions.x86.txt

    r6a9d4b4 r933f32f  
    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))(signed int __anonymous_object0){
     64signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(__attribute__ ((unused)) 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_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)));
     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)));
    113108    }
    114109
  • tests/.expect/abs.txt

    r6a9d4b4 r933f32f  
    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-2i  abs 65.0308
    9 double _Complex         -65-2i  abs 65.0307619515564
    10 long double _Complex    -65-2i  abs 65.0307619515564342
     5float                   -65.    abs 65.
     6double                  -65.    abs 65.
     7long double             -65.    abs 65.
     8float _Complex          -65.-2.i        abs 65.0308
     9double _Complex         -65.-2.i        abs 65.0307619515564
     10long double _Complex    -65.-2.i        abs 65.0307619515564342
  • tests/.expect/ato.txt

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

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

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

    r6a9d4b4 r933f32f  
    1 castError.cfa:7:1 error: Cannot choose between 3 alternatives for expression
    2 Cast of:
     1castError.cfa:21:1 error: Cannot choose between 3 alternatives for expression
     2Explicit Cast of:
    33  Name: f
    44... to:
    55  char Alternatives are:
    6 Cost ( 1, 0, 0, 0, 0, 0 ): Cast of:
     6Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    77     Variable Expression: f: function
    88       accepting unspecified arguments
     
    1616 Environment:
    1717
    18 Cost ( 1, 0, 0, 0, 0, 0 ): Cast of:
     18Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    1919     Variable Expression: f: double
    2020   ... to:
     
    2525 Environment:
    2626
    27 Cost ( 1, 0, 0, 0, 0, 0 ): Cast of:
     27Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    2828     Variable Expression: f: signed int
    2929   ... to:
     
    3535
    3636
     37castError.cfa:26:1 error: Cannot choose between 2 alternatives for expression
     38Generated Cast of:
     39  Comma Expression:
     40    constant expression (3 3: signed int)
     41    Name: v
     42... to: nothing Alternatives are:
     43Cost ( 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
     53Cost ( 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

    r6a9d4b4 r933f32f  
    1 completeTypeError.cfa:33:1 error: No reasonable alternatives for expression Applying untyped:
    2   Name: *?
    3 ...to:
    4   Name: v
     1completeTypeError.cfa:34:1 error: Cannot choose between 2 alternatives for expression
     2Generated Cast of:
     3  Applying untyped:
     4    Name: *?
     5  ...to:
     6    Name: x
    57
    6 completeTypeError.cfa:34:1 error: No reasonable alternatives for expression Applying untyped:
    7   Name: *?
    8 ...to:
    9   Name: y
     8... to: nothing Alternatives are:
     9Cost ( 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
     32Cost ( 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
    1055
    1156completeTypeError.cfa:35:1 error: No reasonable alternatives for expression Applying untyped:
     
    2469  Name: v
    2570
    26 completeTypeError.cfa:58:1 error: No reasonable alternatives for expression Applying untyped:
     71completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
    2772  Name: baz
    2873...to:
    2974  Name: y
    3075
    31 completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
     76completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
    3277  Name: quux
    3378...to:
    3479  Name: y
    3580
    36 completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
    37   Name: *?
    38 ...to:
    39   Name: y
    40 
    41 completeTypeError.cfa:72:1 error: No resolvable alternatives for expression Applying untyped:
     81completeTypeError.cfa:72:1 error: No alternatives with satisfiable assertions for Applying untyped:
    4282  Name: baz
    4383...to:
    4484  Name: z
    4585
    46 Alternatives with failing assertions are:
    47 Cost ( 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
     86   Unsatisfiable alternative:
     87Cost ( 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
    5999
    60100
    61          ?{}: pointer to function
     101             ?{}: pointer to function
     102             ... with parameters
     103               reference to instance of type T (not function type)
     104             ... returning nothing
     105
     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
     111
     112             ^?{}: pointer to function
     113             ... with parameters
     114               reference to instance of type T (not function type)
     115             ... returning nothing
     116
     117
     118           function
    62119         ... with parameters
    63            reference to instance of type T (not function type)
     120           pointer to instance of type T (not function type)
    64121         ... returning nothing
    65122
    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
     123       ... to arguments
     124         Variable Expression: z: pointer to instance of type T (not function type)
    71125
    72          ^?{}: pointer to function
    73          ... with parameters
    74            reference to instance of type T (not function type)
    75          ... returning nothing
     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
    76140
    77141
    78        function
    79      ... with parameters
    80        pointer to instance of type T (not function type)
    81      ... returning nothing
    82 
    83    ... to arguments
    84      Variable Expression: z: pointer to instance of type T (not function type)
    85 
    86  (types:
    87    void
    88  )
    89  Environment:( _73_0_T ) -> instance of type T (not function type) (no widening)
    90 
    91 
    92 
  • tests/.expect/complex.txt

    r6a9d4b4 r933f32f  
    11x:3+2i y:4+5i z:7+7i
    2 x:3+2i y:4+5i z:7+7i
     2x:3.+2.i y:4.+5.i z:7.+7.i
    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

    r6a9d4b4 r933f32f  
    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     {
    11291124        ((void)(_X12_retval_maini_1=0) /* ?{} */);
    11301125    }
     
    11371132    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11381133    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    11431136    }
    11441137
  • tests/.expect/declarationSpecifier.x86.txt

    r6a9d4b4 r933f32f  
    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     {
    11291124        ((void)(_X12_retval_maini_1=0) /* ?{} */);
    11301125    }
     
    11371132    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11381133    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    11431136    }
    11441137
  • tests/.expect/extension.x64.txt

    r6a9d4b4 r933f32f  
    457457
    458458    {
    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));
     459        signed int _tmp_cp_ret4;
     460        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
    463461    }
    464462
  • tests/.expect/extension.x86.txt

    r6a9d4b4 r933f32f  
    457457
    458458    {
    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));
     459        signed int _tmp_cp_ret4;
     460        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
    463461    }
    464462
  • tests/.expect/functions.x64.txt

    r6a9d4b4 r933f32f  
    11void _X1hFv___1(void){
    22}
    3 signed 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)){
     3signed 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)){
    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(signed int __anonymous_object7){
     101signed int _X1fFi_i__1(__attribute__ ((unused)) 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(signed int __anonymous_object9, signed int _X1xi_1){
     132struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) 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(signed int __anonymous_object12, signed int _X1xi_1, signed int __anonymous_object13){
     169struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object12, signed int _X1xi_1, __attribute__ ((unused)) 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(signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){
     182struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) 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(double __anonymous_object20){
     192const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object20){
    193193    __attribute__ ((unused)) const double _X11_retval_fooKd_1;
    194194    {
     
    242242
    243243}
    244 struct S _X3rtnFS1S_i__1(signed int __anonymous_object21){
     244struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object21){
    245245    __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1;
    246246}
    247 signed 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)){
     247signed 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)){
    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(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)]){
     273signed 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)]){
    274274    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    275275}
  • tests/.expect/functions.x86.txt

    r6a9d4b4 r933f32f  
    11void _X1hFv___1(void){
    22}
    3 signed 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)){
     3signed 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)){
    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(signed int __anonymous_object7){
     101signed int _X1fFi_i__1(__attribute__ ((unused)) 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(signed int __anonymous_object9, signed int _X1xi_1){
     132struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) 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(signed int __anonymous_object12, signed int _X1xi_1, signed int __anonymous_object13){
     169struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object12, signed int _X1xi_1, __attribute__ ((unused)) 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(signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){
     182struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) 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(double __anonymous_object20){
     192const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object20){
    193193    __attribute__ ((unused)) const double _X11_retval_fooKd_1;
    194194    {
     
    242242
    243243}
    244 struct S _X3rtnFS1S_i__1(signed int __anonymous_object21){
     244struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object21){
    245245    __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1;
    246246}
    247 signed 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)){
     247signed 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)){
    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(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)]){
     273signed 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)]){
    274274    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    275275}
  • tests/.expect/gccExtensions.x64.txt

    r6a9d4b4 r933f32f  
    292292    signed int _X2m3A0A0i_2[((unsigned long int )10)][((unsigned long int )10)];
    293293    {
    294         ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */);
     294        ((void)(_X12_retval_maini_1=0) /* ?{} */);
    295295    }
    296296
     
    307307    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    308308    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    313311    }
    314312
  • tests/.expect/gccExtensions.x86.txt

    r6a9d4b4 r933f32f  
    292292    signed int _X2m3A0A0i_2[((unsigned int )10)][((unsigned int )10)];
    293293    {
    294         ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */);
     294        ((void)(_X12_retval_maini_1=0) /* ?{} */);
    295295    }
    296296
     
    307307    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    308308    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    313311    }
    314312
  • tests/.expect/identity.txt

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

    r6a9d4b4 r933f32f  
    119 6 28 0 7 1 2
    2 1 2 3
    3 123
    4 123
     20 1 2 3
     30123
     40123
    55
    66opening delimiters
  • tests/.expect/loopctrl.txt

    r6a9d4b4 r933f32f  
    191910 8 6 4 2
    2020
     211 2 3 4 5 6 7 8 9 10
     2210 9 8 7 6 5 4 3 2 1 0
     232 4 6 8 10
     242.1 3.8 5.5 7.2 8.9
     2510 8 6 4 2 0
     2612.1 10.4 8.7 7. 5.3 3.6
    2127
    2228N N N N N N N N N N
     
    243010 9 8 7 6 5 4 3 2 1
    2531
    26 
    27323 6 9
    28 
    2933
    3034(0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9)
     
    4044(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)
    4145(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)
     46
     470 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4
     480 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14
     490 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13
     500 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23
     51
     520 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4
     530 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14
     540 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13
     550 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23
     56
     570 -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
     580 -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
     590 -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

    r6a9d4b4 r933f32f  
    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 256
    13 \ 912673 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
     11pow:1. 1. 1. 0.273957+0.583701i 0.273957253830121+0.583700758758615i -0.638110484918098871+0.705394566961838155i
     1216 \ 2 = 256
     13912673 256 64 -64 0 0
     140.015625 -0.015625 18.3791736799526 0.264715-1.1922i
     150 0 18.3791736799526 0.264715-1.1922i
     1616
     174 16
  • tests/.expect/math2.txt

    r6a9d4b4 r933f32f  
    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

    r6a9d4b4 r933f32f  
    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

    r6a9d4b4 r933f32f  
    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

    r6a9d4b4 r933f32f  
    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

    r6a9d4b4 r933f32f  
    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

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

    r6a9d4b4 r933f32f  
    2323installed=no
    2424
     25INSTALL_FLAGS=-in-tree
     26DEBUG_FLAGS=-debug -O0
     27
    2528quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes
    2629
     
    2831timeouts=
    2932
    30 TEST_PY = python ${builddir}/test.py
     33TEST_PY = python3 ${builddir}/test.py
    3134
    3235# applies to both programs
     
    3639        -Wno-unused-function \
    3740        -quiet @CFA_FLAGS@ \
    38         -DIN_DIR="${srcdir}/.in/"
     41        -DIN_DIR="${abs_srcdir}/.in/"
    3942
    4043AM_CFLAGS += ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS}
    4144CC = @CFACC@
    4245
    43 PRETTY_PATH=cd ${srcdir} &&
     46PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
    4447
    4548.PHONY: list .validate
     
    4851
    4952avl_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
    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
     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
    5255
    5356#----------------------------------------------------------------------------------------------------------------
     
    7477        @echo "int main() { return 0; }" > ${@}
    7578
     79.dummy_hackxx.cpp:
     80        @echo "int bar() { return 0; }" > ${@}
     81
    7682concurrency :
    7783        @+${TEST_PY} --debug=${debug}  --install=${installed} -Iconcurrent
     
    7985#----------------------------------------------------------------------------------------------------------------
    8086
     87# Use for all tests, make sure the path are correct and all flags are added
     88CFACOMPILETEST=$(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
     91CFATEST_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
     94CFATEST_STDERR=$(CFACOMPILETEST) 2> $(abspath ${@})
     95
     96#----------------------------------------------------------------------------------------------------------------
     97
    8198# implicit rule so not all test require a rule
    8299% : %.cfa $(CFACC)
    83         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     100        $(CFATEST_STDOUT)
    84101
    85 declarationSpecifier: declarationSpecifier.cfa $(CFACC)
    86         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     102% : %.cpp
     103        $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    87104
    88 gccExtensions : gccExtensions.cfa $(CFACC)
    89         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     105#------------------------------------------------------------------------------
     106# TARGET WITH STANDARD RULE BUT CUSTOM FLAGS
     107#------------------------------------------------------------------------------
     108# Expected failures
     109declarationSpecifier_FLAGS= -CFA -XCFA -p
     110gccExtensions_FLAGS= -CFA -XCFA -p
     111extension_FLAGS= -CFA -XCFA -p
     112attributes_FLAGS= -CFA -XCFA -p
     113functions_FLAGS= -CFA -XCFA -p
     114KRfunctions_FLAGS= -CFA -XCFA -p
     115gmp_FLAGS= -lgmp
    90116
    91 extension : extension.cfa $(CFACC)
    92         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     117#------------------------------------------------------------------------------
     118# Expected failures
     119completeTypeError_FLAGS= -DERR1
    93120
    94 attributes : attributes.cfa $(CFACC)
    95         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     121#------------------------------------------------------------------------------
     122# CUSTOM TARGET
     123#------------------------------------------------------------------------------
     124typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
     125        $(CFATEST_STDOUT) -DERR1
    96126
    97 functions: functions.cfa $(CFACC)
    98         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     127alloc-ERROR: alloc.cfa $(CFACC)
     128        $(CFATEST_STDOUT) -DERR1
    99129
    100 KRfunctions : KRfunctions.cfa $(CFACC)
    101         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     130nested-types-ERR1: nested-types.cfa $(CFACC)
     131        $(CFATEST_STDOUT) -DERR1
    102132
    103 sched-ext-parse : sched-ext-parse.c $(CFACC)
    104         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     133nested-types-ERR2: nested-types.cfa $(CFACC)
     134        $(CFATEST_STDOUT) -DERR2
    105135
    106 gmp : gmp.cfa $(CFACC)
    107         $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     136raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
     137        $(CFATEST_STDOUT) -DERR1
     138
     139raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
     140        $(CFATEST_STDOUT) -DERR2
     141
     142raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
     143        $(CFATEST_STDOUT) -DERR1
     144
     145raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
     146        $(CFATEST_STDOUT) -DERR1
    108147
    109148#builtins
    110149builtins/sync: builtins/sync.cfa $(CFACC)
    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
    116 completeTypeError : completeTypeError.cfa $(CFACC)
    117         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    118 
    119 typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
    120         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    121 
    122 alloc-ERROR: alloc.cfa $(CFACC)
    123         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    124 
    125 fallthrough-ERROR: fallthrough.cfa $(CFACC)
    126         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    127 
    128 nested-types-ERR1: nested-types.cfa $(CFACC)
    129         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    130 
    131 nested-types-ERR2: nested-types.cfa $(CFACC)
    132         $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    133 
    134 # Constructor/destructor tests
    135 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
    136         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    137 
    138 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
    139         $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    140 
    141 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
    142         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    143 
    144 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
    145         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     150        $(CFATEST_STDERR) -fsyntax-only
    146151
    147152# Warnings
    148153warnings/self-assignment: warnings/self-assignment.cfa $(CFACC)
    149         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
     154        $(CFATEST_STDERR) -fsyntax-only
  • tests/Makefile.in

    r6a9d4b4 r933f32f  
    107107CONFIG_CLEAN_FILES = config.py
    108108CONFIG_CLEAN_VPATH_FILES = test.py
    109 am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT)
     109am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT) .dummy_hackxx.$(OBJEXT)
    110110_dummy_hack_OBJECTS = $(am__dummy_hack_OBJECTS)
    111111_dummy_hack_LDADD = $(LDADD)
     
    155155am__v_CCLD_0 = @echo "  CCLD    " $@;
    156156am__v_CCLD_1 =
     157CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
     158        $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
     159LTCXXCOMPILE = $(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)
     163AM_V_CXX = $(am__v_CXX_@AM_V@)
     164am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
     165am__v_CXX_0 = @echo "  CXX     " $@;
     166am__v_CXX_1 =
     167CXXLD = $(CXX)
     168CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
     169        $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
     170        $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
     171AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
     172am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
     173am__v_CXXLD_0 = @echo "  CXXLD   " $@;
     174am__v_CXXLD_1 =
    157175SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES)
    158176DIST_SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES)
     
    186204DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    187205ACLOCAL = @ACLOCAL@
    188 ALLOCA = @ALLOCA@
    189206AMTAR = @AMTAR@
    190207AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
     
    358375debug = yes
    359376installed = no
     377INSTALL_FLAGS = -in-tree
     378DEBUG_FLAGS = -debug -O0
    360379quick_test = avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes
    361380concurrent =
    362381timeouts =
    363 TEST_PY = python ${builddir}/test.py
     382TEST_PY = python3 ${builddir}/test.py
    364383
    365384# applies to both programs
    366385AM_CFLAGS = $(if $(test), 2> $(test), ) -g -Wall -Wno-unused-function \
    367         -quiet @CFA_FLAGS@ -DIN_DIR="${srcdir}/.in/" ${DEBUG_FLAGS} \
    368         ${INSTALL_FLAGS} ${ARCH_FLAGS}
    369 PRETTY_PATH = cd ${srcdir} &&
     386        -quiet @CFA_FLAGS@ -DIN_DIR="${abs_srcdir}/.in/" \
     387        ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS}
     388PRETTY_PATH = mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
    370389avl_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
    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
     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
     396CFACOMPILETEST = $(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
     399CFATEST_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
     402CFATEST_STDERR = $(CFACOMPILETEST) 2> $(abspath ${@})
     403
     404#------------------------------------------------------------------------------
     405# TARGET WITH STANDARD RULE BUT CUSTOM FLAGS
     406#------------------------------------------------------------------------------
     407# Expected failures
     408declarationSpecifier_FLAGS = -CFA -XCFA -p
     409gccExtensions_FLAGS = -CFA -XCFA -p
     410extension_FLAGS = -CFA -XCFA -p
     411attributes_FLAGS = -CFA -XCFA -p
     412functions_FLAGS = -CFA -XCFA -p
     413KRfunctions_FLAGS = -CFA -XCFA -p
     414gmp_FLAGS = -lgmp
     415
     416#------------------------------------------------------------------------------
     417# Expected failures
     418completeTypeError_FLAGS = -DERR1
    373419all: all-am
    374420
    375421.SUFFIXES:
    376 .SUFFIXES: .c .cfa .dummy_hack .lo .o .obj .validate
     422.SUFFIXES: .c .cfa .cpp .dummy_hack .dummy_hackxx .lo .o .obj .validate
    377423$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/src/cfa.make $(am__configure_deps)
    378424        @for dep in $?; do \
     
    410456.dummy_hack$(EXEEXT): $(_dummy_hack_OBJECTS) $(_dummy_hack_DEPENDENCIES) $(EXTRA__dummy_hack_DEPENDENCIES)
    411457        @rm -f .dummy_hack$(EXEEXT)
    412         $(AM_V_CCLD)$(LINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)
     458        $(AM_V_CXXLD)$(CXXLINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)
    413459avltree/$(am__dirstamp):
    414460        @$(MKDIR_P) avltree
     
    444490
    445491@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@
    446493
    447494.c.o:
     
    468515@AMDEP_TRUE@@am__fastdepCC_FALSE@       DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
    469516@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 $@ $<
    470541
    471542mostlyclean-libtool:
     
    718789        @echo "int main() { return 0; }" > ${@}
    719790
     791.dummy_hackxx.cpp:
     792        @echo "int bar() { return 0; }" > ${@}
     793
    720794concurrency :
    721795        @+${TEST_PY} --debug=${debug}  --install=${installed} -Iconcurrent
     
    725799# implicit rule so not all test require a rule
    726800% : %.cfa $(CFACC)
    727         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    728 
    729 declarationSpecifier: declarationSpecifier.cfa $(CFACC)
    730         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    731 
    732 gccExtensions : gccExtensions.cfa $(CFACC)
    733         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    734 
    735 extension : extension.cfa $(CFACC)
    736         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    737 
    738 attributes : attributes.cfa $(CFACC)
    739         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    740 
    741 functions: functions.cfa $(CFACC)
    742         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    743 
    744 KRfunctions : KRfunctions.cfa $(CFACC)
    745         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    746 
    747 sched-ext-parse : sched-ext-parse.c $(CFACC)
    748         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    749 
    750 gmp : gmp.cfa $(CFACC)
    751         $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     801        $(CFATEST_STDOUT)
     802
     803% : %.cpp
     804        $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     805
     806#------------------------------------------------------------------------------
     807# CUSTOM TARGET
     808#------------------------------------------------------------------------------
     809typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
     810        $(CFATEST_STDOUT) -DERR1
     811
     812alloc-ERROR: alloc.cfa $(CFACC)
     813        $(CFATEST_STDOUT) -DERR1
     814
     815nested-types-ERR1: nested-types.cfa $(CFACC)
     816        $(CFATEST_STDOUT) -DERR1
     817
     818nested-types-ERR2: nested-types.cfa $(CFACC)
     819        $(CFATEST_STDOUT) -DERR2
     820
     821raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
     822        $(CFATEST_STDOUT) -DERR1
     823
     824raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
     825        $(CFATEST_STDOUT) -DERR2
     826
     827raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
     828        $(CFATEST_STDOUT) -DERR1
     829
     830raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
     831        $(CFATEST_STDOUT) -DERR1
    752832
    753833#builtins
    754834builtins/sync: builtins/sync.cfa $(CFACC)
    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
    760 completeTypeError : completeTypeError.cfa $(CFACC)
    761         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    762 
    763 typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
    764         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    765 
    766 alloc-ERROR: alloc.cfa $(CFACC)
    767         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    768 
    769 fallthrough-ERROR: fallthrough.cfa $(CFACC)
    770         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    771 
    772 nested-types-ERR1: nested-types.cfa $(CFACC)
    773         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    774 
    775 nested-types-ERR2: nested-types.cfa $(CFACC)
    776         $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    777 
    778 # Constructor/destructor tests
    779 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
    780         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    781 
    782 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
    783         $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    784 
    785 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
    786         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    787 
    788 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
    789         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     835        $(CFATEST_STDERR) -fsyntax-only
    790836
    791837# Warnings
    792838warnings/self-assignment: warnings/self-assignment.cfa $(CFACC)
    793         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
     839        $(CFATEST_STDERR) -fsyntax-only
    794840
    795841# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • tests/array.cfa

    r6a9d4b4 r933f32f  
    1 //Testing array declarations
     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
    217int a1[];
    318//int a2[*];
     
    3449}
    3550
    36 //Dummy main
    37 int main(int argc, char const *argv[])
    38 {
    39         return 0;
    40 }
     51int main() {}
     52
     53// Local Variables: //
     54// tab-width: 4 //
     55// compile-command: "cfa array.cfa" //
     56// End: //
  • tests/builtins/sync.cfa

    r6a9d4b4 r933f32f  
    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;
    1314
    1415        { char ret; ret = __sync_fetch_and_add(vp1, v1); }
     
    180181        { _Bool ret; ret = __sync_bool_compare_and_swap_16(vp16, v16,v16); }
    181182        #endif
     183        { _Bool ret; ret = __sync_bool_compare_and_swap(vpp, vp, vp); }
    182184
    183185        { char ret; ret = __sync_val_compare_and_swap(vp1, v1, v1); }
     
    193195        { __int128 ret; ret = __sync_val_compare_and_swap_16(vp16, v16,v16); }
    194196        #endif
     197        { struct type * ret; ret = __sync_val_compare_and_swap(vpp, vp, vp); }
     198
    195199
    196200        { char ret; ret = __sync_lock_test_and_set(vp1, v1); }
     
    230234        { __atomic_clear(vp1, v1); }
    231235
    232         { char ret; ret = __atomic_exchange_n(vp1, &v1, __ATOMIC_SEQ_CST); }
     236        { char ret; ret = __atomic_exchange_n(vp1, v1, __ATOMIC_SEQ_CST); }
    233237        { char ret; ret = __atomic_exchange_1(vp1, v1, __ATOMIC_SEQ_CST); }
    234238        { char ret; __atomic_exchange(vp1, &v1, &ret, __ATOMIC_SEQ_CST); }
    235         { short ret; ret = __atomic_exchange_n(vp2, &v2, __ATOMIC_SEQ_CST); }
     239        { short ret; ret = __atomic_exchange_n(vp2, v2, __ATOMIC_SEQ_CST); }
    236240        { short ret; ret = __atomic_exchange_2(vp2, v2, __ATOMIC_SEQ_CST); }
    237241        { short ret; __atomic_exchange(vp2, &v2, &ret, __ATOMIC_SEQ_CST); }
    238         { int ret; ret = __atomic_exchange_n(vp4, &v4, __ATOMIC_SEQ_CST); }
     242        { int ret; ret = __atomic_exchange_n(vp4, v4, __ATOMIC_SEQ_CST); }
    239243        { int ret; ret = __atomic_exchange_4(vp4, v4, __ATOMIC_SEQ_CST); }
    240244        { int ret; __atomic_exchange(vp4, &v4, &ret, __ATOMIC_SEQ_CST); }
    241         { long long int ret; ret = __atomic_exchange_n(vp8, &v8, __ATOMIC_SEQ_CST); }
     245        { long long int ret; ret = __atomic_exchange_n(vp8, v8, __ATOMIC_SEQ_CST); }
    242246        { long long int ret; ret = __atomic_exchange_8(vp8, v8, __ATOMIC_SEQ_CST); }
    243247        { long long int ret; __atomic_exchange(vp8, &v8, &ret, __ATOMIC_SEQ_CST); }
    244248        #if defined(__SIZEOF_INT128__)
    245         { __int128 ret; ret = __atomic_exchange_n(vp16, &v16, __ATOMIC_SEQ_CST); }
     249        { __int128 ret; ret = __atomic_exchange_n(vp16, v16, __ATOMIC_SEQ_CST); }
    246250        { __int128 ret; ret = __atomic_exchange_16(vp16, v16, __ATOMIC_SEQ_CST); }
    247251        { __int128 ret; __atomic_exchange(vp16, &v16, &ret, __ATOMIC_SEQ_CST); }
    248252        #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); }
    249255
    250256        { char ret; ret = __atomic_load_n(vp1, __ATOMIC_SEQ_CST); }
     
    265271        { __int128 ret; __atomic_load(vp16, &ret, __ATOMIC_SEQ_CST); }
    266272        #endif
     273        { struct type * ret; ret = __atomic_load_n(vpp, __ATOMIC_SEQ_CST); }
     274        { struct type * ret; __atomic_load(vpp, &ret, __ATOMIC_SEQ_CST); }
    267275
    268276        { _Bool ret; ret = __atomic_compare_exchange_n(vp1, rp1, v1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     
    283291        { _Bool ret; ret = __atomic_compare_exchange(vp16, rp16, &v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    284292        #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); }
    285295
    286296        { __atomic_store_n(vp1, v1, __ATOMIC_SEQ_CST); }
     
    301311        { __atomic_store(vp16, &v16, __ATOMIC_SEQ_CST); }
    302312        #endif
     313        { __atomic_store_n(vpp, vp, __ATOMIC_SEQ_CST); }
     314        { __atomic_store(vpp, &vp, __ATOMIC_SEQ_CST); }
    303315
    304316        { char ret; ret = __atomic_add_fetch(vp1, v1, __ATOMIC_SEQ_CST); }
  • tests/castError.cfa

    r6a9d4b4 r933f32f  
    1 //Testing some of the invalid casts of chars
     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
    216int f;
    317
     
    721        (char)f;
    822        (int(*)())f;
     23
     24        unsigned char v;
     25        short int v;
     26        3, v;           // implicit void cast
    927}
    1028
    11 //Dummy main
    12 int main(int argc, char const *argv[])
    13 {
    14         return 0;
    15 }
     29int main() {}
     30
     31// Local Variables: //
     32// tab-width: 4 //
     33// compile-command: "cfa castError.cfa" //
     34// End: //
  • tests/completeTypeError.cfa

    r6a9d4b4 r933f32f  
    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         *x; // picks B
     21        *y;
    2222        *z;
    2323        foo(i);
     
    3232        // bad
    3333        *v;
    34         *y;
     34        *x;     // ambiguous
    3535        foo(v);
    3636        baz(v);
     
    5252void qux(T * y) {
    5353        // okay
     54        *y;
    5455        bar(y);
    5556        qux(y);
     
    5859        baz(y);
    5960        quux(y);
    60         *y;
    6161}
    6262
  • tests/concurrent/examples/boundedBufferEXT.cfa

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

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

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

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

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

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

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

    r6a9d4b4 r933f32f  
    1616difi  ed B  y :   Pete  r A. 
    1717 Buh  r//   Last   Mod  ifie 
    18 d On   : T  ue D  ec 1  1 2
    19 :31:  12 2  018/  / Up  date 
    20  Cou  nt       :   32/  /#in 
     18d On   : F  ri M  ar 2  2 1
     19:41:  03 2  019/  / Up  date 
     20 Cou  nt       :   33/  /#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.c"   ///  / En  d: /  /
     78s.cf  a" /  ///   End:   //
  • tests/coroutine/.in/fmtLines.txt

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

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

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

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed Sep 20 11:55:23 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 11 21:58:06 2018
    13 // Update Count     : 29
     12// Last Modified On : Tue Mar 26 17:54:14 2019
     13// Update Count     : 35
    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.__cor){name};
    27         this.name = name;
    28         this.N = N;
    29         this.part = &part;
     26        this.[name, N] = [name, N];  &this.part = &part;
    3027}
    3128void ?{}( PingPong & this, const char * name, unsigned int N ) {
    32         this{ name, N, *(PingPong *)0 };
     29        this{ name, N, *0p };                                                           // call first constructor
    3330}
    3431void cycle( PingPong & pingpong ) {
     
    3633}
    3734void partner( PingPong & this, PingPong & part ) {
    38         this.part = &part;
     35        &this.part = &part;
    3936        resume( this );
    4037}
    41 void 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 );
     38void 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 );
    4542        } // for
    4643}
     
    5350// Local Variables: //
    5451// tab-width: 4 //
    55 // compile-command: "cfa pingpong.c" //
     52// compile-command: "cfa pingpong.cfa" //
    5653// End: //
  • tests/coroutine/prodcons.cfa

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

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

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

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

    r6a9d4b4 r933f32f  
    1010// Created On       : Fri Aug 25 15:21:11 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec  4 21:37:09 2018
    13 // Update Count     : 9
     12// Last Modified On : Thu Apr 11 18:27:45 2019
     13// Update Count     : 10
    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

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed Mar  2 16:56:02 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 21 16:02:55 2018
    13 // Update Count     : 114
     12// Last Modified On : Mon Mar  4 21:42:47 2019
     13// Update Count     : 115
    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 | 1 | 2 | 3;
    22         sout | '1' | '2' | '3';
    23         sout | 1 | "" | 2 | "" | 3;
     21        sout | 0 | 1 | 2 | 3;
     22        sout | '0' | '1' | '2' | '3';
     23        sout | 0 | "" | 1 | "" | 2 | "" | 3;
    2424        sout | nl;
    2525
  • tests/io2.cfa

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed Mar  2 16:56:02 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 21 08:20:14 2018
    13 // Update Count     : 112
     12// Last Modified On : Thu Apr 18 08:03:30 2019
     13// Update Count     : 113
    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

    r6a9d4b4 r933f32f  
    1010// Created On       : Sat Sep  9 16:34:38 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec  4 21:44:01 2018
    13 // Update Count     : 139
    14 //
    15 
     12// Last Modified On : Tue Feb 12 08:07:39 2019
     13// Update Count     : 224
     14//
     15
     16#include <features.h>                                                                   // __GNUC_PREREQ
    1617#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
    153197#ifdef __CFA__
    154198// fixed-size length
     
    167211        // octal
    168212         01234567_l8;   01234567_l16;   01234567_l32;   01234567_l64;   01234567_l8u;   01234567_ul16;   01234567_l32u;   01234567_ul64;
    169         +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;
    170214        -01234567_l8;  -01234567_l16;  -01234567_l32;  -01234567_l64;  -01234567_l8u;  -01234567_ul16;  -01234567_l32u;  -01234567_ul64;
    171215
     
    203247        +0X0123456789ABCDEF_l8;  +0X0123456789ABCDEF_l16;  +0X0123456789ABCDEFl32;  +0X0123456789ABCDEFl64;  +0X0123456789ABCDEF_ul8;  +0X0123456789ABCDEF_l16u;  +0X0123456789ABCDEFul32;  +0X0123456789ABCDEFl64u;
    204248        -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;
    231249
    232250// char, short, int suffix overloading
  • tests/loopctrl.cfa

    r6a9d4b4 r933f32f  
    1010// Created On       : Wed Aug  8 18:32:59 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 23 23:00:29 2018
    13 // Update Count     : 79
     12// Last Modified On : Sat Apr 13 11:03:09 2019
     13// Update Count     : 104
    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 | nl;
     56        for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; }                      sout | 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       
    5886        enum { N = 10 };
    5987        for ( N ) { sout | "N"; }                                                       sout | nl;
    6088        for ( i; N ) { sout | i; }                                                      sout | nl;
    61         for ( i; N -~ 0 ) { sout | i; }                                         sout | nl | nl | nl;
     89        for ( i; N -~ 0 ) { sout | i; }                                         sout | nl | nl;
    6290
    6391        const int start = 3, comp = 10, inc = 2;
    6492        for ( i; start ~ comp ~ inc + 1 ) { sout | i; }         sout | nl | nl;
    6593
    66         sout | nl;
    6794        for ( S s = (S){0}; s < (S){10,10}; s += (S){1} ) { sout | s; } sout | nl;
    6895        for ( s; (S){10,10} ) { sout | s; } sout | nl;
     
    76103        for ( s; (S){10,10} -~ (S){0} ~ (S){1} ) { sout | s; } sout | nl;
    77104        for ( s; (S){10,10} -~= (S){0} ) { sout | s; }           sout | nl;
    78         for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { 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;
    79120}
    80121
  • tests/math1.cfa

    r6a9d4b4 r933f32f  
    1010// Created On       : Fri Apr 22 14:59:21 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 12 16:28:49 2018
    13 // Update Count     : 89
     12// Last Modified On : Mon Mar 25 22:56:47 2019
     13// Update Count     : 109
    1414//
    1515
     
    4949        unsigned int e = 2;
    5050    b \= e;
    51     sout | "\\" | b | b \ e;
    52     sout | "\\" | 'a' \ 3u | 2 \ 8u | 4 \ 3u | -4 \ 3u | nonl;
     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);
    5354        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;
    5466} // main
    5567
  • tests/numericConstants.cfa

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

    r6a9d4b4 r933f32f  
    1 from __future__ import print_function
    2 
    31import os
     2import subprocess
    43import sys
    5 import tools
     4from . import tools
    65
    76try :
     
    3938        def __init__(self, arch):
    4039                try:
    41                         canonical_host = Architecture.makeCanonical( config.HOSTARCH )
     40                        canonical_host = Architecture.make_canonical( config.HOSTARCH )
    4241                except KeyError:
    4342                        print("Unkown host architecture %s" % config.HOSTARCH, file=sys.stderr)
     
    4645                if arch:
    4746                        try:
    48                                 arch = Architecture.makeCanonical( arch )
     47                                arch = Architecture.make_canonical( arch )
    4948                        except KeyError:
    5049                                print("Unkown architecture %s" % arch, file=sys.stderr)
     
    7776
    7877        @classmethod
    79         def makeCanonical(_, arch):
     78        def make_canonical(_, arch):
    8079                return Architecture.KnownArchitectures[arch]
    8180
     
    8483        def __init__(self, value):
    8584                self.string = "debug" if value else "no debug"
    86                 self.flags  = """DEBUG_FLAGS="%s" """ % ("-debug -O0" if value else "-nodebug -O2")
     85                self.flags  = """DEBUG_FLAGS=%s""" % ("-debug -O0" if value else "-nodebug -O2")
    8786
    8887class Install:
    8988        def __init__(self, value):
    9089                self.string = "installed" if value else "in-tree"
    91                 self.flags  = """INSTALL_FLAGS="%s" """ % ("" if value else "-in-tree")
     90                self.flags  = """INSTALL_FLAGS=%s""" % ("" if value else "-in-tree")
    9291
    9392class Timeouts:
     
    112111        global install
    113112        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)
     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
    122123
    123124
    124 def updateMakeCmd(force, jobs):
     125def update_make_cmd(force, jobs):
    125126        global make
    126127
    127         make = "make" if not force else ("make -j%i" % jobs)
     128        make = ['make'] if not force else ['make', "-j%i" % jobs]
    128129
    129130def validate():
    130131        errf = os.path.join(BUILDDIR, ".validate.err")
    131         make_ret, _ = tools.make( ".validate", error_file = errf, redirects  = "2> /dev/null 1> /dev/null", )
     132        make_ret, out = tools.make( ".validate", error_file = errf, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
    132133        if make_ret != 0:
    133134                with open (errf, "r") as myfile:
     
    139140
    140141        tools.rm(errf)
     142
     143def prep_output(tests):
     144        global output_width
     145        output_width = max(map(lambda t: len(t.target()), tests))
  • tests/pybin/test_run.py

    r6a9d4b4 r933f32f  
    44
    55import pybin.settings
    6 import datetime
    7 
    8 from string import Template
    9 
    10 class DeltaTemplate(Template):
    11     delimiter = "%"
    12 
    13 def 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)
    186
    197# Test class that defines what a test is
  • tests/pybin/tools.py

    r6a9d4b4 r933f32f  
    1 from __future__ import print_function
    2 
    31import __main__
    42import argparse
     3import contextlib
    54import fileinput
    65import multiprocessing
     
    109import signal
    1110import stat
     11import subprocess
    1212import sys
     13import tempfile
    1314import time
     15import types
    1416
    1517from pybin import settings
    16 from subprocess import Popen, PIPE, STDOUT
    1718
    1819################################################################################
     
    2122
    2223# helper functions to run terminal commands
    23 def sh(cmd, print2stdout = True, input = None):
    24         # add input redirection if needed
    25         if input and os.path.isfile(input):
    26                 cmd += " < %s" % input
     24def sh(*cmd, timeout = False, output = None, input = None, error = subprocess.STDOUT):
     25        cmd = list(cmd)
    2726
    2827        # if this is a dry_run, only print the commands that would be ran
    2928        if settings.dry_run :
    30                 print("cmd: %s" % cmd)
     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)
    3143                return 0, None
    3244
    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
     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)
    3867
    3968def is_ascii(fname):
     
    4574                return False
    4675
    47         code, out = sh("file %s" % fname, print2stdout = False)
     76        code, out = sh("file %s" % fname, output=subprocess.PIPE)
    4877        if code != 0:
    4978                return False
     
    5685        return match.group(1).startswith("ASCII text")
    5786
     87def is_exe(fname):
     88        return os.path.isfile(fname) and os.access(fname, os.X_OK)
     89
     90def 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
     103
    58104# Remove 1 or more files silently
    59105def rm( files ):
    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 )
     106        if isinstance(files, str ): files = [ files ]
     107        for file in files:
     108                sh( 'rm', '-f', file, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
    65109
    66110# Create 1 or more directory
    67111def mkdir( files ):
    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) )
     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 )
    73117
    74118
     
    80124# diff two files
    81125def 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 
    100126        # fetch return code and error from the diff command
    101         return sh(diff_cmd % (lhs, rhs), False)
     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        )
    102141
    103142# call make
    104 def 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 '',
     143def 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,
    109148                test_param,
    110149                settings.arch.flags,
     
    112151                settings.install.flags,
    113152                flags,
    114                 target,
    115                 redirects
    116         ])
    117         return sh(cmd)
     153                target
     154        ]
     155        cmd = [s for s in cmd if s]
     156        return sh(*cmd, output=output, error=error)
    118157
    119158def which(program):
    120     import os
    121     def is_exe(fpath):
    122         return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
    123 
    124159    fpath, fname = os.path.split(program)
    125160    if fpath:
     
    134169    return None
    135170
    136 def run(exe, output, input):
    137         ret, _ = sh("timeout %d %s > %s 2>&1" % (settings.timeout.single, exe, output), input = input)
    138         return ret
     171@contextlib.contextmanager
     172def 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)
    139180
    140181################################################################################
     
    143184# move a file
    144185def mv(source, dest):
    145         ret, _ = sh("mv %s %s" % (source, dest))
     186        ret, _ = sh("mv", source, dest)
    146187        return ret
    147188
    148189# cat one file into the other
    149190def cat(source, dest):
    150         ret, _ = sh("cat %s > %s" % (source, dest))
     191        ret, _ = sh("cat", source, output=dest)
    151192        return ret
    152193
     
    163204
    164205# helper function to check if a files contains only a specific string
    165 def fileContainsOnly(file, text) :
     206def file_contains_only(file, text) :
    166207        with open(file) as f:
    167208                ff = f.read().strip()
    168209                result = ff == text.strip()
    169210
    170                 return result;
    171 
    172 # check whether or not a file is executable
    173 def 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
     211                return result
    182212
    183213# transform path to canonical form
    184 def canonicalPath(path):
     214def canonical_path(path):
    185215        abspath = os.path.abspath(__main__.__file__)
    186216        dname = os.path.dirname(abspath)
     
    188218
    189219# compare path even if form is different
    190 def pathCmp(lhs, rhs):
    191         return canonicalPath( lhs ) == canonicalPath( rhs )
     220def path_cmp(lhs, rhs):
     221        return canonical_path( lhs ) == canonical_path( rhs )
    192222
    193223# walk all files in a path
    194 def pathWalk( op ):
    195         def step(_, dirname, names):
     224def path_walk( op ):
     225        dname = settings.SRCDIR
     226        for dirname, _, names in os.walk(dname):
    196227                for name in names:
    197228                        path = os.path.join(dirname, name)
    198229                        op( path )
    199230
    200         # Start the walk
    201         dname = settings.SRCDIR
    202         os.path.walk(dname, step, '')
    203 
    204231################################################################################
    205232#               system
    206233################################################################################
    207234# count number of jobs to create
    208 def jobCount( options, tests ):
     235def job_count( options, tests ):
    209236        # check if the user already passed in a number of jobs for multi-threading
    210237        if not options.jobs:
     
    228255        return min( options.jobs, len(tests) ), force
    229256
    230 # setup a proper processor pool with correct signal handling
    231 def 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
    239 class 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 
    249257# enable core dumps for all the test children
    250258resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
     
    261269                return False
    262270        raise argparse.ArgumentTypeError(msg)
    263         return False
    264271
    265272def fancy_print(text):
    266273        column = which('column')
    267274        if column:
    268                 cmd = "%s 2> /dev/null" % column
    269                 proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True)
    270                 proc.communicate(input=text + "\n")
     275                subprocess.run(column, input=bytes(text + "\n", "UTF-8"))
    271276        else:
    272277                print(text)
    273278
    274279
    275 def coreInfo(path):
     280def core_info(path):
     281        if not os.path.isfile(path):
     282                return 1, "ERR Executable path is wrong"
     283
    276284        cmd   = os.path.join(settings.SRCDIR, "pybin/print-core.gdb")
    277285        if not os.path.isfile(cmd):
    278286                return 1, "ERR Printing format for core dumps not found"
    279287
    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"
     288        core  = os.path.join(os.getcwd(), "core" )
    284289
    285290        if not os.path.isfile(core):
    286291                return 1, "ERR No core dump"
    287292
    288         return sh("gdb -n %s %s -batch -x %s" % (path, core, cmd), print2stdout=False)
     293        return sh('gdb', '-n', path, core, '-batch', '-x', cmd, output=subprocess.PIPE)
    289294
    290295class Timed:
  • tests/raii/.expect/ctor-autogen-ERR1.txt

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

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

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

    r6a9d4b4 r933f32f  
    1111// Created On       : Wed May 27 17:56:53 2015
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Sun Dec 23 23:00:38 2018
    14 // Update Count     : 287
     13// Last Modified On : Sun May 19 11:21:02 2019
     14// Update Count     : 330
    1515//
    1616
    1717#include <fstream.hfa>
    1818#include <stdlib.hfa>
    19 
    20 void ?{}( int & c, zero_t ) { c = 0; }                                  // not in prelude
    2119
    2220trait sumable( otype T ) {
     
    3129T sum( size_t size, T a[] ) {
    3230        T total = 0;                                                                            // initialize by 0 constructor
    33         for ( size_t i = 0; i < size; i += 1 )
     31        for ( i; size )
    3432                total += a[i];                                                                  // select appropriate +
    3533        return total;
    3634} // sum
    3735
    38 // Not in prelude.
    39 unsigned char ?+?( unsigned char t1, unsigned char t2 ) { return (int)t1 + t2; } // cast forces integer addition, otherwise recursion
    40 unsigned char ?+=?( unsigned char & t1, unsigned char t2 ) { t1 = t1 + t2; return t1; }
    41 unsigned char ++?( unsigned char & t ) { t += 1; return t; }
    42 unsigned char ?++( unsigned char & t ) { unsigned char temp = t; t += 1; return temp; }
    43 
    44 // Not in prelude.
    45 void ?{}( unsigned char & c, zero_t ) { c = 0; }
    46 void ?{}( float & f, zero_t ) { f = 0.0; }
    47 void ?{}( double & d, zero_t ) { d = 0.0; }
    48 
    4936int main( void ) {
    5037        const int low = 5, High = 15, size = High - low;
    5138
    52         unsigned char s = 0, a[size], v = (char)low;
    53         for ( int i = 0; i < size; i += 1, v += 1 ) {
     39        signed char s = 0, a[size], v = (char)low;
     40        for ( int i = 0; i < size; i += 1, v += 1hh ) {
    5441                s += v;
    5542                a[i] = v;
    5643        } // for
    5744        sout | "sum from" | low | "to" | High | "is"
    58                  | sum( size, (unsigned char *)a ) | ", check" | (int)s;
     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;
    5962
    6063        int s = 0, a[size], v = low;
  • tests/test.py

    r6a9d4b4 r933f32f  
    1 #!/usr/bin/python
    2 from __future__ import print_function
     1#!/usr/bin/python3
    32
    43from pybin.tools import *
     
    98import re
    109import sys
     10import tempfile
    1111import time
    1212
     
    1515################################################################################
    1616
    17 def findTests():
     17def find_tests():
    1818        expected = []
    1919
    20         def matchTest(path):
     20        def match_test(path):
    2121                match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
    2222                if match :
     
    2828                                expected.append(test)
    2929
    30         pathWalk( matchTest )
     30        path_walk( match_test )
    3131
    3232        return expected
    3333
    3434# reads the directory ./.expect and indentifies the tests
    35 def listTests( includes, excludes ):
     35def list_tests( includes, excludes ):
    3636        # tests directly in the .expect folder will always be processed
    37         test_list = findTests()
     37        test_list = find_tests()
    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 validTests( options ):
     54def valid_tests( options ):
    5555        tests = []
    5656
     
    5959        if options.regenerate_expected :
    6060                for testname in options.tests :
    61                         testname = canonicalPath( testname )
     61                        testname = canonical_path( testname )
    6262                        if Test.valid_name(testname):
    63                                 found = [test for test in allTests if canonicalPath( test.target() ) == testname]
     63                                found = [test for test in all_tests if canonical_path( 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 allTests if pathCmp( t.target(), testname )]
     71                        test = [t for t in all_tests if path_cmp( t.target(), testname )]
    7272
    7373                        if test :
     
    7979
    8080# parses the option
    81 def getOptions():
     81def parse_args():
    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 isExe(file):
    127         return settings.dry_run or fileIsExecutable(file)
    128 
    129 def noRule(file, target):
    130         return not settings.dry_run and fileContainsOnly(file, "make: *** No rule to make target `%s'.  Stop." % target)
     126def no_rule(file, target):
     127        return not settings.dry_run and file_contains_only(file, "make: *** No rule to make target `%s'.  Stop." % target)
    131128
    132129# logic to run a single test and return the result (No handling of printing or other test framework logic)
     
    145142        # build, skipping to next test on error
    146143        with Timed() as comp_dur:
    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
     144                make_ret, _ = make( test.target(), output=subprocess.DEVNULL, error=out_file, error_file = err_file )
     145
    150146        run_dur = 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)
     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
    156170                        else :
    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
     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
    181180
    182181
     
    189188# run a single test and handle the errors, outputs, printing, exception handling, etc.
    190189def run_test_worker(t) :
    191 
    192         with SignalHandling():
     190        try :
    193191                # print formated name
    194                 name_txt = "%24s  " % t.name
     192                name_txt = '{0:{width}}  '.format(t.target(), width=settings.output_width)
    195193
    196194                retcode, error, duration = run_single_test(t)
     
    200198
    201199                #print result with error if needed
    202                 text = name_txt + result_txt
     200                text = '\t' + name_txt + result_txt
    203201                out = sys.stdout
    204202                if error :
    205                         text = text + "\n" + error
     203                        text = text + '\n' + error
    206204                        out = sys.stderr
    207205
     
    210208                sys.stderr.flush()
    211209
    212         return retcode != TestResult.SUCCESS
     210                return retcode != TestResult.SUCCESS
     211        except KeyboardInterrupt:
     212                False
    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', redirects = '> /dev/null 2>&1')
     217        make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)
    218218
    219219        # create the executor for our jobs and handle the signal properly
    220         pool = setupPool(jobs)
     220        pool = multiprocessing.Pool(jobs)
    221221
    222222        # for each test to run
     
    233233
    234234        # clean the workspace
    235         make('clean', redirects = '> /dev/null 2>&1')
     235        make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)
    236236
    237237        for failed in results:
     
    248248
    249249        # parse the command line arguments
    250         options = getOptions()
     250        options = parse_args()
    251251
    252252        # init global settings
     
    254254
    255255        # fetch the liest of all valid tests
    256         allTests = listTests( options.include, options.exclude )
     256        all_tests = list_tests( 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 = allTests
     261                tests = all_tests
    262262
    263263        #otherwise we need to validate that the test list that was entered is valid
    264264        else :
    265                 tests = validTests( options )
     265                tests = valid_tests( 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: "%s" % (t.toString()), tests)))
     283                fancy_print("\n".join(map(lambda t: t.toString(), tests)))
    284284
    285285        else :
    286286                # check the build configuration works
     287                settings.prep_output(tests)
    287288                settings.validate()
    288289
    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',
     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,
    294297                        settings.arch.string,
    295                         settings.debug.string,
    296                         options.jobs
     298                        settings.debug.string
    297299                ))
    298300
  • tests/warnings/.expect/self-assignment.txt

    r6a9d4b4 r933f32f  
    1 warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Cast of:
     1warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Generated 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: Cast of:
     5warnings/self-assignment.cfa:30:1 warning: self assignment of expression: Generated 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: Cast of:
     9warnings/self-assignment.cfa:31:1 warning: self assignment of expression: Generated 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: Cast of:
     16warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Generated Cast of:
    1717  Member Expression, with field:
    1818    i: signed int
  • tests/warnings/self-assignment.cfa

    r6a9d4b4 r933f32f  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Mar 1 13:53:57 2018
    11 // Last Modified By : Rob Schluntz
    12 // Last Modified On : Thu Mar 1 13:53:57 2018
    13 // Update Count     : 2
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Feb 20 07:56:17 2019
     13// Update Count     : 3
    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

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

    r6a9d4b4 r933f32f  
    2727git rev-list --format=short ${GitOldRef}...${GitNewRef} >  ${GIT_LOG}
    2828
    29 git diff --stat ${GitNewRef} ${GitOldRef} >  ${GIT_DIFF}
     29git 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}
  • tools/prettyprinter/Makefile.in

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