Changeset 74ec742


Ignore:
Timestamp:
May 20, 2022, 10:36:45 AM (3 years ago)
Author:
m3zulfiq <m3zulfiq@…>
Branches:
ADT, ast-experimental, master, pthread-emulation, qualifiedEnum
Children:
25fa20a
Parents:
29d8c02 (diff), 7831e8fb (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' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
35 added
3 deleted
137 edited
1 moved

Legend:

Unmodified
Added
Removed
  • benchmark/Cargo.toml.in

    r29d8c02 r74ec742  
    44authors = ["Cforall"]
    55edition = "2018"
     6
     7[[bin]]
     8name = "rdq-churn-tokio"
     9path = "@abs_srcdir@/readyQ/churn.rs"
    610
    711[[bin]]
  • benchmark/Makefile.am

    r29d8c02 r74ec742  
    614614RDQBENCHES = \
    615615        rdq-churn-cfa \
     616        rdq-churn-tokio \
     617        rdq-churn-go \
     618        rdq-churn-fibre \
    616619        rdq-cycle-cfa \
    617620        rdq-cycle-tokio \
  • benchmark/plot.py

    r29d8c02 r74ec742  
    2222
    2323class Field:
    24         def __init__(self, unit, _min, _log):
     24        def __init__(self, unit, _min, _log, _name=None):
    2525                self.unit = unit
    2626                self.min  = _min
    2727                self.log  = _log
     28                self.name = _name
    2829
    2930field_names = {
     
    3233        "Ops per procs"         : Field('Ops'   , 0, False),
    3334        "Ops per threads"       : Field('Ops'   , 0, False),
    34         "ns per ops/procs"      : Field('ns'    , 0, False),
    35         "Number of threads"     : Field('thrd'  , 1, False),
     35        "ns per ops/procs"      : Field(''    , 0, False, _name = "Latency (ns $/$ (Processor $\\times$ Operation))" ),
     36        "Number of threads"     : Field(''      , 1, False),
    3637        "Total Operations(ops)" : Field('Ops'   , 0, False),
    3738        "Ops/sec/procs"         : Field('Ops'   , 0, False),
    3839        "Total blocks"          : Field('Blocks', 0, False),
    39         "Ops per second"        : Field('Ops'   , 0, False),
     40        "Ops per second"        : Field(''   , 0, False),
    4041        "Cycle size (# thrds)"  : Field('thrd'  , 1, False),
    4142        "Duration (ms)"         : Field('ms'    , 0, False),
    42         "Target QPS"            : Field('QPS'   , 0, False),
    43         "Actual QPS"            : Field('QPS'   , 0, False),
     43        "Target QPS"            : Field(''      , 0, False),
     44        "Actual QPS"            : Field(''      , 0, False),
     45        "Average Read Latency"  : Field('us'    , 0, True),
    4446        "Median Read Latency"   : Field('us'    , 0, True),
    4547        "Tail Read Latency"     : Field('us'    , 0, True),
     48        "Average Update Latency": Field('us'    , 0, True),
    4649        "Median Update Latency" : Field('us'    , 0, True),
    4750        "Tail Update Latency"   : Field('us'    , 0, True),
     51        "Update Ratio"          : Field('\%'    , 0, False),
    4852}
    4953
    50 def plot(in_data, x, y, out):
     54def plot(in_data, x, y, options):
    5155        fig, ax = plt.subplots()
    5256        colors = itertools.cycle(['#0095e3','#006cb4','#69df00','#0aa000','#fb0300','#e30002','#fd8f00','#ff7f00','#8f00d6','#4b009a','#ffff00','#b13f00'])
     
    9296        print("Making Plots")
    9397
    94         for name, data in series.items():
     98        for name, data in sorted(series.items()):
    9599                _col = next(colors)
    96100                plt.scatter(data['x'], data['y'], color=_col, label=name, marker='x')
     
    106110        print("Finishing Plots")
    107111
    108         plt.ylabel(y)
     112        plt.ylabel(field_names[y].name if field_names[y].name else y)
    109113        # plt.xticks(range(1, math.ceil(mx) + 1))
    110         plt.xlabel(x)
     114        plt.xlabel(field_names[x].name if field_names[x].name else x)
    111115        plt.grid(b = True)
    112116        ax.xaxis.set_major_formatter( EngFormatter(unit=field_names[x].unit) )
    113         if field_names[x].log:
     117        if options.logx:
     118                ax.set_xscale('log')
     119        elif field_names[x].log:
    114120                ax.set_xscale('log')
    115121        else:
     
    117123
    118124        ax.yaxis.set_major_formatter( EngFormatter(unit=field_names[y].unit) )
    119         if field_names[y].log:
     125        if options.logy:
     126                ax.set_yscale('log')
     127        elif field_names[y].log:
    120128                ax.set_yscale('log')
    121129        else:
    122                 plt.ylim(field_names[y].min, my*1.2)
     130                plt.ylim(field_names[y].min, options.MaxY if options.MaxY else my*1.2)
    123131
    124132        plt.legend(loc='upper left')
    125133
    126134        print("Results Ready")
    127         if out:
    128                 plt.savefig(out)
     135        if options.out:
     136                plt.savefig(options.out, bbox_inches='tight')
    129137        else:
    130138                plt.show()
     
    139147        parser.add_argument('-y', nargs='?', type=str, default="", help="Which field to use as the Y axis")
    140148        parser.add_argument('-x', nargs='?', type=str, default="", help="Which field to use as the X axis")
     149        parser.add_argument('--logx', action='store_true', help="if set, makes the x-axis logscale")
     150        parser.add_argument('--logy', action='store_true', help="if set, makes the y-axis logscale")
     151        parser.add_argument('--MaxY', nargs='?', type=int, help="maximum value of the y-axis")
    141152
    142153        options =  parser.parse_args()
     
    182193
    183194
    184         plot(data, wantx, wanty, options.out)
     195        plot(data, wantx, wanty, options)
  • benchmark/process-mutilate.py

    r29d8c02 r74ec742  
    1414parser = argparse.ArgumentParser(description='Python Script to convert output from mutilate to rmit like output')
    1515parser.add_argument('--out', nargs='?', type=argparse.FileType('w'), default=sys.stdout)
     16parser.add_argument('--var', nargs='?', type=str, default='Target QPS')
    1617try:
    1718        options =  parser.parse_args()
     
    3132
    3233        try:
     34                latAvs = fields[1]
    3335                lat50s = fields[6]
    3436                lat99s = fields[9]
     
    3739
    3840        try:
     41                latAv = locale.atof(latAvs)
    3942                lat50 = locale.atof(lat50s)
    4043                lat99 = locale.atof(lat99s)
     
    4245                raise Warning("Warning: \"{}\" \"{}\"! can't convert to float".format(lat50s, lat99s))
    4346
    44         return lat50, lat99
     47        return latAv, lat50, lat99
    4548
    4649def want0(line):
     
    5861                try:
    5962                        if   line.startswith("read"):
    60                                 rlat50, rlat99 = precentile(line)
     63                                rlatAv, rlat50, rlat99 = precentile(line)
    6164
    6265                        elif line.startswith("update"):
    63                                 ulat50, ulat99 = precentile(line)
     66                                ulatAv, ulat50, ulat99 = precentile(line)
    6467
    6568                        elif line.startswith("Total QPS"):
     
    8487
    8588        try:
     89                out['Average Read Latency'] = rlatAv
    8690                out['Median Read Latency'] = rlat50
    8791                out['Tail Read Latency'] = rlat99
     
    9094
    9195        try:
     96                out['Average Update Latency'] = ulatAv
    9297                out['Median Update Latency'] = ulat50
    9398                out['Tail Update Latency'] = ulat99
     
    112117                        continue
    113118
    114                 d = { 'Target QPS': int(rate) }
     119                d = { options.var : int(rate) }
    115120
    116121                w = extract( f, d )
  • benchmark/readyQ/bench.go

    r29d8c02 r74ec742  
    7171                duration = 5
    7272                clock_mode = true
    73                 fmt.Printf("Running for %f seconds\n", duration)
     73                fmt.Printf("Running for %f seconds (default)\n", duration)
    7474        }
    7575
  • benchmark/readyQ/churn.cfa

    r29d8c02 r74ec742  
    11#include "rq_bench.hfa"
    22
     3#include <locks.hfa>
     4
    35unsigned spot_cnt = 2;
    4 bench_sem * volatile * spots;
     6semaphore * spots;
    57
    68thread BThrd {
    79        unsigned long long count;
    810        unsigned long long blocks;
    9         bench_sem sem;
     11        bool skip;
    1012};
    1113
     
    1416        this.count  = 0;
    1517        this.blocks = 0;
     18        this.skip = false;
    1619}
    1720
     
    1922
    2023void main( BThrd & this ) with( this ) {
    21         wait( sem );
     24        park();
    2225        for() {
    23                 uint32_t r = prng();
    24                 bench_sem * next = __atomic_exchange_n(&spots[r % spot_cnt], &sem, __ATOMIC_SEQ_CST);
    25                 if(next) post( *next );
    26                 blocks += wait( sem );
     26                uint32_t r = prng(this);
     27                semaphore & sem = spots[r % spot_cnt];
     28                if(!skip) V( sem );
     29                blocks += P( sem );
     30                skip = false;
     31
    2732                count ++;
    2833                if( clock_mode && stop) break;
     
    3944                { 's', "spots", "Number of spots in the system", spot_cnt }
    4045        };
    41         BENCH_OPT_PARSE("cforall cycle benchmark");
     46        BENCH_OPT_PARSE("cforall churn benchmark");
    4247
    4348        {
     
    4954                        spots = aalloc(spot_cnt);
    5055                        for(i; spot_cnt) {
    51                                 spots[i] = 0p;
     56                                (spots[i]){ 0 };
    5257                        }
    5358
     
    5560                        BThrd * threads[nthreads];
    5661                        for(i; nthreads ) {
    57                                 threads[i] = malloc();
    58                                 (*threads[i]){};
     62                                BThrd & t = *(threads[i] = malloc());
     63                                (t){};
     64                                t.skip = i < spot_cnt;
    5965                        }
    6066                        printf("Starting\n");
     
    6470
    6571                        for(i; nthreads) {
    66                                 post( threads[i]->sem );
     72                                unpark( *threads[i] );
    6773                        }
    6874                        wait(start, is_tty);
     
    7278                        printf("\nDone\n");
    7379
     80                        for(i; spot_cnt) {
     81                                for(10000) V( spots[i] );
     82                        }
     83
    7484                        for(i; nthreads) {
    75                                 post( threads[i]->sem );
    7685                                BThrd & thrd = join( *threads[i] );
    7786                                global_counter += thrd.count;
  • benchmark/readyQ/cycle.cpp

    r29d8c02 r74ec742  
    4646                        }
    4747                        for(unsigned i = 0; i < tthreads; i++) {
    48                                 threads[i] = new Fibre( reinterpret_cast<void (*)(void *)>(partner_main), &thddata[i] );
     48                                threads[i] = new Fibre();
     49                                threads[i]->run( partner_main, &thddata[i] );
    4950                        }
    5051                        printf("Starting\n");
  • benchmark/readyQ/rq_bench.hpp

    r29d8c02 r74ec742  
    143143        }
    144144
     145        if(strcmp(arg, "Y") == 0) {
     146                value = true;
     147                return true;
     148        }
     149
     150        if(strcmp(arg, "y") == 0) {
     151                value = true;
     152                return true;
     153        }
     154
    145155        if(strcmp(arg, "no") == 0) {
     156                value = false;
     157                return true;
     158        }
     159
     160        if(strcmp(arg, "N") == 0) {
     161                value = false;
     162                return true;
     163        }
     164
     165        if(strcmp(arg, "n") == 0) {
    146166                value = false;
    147167                return true;
  • benchmark/readyQ/transfer.cfa

    r29d8c02 r74ec742  
    1414
    1515bool exhaust = false;
     16volatile bool estop = false;
     17
    1618
    1719thread$ * the_main;
     
    3537static void waitgroup() {
    3638        Time start = timeHiRes();
    37         for(i; nthreads) {
     39        OUTER: for(i; nthreads) {
    3840                PRINT( sout | "Waiting for :" | i | "(" | threads[i]->idx | ")"; )
    3941                while( threads[i]->idx != lead_idx ) {
     
    4244                                print_stats_now( bench_cluster, CFA_STATS_READY_Q | CFA_STATS_IO );
    4345                                serr | "Programs has been blocked for more than 5 secs";
    44                                 exit(1);
     46                                estop = true;
     47                                unpark( the_main );
     48                                break OUTER;
    4549                        }
    4650                }
     
    5963static void lead(MyThread & this) {
    6064        this.idx = ++lead_idx;
    61         if(lead_idx > stop_count) {
     65        if(lead_idx > stop_count || estop) {
    6266                PRINT( sout | "Leader" | this.id | "done"; )
    6367                unpark( the_main );
     
    100104                        wait( this );
    101105                }
    102                 if(lead_idx > stop_count) break;
     106                if(lead_idx > stop_count || estop) break;
    103107        }
    104108}
     
    172176        sout | "Number of processors    : " | nprocs;
    173177        sout | "Number of threads       : " | nthreads;
    174         sout | "Total Operations(ops)   : " | stop_count;
     178        sout | "Total Operations(ops)   : " | lead_idx - 1;
    175179        sout | "Threads parking on wait : " | (exhaust ? "yes" : "no");
    176180        sout | "Rechecking              : " | rechecks;
     181        sout | "ns per transfer         : " | (end - start)`dms / lead_idx;
    177182
    178183
  • benchmark/readyQ/transfer.cpp

    r29d8c02 r74ec742  
    1212
    1313bool exhaust = false;
     14volatile bool estop = false;
    1415
    1516bench_sem the_main;
     
    4243                                if( to_miliseconds(timeHiRes() - start) > 5'000 ) {
    4344                                        std::cerr << "Programs has been blocked for more than 5 secs" << std::endl;
    44                                         std::exit(1);
     45                                        estop = true;
     46                                        the_main.post();
     47                                        goto END;
    4548                                }
    4649                        }
    4750                }
     51                END:;
    4852                PRINT( std::cout | "Waiting done"; )
    4953        }
     
    5963        void lead() {
    6064                this->idx = ++lead_idx;
    61                 if(lead_idx > stop_count) {
     65                if(lead_idx > stop_count || estop) {
    6266                        PRINT( std::cout << "Leader " << this->id << " done" << std::endl; )
    6367                        the_main.post();
     
    8892        }
    8993
    90         static void main(void * arg) {
    91                 MyThread & self = *reinterpret_cast<MyThread*>(arg);
     94        static void main(MyThread * arg) {
     95                MyThread & self = *arg;
    9296                self.park();
    9397
     
    101105                                self.wait();
    102106                        }
    103                         if(lead_idx > stop_count) break;
     107                        if(lead_idx > stop_count || estop) break;
    104108                }
    105109        }
     
    144148                        for(size_t i = 0; i < nthreads; i++) {
    145149                                threads[i] = new MyThread( i );
    146                                 handles[i] = new Fibre( MyThread::main, threads[i] );
     150                                handles[i] = new Fibre();
     151                                handles[i]->run( MyThread::main, threads[i] );
    147152                        }
    148153
     
    164169                                PRINT( std::cout << i << " joined" << std::endl; )
    165170                                rechecks += thrd.rechecks;
    166                                 // delete( handles[i] );
    167171                                delete( threads[i] );
    168172                        }
     
    176180        std::cout << "Number of processors    : " << nprocs << std::endl;
    177181        std::cout << "Number of threads       : " << nthreads << std::endl;
    178         std::cout << "Total Operations(ops)   : " << stop_count << std::endl;
     182        std::cout << "Total Operations(ops)   : " << (lead_idx - 1) << std::endl;
    179183        std::cout << "Threads parking on wait : " << (exhaust ? "yes" : "no") << std::endl;
    180184        std::cout << "Rechecking              : " << rechecks << std::endl;
     185        std::cout << "ns per transfer         : " << std::fixed << (((double)(end - start)) / (lead_idx)) << std::endl;
    181186
    182187
  • benchmark/readyQ/transfer.go

    r29d8c02 r74ec742  
    66        "math/rand"
    77        "os"
     8        "regexp"
    89        "runtime"
    910        "sync/atomic"
     
    1617        id uint64
    1718        idx uint64
     19        estop uint64
    1820        seed uint64
    1921}
     
    3436
    3537func NewLeader(size uint64) (*LeaderInfo) {
    36         this := &LeaderInfo{0, 0, uint64(os.Getpid())}
     38        this := &LeaderInfo{0, 0, 0, uint64(os.Getpid())}
    3739
    3840        r := rand.Intn(10)
     
    5153}
    5254
    53 func waitgroup(idx uint64, threads [] MyThread) {
     55func waitgroup(leader * LeaderInfo, idx uint64, threads [] MyThread, main_sem chan struct {}) {
    5456        start := time.Now()
     57        Outer:
    5558        for i := 0; i < len(threads); i++ {
    5659                // fmt.Fprintf(os.Stderr, "Waiting for :%d (%d)\n", threads[i].id, atomic.LoadUint64(&threads[i].idx) );
     
    6164                        if delta.Seconds() > 5 {
    6265                                fmt.Fprintf(os.Stderr, "Programs has been blocked for more than 5 secs")
    63                                 os.Exit(1)
     66                                atomic.StoreUint64(&leader.estop, 1);
     67                                main_sem <- (struct {}{})
     68                                break Outer
    6469                        }
    6570                }
     
    7479                if i != me {
    7580                        // debug!( "Leader waking {}", i);
     81                        defer func() {
     82                                if err := recover(); err != nil {
     83                                        fmt.Fprintf(os.Stderr, "Panic occurred: %s\n", err)
     84                                }
     85                        }()
    7686                        threads[i].sem <- (struct {}{})
    7787                }
     
    8494        atomic.StoreUint64(&leader.idx, nidx);
    8595
    86         if nidx > stop_count {
     96        if nidx > stop_count || atomic.LoadUint64(&leader.estop) != 0 {
    8797                // debug!( "Leader {} done", this.id);
    8898                main_sem <- (struct {}{})
     
    92102        // debug!( "====================\nLeader no {} : {}", nidx, this.id);
    93103
    94         waitgroup(nidx, threads);
     104        waitgroup(leader, nidx, threads, main_sem);
    95105
    96106        leader.next( uint64(len(threads)) );
     
    146156                        waitleader( exhaust, leader, &threads[me], &r )
    147157                }
    148                 if atomic.LoadUint64(&leader.idx) > stop_count { break; }
     158                if atomic.LoadUint64(&leader.idx) > stop_count || atomic.LoadUint64(&leader.estop) != 0 { break; }
    149159        }
    150160
     
    155165func main() {
    156166        // Benchmark specific command line arguments
    157         exhaustOpt := flag.Bool("e", false, "Whether or not threads that have seen the new epoch should park instead of yielding.")
     167        exhaustOpt := flag.String("e", "no", "Whether or not threads that have seen the new epoch should park instead of yielding.")
    158168
    159169        // General benchmark initialization and deinitialization
    160         defer bench_init()()
    161 
    162         exhaust := *exhaustOpt;
     170        bench_init()
     171
     172        exhaustVal := *exhaustOpt;
     173
     174        var exhaust bool
     175        re_yes := regexp.MustCompile("[Yy]|[Yy][Ee][Ss]")
     176        re_no  := regexp.MustCompile("[Nn]|[Nn][Oo]")
     177        if re_yes.Match([]byte(exhaustVal)) {
     178                exhaust = true
     179        } else if re_no.Match([]byte(exhaustVal)) {
     180                exhaust = false
     181        } else {
     182                fmt.Fprintf(os.Stderr, "Unrecognized exhaust(-e) option '%s'\n", exhaustVal)
     183                os.Exit(1)
     184        }
     185
    163186        if clock_mode {
    164                 fmt.Fprintf(os.Stderr, "Programs does not support fixed duration mode")
     187                fmt.Fprintf(os.Stderr, "Programs does not support fixed duration mode\n")
    165188                os.Exit(1)
    166189        }
     
    215238                ws = "no"
    216239        }
    217         p.Printf("Duration (ms)           : %f\n", delta.Milliseconds() )
     240        p.Printf("Duration (ms)           : %d\n", delta.Milliseconds() )
    218241        p.Printf("Number of processors    : %d\n", nprocs )
    219242        p.Printf("Number of threads       : %d\n", nthreads )
    220         p.Printf("Total Operations(ops)   : %15d\n", stop_count )
     243        p.Printf("Total Operations(ops)   : %15d\n", (leader.idx - 1) )
    221244        p.Printf("Threads parking on wait : %s\n", ws)
    222245        p.Printf("Rechecking              : %d\n", rechecks )
    223 }
     246        p.Printf("ns per transfer         : %f\n", float64(delta.Nanoseconds()) / float64(leader.idx) )
     247}
  • benchmark/readyQ/transfer.rs

    r29d8c02 r74ec742  
    66use std::hint;
    77use std::sync::Arc;
    8 use std::sync::atomic::{AtomicUsize, Ordering};
     8use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
    99use std::time::{Instant,Duration};
    1010
     
    4444                        match val {
    4545                                "yes" => true,
     46                                "Y" => true,
     47                                "y" => true,
    4648                                "no"  => false,
     49                                "N"  => false,
     50                                "n"  => false,
    4751                                "maybe" | "I don't know" | "Can you repeat the question?" => {
    4852                                        eprintln!("Lines for 'Malcolm in the Middle' are not acceptable values of parameter 'exhaust'");
     
    6468        id: AtomicUsize,
    6569        idx: AtomicUsize,
     70        estop: AtomicBool,
    6671        seed: u128,
    6772}
     
    7277                        id: AtomicUsize::new(nthreads),
    7378                        idx: AtomicUsize::new(0),
     79                        estop: AtomicBool::new(false),
    7480                        seed: process::id() as u128
    7581                };
     
    100106}
    101107
    102 fn waitgroup(idx: usize, threads: &Vec<Arc<MyThread>>) {
     108fn waitgroup(leader: &LeaderInfo, idx: usize, threads: &Vec<Arc<MyThread>>, main_sem: &sync::Semaphore) {
    103109        let start = Instant::now();
    104         for t in threads {
     110        'outer: for t in threads {
    105111                debug!( "Waiting for :{} ({})", t.id, t.idx.load(Ordering::Relaxed) );
    106112                while t.idx.load(Ordering::Relaxed) != idx {
     
    108114                        if start.elapsed() > Duration::from_secs(5) {
    109115                                eprintln!("Programs has been blocked for more than 5 secs");
    110                                 std::process::exit(1);
     116                                leader.estop.store(true, Ordering::Relaxed);
     117                                main_sem.add_permits(1);
     118                                break 'outer;
    111119                        }
    112120                }
     
    131139        leader.idx.store(nidx, Ordering::Relaxed);
    132140
    133         if nidx as u64 > exp.stop_count {
     141        if nidx as u64 > exp.stop_count || leader.estop.load(Ordering::Relaxed) {
    134142                debug!( "Leader {} done", this.id);
    135143                main_sem.add_permits(1);
     
    139147        debug!( "====================\nLeader no {} : {}", nidx, this.id);
    140148
    141         waitgroup(nidx, threads);
     149        waitgroup(leader, nidx, threads, main_sem);
    142150
    143151        leader.next( threads.len() );
     
    192200                        wait( exhaust, &leader, &threads[me], &mut rechecks ).await;
    193201                }
    194                 if leader.idx.load(Ordering::Relaxed) as u64 > exp.stop_count { break; }
     202                if leader.idx.load(Ordering::Relaxed) as u64 > exp.stop_count || leader.estop.load(Ordering::Relaxed) { break; }
    195203        }
    196204
     
    273281        println!("Number of processors    : {}", (nprocs).to_formatted_string(&Locale::en));
    274282        println!("Number of threads       : {}", (nthreads).to_formatted_string(&Locale::en));
    275         println!("Total Operations(ops)   : {:>15}", (exp.stop_count).to_formatted_string(&Locale::en));
     283        println!("Total Operations(ops)   : {:>15}", (leader.idx.load(Ordering::Relaxed) - 1).to_formatted_string(&Locale::en));
    276284        println!("Threads parking on wait : {}", if exhaust { "yes" } else { "no" });
    277285        println!("Rechecking              : {}", rechecks );
    278 }
     286        println!("ns per transfer         : {}", ((duration.as_nanos() as f64) / leader.idx.load(Ordering::Relaxed) as f64));
     287
     288}
  • benchmark/readyQ/yield.cfa

    r29d8c02 r74ec742  
    1 #include <stdlib.h>
    2 #include <stdio.h>
    3 #include <string.h>
    4 #include <limits.h>
    5 
    6 extern "C" {
    7         #include <locale.h>
    8         #include <getopt.h>
    9 }
    10 
    11 #include <unistd.h>
    12 
    13 #include <clock.hfa>
    14 #include <time.hfa>
    15 #include <stats.hfa>
    16 
    17 #include "../benchcltr.hfa"
    18 
    19 extern bool traceHeapOn();
    20 
    21 
    22 volatile bool run = false;
    23 volatile unsigned long long global_counter;
     1#include "rq_bench.hfa"
    242
    253thread __attribute__((aligned(128))) Yielder {
    26         unsigned long long counter;
     4        unsigned long long count;
    275};
    286void ?{}( Yielder & this ) {
    29         this.counter = 0;
    30         ((thread&)this){ "Yielder Thread", *the_benchmark_cluster };
     7        ((thread&)this){ "Yielder Thread", bench_cluster };
     8        this.count = 0;
    319}
    3210
    3311void main( Yielder & this ) {
    3412        park();
    35         /* paranoid */ assert( true == __atomic_load_n(&run, __ATOMIC_RELAXED) );
     13        for() {
     14                yield();
     15                this.count++;
     16                if( clock_mode && stop) break;
     17                if(!clock_mode && this.count >= stop_count) break;
     18        }
    3619
    37         while(__atomic_load_n(&run, __ATOMIC_RELAXED)) {
    38                 yield();
    39                 this.counter++;
    40         }
    41         __atomic_fetch_add(&global_counter, this.counter, __ATOMIC_SEQ_CST);
     20        __atomic_fetch_add(&threads_left, -1, __ATOMIC_SEQ_CST);
    4221}
    4322
    4423int main(int argc, char * argv[]) {
    45         unsigned num_io = 1;
    46         io_context_params params;
    47 
    4824        cfa_option opt[] = {
    49                 BENCH_OPT_CFA
     25                BENCH_OPT
    5026        };
    51         int opt_cnt = sizeof(opt) / sizeof(cfa_option);
    52 
    53         char **left;
    54         parse_args( argc, argv, opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", left );
     27        BENCH_OPT_PARSE("cforall yield benchmark");
    5528
    5629        {
    57                 printf("Running %d threads on %d processors for %f seconds\n", nthreads, nprocs, duration);
     30                unsigned long long global_counter = 0;
    5831
    5932                Time start, end;
    60                 BenchCluster cl = { num_io, params, CFA_STATS_READY_Q };
     33                BenchCluster bc = { nprocs };
    6134                {
    62                         BenchProc procs[nprocs];
    63                         {
    64                                 Yielder threads[nthreads];
    65                                 printf("Starting\n");
     35                        threads_left = nthreads;
     36                        Yielder threads[nthreads];
     37                        printf("Starting\n");
    6638
    67                                 bool is_tty = isatty(STDOUT_FILENO);
    68                                 start = timeHiRes();
    69                                 run = true;
     39                        bool is_tty = isatty(STDOUT_FILENO);
     40                        start = timeHiRes();
    7041
    71                                 for(i; nthreads) {
    72                                         unpark( threads[i] );
    73                                 }
    74                                 wait(duration, start, end, is_tty);
     42                        for(i; nthreads) {
     43                                unpark( threads[i] );
     44                        }
     45                        wait(start, is_tty);
    7546
    76                                 run = false;
    77                                 end = timeHiRes();
    78                                 printf("\nDone\n");
     47                        stop = true;
     48                        end = timeHiRes();
     49                        printf("\nDone\n");
     50
     51                        for(i; nthreads) {
     52                                Yielder & y = join( threads[i] );
     53                                global_counter += y.count;
    7954                        }
    8055                }
    8156
    82                 printf("Duration (ms)       : %'ld\n", (end - start)`dms);
    83                 printf("Number of processors: %'d\n", nprocs);
    84                 printf("Number of threads   : %'d\n", nthreads);
    85                 printf("Total yields        : %'15llu\n", global_counter);
    86                 printf("Yields per second   : %'18.2lf\n", ((double)global_counter) / (end - start)`s);
    87                 printf("ns per yields       : %'18.2lf\n", ((double)(end - start)`ns) / global_counter);
    88                 printf("Yields per procs    : %'15llu\n", global_counter / nprocs);
    89                 printf("Yields/sec/procs    : %'18.2lf\n", (((double)global_counter) / nprocs) / (end - start)`s);
    90                 printf("ns per yields/procs : %'18.2lf\n", ((double)(end - start)`ns) / (global_counter / nprocs));
     57                printf("Duration (ms)        : %'ld\n", (end - start)`dms);
     58                printf("Number of processors : %'d\n", nprocs);
     59                printf("Number of threads    : %'d\n", nthreads);
     60                printf("Total Operations(ops): %'15llu\n", global_counter);
     61                printf("Ops per second       : %'18.2lf\n", ((double)global_counter) / (end - start)`s);
     62                printf("ns per ops           : %'18.2lf\n", (end - start)`dns / global_counter);
     63                printf("Ops per threads      : %'15llu\n", global_counter / nthreads);
     64                printf("Ops per procs        : %'15llu\n", global_counter / nprocs);
     65                printf("Ops/sec/procs        : %'18.2lf\n", (((double)global_counter) / nprocs) / (end - start)`s);
     66                printf("ns per ops/procs     : %'18.2lf\n", (end - start)`dns / (global_counter / nprocs));
    9167                fflush(stdout);
    9268        }
  • benchmark/readyQ/yield.cpp

    r29d8c02 r74ec742  
    1 #include <cassert>
    2 #include <cstdlib>
    3 #include <cstdio>
    4 #include <cstring>
    5 #include <climits>
    6 
    7 extern "C" {
    8         #include <locale.h>
    9         #include <getopt.h>
    10 }
    11 
    12 #include <unistd.h>
    13 
    14 #include <chrono>
    15 
    16 using Clock = std::chrono::high_resolution_clock;
    17 using duration_t = std::chrono::duration<double>;
    18 using std::chrono::nanoseconds;
    19 
    20 
    21 template<typename Ratio, typename T>
    22 T duration_cast(T seconds) {
    23         return std::chrono::duration_cast<std::chrono::duration<T, Ratio>>(std::chrono::duration<T>(seconds)).count();
    24 }
     1#include "rq_bench.hpp"
     2#include <libfibre/fibre.h>
    253
    264volatile bool run = false;
    275volatile unsigned long long global_counter;
    286
    29 #include "libfibre/fibre.h"
    307
    31 FredBarrier * barrier;
    32 struct __attribute__((aligned(128))) counter_t {
    33         int value = 0;
    34 };
     8void fibre_main() {
     9        fibre_park();
     10        unsigned long long count = 0;
     11        for(;;) {
     12                Fibre::yield();
     13                count++;
     14                if( clock_mode && stop) break;
     15                if(!clock_mode && count >= stop_count) break;
     16        }
    3517
    36 void fibre_main( counter_t * counter ) {
    37         barrier->wait();
    38         // /* paranoid */ assert( true == __atomic_load_n(&run, __ATOMIC_RELAXED) );
    39 
    40         while(__atomic_load_n(&run, __ATOMIC_RELAXED)) {
    41                 Fibre::forceYield();
    42                 // fibre_yield();
    43                 counter->value++;
    44         }
    45         __atomic_fetch_add(&global_counter, counter->value, __ATOMIC_SEQ_CST);
     18        __atomic_fetch_add(&global_counter, count, __ATOMIC_SEQ_CST);
     19        __atomic_fetch_add(&threads_left, -1, __ATOMIC_SEQ_CST);
    4620}
    4721
    4822int main(int argc, char * argv[]) {
    49         double duration = 5;
    50         int nprocs = 1;
    51         int nthreads = 1;
    52 
    53         std::cout.imbue(std::locale(""));
    54         setlocale(LC_ALL, "");
    55 
    56         for(;;) {
    57                 static struct option options[] = {
    58                         {"duration",  required_argument, 0, 'd'},
    59                         {"nprocs",    required_argument, 0, 'p'},
    60                         {"nthreads",  required_argument, 0, 't'},
    61                         {0, 0, 0, 0}
    62                 };
    63 
    64                 int idx = 0;
    65                 int opt = getopt_long(argc, argv, "d:p:t:", options, &idx);
    66 
    67                 const char * arg = optarg ? optarg : "";
    68                 char * end;
    69                 switch(opt) {
    70                         case -1:
    71                                 goto run;
    72                         // Numeric Arguments
    73                         case 'd':
    74                                 duration = strtod(arg, &end);
    75                                 if(*end != '\0') {
    76                                         fprintf(stderr, "Duration must be a valid double, was %s\n", arg);
    77                                         goto usage;
    78                                 }
    79                                 break;
    80                         case 't':
    81                                 nthreads = strtoul(arg, &end, 10);
    82                                 if(*end != '\0' || nthreads < 1) {
    83                                         fprintf(stderr, "Number of threads must be a positive integer, was %s\n", arg);
    84                                         goto usage;
    85                                 }
    86                                 break;
    87                         case 'p':
    88                                 nprocs = strtoul(arg, &end, 10);
    89                                 if(*end != '\0' || nprocs < 1) {
    90                                         fprintf(stderr, "Number of processors must be a positive integer, was %s\n", arg);
    91                                         goto usage;
    92                                 }
    93                                 break;
    94                         // Other cases
    95                         default: /* ? */
    96                                 fprintf( stderr, "Unkown option '%c'\n", opt);
    97                         usage:
    98                                 fprintf( stderr, "Usage: %s [options]\n", argv[0]);
    99                                 fprintf( stderr, "\n" );
    100                                 fprintf( stderr, "  -d, --duration=DURATION  Duration of the experiment, in seconds\n" );
    101                                 fprintf( stderr, "  -t, --nthreads=NTHREADS  Number of kernel threads\n" );
    102                                 fprintf( stderr, "  -q, --nqueues=NQUEUES    Number of queues per threads\n" );
    103                                 exit(1);
    104                 }
    105         }
    106         run:
     23        option_t opt[] = {
     24                BENCH_OPT
     25        };
     26        BENCH_OPT_PARSE("libfibre yield benchmark");
    10727
    10828        {
    10929                printf("Running %d threads on %d processors for %lf seconds\n", nthreads, nprocs, duration);
    11030
    111                 FibreInit();
    112                 barrier = new FredBarrier(nthreads + 1);
     31                FibreInit(1, nprocs);
     32                uint64_t start, end;
    11333                {
    114                         Context::CurrCluster().addWorkers(nprocs);
    115                         {
    116                                 counter_t counters[nthreads];
    117                                 Fibre threads[nthreads];
    118                                 for(int i = 0; i < nthreads; i++) {
    119                                         threads[i].run(fibre_main, &counters[i]);
    120                                 }
    121                                 printf("Starting\n");
    122                                 bool is_tty = isatty(STDOUT_FILENO);
    123                                 auto before = Clock::now();
    124                                 run = true;
     34                        threads_left = nthreads;
     35                        Fibre * threads[nthreads];
     36                        for(unsigned i = 0; i < nthreads; i++) {
     37                                threads[i] = new Fibre();
     38                                threads[i]->run(fibre_main);
     39                        }
     40                        printf("Starting\n");
     41                        bool is_tty = isatty(STDOUT_FILENO);
     42                        start = timeHiRes();
    12543
    126                                 barrier->wait();
    127                                 for(;;) {
    128                                         usleep(500'000);
    129                                         auto now = Clock::now();
    130                                         duration_t durr = now - before;
    131                                         if( durr.count() > duration ) {
    132                                                 break;
    133                                         }
    134                                         if(is_tty) {
    135                                                 std::cout << "\r" << std::setprecision(4) << durr.count();
    136                                                 std::cout.flush();
    137                                         }
    138                                 }
     44                        for(unsigned i = 0; i < nthreads; i++ ) {
     45                                fibre_unpark( threads[i] );
     46                        }
     47                        wait<Fibre>(start, is_tty);
    13948
    140                                 auto after = Clock::now();
    141                                 duration_t durr = after - before;
    142                                 duration = durr.count();
    143                                 run = false;
    144                                 printf("\nDone\n");
    145                                 for(auto & thread : threads) {
    146                                         thread.join();
    147                                 }
    148 
    149                                 // for(const auto & counter : counters) {
    150                                 //      std::cout << counter.value << std::endl;
    151                                 // }
     49                        stop = true;
     50                        end = timeHiRes();
     51                        for(unsigned i = 0; i < nthreads; i++ ) {
     52                                fibre_join( threads[i], nullptr );
    15253                        }
    15354                }
    15455
    155                 auto dur_nano = duration_cast<std::nano>(duration);
    156                 auto dur_dms  = duration_cast<std::milli>(duration);
    157 
    158                 printf("Duration (ms)       : %'.2lf\n", dur_dms );
    159                 printf("Total yields        : %'15llu\n", global_counter );
    160                 printf("Yields per procs    : %'15llu\n", global_counter / nprocs );
    161                 printf("Yields per second   : %'18.2lf\n", ((double)global_counter) / duration );
    162                 printf("Yields/sec/procs    : %'18.2lf\n", (((double)global_counter) / nprocs) / duration );
    163                 printf("ns per yields       : %'18.2lf\n", dur_nano / global_counter );
    164                 printf("ns per yields/procs : %'18.2lf\n", dur_nano / (global_counter / nprocs) );
    165 
     56                printf("Duration (ms)        : %'ld\n", to_miliseconds(end - start));
     57                printf("Number of processors : %'d\n", nprocs);
     58                printf("Number of threads    : %'d\n", nthreads);
     59                printf("Total Operations(ops): %'15llu\n", global_counter);
     60                printf("Ops per second       : %'18.2lf\n", ((double)global_counter) / to_fseconds(end - start));
     61                printf("ns per ops           : %'18.2lf\n", ((double)(end - start)) / global_counter);
     62                printf("Ops per threads      : %'15llu\n", global_counter / nthreads);
     63                printf("Ops per procs        : %'15llu\n", global_counter / nprocs);
     64                printf("Ops/sec/procs        : %'18.2lf\n", (((double)global_counter) / nprocs) / to_fseconds(end - start));
     65                printf("ns per ops/procs     : %'18.2lf\n", ((double)(end - start)) / (global_counter / nprocs));
     66                fflush(stdout);
    16667        }
    16768}
  • benchmark/readyQ/yield.rs

    r29d8c02 r74ec742  
    9090        });
    9191
    92         println!("Duration (ms)       : {}", (duration.as_millis()).to_formatted_string(&Locale::en));
    93         println!("Number of processors: {}", (nprocs).to_formatted_string(&Locale::en));
    94         println!("Number of threads   : {}", (nthreads).to_formatted_string(&Locale::en));
    95         println!("Total yields        : {:>15}", (global_counter).to_formatted_string(&Locale::en));
    96         println!("Yields per second   : {:>15}", (((global_counter as f64) / duration.as_secs() as f64) as u64).to_formatted_string(&Locale::en));
    97         println!("ns per yields       : {:>15}", ((duration.as_nanos() as f64 / global_counter as f64) as u64).to_formatted_string(&Locale::en));
    98         println!("Yields per threads  : {:>15}", (global_counter / nthreads as u64).to_formatted_string(&Locale::en));
    99         println!("Yields per procs    : {:>15}", (global_counter / nprocs as u64).to_formatted_string(&Locale::en));
    100         println!("Yields/sec/procs    : {:>15}", ((((global_counter as f64) / nprocs as f64) / duration.as_secs() as f64) as u64).to_formatted_string(&Locale::en));
    101         println!("ns per yields/procs : {:>15}", ((duration.as_nanos() as f64 / (global_counter as f64 / nprocs as f64)) as u64).to_formatted_string(&Locale::en));
     92        println!("Duration (ms)        : {}", (duration.as_millis()).to_formatted_string(&Locale::en));
     93        println!("Number of processors : {}", (nprocs).to_formatted_string(&Locale::en));
     94        println!("Number of threads    : {}", (nthreads).to_formatted_string(&Locale::en));
     95        println!("Total Operations(ops): {:>15}", (global_counter).to_formatted_string(&Locale::en));
     96        println!("Ops per second       : {:>15}", (((global_counter as f64) / duration.as_secs() as f64) as u64).to_formatted_string(&Locale::en));
     97        println!("ns per ops           : {:>15}", ((duration.as_nanos() as f64 / global_counter as f64) as u64).to_formatted_string(&Locale::en));
     98        println!("Ops per threads      : {:>15}", (global_counter / nthreads as u64).to_formatted_string(&Locale::en));
     99        println!("Ops per procs        : {:>15}", (global_counter / nprocs as u64).to_formatted_string(&Locale::en));
     100        println!("Ops/sec/procs        : {:>15}", ((((global_counter as f64) / nprocs as f64) / duration.as_secs() as f64) as u64).to_formatted_string(&Locale::en));
     101        println!("ns per ops/procs    : {:>15}", ((duration.as_nanos() as f64 / (global_counter as f64 / nprocs as f64)) as u64).to_formatted_string(&Locale::en));
    102102}
  • benchmark/rmit.py

    r29d8c02 r74ec742  
    4646                pass
    4747
    48         if re.search("^[0-9-,]+$", values):
     48        if values.startswith('\\'):
     49                return key, values[1:].split(',')
     50        elif re.search("^[0-9-,]+$", values):
    4951                values = parse_range(values)
    5052                return key, [v for v in values]
     
    6365        return eval(fmt)
    6466
     67# Evaluate all the options
     68# options can be of the for key = val or key = some_math(other_key)
     69# produce a list of all the options to replace some_math(other_key) with actual value
    6570def eval_options(opts):
     71        # Find all the options with dependencies
    6672        dependents = [d for d in opts.values() if type(d) is DependentOpt]
     73
     74        # we need to find all the straglers
    6775        processed = []
    68         nopts = []
     76
     77        # extract all the necessary inputs
     78        input_keys = {}
    6979        for d in dependents:
     80                # Mark the dependent as seen
    7081                processed.append(d.key)
    71                 lists = []
     82
     83                # process each of the dependencies
    7284                for dvar in d.vars:
     85                        # Check that it depends on something that exists
    7386                        if not dvar in opts.keys():
    7487                                print('ERROR: extra pattern option {}:{} uses unknown key {}'.format(d.key,d.value,dvar), file=sys.stderr)
    7588                                sys.exit(1)
    7689
    77                         lists.append([(dvar, o) for o in opts[dvar]])
     90                        # Check that it's not nested
     91                        if type(dvar) is DependentOpt:
     92                                print('ERROR: dependent options cannot be nested {}:{} uses key {}'.format(d.key,d.value,dvar), file=sys.stderr)
     93                                sys.exit(1)
     94
     95                        # Add the values to the input keys
     96                        if dvar not in input_keys:
     97                                input_keys[dvar] = opts[dvar]
     98                        else :
     99                                if input_keys[dvar] != opts[dvar]:
     100                                        print('INTERNAL ERROR: repeat input do not match {}:{} vs {}'.format(dvar,opts[dvar],input_keys[dvar]), file=sys.stderr)
     101                                        sys.exit(1)
     102
     103                        # Mark the input as seen
    78104                        processed.append(dvar)
    79105
    80                 kopt = []
    81                 for vals in list(itertools.product(*lists)):
    82                         res = ['-{}'.format(d.key), "{}".format(eval_one(d.value, vals))]
    83                         for k, v in vals:
    84                                 res.extend(['-{}'.format(k), "{}".format(v)])
    85                         kopt.append(res)
    86                 nopts.append(kopt)
    87 
    88 
    89         for k, vals in opts.items():
    90                 if k not in processed:
    91                         kopt = []
    92                         for v in vals:
    93                                 kopt.append(['-{}'.format(k), "{}".format(v)])
    94                         nopts.append(kopt)
    95 
    96         return nopts
     106        # add in all the straglers they should cause too many problems
     107        for k, v in opts.items():
     108                if type(v) is DependentOpt:
     109                        continue
     110
     111                if k in processed:
     112                        # consistency check
     113                        if k not in input_keys:
     114                                print('INTERNAL ERROR: key \'{}\' marked as processed but not in input_keys'.format(k), file=sys.stderr)
     115                                sys.exit(1)
     116                        continue
     117
     118                # consistency check
     119                if k in input_keys:
     120                        print('INTERNAL ERROR: key \'{}\' in input_keys but not marked as processed'.format(k), file=sys.stderr)
     121                        sys.exit(1)
     122
     123                # add the straggler
     124                input_keys[k] = v
     125
     126        # flatten the dict into a list of pairs so it's easier to work with
     127        input_list = []
     128        for k, v in input_keys.items():
     129                input_list.append([(k, o) for o in v])
     130
     131        # evaluate all the dependents
     132        # they are not allowed to produce new values so it's a one-to-one mapping from here
     133        evaluated = []
     134        for inputs in list(itertools.product(*input_list)):
     135                this_eval = list(inputs)
     136                for d in dependents:
     137                        this_eval.append((d.key, eval_one(d.value, inputs)))
     138
     139                evaluated.append(this_eval)
     140
     141        # reformat everything to a list of arguments
     142        formated = []
     143        for o in evaluated:
     144                inner = []
     145                for k,v in o:
     146                        inner.append("-{}".format(k))
     147                        inner.append("{}".format(v))
     148
     149                # print(inner)
     150                formated.append(inner)
     151
     152        return formated
    97153
    98154# returns the first option with key 'opt'
     
    122178        known_hosts = {
    123179                "jax": {
    124                         range(  1,  24) : "48-71",
    125                         range( 25,  48) : "48-71,144-167",
    126                         range( 49,  96) : "48-95,144-191",
    127                         range( 97, 144) : "24-95,120-191",
    128                         range(145, 192) : "0-95,96-191",
     180                        range(  1,  25) : "48-71",
     181                        range( 25,  49) : "48-71,144-167",
     182                        range( 49,  97) : "48-95,144-191",
     183                        range( 97, 145) : "24-95,120-191",
     184                        range(145, 193) : "0-95,96-191",
    129185                },
    130186        }
     
    184240
    185241        except:
    186                 print('ERROR: invalid arguments', file=sys.stderr)
    187                 parser.print_help(sys.stderr)
    188242                sys.exit(1)
    189243
     
    215269        # Figure out all the combinations to run
    216270        actions = []
    217         for p in itertools.product(range(options.trials), commands, *opts):
     271        for p in itertools.product(range(options.trials), commands, opts):
    218272                act = [p[1]]
    219273                for o in p[2:]:
     
    281335
    282336        if options.file != sys.stdout:
    283                 print("Done");                                                                                ")
     337                print("Done                                                                                ")
  • doc/theses/thierry_delisle_PhD/thesis/Makefile

    r29d8c02 r74ec742  
    3737        emptytree \
    3838        fairness \
     39        idle \
     40        idle1 \
     41        idle2 \
     42        idle_state \
    3943        io_uring \
    4044        pivot_ring \
     
    4246        cycle \
    4347        result.cycle.jax.ops \
     48        result.yield.jax.ops \
     49        result.churn.jax.ops \
     50        result.cycle.jax.ns \
     51        result.yield.jax.ns \
     52        result.churn.jax.ns \
     53        result.cycle.low.jax.ops \
     54        result.yield.low.jax.ops \
     55        result.churn.low.jax.ops \
     56        result.cycle.low.jax.ns \
     57        result.yield.low.jax.ns \
     58        result.churn.low.jax.ns \
     59        result.memcd.updt.qps \
     60        result.memcd.updt.lat \
     61        result.memcd.rate.qps \
     62        result.memcd.rate.99th \
    4463}
    4564
     
    116135        python3 $< $@
    117136
    118 build/result.%.ns.svg : data/% | ${Build}
    119         ../../../../benchmark/plot.py -f $< -o $@ -y "ns per ops"
     137cycle_jax_ops_FLAGS = --MaxY=120000000
     138cycle_low_jax_ops_FLAGS = --MaxY=120000000
     139cycle_jax_ns_FLAGS = --MaxY=2000
     140cycle_low_jax_ns_FLAGS = --MaxY=2000
    120141
    121 build/result.%.ops.svg : data/% | ${Build}
    122         ../../../../benchmark/plot.py -f $< -o $@ -y "Ops per second"
     142yield_jax_ops_FLAGS = --MaxY=150000000
     143yield_low_jax_ops_FLAGS = --MaxY=150000000
     144yield_jax_ns_FLAGS = --MaxY=1500
     145yield_low_jax_ns_FLAGS = --MaxY=1500
     146
     147build/result.%.ns.svg : data/% Makefile | ${Build}
     148        ../../../../benchmark/plot.py -f $< -o $@ -y "ns per ops/procs" $($(subst .,_,$*)_ns_FLAGS)
     149
     150build/result.%.ops.svg : data/% Makefile | ${Build}
     151        ../../../../benchmark/plot.py -f $< -o $@ -y "Ops per second" $($(subst .,_,$*)_ops_FLAGS)
     152
     153build/result.memcd.updt.qps.svg : data/memcd.updt Makefile | ${Build}
     154        ../../../../benchmark/plot.py -f $< -o $@ -y "Actual QPS" -x "Update Ratio"
     155
     156build/result.memcd.updt.lat.svg : data/memcd.updt Makefile | ${Build}
     157        ../../../../benchmark/plot.py -f $< -o $@ -y "Average Read Latency" -x "Update Ratio"
     158
     159build/result.memcd.rate.qps.svg : data/memcd.rate Makefile | ${Build}
     160        ../../../../benchmark/plot.py -f $< -o $@ -y "Actual QPS" -x "Target QPS"
     161
     162build/result.memcd.rate.99th.svg : data/memcd.rate Makefile | ${Build}
     163        ../../../../benchmark/plot.py -f $< -o $@ -y "Tail Read Latency" -x "Target QPS"
    123164
    124165## pstex with inverted colors
  • doc/theses/thierry_delisle_PhD/thesis/data/cycle.jax

    r29d8c02 r74ec742  
    1 [["rdq-cycle-go", "./rdq-cycle-go -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 43606897.0, "Ops per second": 8720908.73, "ns per ops": 114.67, "Ops per threads": 2180344.0, "Ops per procs": 10901724.0, "Ops/sec/procs": 2180227.18, "ns per ops/procs": 458.67}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5010.922033, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 93993568.0, "Total blocks": 93993209.0, "Ops per second": 18757739.07, "ns per ops": 53.31, "Ops per threads": 1174919.0, "Ops per procs": 5874598.0, "Ops/sec/procs": 1172358.69, "ns per ops/procs": 852.98}],["rdq-cycle-go", "./rdq-cycle-go -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 136763517.0, "Ops per second": 27351079.35, "ns per ops": 36.56, "Ops per threads": 1709543.0, "Ops per procs": 8547719.0, "Ops/sec/procs": 1709442.46, "ns per ops/procs": 584.99}],["rdq-cycle-go", "./rdq-cycle-go -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 27778961.0, "Ops per second": 5555545.09, "ns per ops": 180.0, "Ops per threads": 5555792.0, "Ops per procs": 27778961.0, "Ops/sec/procs": 5555545.09, "ns per ops/procs": 180.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5009.290878, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 43976310.0, "Total blocks": 43976217.0, "Ops per second": 8778949.17, "ns per ops": 113.91, "Ops per threads": 2198815.0, "Ops per procs": 10994077.0, "Ops/sec/procs": 2194737.29, "ns per ops/procs": 455.64}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5009.151542, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 44132300.0, "Total blocks": 44132201.0, "Ops per second": 8810334.37, "ns per ops": 113.5, "Ops per threads": 2206615.0, "Ops per procs": 11033075.0, "Ops/sec/procs": 2202583.59, "ns per ops/procs": 454.01}],["rdq-cycle-go", "./rdq-cycle-go -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 46353896.0, "Ops per second": 9270294.11, "ns per ops": 107.87, "Ops per threads": 2317694.0, "Ops per procs": 11588474.0, "Ops/sec/procs": 2317573.53, "ns per ops/procs": 431.49}],["rdq-cycle-go", "./rdq-cycle-go -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 27894379.0, "Ops per second": 5578591.58, "ns per ops": 179.26, "Ops per threads": 5578875.0, "Ops per procs": 27894379.0, "Ops/sec/procs": 5578591.58, "ns per ops/procs": 179.26}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5008.743463, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 32825528.0, "Total blocks": 32825527.0, "Ops per second": 6553645.29, "ns per ops": 152.59, "Ops per threads": 6565105.0, "Ops per procs": 32825528.0, "Ops/sec/procs": 6553645.29, "ns per ops/procs": 152.59}],["rdq-cycle-go", "./rdq-cycle-go -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 138213098.0, "Ops per second": 27640977.5, "ns per ops": 36.18, "Ops per threads": 1727663.0, "Ops per procs": 8638318.0, "Ops/sec/procs": 1727561.09, "ns per ops/procs": 578.85}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5007.914168, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 44109513.0, "Total blocks": 44109419.0, "Ops per second": 8807961.06, "ns per ops": 113.53, "Ops per threads": 2205475.0, "Ops per procs": 11027378.0, "Ops/sec/procs": 2201990.27, "ns per ops/procs": 454.13}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5012.121876, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 94130673.0, "Total blocks": 94130291.0, "Ops per second": 18780603.37, "ns per ops": 53.25, "Ops per threads": 1176633.0, "Ops per procs": 5883167.0, "Ops/sec/procs": 1173787.71, "ns per ops/procs": 851.94}],["rdq-cycle-go", "./rdq-cycle-go -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 140936367.0, "Ops per second": 28185668.38, "ns per ops": 35.48, "Ops per threads": 1761704.0, "Ops per procs": 8808522.0, "Ops/sec/procs": 1761604.27, "ns per ops/procs": 567.66}],["rdq-cycle-go", "./rdq-cycle-go -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 44279585.0, "Ops per second": 8855475.01, "ns per ops": 112.92, "Ops per threads": 2213979.0, "Ops per procs": 11069896.0, "Ops/sec/procs": 2213868.75, "ns per ops/procs": 451.7}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5008.37392, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 32227534.0, "Total blocks": 32227533.0, "Ops per second": 6434730.02, "ns per ops": 155.41, "Ops per threads": 6445506.0, "Ops per procs": 32227534.0, "Ops/sec/procs": 6434730.02, "ns per ops/procs": 155.41}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5011.019789, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 90600569.0, "Total blocks": 90600173.0, "Ops per second": 18080265.66, "ns per ops": 55.31, "Ops per threads": 1132507.0, "Ops per procs": 5662535.0, "Ops/sec/procs": 1130016.6, "ns per ops/procs": 884.94}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5008.52474, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 32861776.0, "Total blocks": 32861775.0, "Ops per second": 6561168.75, "ns per ops": 152.41, "Ops per threads": 6572355.0, "Ops per procs": 32861776.0, "Ops/sec/procs": 6561168.75, "ns per ops/procs": 152.41}],["rdq-cycle-go", "./rdq-cycle-go -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 28097680.0, "Ops per second": 5619274.9, "ns per ops": 177.96, "Ops per threads": 5619536.0, "Ops per procs": 28097680.0, "Ops/sec/procs": 5619274.9, "ns per ops/procs": 177.96}]]
     1[["rdq-cycle-go", "./rdq-cycle-go -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10001.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 1138076440.0, "Ops per second": 113792094.48, "ns per ops": 8.79, "Ops per threads": 94839.0, "Ops per procs": 47419851.0, "Ops/sec/procs": 4741337.27, "ns per ops/procs": 210.91}],["rdq-cycle-go", "./rdq-cycle-go -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 200285.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 17638575791.0, "Ops per second": 88067238.72, "ns per ops": 11.35, "Ops per threads": 2204821.0, "Ops per procs": 1102410986.0, "Ops/sec/procs": 5504202.42, "ns per ops/procs": 181.68}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10100.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54856916.0, "Ops per second": 5485691.0, "ns per ops": 184.0, "Ops per threads": 109713.0, "Ops per procs": 54856916.0, "Ops/sec/procs": 5485691.0, "ns per ops/procs": 184.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10025.449006, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 558836360.0, "Total blocks": 558836360.0, "Ops per second": 55741778.71, "ns per ops": 17.94, "Ops per threads": 69854.0, "Ops per procs": 34927272.0, "Ops/sec/procs": 3483861.17, "ns per ops/procs": 287.04}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10038.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 58647049.0, "Total blocks": 58647049.0, "Ops per second": 5842287.68, "ns per ops": 171.17, "Ops per threads": 7330.0, "Ops per procs": 3665440.0, "Ops/sec/procs": 365142.98, "ns per ops/procs": 2738.65}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10003.489711, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 728096996.0, "Total blocks": 728096996.0, "Ops per second": 72784299.98, "ns per ops": 13.74, "Ops per threads": 60674.0, "Ops per procs": 30337374.0, "Ops/sec/procs": 3032679.17, "ns per ops/procs": 329.74}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10021.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 63157049.0, "Total blocks": 63157049.0, "Ops per second": 6302255.13, "ns per ops": 158.67, "Ops per threads": 15789.0, "Ops per procs": 7894631.0, "Ops/sec/procs": 787781.89, "ns per ops/procs": 1269.39}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10009.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62412200.0, "Total blocks": 62411700.0, "Ops per second": 6235572.31, "ns per ops": 160.37, "Ops per threads": 124824.0, "Ops per procs": 62412200.0, "Ops/sec/procs": 6235572.31, "ns per ops/procs": 160.37}],["rdq-cycle-go", "./rdq-cycle-go -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10000.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 464608617.0, "Ops per second": 46457191.42, "ns per ops": 21.53, "Ops per threads": 116152.0, "Ops per procs": 58076077.0, "Ops/sec/procs": 5807148.93, "ns per ops/procs": 172.2}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10099.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 391521066.0, "Ops per second": 39152106.0, "ns per ops": 25.0, "Ops per threads": 97880.0, "Ops per procs": 48940133.0, "Ops/sec/procs": 4894013.0, "ns per ops/procs": 206.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10099.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 963549550.0, "Ops per second": 96354955.0, "ns per ops": 10.0, "Ops per threads": 80295.0, "Ops per procs": 40147897.0, "Ops/sec/procs": 4014789.0, "ns per ops/procs": 251.0}],["rdq-cycle-go", "./rdq-cycle-go -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10001.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 867718190.0, "Ops per second": 86761170.55, "ns per ops": 11.53, "Ops per threads": 108464.0, "Ops per procs": 54232386.0, "Ops/sec/procs": 5422573.16, "ns per ops/procs": 184.41}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10100.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 962016289.0, "Ops per second": 96201628.0, "ns per ops": 10.0, "Ops per threads": 80168.0, "Ops per procs": 40084012.0, "Ops/sec/procs": 4008401.0, "ns per ops/procs": 251.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10016.837824, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54738237.0, "Total blocks": 54737741.0, "Ops per second": 5464622.46, "ns per ops": 183.0, "Ops per threads": 109476.0, "Ops per procs": 54738237.0, "Ops/sec/procs": 5464622.46, "ns per ops/procs": 183.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10099.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 731309408.0, "Ops per second": 73130940.0, "ns per ops": 13.0, "Ops per threads": 91413.0, "Ops per procs": 45706838.0, "Ops/sec/procs": 4570683.0, "ns per ops/procs": 220.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10100.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 739772688.0, "Ops per second": 73977268.0, "ns per ops": 13.0, "Ops per threads": 92471.0, "Ops per procs": 46235793.0, "Ops/sec/procs": 4623579.0, "ns per ops/procs": 218.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10100.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 391449785.0, "Ops per second": 39144978.0, "ns per ops": 25.0, "Ops per threads": 97862.0, "Ops per procs": 48931223.0, "Ops/sec/procs": 4893122.0, "ns per ops/procs": 206.0}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10048.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 57239183.0, "Total blocks": 57239183.0, "Ops per second": 5696211.13, "ns per ops": 175.56, "Ops per threads": 4769.0, "Ops per procs": 2384965.0, "Ops/sec/procs": 237342.13, "ns per ops/procs": 4213.33}],["rdq-cycle-go", "./rdq-cycle-go -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10000.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55248375.0, "Ops per second": 5524562.87, "ns per ops": 181.01, "Ops per threads": 110496.0, "Ops per procs": 55248375.0, "Ops/sec/procs": 5524562.87, "ns per ops/procs": 181.01}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10021.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 61553053.0, "Total blocks": 61553053.0, "Ops per second": 6142186.88, "ns per ops": 162.81, "Ops per threads": 15388.0, "Ops per procs": 7694131.0, "Ops/sec/procs": 767773.36, "ns per ops/procs": 1302.47}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10008.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62811642.0, "Total blocks": 62811142.0, "Ops per second": 6275517.47, "ns per ops": 159.35, "Ops per threads": 125623.0, "Ops per procs": 62811642.0, "Ops/sec/procs": 6275517.47, "ns per ops/procs": 159.35}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10018.820873, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 260866706.0, "Total blocks": 260862710.0, "Ops per second": 26037665.44, "ns per ops": 38.41, "Ops per threads": 65216.0, "Ops per procs": 32608338.0, "Ops/sec/procs": 3254708.18, "ns per ops/procs": 307.25}],["rdq-cycle-go", "./rdq-cycle-go -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10000.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 874581175.0, "Ops per second": 87449851.2, "ns per ops": 11.44, "Ops per threads": 109322.0, "Ops per procs": 54661323.0, "Ops/sec/procs": 5465615.7, "ns per ops/procs": 182.96}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10099.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55228782.0, "Ops per second": 5522878.0, "ns per ops": 182.0, "Ops per threads": 110457.0, "Ops per procs": 55228782.0, "Ops/sec/procs": 5522878.0, "ns per ops/procs": 182.0}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10009.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62564955.0, "Total blocks": 62564455.0, "Ops per second": 6250797.96, "ns per ops": 159.98, "Ops per threads": 125129.0, "Ops per procs": 62564955.0, "Ops/sec/procs": 6250797.96, "ns per ops/procs": 159.98}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10100.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 738848909.0, "Ops per second": 73884890.0, "ns per ops": 13.0, "Ops per threads": 92356.0, "Ops per procs": 46178056.0, "Ops/sec/procs": 4617805.0, "ns per ops/procs": 218.0}],["rdq-cycle-go", "./rdq-cycle-go -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10001.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 1131221613.0, "Ops per second": 113108175.94, "ns per ops": 8.84, "Ops per threads": 94268.0, "Ops per procs": 47134233.0, "Ops/sec/procs": 4712840.66, "ns per ops/procs": 212.19}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10008.209159, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 729328104.0, "Total blocks": 729328099.0, "Ops per second": 72872987.81, "ns per ops": 13.72, "Ops per threads": 60777.0, "Ops per procs": 30388671.0, "Ops/sec/procs": 3036374.49, "ns per ops/procs": 329.34}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10099.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 961002611.0, "Ops per second": 96100261.0, "ns per ops": 10.0, "Ops per threads": 80083.0, "Ops per procs": 40041775.0, "Ops/sec/procs": 4004177.0, "ns per ops/procs": 252.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10099.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 390098231.0, "Ops per second": 39009823.0, "ns per ops": 25.0, "Ops per threads": 97524.0, "Ops per procs": 48762278.0, "Ops/sec/procs": 4876227.0, "ns per ops/procs": 207.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10100.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55237591.0, "Ops per second": 5523759.0, "ns per ops": 182.0, "Ops per threads": 110475.0, "Ops per procs": 55237591.0, "Ops/sec/procs": 5523759.0, "ns per ops/procs": 182.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10016.576699, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54510321.0, "Total blocks": 54509820.0, "Ops per second": 5442011.04, "ns per ops": 183.76, "Ops per threads": 109020.0, "Ops per procs": 54510321.0, "Ops/sec/procs": 5442011.04, "ns per ops/procs": 183.76}],["rdq-cycle-go", "./rdq-cycle-go -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10001.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 1135730371.0, "Ops per second": 113558509.97, "ns per ops": 8.81, "Ops per threads": 94644.0, "Ops per procs": 47322098.0, "Ops/sec/procs": 4731604.58, "ns per ops/procs": 211.34}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10039.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 61004037.0, "Total blocks": 61004037.0, "Ops per second": 6076255.04, "ns per ops": 164.58, "Ops per threads": 7625.0, "Ops per procs": 3812752.0, "Ops/sec/procs": 379765.94, "ns per ops/procs": 2633.2}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10004.891999, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 747946345.0, "Total blocks": 747934349.0, "Ops per second": 74758062.86, "ns per ops": 13.38, "Ops per threads": 62328.0, "Ops per procs": 31164431.0, "Ops/sec/procs": 3114919.29, "ns per ops/procs": 321.04}],["rdq-cycle-go", "./rdq-cycle-go -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10000.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 466424792.0, "Ops per second": 46638931.23, "ns per ops": 21.44, "Ops per threads": 116606.0, "Ops per procs": 58303099.0, "Ops/sec/procs": 5829866.4, "ns per ops/procs": 171.53}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10086.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 57343570.0, "Total blocks": 57343570.0, "Ops per second": 5685308.81, "ns per ops": 175.89, "Ops per threads": 4778.0, "Ops per procs": 2389315.0, "Ops/sec/procs": 236887.87, "ns per ops/procs": 4221.41}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10020.39533, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 263517289.0, "Total blocks": 263513293.0, "Ops per second": 26298093.07, "ns per ops": 38.03, "Ops per threads": 65879.0, "Ops per procs": 32939661.0, "Ops/sec/procs": 3287261.63, "ns per ops/procs": 304.2}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10025.357431, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 551670395.0, "Total blocks": 551662399.0, "Ops per second": 55027503.89, "ns per ops": 18.17, "Ops per threads": 68958.0, "Ops per procs": 34479399.0, "Ops/sec/procs": 3439218.99, "ns per ops/procs": 290.76}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10050.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 56162695.0, "Total blocks": 56162695.0, "Ops per second": 5588033.65, "ns per ops": 178.95, "Ops per threads": 4680.0, "Ops per procs": 2340112.0, "Ops/sec/procs": 232834.74, "ns per ops/procs": 4294.89}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10019.690183, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 271866976.0, "Total blocks": 271862980.0, "Ops per second": 27133271.69, "ns per ops": 36.86, "Ops per threads": 67966.0, "Ops per procs": 33983372.0, "Ops/sec/procs": 3391658.96, "ns per ops/procs": 294.84}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10057.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62105022.0, "Total blocks": 62105022.0, "Ops per second": 6175186.04, "ns per ops": 161.94, "Ops per threads": 15526.0, "Ops per procs": 7763127.0, "Ops/sec/procs": 771898.25, "ns per ops/procs": 1295.51}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10025.81217, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 537080117.0, "Total blocks": 537072121.0, "Ops per second": 53569736.59, "ns per ops": 18.67, "Ops per threads": 67135.0, "Ops per procs": 33567507.0, "Ops/sec/procs": 3348108.54, "ns per ops/procs": 298.68}],["rdq-cycle-go", "./rdq-cycle-go -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10000.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55967030.0, "Ops per second": 5596438.25, "ns per ops": 178.69, "Ops per threads": 111934.0, "Ops per procs": 55967030.0, "Ops/sec/procs": 5596438.25, "ns per ops/procs": 178.69}],["rdq-cycle-go", "./rdq-cycle-go -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10000.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55703320.0, "Ops per second": 5570084.72, "ns per ops": 179.53, "Ops per threads": 111406.0, "Ops per procs": 55703320.0, "Ops/sec/procs": 5570084.72, "ns per ops/procs": 179.53}],["rdq-cycle-go", "./rdq-cycle-go -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10000.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 469211793.0, "Ops per second": 46918327.16, "ns per ops": 21.31, "Ops per threads": 117302.0, "Ops per procs": 58651474.0, "Ops/sec/procs": 5864790.9, "ns per ops/procs": 170.51}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10016.545208, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54925472.0, "Total blocks": 54924976.0, "Ops per second": 5483474.68, "ns per ops": 182.37, "Ops per threads": 109850.0, "Ops per procs": 54925472.0, "Ops/sec/procs": 5483474.68, "ns per ops/procs": 182.37}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10037.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 60770550.0, "Total blocks": 60770550.0, "Ops per second": 6054474.7, "ns per ops": 165.17, "Ops per threads": 7596.0, "Ops per procs": 3798159.0, "Ops/sec/procs": 378404.67, "ns per ops/procs": 2642.67}]]
  • doc/theses/thierry_delisle_PhD/thesis/local.bib

    r29d8c02 r74ec742  
    701701  note = "[Online; accessed 12-April-2022]"
    702702}
     703
     704% RMR notes :
     705% [05/04, 12:36] Trevor Brown
     706%     i don't know where rmr complexity was first introduced, but there are many many many papers that use the term and define it
     707% ​[05/04, 12:37] Trevor Brown
     708%     here's one paper that uses the term a lot and links to many others that use it... might trace it to something useful there https://drops.dagstuhl.de/opus/volltexte/2021/14832/pdf/LIPIcs-DISC-2021-30.pdf
     709% ​[05/04, 12:37] Trevor Brown
     710%     another option might be to cite a textbook
     711% ​[05/04, 12:42] Trevor Brown
     712%     but i checked two textbooks in the area i'm aware of and i don't see a definition of rmr complexity in either
     713% ​[05/04, 12:42] Trevor Brown
     714%     this one has a nice statement about the prevelance of rmr complexity, as well as some rough definition
     715% ​[05/04, 12:42] Trevor Brown
     716%     https://dl.acm.org/doi/pdf/10.1145/3465084.3467938
     717
     718% Race to idle notes :
     719% [13/04, 16:56] Martin Karsten
     720%       I don't have a citation. Google brings up this one, which might be good:
     721%
     722% https://doi.org/10.1137/1.9781611973099.100
  • doc/theses/thierry_delisle_PhD/thesis/text/eval_macro.tex

    r29d8c02 r74ec742  
    77Networked ZIPF
    88
     9Nginx : 5Gb still good, 4Gb starts to suffer
     10
     11Cforall : 10Gb too high, 4 Gb too low
     12
    913\section{Memcached}
    1014
    11 In Memory
     15\subsection{Benchmark Environment}
     16These experiments are run on a cluster of homogenous Supermicro SYS-6017R-TDF compute nodes with the following characteristics:
     17The server runs Ubuntu 20.04.3 LTS on top of Linux Kernel 5.11.0-34.
     18Each node has 2 Intel(R) Xeon(R) CPU E5-2620 v2 running at 2.10GHz.
     19These CPUs have 6 cores per CPUs and 2 \glspl{hthrd} per core, for a total of 24 \glspl{hthrd}.
     20The cpus each have 384 KB, 3 MB and 30 MB of L1, L2 and L3 caches respectively.
     21Each node is connected to the network through a Mellanox 10 Gigabit Ethernet port.
     22The network route uses 1 Mellanox SX1012 10/40 Gigabit Ethernet cluster switch.
    1223
    13 Networked
     24
     25
     26\begin{figure}
     27        \centering
     28        \input{result.memcd.updt.qps.pstex_t}
     29        \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description}
     30        \label{fig:memcd:updt:qps}
     31\end{figure}
     32
     33\begin{figure}
     34        \centering
     35        \input{result.memcd.updt.lat.pstex_t}
     36        \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description}
     37        \label{fig:memcd:updt:lat}
     38\end{figure}
     39
     40\begin{figure}
     41        \centering
     42        \input{result.memcd.rate.qps.pstex_t}
     43        \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description}
     44        \label{fig:memcd:rate:qps}
     45\end{figure}
     46
     47\begin{figure}
     48        \centering
     49        \input{result.memcd.rate.99th.pstex_t}
     50        \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description}
     51        \label{fig:memcd:rate:tail}
     52\end{figure}
  • doc/theses/thierry_delisle_PhD/thesis/text/eval_micro.tex

    r29d8c02 r74ec742  
    66\section{Benchmark Environment}
    77All of these benchmarks are run on two distinct hardware environment, an AMD and an INTEL machine.
     8
     9For all benchmarks, \texttt{taskset} is used to limit the experiment to 1 NUMA Node with no hyper threading.
     10If more \glspl{hthrd} are needed, then 1 NUMA Node with hyperthreading is used.
     11If still more \glspl{hthrd} are needed then the experiment is limited to as few NUMA Nodes as needed.
     12
    813
    914\paragraph{AMD} The AMD machine is a server with two AMD EPYC 7662 CPUs and 256GB of DDR4 RAM.
     
    2328
    2429\section{Cycling latency}
     30\begin{figure}
     31        \centering
     32        \input{cycle.pstex_t}
     33        \caption[Cycle benchmark]{Cycle benchmark\smallskip\newline Each \gls{at} unparks the next \gls{at} in the cycle before parking itself.}
     34        \label{fig:cycle}
     35\end{figure}
    2536The most basic evaluation of any ready queue is to evaluate the latency needed to push and pop one element from the ready-queue.
    2637Since these two operation also describe a \texttt{yield} operation, many systems use this as the most basic benchmark.
     
    4253Note that this problem is only present on SMP machines and is significantly mitigated by the fact that there are multiple rings in the system.
    4354
    44 \begin{figure}
    45         \centering
    46         \input{cycle.pstex_t}
    47         \caption[Cycle benchmark]{Cycle benchmark\smallskip\newline Each \gls{at} unparks the next \gls{at} in the cycle before parking itself.}
    48         \label{fig:cycle}
    49 \end{figure}
    50 
    5155To avoid this benchmark from being dominated by the idle sleep handling, the number of rings is kept at least as high as the number of \glspl{proc} available.
    5256Beyond this point, adding more rings serves to mitigate even more the idle sleep handling.
     
    5458
    5559The actual benchmark is more complicated to handle termination, but that simply requires using a binary semphore or a channel instead of raw \texttt{park}/\texttt{unpark} and carefully picking the order of the \texttt{P} and \texttt{V} with respect to the loop condition.
    56 
    57 \begin{lstlisting}
    58         Thread.main() {
    59                 count := 0
    60                 for {
    61                         wait()
    62                         this.next.wake()
    63                         count ++
    64                         if must_stop() { break }
    65                 }
    66                 global.count += count
    67         }
    68 \end{lstlisting}
    69 
    70 \begin{figure}
    71         \centering
    72         \input{result.cycle.jax.ops.pstex_t}
    73         \vspace*{-10pt}
    74         \label{fig:cycle:ns:jax}
    75 \end{figure}
     60Figure~\ref{fig:cycle:code} shows pseudo code for this benchmark.
     61
     62\begin{figure}
     63        \begin{lstlisting}
     64                Thread.main() {
     65                        count := 0
     66                        for {
     67                                wait()
     68                                this.next.wake()
     69                                count ++
     70                                if must_stop() { break }
     71                        }
     72                        global.count += count
     73                }
     74        \end{lstlisting}
     75        \caption[Cycle Benchmark : Pseudo Code]{Cycle Benchmark : Pseudo Code}
     76        \label{fig:cycle:code}
     77\end{figure}
     78
     79
     80
     81\subsection{Results}
     82\begin{figure}
     83        \subfloat[][Throughput, 100 \ats per \proc]{
     84                \resizebox{0.5\linewidth}{!}{
     85                        \input{result.cycle.jax.ops.pstex_t}
     86                }
     87                \label{fig:cycle:jax:ops}
     88        }
     89        \subfloat[][Throughput, 1 \ats per \proc]{
     90                \resizebox{0.5\linewidth}{!}{
     91                        \input{result.cycle.low.jax.ops.pstex_t}
     92                }
     93                \label{fig:cycle:jax:low:ops}
     94        }
     95
     96        \subfloat[][Latency, 100 \ats per \proc]{
     97                \resizebox{0.5\linewidth}{!}{
     98                        \input{result.cycle.jax.ns.pstex_t}
     99                }
     100
     101        }
     102        \subfloat[][Latency, 1 \ats per \proc]{
     103                \resizebox{0.5\linewidth}{!}{
     104                        \input{result.cycle.low.jax.ns.pstex_t}
     105                }
     106                \label{fig:cycle:jax:low:ns}
     107        }
     108        \caption[Cycle Benchmark on Intel]{Cycle Benchmark on Intel\smallskip\newline Throughput as a function of \proc count, using 100 cycles per \proc, 5 \ats per cycle.}
     109        \label{fig:cycle:jax}
     110\end{figure}
     111Figure~\ref{fig:cycle:jax} shows the throughput as a function of \proc count, with the following constants:
     112Each run uses 100 cycles per \proc, 5 \ats per cycle.
     113
     114\todo{results discussion}
    76115
    77116\section{Yield}
     
    81120Its only interesting variable is the number of \glspl{at} per \glspl{proc}, where ratios close to 1 means the ready queue(s) could be empty.
    82121This sometimes puts more strain on the idle sleep handling, compared to scenarios where there is clearly plenty of work to be done.
    83 
    84 \todo{code, setup, results}
    85 
    86 \begin{lstlisting}
    87         Thread.main() {
    88                 count := 0
    89                 while !stop {
    90                         yield()
    91                         count ++
    92                 }
    93                 global.count += count
    94         }
    95 \end{lstlisting}
     122Figure~\ref{fig:yield:code} shows pseudo code for this benchmark, the ``wait/wake-next'' is simply replaced by a yield.
     123
     124\begin{figure}
     125        \begin{lstlisting}
     126                Thread.main() {
     127                        count := 0
     128                        for {
     129                                yield()
     130                                count ++
     131                                if must_stop() { break }
     132                        }
     133                        global.count += count
     134                }
     135        \end{lstlisting}
     136        \caption[Yield Benchmark : Pseudo Code]{Yield Benchmark : Pseudo Code}
     137        \label{fig:yield:code}
     138\end{figure}
     139
     140\subsection{Results}
     141\begin{figure}
     142        \subfloat[][Throughput, 100 \ats per \proc]{
     143                \resizebox{0.5\linewidth}{!}{
     144                        \input{result.yield.jax.ops.pstex_t}
     145                }
     146                \label{fig:yield:jax:ops}
     147        }
     148        \subfloat[][Throughput, 1 \ats per \proc]{
     149                \resizebox{0.5\linewidth}{!}{
     150                \input{result.yield.low.jax.ops.pstex_t}
     151                }
     152                \label{fig:yield:jax:low:ops}
     153        }
     154
     155        \subfloat[][Latency, 100 \ats per \proc]{
     156                \resizebox{0.5\linewidth}{!}{
     157                \input{result.yield.jax.ns.pstex_t}
     158                }
     159                \label{fig:yield:jax:ns}
     160        }
     161        \subfloat[][Latency, 1 \ats per \proc]{
     162                \resizebox{0.5\linewidth}{!}{
     163                \input{result.yield.low.jax.ns.pstex_t}
     164                }
     165                \label{fig:yield:jax:low:ns}
     166        }
     167        \caption[Yield Benchmark on Intel]{Yield Benchmark on Intel\smallskip\newline Throughput as a function of \proc count, using 1 \ats per \proc.}
     168        \label{fig:yield:jax}
     169\end{figure}
     170Figure~\ref{fig:yield:ops:jax} shows the throughput as a function of \proc count, with the following constants:
     171Each run uses 100 \ats per \proc.
     172
     173\todo{results discussion}
    96174
    97175
     
    105183In either case, this benchmark aims to highlight how each scheduler handles these cases, since both cases can lead to performance degradation if they are not handled correctly.
    106184
    107 To achieve this the benchmark uses a fixed size array of \newterm{chair}s, where a chair is a data structure that holds a single blocked \gls{at}.
    108 When a \gls{at} attempts to block on the chair, it must first unblocked the \gls{at} currently blocked on said chair, if any.
    109 This creates a flow where \glspl{at} push each other out of the chairs before being pushed out themselves.
    110 For this benchmark to work however, the number of \glspl{at} must be equal or greater to the number of chairs plus the number of \glspl{proc}.
     185To achieve this the benchmark uses a fixed size array of semaphores.
     186Each \gls{at} picks a random semaphore, \texttt{V}s it to unblock a \at waiting and then \texttt{P}s on the semaphore.
     187This creates a flow where \glspl{at} push each other out of the semaphores before being pushed out themselves.
     188For this benchmark to work however, the number of \glspl{at} must be equal or greater to the number of semaphores plus the number of \glspl{proc}.
     189Note that the nature of these semaphores mean the counter can go beyond 1, which could lead to calls to \texttt{P} not blocking.
    111190
    112191\todo{code, setup, results}
     
    116195                for {
    117196                        r := random() % len(spots)
    118                         next := xchg(spots[r], this)
    119                         if next { next.wake() }
    120                         wait()
     197                        spots[r].V()
     198                        spots[r].P()
    121199                        count ++
    122200                        if must_stop() { break }
     
    125203        }
    126204\end{lstlisting}
     205
     206\begin{figure}
     207        \subfloat[][Throughput, 100 \ats per \proc]{
     208                \resizebox{0.5\linewidth}{!}{
     209                        \input{result.churn.jax.ops.pstex_t}
     210                }
     211                \label{fig:churn:jax:ops}
     212        }
     213        \subfloat[][Throughput, 1 \ats per \proc]{
     214                \resizebox{0.5\linewidth}{!}{
     215                        \input{result.churn.low.jax.ops.pstex_t}
     216                }
     217                \label{fig:churn:jax:low:ops}
     218        }
     219
     220        \subfloat[][Latency, 100 \ats per \proc]{
     221                \resizebox{0.5\linewidth}{!}{
     222                        \input{result.churn.jax.ns.pstex_t}
     223                }
     224
     225        }
     226        \subfloat[][Latency, 1 \ats per \proc]{
     227                \resizebox{0.5\linewidth}{!}{
     228                        \input{result.churn.low.jax.ns.pstex_t}
     229                }
     230                \label{fig:churn:jax:low:ns}
     231        }
     232        \caption[Churn Benchmark on Intel]{\centering Churn Benchmark on Intel\smallskip\newline Throughput and latency of the Churn on the benchmark on the Intel machine. Throughput is the total operation per second across all cores. Latency is the duration of each opeartion.}
     233        \label{fig:churn:jax}
     234\end{figure}
    127235
    128236\section{Locality}
  • doc/theses/thierry_delisle_PhD/thesis/text/practice.tex

    r29d8c02 r74ec742  
    77More precise \CFA supports adding \procs using the RAII object @processor@.
    88These objects can be created at any time and can be destroyed at any time.
    9 They are normally create as automatic stack variables, but this is not a requirement.
     9They are normally created as automatic stack variables, but this is not a requirement.
    1010
    1111The consequence is that the scheduler and \io subsystems must support \procs comming in and out of existence.
    1212
    1313\section{Manual Resizing}
    14 The consequence of dynamically changing the number of \procs is that all internal arrays that are sized based on the number of \procs neede to be \texttt{realloc}ed.
    15 This also means that any references into these arrays, pointers or indexes, may need to be fixed when shrinking\footnote{Indexes may still need fixing because there is no guarantee the \proc causing the shrink had the highest index. Therefore indexes need to be reassigned to preserve contiguous indexes.}.
    16 
    17 There are no performance requirements, within reason, for resizing since this is usually considered as part of setup and teardown.
     14Manual resizing is expected to be a rare operation.
     15Programmers are mostly expected to resize clusters on startup or teardown.
     16Therefore dynamically changing the number of \procs is an appropriate moment to allocate or free resources to match the new state.
     17As such all internal arrays that are sized based on the number of \procs need to be \texttt{realloc}ed.
     18This also means that any references into these arrays, pointers or indexes, may need to be fixed when shrinking\footnote{Indexes may still need fixing when shrinkingbecause some indexes are expected to refer to dense contiguous resources and there is no guarantee the resource being removed has the highest index.}.
     19
     20There are no performance requirements, within reason, for resizing since it is expected to be rare.
    1821However, this operation has strict correctness requirements since shrinking and idle sleep can easily lead to deadlocks.
    1922It should also avoid as much as possible any effect on performance when the number of \procs remain constant.
    20 This later requirement prehibits simple solutions, like simply adding a global lock to these arrays.
     23This later requirement prohibits naive solutions, like simply adding a global lock to the ready-queue arrays.
    2124
    2225\subsection{Read-Copy-Update}
     
    2427In this pattern, resizing is done by creating a copy of the internal data strucures, updating the copy with the desired changes, and then attempt an Idiana Jones Switch to replace the original witht the copy.
    2528This approach potentially has the advantage that it may not need any synchronization to do the switch.
    26 The switch definitely implies a race where \procs could still use the previous, original, data structure after the copy was switched in.
    27 The important question then becomes whether or not this race can be recovered from.
    28 If the changes that arrived late can be transferred from the original to the copy then this solution works.
    29 
    30 For linked-lists, dequeing is somewhat of a problem.
     29However, there is a race where \procs could still use the previous, original, data structure after the copy was switched in.
     30This race not only requires some added memory reclamation scheme, it also requires that operations made on the stale original version be eventually moved to the copy.
     31
     32For linked-lists, enqueing is only somewhat problematic, \ats enqueued to the original queues need to be transferred to the new, which might not preserve ordering.
     33Dequeing is more challenging.
    3134Dequeing from the original will not necessarily update the copy which could lead to multiple \procs dequeing the same \at.
    32 Fixing this requires making the array contain pointers to subqueues rather than the subqueues themselves.
     35Fixing this requires more synchronization or more indirection on the queues.
    3336
    3437Another challenge is that the original must be kept until all \procs have witnessed the change.
     
    97100In addition to users manually changing the number of \procs, it is desireable to support ``removing'' \procs when there is not enough \ats for all the \procs to be useful.
    98101While manual resizing is expected to be rare, the number of \ats is expected to vary much more which means \procs may need to be ``removed'' for only short periods of time.
    99 Furthermore, race conditions that spuriously lead to the impression no \ats are ready are actually common in practice.
    100 Therefore \procs should not be actually \emph{removed} but simply put into an idle state where the \gls{kthrd} is blocked until more \ats become ready.
     102Furthermore, race conditions that spuriously lead to the impression that no \ats are ready are actually common in practice.
     103Therefore resources associated with \procs should not be freed but \procs simply put into an idle state where the \gls{kthrd} is blocked until more \ats become ready.
    101104This state is referred to as \newterm{Idle-Sleep}.
    102105
     
    110113The \CFA scheduler simply follows the ``Race-to-Idle'\cit{https://doi.org/10.1137/1.9781611973099.100}' approach where a sleeping \proc is woken any time an \at becomes ready and \procs go to idle sleep anytime they run out of work.
    111114
     115\section{Sleeping}
     116As usual, the corner-stone of any feature related to the kernel is the choice of system call.
     117In terms of blocking a \gls{kthrd} until some event occurs the linux kernel has many available options:
     118
     119\paragraph{\texttt{pthread\_mutex}/\texttt{pthread\_cond}}
     120The most classic option is to use some combination of \texttt{pthread\_mutex} and \texttt{pthread\_cond}.
     121These serve as straight forward mutual exclusion and synchronization tools and allow a \gls{kthrd} to wait on a \texttt{pthread\_cond} until signalled.
     122While this approach is generally perfectly appropriate for \glspl{kthrd} waiting after eachother, \io operations do not signal \texttt{pthread\_cond}s.
     123For \io results to wake a \proc waiting on a \texttt{pthread\_cond} means that a different \glspl{kthrd} must be woken up first, and then the \proc can be signalled.
     124
     125\subsection{\texttt{io\_uring} and Epoll}
     126An alternative is to flip the problem on its head and block waiting for \io, using \texttt{io\_uring} or even \texttt{epoll}.
     127This creates the inverse situation, where \io operations directly wake sleeping \procs but waking \proc from a running \gls{kthrd} must use an indirect scheme.
     128This generally takes the form of creating a file descriptor, \eg, a dummy file, a pipe or an event fd, and using that file descriptor when \procs need to wake eachother.
     129This leads to additional complexity because there can be a race between these artificial \io operations and genuine \io operations.
     130If not handled correctly, this can lead to the artificial files going out of sync.
     131
     132\subsection{Event FDs}
     133Another interesting approach is to use an event file descriptor\cit{eventfd}.
     134This is a Linux feature that is a file descriptor that behaves like \io, \ie, uses \texttt{read} and \texttt{write}, but also behaves like a semaphore.
     135Indeed, all read and writes must use 64bits large values\footnote{On 64-bit Linux, a 32-bit Linux would use 32 bits values.}.
     136Writes add their values to the buffer, that is arithmetic addition and not buffer append, and reads zero out the buffer and return the buffer values so far\footnote{This is without the \texttt{EFD\_SEMAPHORE} flag. This flags changes the behavior of \texttt{read} but is not needed for this work.}.
     137If a read is made while the buffer is already 0, the read blocks until a non-0 value is added.
     138What makes this feature particularly interesting is that \texttt{io\_uring} supports the \texttt{IORING\_REGISTER\_EVENTFD} command, to register an event fd to a particular instance.
     139Once that instance is registered, any \io completion will result in \texttt{io\_uring} writing to the event FD.
     140This means that a \proc waiting on the event FD can be \emph{directly} woken up by either other \procs or incomming \io.
     141
     142\begin{figure}
     143        \centering
     144        \input{idle1.pstex_t}
     145        \caption[Basic Idle Sleep Data Structure]{Basic Idle Sleep Data Structure \smallskip\newline Each idle \proc is put unto a doubly-linked stack protected by a lock.
     146        Each \proc has a private event FD.}
     147        \label{fig:idle1}
     148\end{figure}
     149
    112150
    113151\section{Tracking Sleepers}
    114152Tracking which \procs are in idle sleep requires a data structure holding all the sleeping \procs, but more importantly it requires a concurrent \emph{handshake} so that no \at is stranded on a ready-queue with no active \proc.
    115153The classic challenge is when a \at is made ready while a \proc is going to sleep, there is a race where the new \at may not see the sleeping \proc and the sleeping \proc may not see the ready \at.
    116 
    117 Furthermore, the ``Race-to-Idle'' approach means that there is some
    118 
    119 \section{Sleeping}
    120 
    121 \subsection{Event FDs}
    122 
    123 \subsection{Epoll}
    124 
    125 \subsection{\texttt{io\_uring}}
    126 
    127 \section{Reducing Latency}
     154Since \ats can be made ready by timers, \io operations or other events outside a clusre, this race can occur even if the \proc going to sleep is the only \proc awake.
     155As a result, improper handling of this race can lead to all \procs going to sleep and the system deadlocking.
     156
     157Furthermore, the ``Race-to-Idle'' approach means that there may be contention on the data structure tracking sleepers.
     158Contention slowing down \procs attempting to sleep or wake-up can be tolerated.
     159These \procs are not doing useful work and therefore not contributing to overall performance.
     160However, notifying, checking if a \proc must be woken-up and doing so if needed, can significantly affect overall performance and must be low cost.
     161
     162\subsection{Sleepers List}
     163Each cluster maintains a list of idle \procs, organized as a stack.
     164This ordering hopefully allows \proc at the tail to stay in idle sleep for extended period of times.
     165Because of these unbalanced performance requirements, the algorithm tracking sleepers is designed to have idle \proc handle as much of the work as possible.
     166The idle \procs maintain the of sleepers among themselves and notifying a sleeping \proc takes as little work as possible.
     167This approach means that maintaining the list is fairly straightforward.
     168The list can simply use a single lock per cluster and only \procs that are getting in and out of idle state will contend for that lock.
     169
     170This approach also simplifies notification.
     171Indeed, \procs need to be notify when a new \at is readied, but they also must be notified during resizing, so the \gls{kthrd} can be joined.
     172This means that whichever entity removes idle \procs from the sleeper list must be able to do so in any order.
     173Using a simple lock over this data structure makes the removal much simpler than using a lock-free data structure.
     174The notification process then simply needs to wake-up the desired idle \proc, using \texttt{pthread\_cond\_signal}, \texttt{write} on an fd, etc., and the \proc will handle the rest.
     175
     176\subsection{Reducing Latency}
     177As mentioned in this section, \procs going idle for extremely short periods of time is likely in certain common scenarios.
     178Therefore, the latency of doing a system call to read from and writing to the event fd can actually negatively affect overall performance in a notable way.
     179Is it important to reduce latency and contention of the notification as much as possible.
     180Figure~\ref{fig:idle1} shoes the basic idle sleep data structure.
     181For the notifiers, this data structure can cause contention on the lock and the event fd syscall can cause notable latency.
     182
     183\begin{figure}
     184        \centering
     185        \input{idle2.pstex_t}
     186        \caption[Improved Idle Sleep Data Structure]{Improved Idle Sleep Data Structure \smallskip\newline An atomic pointer is added to the list, pointing to the Event FD of the first \proc on the list.}
     187        \label{fig:idle2}
     188\end{figure}
     189
     190The contention is mostly due to the lock on the list needing to be held to get to the head \proc.
     191That lock can be contended by \procs attempting to go to sleep, \procs waking or notification attempts.
     192The contentention from the \procs attempting to go to sleep can be mitigated slightly by using \texttt{try\_acquire} instead, so the \procs simply continue searching for \ats if the lock is held.
     193This trick cannot be used for waking \procs since they are not in a state where they can run \ats.
     194However, it is worth nothing that notification does not strictly require accessing the list or the head \proc.
     195Therefore, contention can be reduced notably by having notifiers avoid the lock entirely and adding a pointer to the event fd of the first idle \proc, as in Figure~\ref{fig:idle2}.
     196To avoid contention between the notifiers, instead of simply reading the atomic pointer, notifiers atomically exchange it to \texttt{null} so only only notifier will contend on the system call.
     197
     198\begin{figure}
     199        \centering
     200        \input{idle_state.pstex_t}
     201        \caption[Improved Idle Sleep Data Structure]{Improved Idle Sleep Data Structure \smallskip\newline An atomic pointer is added to the list, pointing to the Event FD of the first \proc on the list.}
     202        \label{fig:idle:state}
     203\end{figure}
     204
     205The next optimization that can be done is to avoid the latency of the event fd when possible.
     206This can be done by adding what is effectively a benaphore\cit{benaphore} in front of the event fd.
     207A simple three state flag is added beside the event fd to avoid unnecessary system calls, as shown in Figure~\ref{fig:idle:state}.
     208The flag starts in state \texttt{SEARCH}, while the \proc is searching for \ats to run.
     209The \proc then confirms the sleep by atomically swaping the state to \texttt{SLEEP}.
     210If the previous state was still \texttt{SEARCH}, then the \proc does read the event fd.
     211Meanwhile, notifiers atomically exchange the state to \texttt{AWAKE} state.
     212if the previous state was \texttt{SLEEP}, then the notifier must write to the event fd.
     213However, if the notify arrives almost immediately after the \proc marks itself idle, then both reads and writes on the event fd can be omitted, which reduces latency notably.
     214This leads to the final data structure shown in Figure~\ref{fig:idle}.
     215
     216\begin{figure}
     217        \centering
     218        \input{idle.pstex_t}
     219        \caption[Low-latency Idle Sleep Data Structure]{Low-latency Idle Sleep Data Structure \smallskip\newline Each idle \proc is put unto a doubly-linked stack protected by a lock.
     220        Each \proc has a private event FD with a benaphore in front of it.
     221        The list also has an atomic pointer to the event fd and benaphore of the first \proc on the list.}
     222        \label{fig:idle}
     223\end{figure}
  • doc/theses/thierry_delisle_PhD/thesis/thesis.tex

    r29d8c02 r74ec742  
    8282\usepackage{xcolor}
    8383\usepackage{graphicx} % For including graphics
     84\usepackage{subcaption}
    8485
    8586% Hyperlinks make it very easy to navigate an electronic document.
     
    204205\newcommand\at{\gls{at}\xspace}%
    205206\newcommand\ats{\glspl{at}\xspace}%
     207\newcommand\Proc{\Pls{proc}\xspace}%
    206208\newcommand\proc{\gls{proc}\xspace}%
    207209\newcommand\procs{\glspl{proc}\xspace}%
  • libcfa/src/Makefile.am

    r29d8c02 r74ec742  
    3333# The built sources must not depend on the installed inst_headers_src
    3434AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr -I$(srcdir)/concurrency $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@
    35 AM_CFLAGS = -g -Wall -Werror=return-type -Wno-unused-function -fPIC -fexceptions -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
     35AM_CFLAGS = -g -Wall -Werror=return-type -Wno-unused-function -fPIC -fexceptions -fvisibility=hidden -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3636AM_CCASFLAGS = -g -Wall -Werror=return-type -Wno-unused-function @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3737CFACC = @CFACC@
     
    194194
    195195prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@
    196         ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@}
     196        ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@}
    197197
    198198prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@
    199199        ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
    200         $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@}
     200        $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@}
    201201
    202202concurrency/io/call.cfa: $(srcdir)/concurrency/io/call.cfa.in
  • libcfa/src/algorithms/range_iterator.cfa

    r29d8c02 r74ec742  
    2020#include <fstream.hfa>
    2121
    22 void main(RangeIter & this) {
     22#include "bits/defs.hfa"
     23
     24void main(RangeIter & this) libcfa_public {
    2325        for() {
    2426                this._start = -1;
  • libcfa/src/assert.cfa

    r29d8c02 r74ec742  
    1919#include <unistd.h>                                                             // STDERR_FILENO
    2020#include "bits/debug.hfa"
     21#include "bits/defs.hfa"
    2122
    2223extern "C" {
     
    2627
    2728        // called by macro assert in assert.h
    28         void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) {
     29        // would be cool to remove libcfa_public but it's needed for libcfathread
     30        void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) libcfa_public {
    2931                __cfaabi_bits_print_safe( STDERR_FILENO, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file );
    3032                abort();
     
    3234
    3335        // called by macro assertf
    34         void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) {
     36        // would be cool to remove libcfa_public but it's needed for libcfathread
     37        void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) libcfa_public {
    3538                __cfaabi_bits_acquire();
    3639                __cfaabi_bits_print_nolock( STDERR_FILENO, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file );
  • libcfa/src/bits/align.hfa

    r29d8c02 r74ec742  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Nov 16 18:58:22 2019
    13 // Update Count     : 3
     12// Last Modified On : Fri Apr 29 19:14:43 2022
     13// Update Count     : 4
    1414//
    1515// This  library is free  software; you  can redistribute  it and/or  modify it
     
    3535//#define libAlign() (sizeof(double))
    3636// gcc-7 uses xmms instructions, which require 16 byte alignment.
    37 #define libAlign() (16)
     37#define libAlign() (__BIGGEST_ALIGNMENT__)
    3838
    3939// Check for power of 2
  • libcfa/src/bits/debug.cfa

    r29d8c02 r74ec742  
    2121#include <unistd.h>
    2222
     23#include "bits/defs.hfa"
     24
    2325enum { buffer_size = 4096 };
    2426static char buffer[ buffer_size ];
    2527
    2628extern "C" {
    27         void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) {
     29        // would be cool to remove libcfa_public but it's needed for libcfathread
     30        void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) libcfa_public {
    2831                // ensure all data is written
    2932                for ( int count = 0, retcode; count < len; count += retcode ) {
     
    4447        void __cfaabi_bits_release() __attribute__((__weak__)) {}
    4548
    46         int __cfaabi_bits_print_safe  ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) {
     49        // would be cool to remove libcfa_public but it's needed for libcfathread
     50        int __cfaabi_bits_print_safe  ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) libcfa_public {
    4751                va_list args;
    4852
  • libcfa/src/bits/defs.hfa

    r29d8c02 r74ec742  
    3636#define __cfa_dlink(x) struct { struct x * next; struct x * back; } __dlink_substitute
    3737#endif
     38
     39#define libcfa_public __attribute__((visibility("default")))
    3840
    3941#ifdef __cforall
  • libcfa/src/bits/weakso_locks.cfa

    r29d8c02 r74ec742  
    1818#include "bits/weakso_locks.hfa"
    1919
     20#pragma GCC visibility push(default)
     21
    2022void  ?{}( blocking_lock &, bool, bool ) {}
    2123void ^?{}( blocking_lock & ) {}
  • libcfa/src/common.cfa

    r29d8c02 r74ec742  
    1818#include <stdlib.h>                                     // div_t, *div
    1919
     20#pragma GCC visibility push(default)
     21
    2022//---------------------------------------
    2123
  • libcfa/src/concurrency/alarm.cfa

    r29d8c02 r74ec742  
    141141//=============================================================================================
    142142
    143 void sleep( Duration duration ) {
     143void sleep( Duration duration ) libcfa_public {
    144144        alarm_node_t node = { active_thread(), duration, 0`s };
    145145
  • libcfa/src/concurrency/clib/cfathread.cfa

    r29d8c02 r74ec742  
    326326}
    327327
     328#pragma GCC visibility push(default)
     329
    328330//================================================================================
    329331// Main Api
    330332extern "C" {
    331         int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) {
     333        int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) libcfa_public {
    332334                *cl = new();
    333335                return 0;
    334336        }
    335337
    336         cfathread_cluster_t cfathread_cluster_self(void) {
     338        cfathread_cluster_t cfathread_cluster_self(void) libcfa_public {
    337339                return active_cluster();
    338340        }
    339341
    340         int cfathread_cluster_print_stats( cfathread_cluster_t cl ) {
     342        int cfathread_cluster_print_stats( cfathread_cluster_t cl ) libcfa_public {
    341343                #if !defined(__CFA_NO_STATISTICS__)
    342344                        print_stats_at_exit( *cl, CFA_STATS_READY_Q | CFA_STATS_IO );
  • libcfa/src/concurrency/coroutine.cfa

    r29d8c02 r74ec742  
    4848//-----------------------------------------------------------------------------
    4949forall(T &)
    50 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
     50void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) libcfa_public {
    5151        dst->virtual_table = src->virtual_table;
    5252        dst->the_coroutine = src->the_coroutine;
     
    5555
    5656forall(T &)
    57 const char * msg(CoroutineCancelled(T) *) {
     57const char * msg(CoroutineCancelled(T) *) libcfa_public {
    5858        return "CoroutineCancelled(...)";
    5959}
     
    6262forall(T & | is_coroutine(T))
    6363void __cfaehm_cancelled_coroutine(
    64                 T & cor, coroutine$ * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) {
     64                T & cor, coroutine$ * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) libcfa_public {
    6565        verify( desc->cancellation );
    6666        desc->state = Cancelled;
     
    8989
    9090void __stack_prepare( __stack_info_t * this, size_t create_size );
    91 void __stack_clean  ( __stack_info_t * this );
     91static void __stack_clean  ( __stack_info_t * this );
    9292
    9393//-----------------------------------------------------------------------------
     
    114114}
    115115
    116 void ?{}( coroutine$ & this, const char name[], void * storage, size_t storageSize ) with( this ) {
     116void ?{}( coroutine$ & this, const char name[], void * storage, size_t storageSize ) libcfa_public with( this ) {
    117117        (this.context){0p, 0p};
    118118        (this.stack){storage, storageSize};
     
    124124}
    125125
    126 void ^?{}(coroutine$& this) {
     126void ^?{}(coroutine$& this) libcfa_public {
    127127        if(this.state != Halted && this.state != Start && this.state != Primed) {
    128128                coroutine$ * src = active_coroutine();
     
    147147// Not inline since only ever called once per coroutine
    148148forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
    149 void prime(T& cor) {
     149void prime(T& cor) libcfa_public {
    150150        coroutine$* this = get_coroutine(cor);
    151151        assert(this->state == Start);
     
    155155}
    156156
    157 [void *, size_t] __stack_alloc( size_t storageSize ) {
     157static [void *, size_t] __stack_alloc( size_t storageSize ) {
    158158        const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
    159159        assert(__page_size != 0l);
     
    193193}
    194194
    195 void __stack_clean  ( __stack_info_t * this ) {
     195static void __stack_clean  ( __stack_info_t * this ) {
    196196        void * storage = this->storage->limit;
    197197
     
    215215}
    216216
    217 void __stack_prepare( __stack_info_t * this, size_t create_size ) {
     217void __stack_prepare( __stack_info_t * this, size_t create_size ) libcfa_public {
    218218        const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
    219219        bool userStack;
  • libcfa/src/concurrency/coroutine.hfa

    r29d8c02 r74ec742  
    113113
    114114extern void __stack_prepare( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
    115 extern void __stack_clean  ( __stack_info_t * this );
    116 
    117115
    118116// Suspend implementation inlined for performance
  • libcfa/src/concurrency/exception.cfa

    r29d8c02 r74ec742  
    6464extern "C" {
    6565
    66 struct exception_context_t * this_exception_context(void) {
     66struct exception_context_t * this_exception_context(void) libcfa_public {
    6767        return &__get_stack( active_coroutine() )->exception_context;
    6868}
    6969
    70 _Unwind_Reason_Code __cfaehm_cancellation_unwind( struct _Unwind_Exception * unwind_exception ) {
     70_Unwind_Reason_Code __cfaehm_cancellation_unwind( struct _Unwind_Exception * unwind_exception ) libcfa_public {
    7171        _Unwind_Stop_Fn stop_func;
    7272        void * stop_param;
  • libcfa/src/concurrency/invoke.c

    r29d8c02 r74ec742  
    3636extern void enable_interrupts( _Bool poll );
    3737
    38 void __cfactx_invoke_coroutine(
     38libcfa_public void __cfactx_invoke_coroutine(
    3939        void (*main)(void *),
    4040        void *this
     
    7070}
    7171
    72 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) __attribute__ ((__noreturn__));
     72libcfa_public void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) __attribute__ ((__noreturn__));
    7373void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) {
    7474        _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, __cfactx_coroutine_unwindstop, cor );
     
    7777}
    7878
    79 void __cfactx_invoke_thread(
     79libcfa_public void __cfactx_invoke_thread(
    8080        void (*main)(void *),
    8181        void *this
     
    9898}
    9999
    100 void __cfactx_start(
     100libcfa_public void __cfactx_start(
    101101        void (*main)(void *),
    102102        struct coroutine$ * cor,
  • libcfa/src/concurrency/io.cfa

    r29d8c02 r74ec742  
    244244
    245245                                        remote = true;
    246                                         __STATS__( false, io.calls.helped++; )
     246                                        __STATS__( true, io.calls.helped++; )
    247247                                }
    248248                                proc->io.target = MAX;
     
    340340        // for convenience, return both the index and the pointer to the sqe
    341341        // sqe == &sqes[idx]
    342         struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) {
     342        struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) libcfa_public {
    343343                // __cfadbg_print_safe(io, "Kernel I/O : attempting to allocate %u\n", want);
    344344
     
    419419        }
    420420
    421         void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) {
     421        void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) libcfa_public {
    422422                // __cfadbg_print_safe(io, "Kernel I/O : attempting to submit %u (%s)\n", have, lazy ? "lazy" : "eager");
    423423
  • libcfa/src/concurrency/io/call.cfa.in

    r29d8c02 r74ec742  
    139139// I/O Interface
    140140//=============================================================================================
     141#pragma GCC visibility push(default)
    141142"""
    142143
  • libcfa/src/concurrency/io/setup.cfa

    r29d8c02 r74ec742  
    2626
    2727#if !defined(CFA_HAVE_LINUX_IO_URING_H)
    28         void ?{}(io_context_params & this) {}
     28        void ?{}(io_context_params & this) libcfa_public {}
    2929
    3030        void  ?{}($io_context & this, struct cluster & cl) {}
     
    6666#pragma GCC diagnostic pop
    6767
    68         void ?{}(io_context_params & this) {
     68        void ?{}(io_context_params & this) libcfa_public {
    6969                this.num_entries = 256;
    7070        }
  • libcfa/src/concurrency/kernel.cfa

    r29d8c02 r74ec742  
    389389
    390390// KERNEL_ONLY
    391 void returnToKernel() {
     391static void returnToKernel() {
    392392        /* paranoid */ verify( ! __preemption_enabled() );
    393393        coroutine$ * proc_cor = get_coroutine(kernelTLS().this_processor->runner);
     
    547547}
    548548
    549 void unpark( thread$ * thrd, unpark_hint hint ) {
     549void unpark( thread$ * thrd, unpark_hint hint ) libcfa_public {
    550550        if( !thrd ) return;
    551551
     
    558558}
    559559
    560 void park( void ) {
     560void park( void ) libcfa_public {
    561561        __disable_interrupts_checked();
    562562                /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION );
     
    601601
    602602// KERNEL ONLY
    603 bool force_yield( __Preemption_Reason reason ) {
     603bool force_yield( __Preemption_Reason reason ) libcfa_public {
    604604        __disable_interrupts_checked();
    605605                thread$ * thrd = kernelTLS().this_thread;
     
    849849//-----------------------------------------------------------------------------
    850850// Debug
    851 bool threading_enabled(void) __attribute__((const)) {
     851bool threading_enabled(void) __attribute__((const)) libcfa_public {
    852852        return true;
    853853}
     
    856856// Statistics
    857857#if !defined(__CFA_NO_STATISTICS__)
    858         void print_halts( processor & this ) {
     858        void print_halts( processor & this ) libcfa_public {
    859859                this.print_halts = true;
    860860        }
     
    873873        }
    874874
    875         void crawl_cluster_stats( cluster & this ) {
     875        static void crawl_cluster_stats( cluster & this ) {
    876876                // Stop the world, otherwise stats could get really messed-up
    877877                // this doesn't solve all problems but does solve many
     
    889889
    890890
    891         void print_stats_now( cluster & this, int flags ) {
     891        void print_stats_now( cluster & this, int flags ) libcfa_public {
    892892                crawl_cluster_stats( this );
    893893                __print_stats( this.stats, flags, "Cluster", this.name, (void*)&this );
  • libcfa/src/concurrency/kernel.hfa

    r29d8c02 r74ec742  
    4949
    5050// Coroutine used py processors for the 2-step context switch
    51 coroutine processorCtx_t {
     51
     52struct processorCtx_t {
     53        struct coroutine$ self;
    5254        struct processor * proc;
    5355};
  • libcfa/src/concurrency/kernel/cluster.cfa

    r29d8c02 r74ec742  
    4949
    5050// returns the maximum number of processors the RWLock support
    51 __attribute__((weak)) unsigned __max_processors() {
     51__attribute__((weak)) unsigned __max_processors() libcfa_public {
    5252        const char * max_cores_s = getenv("CFA_MAX_PROCESSORS");
    5353        if(!max_cores_s) {
  • libcfa/src/concurrency/kernel/private.hfa

    r29d8c02 r74ec742  
    109109//-----------------------------------------------------------------------------
    110110// Processor
    111 void main(processorCtx_t *);
     111void main(processorCtx_t &);
     112static inline coroutine$* get_coroutine(processorCtx_t & this) { return &this.self; }
    112113
    113114void * __create_pthread( pthread_t *, void * (*)(void *), void * );
  • libcfa/src/concurrency/kernel/startup.cfa

    r29d8c02 r74ec742  
    120120#endif
    121121
    122 cluster              * mainCluster;
     122cluster              * mainCluster libcfa_public;
    123123processor            * mainProcessor;
    124124thread$              * mainThread;
     
    169169};
    170170
    171 void ?{}( current_stack_info_t & this ) {
     171static void ?{}( current_stack_info_t & this ) {
    172172        __stack_context_t ctx;
    173173        CtxGet( ctx );
     
    209209        // Construct the processor context of the main processor
    210210        void ?{}(processorCtx_t & this, processor * proc) {
    211                 (this.__cor){ "Processor" };
    212                 this.__cor.starter = 0p;
     211                (this.self){ "Processor" };
     212                this.self.starter = 0p;
    213213                this.proc = proc;
    214214        }
     
    526526// Construct the processor context of non-main processors
    527527static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {
    528         (this.__cor){ info };
     528        (this.self){ info };
    529529        this.proc = proc;
    530530}
     
    578578}
    579579
    580 void ?{}(processor & this, const char name[], cluster & _cltr, thread$ * initT) {
     580void ?{}(processor & this, const char name[], cluster & _cltr, thread$ * initT) libcfa_public {
    581581        ( this.terminated ){};
    582582        ( this.runner ){};
     
    591591}
    592592
    593 void ?{}(processor & this, const char name[], cluster & _cltr) {
     593void ?{}(processor & this, const char name[], cluster & _cltr) libcfa_public {
    594594        (this){name, _cltr, 0p};
    595595}
    596596
    597597extern size_t __page_size;
    598 void ^?{}(processor & this) with( this ){
     598void ^?{}(processor & this) libcfa_public with( this ) {
    599599        /* paranoid */ verify( !__atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) );
    600600        __cfadbg_print_safe(runtime_core, "Kernel : core %p signaling termination\n", &this);
     
    623623}
    624624
    625 void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) with( this ) {
     625void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) libcfa_public with( this ) {
    626626        this.name = name;
    627627        this.preemption_rate = preemption_rate;
     
    658658}
    659659
    660 void ^?{}(cluster & this) {
     660void ^?{}(cluster & this) libcfa_public {
    661661        destroy(this.io.arbiter);
    662662
  • libcfa/src/concurrency/locks.cfa

    r29d8c02 r74ec742  
    2424#include <stdlib.hfa>
    2525
     26#pragma GCC visibility push(default)
     27
    2628//-----------------------------------------------------------------------------
    2729// info_thread
     
    116118}
    117119
    118 void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
     120static void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
    119121        thread$ * t = &try_pop_front( blocked_threads );
    120122        owner = t;
     
    192194        void ^?{}( alarm_node_wrap(L) & this ) { }
    193195
    194         void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
     196        static void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
    195197                // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
    196198                lock( cond->lock __cfaabi_dbg_ctx2 );
     
    216218
    217219        // this casts the alarm node to our wrapped type since we used type erasure
    218         void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }
     220        static void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }
    219221}
    220222
    221223//-----------------------------------------------------------------------------
    222 // condition variable
     224// Synchronization Locks
    223225forall(L & | is_blocking_lock(L)) {
    224226
     227        //-----------------------------------------------------------------------------
     228        // condition variable
    225229        void ?{}( condition_variable(L) & this ){
    226230                this.lock{};
     
    231235        void ^?{}( condition_variable(L) & this ){ }
    232236
    233         void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {
     237        static void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {
    234238                if(&popped != 0p) {
    235239                        popped.signalled = true;
     
    276280        int counter( condition_variable(L) & this ) with(this) { return count; }
    277281
    278         size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
     282        static size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
    279283                // add info_thread to waiting queue
    280284                insert_last( blocked_threads, *i );
     
    289293
    290294        // helper for wait()'s' with no timeout
    291         void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
     295        static void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
    292296                lock( lock __cfaabi_dbg_ctx2 );
    293297                size_t recursion_count = queue_and_get_recursion(this, &i);
     
    306310
    307311        // helper for wait()'s' with a timeout
    308         void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
     312        static void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    309313                lock( lock __cfaabi_dbg_ctx2 );
    310314                size_t recursion_count = queue_and_get_recursion(this, &info);
     
    337341        bool wait( condition_variable(L) & this, L & l, Duration duration                 ) with(this) { WAIT_TIME( 0   , &l , duration ) }
    338342        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , duration ) }
     343
     344        //-----------------------------------------------------------------------------
     345        // fast_cond_var
     346        void  ?{}( fast_cond_var(L) & this ){
     347                this.blocked_threads{};
     348                #ifdef __CFA_DEBUG__
     349                this.lock_used = 0p;
     350                #endif
     351        }
     352        void ^?{}( fast_cond_var(L) & this ){ }
     353
     354        bool notify_one( fast_cond_var(L) & this ) with(this) {
     355                bool ret = ! blocked_threads`isEmpty;
     356                if ( ret ) {
     357                        info_thread(L) & popped = try_pop_front( blocked_threads );
     358                        on_notify(*popped.lock, popped.t);
     359                }
     360                return ret;
     361        }
     362        bool notify_all( fast_cond_var(L) & this ) with(this) {
     363                bool ret = ! blocked_threads`isEmpty;
     364                while( ! blocked_threads`isEmpty ) {
     365                        info_thread(L) & popped = try_pop_front( blocked_threads );
     366                        on_notify(*popped.lock, popped.t);
     367                }
     368                return ret;
     369        }
     370
     371        uintptr_t front( fast_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty ? NULL : blocked_threads`first.info; }
     372        bool empty ( fast_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty; }
     373
     374        void wait( fast_cond_var(L) & this, L & l ) {
     375                wait( this, l, 0 );
     376        }
     377
     378        void wait( fast_cond_var(L) & this, L & l, uintptr_t info ) with(this) {
     379                // brand cond lock with lock
     380                #ifdef __CFA_DEBUG__
     381                        if ( lock_used == 0p ) lock_used = &l;
     382                        else { assert(lock_used == &l); }
     383                #endif
     384                info_thread( L ) i = { active_thread(), info, &l };
     385                insert_last( blocked_threads, i );
     386                size_t recursion_count = on_wait( *i.lock );
     387                park( );
     388                on_wakeup(*i.lock, recursion_count);
     389        }
    339390}
    340391
  • libcfa/src/concurrency/locks.hfa

    r29d8c02 r74ec742  
    7373static inline void   on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    7474
     75//-----------------------------------------------------------------------------
     76// MCS Lock
    7577struct mcs_node {
    7678        mcs_node * volatile next;
     
    98100}
    99101
     102//-----------------------------------------------------------------------------
     103// Linear backoff Spinlock
    100104struct linear_backoff_then_block_lock {
    101105        // Spin lock used for mutual exclusion
     
    199203
    200204//-----------------------------------------------------------------------------
     205// Fast Block Lock
     206
     207// High efficiency minimal blocking lock
     208// - No reacquire for cond var
     209// - No recursive acquisition
     210// - No ownership
     211struct fast_block_lock {
     212        // Spin lock used for mutual exclusion
     213        __spinlock_t lock;
     214
     215        // List of blocked threads
     216        dlist( thread$ ) blocked_threads;
     217
     218        bool held:1;
     219};
     220
     221static inline void  ?{}( fast_block_lock & this ) with(this) {
     222        lock{};
     223        blocked_threads{};
     224        held = false;
     225}
     226static inline void ^?{}( fast_block_lock & this ) {}
     227static inline void ?{}( fast_block_lock & this, fast_block_lock this2 ) = void;
     228static inline void ?=?( fast_block_lock & this, fast_block_lock this2 ) = void;
     229
     230// if this is called recursively IT WILL DEADLOCK!!!!!
     231static inline void lock(fast_block_lock & this) with(this) {
     232        lock( lock __cfaabi_dbg_ctx2 );
     233        if (held) {
     234                insert_last( blocked_threads, *active_thread() );
     235                unlock( lock );
     236                park( );
     237                return;
     238        }
     239        held = true;
     240        unlock( lock );
     241}
     242
     243static inline void unlock(fast_block_lock & this) with(this) {
     244        lock( lock __cfaabi_dbg_ctx2 );
     245        /* paranoid */ verifyf( held != false, "Attempt to release lock %p that isn't held", &this );
     246        thread$ * t = &try_pop_front( blocked_threads );
     247        held = ( t ? true : false );
     248        unpark( t );
     249        unlock( lock );
     250}
     251
     252static inline void on_notify(fast_block_lock & this, struct thread$ * t ) { unpark(t); }
     253static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; }
     254static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { }
     255
     256//-----------------------------------------------------------------------------
    201257// is_blocking_lock
    202258trait is_blocking_lock(L & | sized(L)) {
     
    226282// Synchronization Locks
    227283forall(L & | is_blocking_lock(L)) {
     284
     285        //-----------------------------------------------------------------------------
     286        // condition_variable
     287
     288        // The multi-tool condition variable
     289        // - can pass timeouts to wait for either a signal or timeout
     290        // - can wait without passing a lock
     291        // - can have waiters reacquire different locks while waiting on the same cond var
     292        // - has shadow queue
     293        // - can be signalled outside of critical sections with no locks held
    228294        struct condition_variable {
    229295                // Spin lock used for mutual exclusion
     
    258324        bool wait( condition_variable(L) & this, L & l, Duration duration );
    259325        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration );
    260 }
     326
     327        //-----------------------------------------------------------------------------
     328        // fast_cond_var
     329
     330        // The trimmed and slim condition variable
     331        // - no internal lock so you must hold a lock while using this cond var
     332        // - signalling without holding branded lock is UNSAFE!
     333        // - only allows usage of one lock, cond var is branded after usage
     334        struct fast_cond_var {
     335                // List of blocked threads
     336                dlist( info_thread(L) ) blocked_threads;
     337
     338                #ifdef __CFA_DEBUG__
     339                L * lock_used;
     340                #endif
     341        };
     342
     343
     344        void  ?{}( fast_cond_var(L) & this );
     345        void ^?{}( fast_cond_var(L) & this );
     346
     347        bool notify_one( fast_cond_var(L) & this );
     348        bool notify_all( fast_cond_var(L) & this );
     349
     350        uintptr_t front( fast_cond_var(L) & this );
     351
     352        bool empty  ( fast_cond_var(L) & this );
     353
     354        void wait( fast_cond_var(L) & this, L & l );
     355        void wait( fast_cond_var(L) & this, L & l, uintptr_t info );
     356}
  • libcfa/src/concurrency/monitor.cfa

    r29d8c02 r74ec742  
    4444static inline void restore( monitor$ * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*in */ recursions [], __waitfor_mask_t /*in */ masks [] );
    4545
     46static inline void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info );
     47static inline void ?{}(__condition_criterion_t & this );
     48static inline void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t * owner );
     49
    4650static inline void init     ( __lock_size_t count, monitor$ * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
    4751static inline void init_push( __lock_size_t count, monitor$ * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
     
    243247
    244248// Leave single monitor
    245 void __leave( monitor$ * this ) {
     249static void __leave( monitor$ * this ) {
    246250        // Lock the monitor spinlock
    247251        lock( this->lock __cfaabi_dbg_ctx2 );
     
    278282
    279283// Leave single monitor for the last time
    280 void __dtor_leave( monitor$ * this, bool join ) {
     284static void __dtor_leave( monitor$ * this, bool join ) {
    281285        __cfaabi_dbg_debug_do(
    282286                if( active_thread() != this->owner ) {
     
    344348// Ctor for monitor guard
    345349// Sorts monitors before entering
    346 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func ) {
     350void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func ) libcfa_public {
    347351        thread$ * thrd = active_thread();
    348352
     
    369373}
    370374
    371 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count ) {
     375void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count ) libcfa_public {
    372376        this{ m, count, 0p };
    373377}
     
    375379
    376380// Dtor for monitor guard
    377 void ^?{}( monitor_guard_t & this ) {
     381void ^?{}( monitor_guard_t & this ) libcfa_public {
    378382        // __cfaabi_dbg_print_safe( "MGUARD : leaving %d\n", this.count);
    379383
     
    389393// Ctor for monitor guard
    390394// Sorts monitors before entering
    391 void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, bool join ) {
     395void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, bool join ) libcfa_public {
    392396        // optimization
    393397        thread$ * thrd = active_thread();
     
    409413
    410414// Dtor for monitor guard
    411 void ^?{}( monitor_dtor_guard_t & this ) {
     415void ^?{}( monitor_dtor_guard_t & this ) libcfa_public {
    412416        // Leave the monitors in order
    413417        __dtor_leave( this.m, this.join );
     
    419423//-----------------------------------------------------------------------------
    420424// Internal scheduling types
    421 void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
     425static void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
    422426        this.waiting_thread = waiting_thread;
    423427        this.count = count;
     
    426430}
    427431
    428 void ?{}(__condition_criterion_t & this ) with( this ) {
     432static void ?{}(__condition_criterion_t & this ) with( this ) {
    429433        ready  = false;
    430434        target = 0p;
     
    433437}
    434438
    435 void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t & owner ) {
     439static void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t & owner ) {
    436440        this.ready  = false;
    437441        this.target = target;
     
    442446//-----------------------------------------------------------------------------
    443447// Internal scheduling
    444 void wait( condition & this, uintptr_t user_info = 0 ) {
     448void wait( condition & this, uintptr_t user_info = 0 ) libcfa_public {
    445449        brand_condition( this );
    446450
     
    496500}
    497501
    498 bool signal( condition & this ) {
     502bool signal( condition & this ) libcfa_public {
    499503        if( is_empty( this ) ) { return false; }
    500504
     
    538542}
    539543
    540 bool signal_block( condition & this ) {
     544bool signal_block( condition & this ) libcfa_public {
    541545        if( !this.blocked.head ) { return false; }
    542546
     
    586590
    587591// Access the user_info of the thread waiting at the front of the queue
    588 uintptr_t front( condition & this ) {
     592uintptr_t front( condition & this ) libcfa_public {
    589593        verifyf( !is_empty(this),
    590594                "Attempt to access user data on an empty condition.\n"
     
    608612//              setup mask
    609613//              block
    610 void __waitfor_internal( const __waitfor_mask_t & mask, int duration ) {
     614void __waitfor_internal( const __waitfor_mask_t & mask, int duration ) libcfa_public {
    611615        // This statment doesn't have a contiguous list of monitors...
    612616        // Create one!
     
    994998// Can't be accepted since a mutex stmt is effectively an anonymous routine
    995999// Thus we do not need a monitor group
    996 void lock( monitor$ * this ) {
     1000void lock( monitor$ * this ) libcfa_public {
    9971001        thread$ * thrd = active_thread();
    9981002
     
    10461050// Leave routine for mutex stmt
    10471051// Is just a wrapper around __leave for the is_lock trait to see
    1048 void unlock( monitor$ * this ) { __leave( this ); }
     1052void unlock( monitor$ * this ) libcfa_public { __leave( this ); }
    10491053
    10501054// Local Variables: //
  • libcfa/src/concurrency/monitor.hfa

    r29d8c02 r74ec742  
    119119}
    120120
    121 void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info );
    122 void ?{}(__condition_criterion_t & this );
    123 void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t * owner );
     121// void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info );
     122// void ?{}(__condition_criterion_t & this );
     123// void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t * owner );
    124124
    125125struct condition {
  • libcfa/src/concurrency/preemption.cfa

    r29d8c02 r74ec742  
    3838#endif
    3939
    40 __attribute__((weak)) Duration default_preemption() {
     40__attribute__((weak)) Duration default_preemption() libcfa_public {
    4141        const char * preempt_rate_s = getenv("CFA_DEFAULT_PREEMPTION");
    4242        if(!preempt_rate_s) {
     
    238238//----------
    239239// special case for preemption since used often
    240 __attribute__((optimize("no-reorder-blocks"))) bool __preemption_enabled() {
     240__attribute__((optimize("no-reorder-blocks"))) bool __preemption_enabled() libcfa_public {
    241241        // create a assembler label before
    242242        // marked as clobber all to avoid movement
     
    276276// Get data from the TLS block
    277277// struct asm_region __cfaasm_get;
    278 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems
     278uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__, visibility("default"))); //no inline to avoid problems
    279279uintptr_t __cfatls_get( unsigned long int offset ) {
    280280        // create a assembler label before
     
    295295extern "C" {
    296296        // Disable interrupts by incrementing the counter
    297         void disable_interrupts() {
     297        __attribute__((__noinline__, visibility("default"))) void disable_interrupts() libcfa_public {
    298298                // create a assembler label before
    299299                // marked as clobber all to avoid movement
     
    326326        // Enable interrupts by decrementing the counter
    327327        // If counter reaches 0, execute any pending __cfactx_switch
    328         void enable_interrupts( bool poll ) {
     328        void enable_interrupts( bool poll ) libcfa_public {
    329329                // Cache the processor now since interrupts can start happening after the atomic store
    330330                processor   * proc = __cfaabi_tls.this_processor;
     
    362362//-----------------------------------------------------------------------------
    363363// Kernel Signal Debug
    364 void __cfaabi_check_preemption() {
     364void __cfaabi_check_preemption() libcfa_public {
    365365        bool ready = __preemption_enabled();
    366366        if(!ready) { abort("Preemption should be ready"); }
  • libcfa/src/concurrency/ready_subqueue.hfa

    r29d8c02 r74ec742  
    8383        /* paranoid */ verify( node->link.ts   != 0  );
    8484        /* paranoid */ verify( this.anchor.ts  != 0  );
     85        /* paranoid */ verify( (this.anchor.ts  == MAX) == is_empty );
    8586        return [node, this.anchor.ts];
    8687}
     
    9394// Return the timestamp
    9495static inline unsigned long long ts(__intrusive_lane_t & this) {
    95         // Cannot verify here since it may not be locked
     96        // Cannot verify 'emptiness' here since it may not be locked
    9697        /* paranoid */ verify(this.anchor.ts != 0);
    9798        return this.anchor.ts;
  • libcfa/src/concurrency/thread.cfa

    r29d8c02 r74ec742  
    2626
    2727extern uint32_t __global_random_seed, __global_random_prime, __global_random_mask;
     28
     29#pragma GCC visibility push(default)
    2830
    2931//-----------------------------------------------------------------------------
  • libcfa/src/containers/maybe.cfa

    r29d8c02 r74ec742  
    1717#include <assert.h>
    1818
     19#pragma GCC visibility push(default)
    1920
    2021forall(T)
  • libcfa/src/containers/result.cfa

    r29d8c02 r74ec742  
    1717#include <assert.h>
    1818
     19#pragma GCC visibility push(default)
    1920
    2021forall(T, E)
  • libcfa/src/containers/string.cfa

    r29d8c02 r74ec742  
    1818#include <stdlib.hfa>
    1919
     20#pragma GCC visibility push(default)
    2021
    2122/*
  • libcfa/src/containers/string_sharectx.hfa

    r29d8c02 r74ec742  
    1616#pragma once
    1717
     18#pragma GCC visibility push(default)
     19
    1820//######################### String Sharing Context #########################
    1921
    2022struct VbyteHeap;
    2123
    22 // A string_sharectx 
     24// A string_sharectx
    2325//
    2426// Usage:
  • libcfa/src/containers/vector.cfa

    r29d8c02 r74ec742  
    1818#include <stdlib.hfa>
    1919
     20#pragma GCC visibility push(default)
     21
    2022forall(T, allocator_t | allocator_c(T, allocator_t))
    21 void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other);
     23static void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other);
    2224
    2325//------------------------------------------------------------------------------
     
    8385
    8486forall(T, allocator_t | allocator_c(T, allocator_t))
    85 void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other)
     87static void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other)
    8688{
    8789        this->size = other->size;
  • libcfa/src/device/cpu.cfa

    r29d8c02 r74ec742  
    3131}
    3232
     33#include "bits/defs.hfa"
    3334#include "algorithms/range_iterator.hfa"
    3435
     
    456457}
    457458
    458 cpu_info_t cpu_info;
     459libcfa_public cpu_info_t cpu_info;
  • libcfa/src/exception.c

    r29d8c02 r74ec742  
    2727#include "stdhdr/assert.h"
    2828#include "virtual.h"
     29
     30#pragma GCC visibility push(default)
     31
    2932#include "lsda.h"
    3033
     
    261264#else // defined( __ARM_ARCH )
    262265        // The return code from _Unwind_RaiseException seems to be corrupt on ARM at end of stack.
    263         // This workaround tries to keep default exception handling working. 
     266        // This workaround tries to keep default exception handling working.
    264267        if ( ret == _URC_FATAL_PHASE1_ERROR || ret == _URC_FATAL_PHASE2_ERROR ) {
    265268#endif
  • libcfa/src/fstream.cfa

    r29d8c02 r74ec742  
    2222#include <assert.h>
    2323#include <errno.h>                                                                              // errno
     24
     25#pragma GCC visibility push(default)
    2426
    2527// *********************************** ofstream ***********************************
     
    118120                // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
    119121        } // if
    120         (os){ file };                                                                           // initialize 
     122        (os){ file };                                                                           // initialize
    121123} // open
    122124
     
    157159        va_list args;
    158160        va_start( args, format );
    159                
     161
    160162        int len;
    161163    for ( cnt; 10 ) {
     
    241243                // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
    242244        } // if
    243         (is){ file };                                                                           // initialize 
     245        (is){ file };                                                                           // initialize
    244246} // open
    245247
  • libcfa/src/fstream.hfa

    r29d8c02 r74ec742  
    1818#include "bits/weakso_locks.hfa"                                                // mutex_lock
    1919#include "iostream.hfa"
    20 #include <exception.hfa>
    2120
    2221
  • libcfa/src/heap.cfa

    r29d8c02 r74ec742  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 25 18:51:36 2022
    13 // Update Count     : 1147
     12// Last Modified On : Fri Apr 29 19:05:03 2022
     13// Update Count     : 1167
    1414//
    1515
     
    3636static bool traceHeap = false;
    3737
    38 inline bool traceHeap() { return traceHeap; }
    39 
    40 bool traceHeapOn() {
     38inline bool traceHeap() libcfa_public { return traceHeap; }
     39
     40bool traceHeapOn() libcfa_public {
    4141        bool temp = traceHeap;
    4242        traceHeap = true;
     
    4444} // traceHeapOn
    4545
    46 bool traceHeapOff() {
     46bool traceHeapOff() libcfa_public {
    4747        bool temp = traceHeap;
    4848        traceHeap = false;
     
    5050} // traceHeapOff
    5151
    52 bool traceHeapTerm() { return false; }
     52bool traceHeapTerm() libcfa_public { return false; }
    5353
    5454
    5555static bool prtFree = false;
    5656
    57 bool prtFree() {
     57static bool prtFree() {
    5858        return prtFree;
    5959} // prtFree
    6060
    61 bool prtFreeOn() {
     61static bool prtFreeOn() {
    6262        bool temp = prtFree;
    6363        prtFree = true;
     
    6565} // prtFreeOn
    6666
    67 bool prtFreeOff() {
     67static bool prtFreeOff() {
    6868        bool temp = prtFree;
    6969        prtFree = false;
     
    8787
    8888
    89 #ifdef __CFA_DEBUG__
    90 static size_t allocUnfreed;                                                             // running total of allocations minus frees
    91 
    92 static void prtUnfreed() {
    93         if ( allocUnfreed != 0 ) {
    94                 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    95                 char helpText[512];
    96                 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n"
    97                                                         "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    98                                                         (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid
    99                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    100         } // if
    101 } // prtUnfreed
    102 
    103 extern int cfa_main_returned;                                                   // from interpose.cfa
    104 extern "C" {
    105         void heapAppStart() {                                                           // called by __cfaabi_appready_startup
    106                 allocUnfreed = 0;
    107         } // heapAppStart
    108 
    109         void heapAppStop() {                                                            // called by __cfaabi_appready_startdown
    110                 fclose( stdin ); fclose( stdout );
    111                 if ( cfa_main_returned ) prtUnfreed();                  // do not check unfreed storage if exit called
    112         } // heapAppStop
    113 } // extern "C"
    114 #endif // __CFA_DEBUG__
    115 
    116 
    117 // statically allocated variables => zero filled.
    118 static size_t heapExpand;                                                               // sbrk advance
    119 static size_t mmapStart;                                                                // cross over point for mmap
    120 static unsigned int maxBucketsUsed;                                             // maximum number of buckets in use
    121 // extern visibility, used by runtime kernel
    122 size_t __page_size;                                                                             // architecture pagesize
    123 int __map_prot;                                                                                 // common mmap/mprotect protection
    124 
    125 
    126 #define SPINLOCK 0
    127 #define LOCKFREE 1
    128 #define BUCKETLOCK SPINLOCK
    129 #if BUCKETLOCK == SPINLOCK
    130 #elif BUCKETLOCK == LOCKFREE
    131 #include <stackLockFree.hfa>
    132 #else
    133         #error undefined lock type for bucket lock
    134 #endif // LOCKFREE
    135 
    136 // Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage.
    137 // Break recursion by hardcoding number of buckets and statically checking number is correct after bucket array defined.
    138 enum { NoBucketSizes = 91 };                                                    // number of buckets sizes
    139 
    140 struct Heap {
    141         struct Storage {
    142                 struct Header {                                                                 // header
    143                         union Kind {
    144                                 struct RealHeader {
    145                                         union {
    146                                                 struct {                                                // 4-byte word => 8-byte header, 8-byte word => 16-byte header
    147                                                         union {
    148                                                                 // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped
    149                                                                 // FreeHeader * home;           // allocated block points back to home locations (must overlay alignment)
    150                                                                 void * home;                    // allocated block points back to home locations (must overlay alignment)
    151                                                                 size_t blockSize;               // size for munmap (must overlay alignment)
    152                                                                 #if BUCKETLOCK == SPINLOCK
    153                                                                 Storage * next;                 // freed block points to next freed block of same size
    154                                                                 #endif // SPINLOCK
    155                                                         };
    156                                                         size_t size;                            // allocation size in bytes
    157                                                 };
    158                                                 #if BUCKETLOCK == LOCKFREE
    159                                                 Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
    160                                                 #endif // LOCKFREE
    161                                         };
    162                                 } real; // RealHeader
    163 
    164                                 struct FakeHeader {
    165                                         uintptr_t alignment;                            // 1st low-order bit => fake header & alignment
    166                                         uintptr_t offset;
    167                                 } fake; // FakeHeader
    168                         } kind; // Kind
    169                 } header; // Header
    170 
    171                 char pad[libAlign() - sizeof( Header )];
    172                 char data[0];                                                                   // storage
    173         }; // Storage
    174 
    175         static_assert( libAlign() >= sizeof( Storage ), "minimum alignment < sizeof( Storage )" );
    176 
    177         struct FreeHeader {
    178                 #if BUCKETLOCK == SPINLOCK
    179                 __spinlock_t lock;                                                              // must be first field for alignment
    180                 Storage * freeList;
    181                 #else
    182                 StackLF(Storage) freeList;
    183                 #endif // BUCKETLOCK
    184                 size_t blockSize;                                                               // size of allocations on this list
    185         }; // FreeHeader
    186 
    187         // must be first fields for alignment
    188         __spinlock_t extlock;                                                           // protects allocation-buffer extension
    189         FreeHeader freeLists[NoBucketSizes];                            // buckets for different allocation sizes
    190 
    191         void * heapBegin;                                                                       // start of heap
    192         void * heapEnd;                                                                         // logical end of heap
    193         size_t heapRemaining;                                                           // amount of storage not allocated in the current chunk
    194 }; // Heap
    195 
    196 #if BUCKETLOCK == LOCKFREE
    197 static inline {
    198         Link(Heap.Storage) * ?`next( Heap.Storage * this ) { return &this->header.kind.real.next; }
    199         void ?{}( Heap.FreeHeader & ) {}
    200         void ^?{}( Heap.FreeHeader & ) {}
    201 } // distribution
    202 #endif // LOCKFREE
    203 
    204 static inline size_t getKey( const Heap.FreeHeader & freeheader ) { return freeheader.blockSize; }
    205 
    206 
    207 #ifdef FASTLOOKUP
    208 enum { LookupSizes = 65_536 + sizeof(Heap.Storage) }; // number of fast lookup sizes
    209 static unsigned char lookup[LookupSizes];                               // O(1) lookup for small sizes
    210 #endif // FASTLOOKUP
    211 
    212 static const off_t mmapFd = -1;                                                 // fake or actual fd for anonymous file
    213 #ifdef __CFA_DEBUG__
    214 static bool heapBoot = 0;                                                               // detect recursion during boot
    215 #endif // __CFA_DEBUG__
    216 
    217 
    218 // Size of array must harmonize with NoBucketSizes and individual bucket sizes must be multiple of 16.
    219 // Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size.
    220 // malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed.
    221 static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    222         16 + sizeof(Heap.Storage), 32 + sizeof(Heap.Storage), 48 + sizeof(Heap.Storage), 64 + sizeof(Heap.Storage), // 4
    223         96 + sizeof(Heap.Storage), 112 + sizeof(Heap.Storage), 128 + sizeof(Heap.Storage), // 3
    224         160, 192, 224, 256 + sizeof(Heap.Storage), // 4
    225         320, 384, 448, 512 + sizeof(Heap.Storage), // 4
    226         640, 768, 896, 1_024 + sizeof(Heap.Storage), // 4
    227         1_536, 2_048 + sizeof(Heap.Storage), // 2
    228         2_560, 3_072, 3_584, 4_096 + sizeof(Heap.Storage), // 4
    229         6_144, 8_192 + sizeof(Heap.Storage), // 2
    230         9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 16_384 + sizeof(Heap.Storage), // 8
    231         18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 32_768 + sizeof(Heap.Storage), // 8
    232         36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 65_536 + sizeof(Heap.Storage), // 8
    233         73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 131_072 + sizeof(Heap.Storage), // 8
    234         147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 262_144 + sizeof(Heap.Storage), // 8
    235         294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 524_288 + sizeof(Heap.Storage), // 8
    236         655_360, 786_432, 917_504, 1_048_576 + sizeof(Heap.Storage), // 4
    237         1_179_648, 1_310_720, 1_441_792, 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(Heap.Storage), // 8
    238         2_621_440, 3_145_728, 3_670_016, 4_194_304 + sizeof(Heap.Storage), // 4
    239 };
    240 
    241 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" );
    242 
    243 // The constructor for heapManager is called explicitly in memory_startup.
    244 static Heap heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    245 
    246 
    247 //####################### Memory Allocation Routines Helpers ####################
     89//####################### Heap Statistics ####################
    24890
    24991
     
    307149        return lhs;
    308150} // ?+=?
    309 
     151#endif // __STATISTICS__
     152
     153
     154#define SPINLOCK 0
     155#define LOCKFREE 1
     156#define BUCKETLOCK SPINLOCK
     157#if BUCKETLOCK == SPINLOCK
     158#elif BUCKETLOCK == LOCKFREE
     159#include <stackLockFree.hfa>
     160#else
     161        #error undefined lock type for bucket lock
     162#endif // LOCKFREE
     163
     164// Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage.
     165// Break recursion by hardcoding number of buckets and statically checking number is correct after bucket array defined.
     166enum { NoBucketSizes = 91 };                                                    // number of buckets sizes
     167
     168struct Heap {
     169        struct Storage {
     170                struct Header {                                                                 // header
     171                        union Kind {
     172                                struct RealHeader {
     173                                        union {
     174                                                struct {                                                // 4-byte word => 8-byte header, 8-byte word => 16-byte header
     175                                                        union {
     176                                                                // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped
     177                                                                // FreeHeader * home;           // allocated block points back to home locations (must overlay alignment)
     178                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
     179                                                                size_t blockSize;               // size for munmap (must overlay alignment)
     180                                                                #if BUCKETLOCK == SPINLOCK
     181                                                                Storage * next;                 // freed block points to next freed block of same size
     182                                                                #endif // SPINLOCK
     183                                                        };
     184                                                        size_t size;                            // allocation size in bytes
     185                                                };
     186                                                #if BUCKETLOCK == LOCKFREE
     187                                                Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
     188                                                #endif // LOCKFREE
     189                                        };
     190                                } real; // RealHeader
     191
     192                                struct FakeHeader {
     193                                        uintptr_t alignment;                            // 1st low-order bit => fake header & alignment
     194                                        uintptr_t offset;
     195                                } fake; // FakeHeader
     196                        } kind; // Kind
     197                } header; // Header
     198
     199                char pad[libAlign() - sizeof( Header )];
     200                char data[0];                                                                   // storage
     201        }; // Storage
     202
     203        static_assert( libAlign() >= sizeof( Storage ), "minimum alignment < sizeof( Storage )" );
     204
     205        struct FreeHeader {
     206                size_t blockSize __attribute__(( aligned (8) )); // size of allocations on this list
     207                #if BUCKETLOCK == SPINLOCK
     208                __spinlock_t lock;
     209                Storage * freeList;
     210                #else
     211                StackLF(Storage) freeList;
     212                #endif // BUCKETLOCK
     213        } __attribute__(( aligned (8) )); // FreeHeader
     214
     215        FreeHeader freeLists[NoBucketSizes];                            // buckets for different allocation sizes
     216
     217        __spinlock_t extlock;                                                           // protects allocation-buffer extension
     218        void * heapBegin;                                                                       // start of heap
     219        void * heapEnd;                                                                         // logical end of heap
     220        size_t heapRemaining;                                                           // amount of storage not allocated in the current chunk
     221}; // Heap
     222
     223#if BUCKETLOCK == LOCKFREE
     224static inline {
     225        Link(Heap.Storage) * ?`next( Heap.Storage * this ) { return &this->header.kind.real.next; }
     226        void ?{}( Heap.FreeHeader & ) {}
     227        void ^?{}( Heap.FreeHeader & ) {}
     228} // distribution
     229#endif // LOCKFREE
     230
     231static inline size_t getKey( const Heap.FreeHeader & freeheader ) { return freeheader.blockSize; }
     232
     233
     234#ifdef FASTLOOKUP
     235enum { LookupSizes = 65_536 + sizeof(Heap.Storage) }; // number of fast lookup sizes
     236static unsigned char lookup[LookupSizes];                               // O(1) lookup for small sizes
     237#endif // FASTLOOKUP
     238
     239static const off_t mmapFd = -1;                                                 // fake or actual fd for anonymous file
     240#ifdef __CFA_DEBUG__
     241static bool heapBoot = 0;                                                               // detect recursion during boot
     242#endif // __CFA_DEBUG__
     243
     244
     245// Size of array must harmonize with NoBucketSizes and individual bucket sizes must be multiple of 16.
     246// Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size.
     247// malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed.
     248static const unsigned int bucketSizes[] @= {                    // different bucket sizes
     249        16 + sizeof(Heap.Storage), 32 + sizeof(Heap.Storage), 48 + sizeof(Heap.Storage), 64 + sizeof(Heap.Storage), // 4
     250        96 + sizeof(Heap.Storage), 112 + sizeof(Heap.Storage), 128 + sizeof(Heap.Storage), // 3
     251        160, 192, 224, 256 + sizeof(Heap.Storage), // 4
     252        320, 384, 448, 512 + sizeof(Heap.Storage), // 4
     253        640, 768, 896, 1_024 + sizeof(Heap.Storage), // 4
     254        1_536, 2_048 + sizeof(Heap.Storage), // 2
     255        2_560, 3_072, 3_584, 4_096 + sizeof(Heap.Storage), // 4
     256        6_144, 8_192 + sizeof(Heap.Storage), // 2
     257        9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 16_384 + sizeof(Heap.Storage), // 8
     258        18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 32_768 + sizeof(Heap.Storage), // 8
     259        36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 65_536 + sizeof(Heap.Storage), // 8
     260        73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 131_072 + sizeof(Heap.Storage), // 8
     261        147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 262_144 + sizeof(Heap.Storage), // 8
     262        294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 524_288 + sizeof(Heap.Storage), // 8
     263        655_360, 786_432, 917_504, 1_048_576 + sizeof(Heap.Storage), // 4
     264        1_179_648, 1_310_720, 1_441_792, 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(Heap.Storage), // 8
     265        2_621_440, 3_145_728, 3_670_016, 4_194_304 + sizeof(Heap.Storage), // 4
     266};
     267
     268static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" );
     269
     270// The constructor for heapManager is called explicitly in memory_startup.
     271static Heap heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
     272
     273
     274//####################### Memory Allocation Routines Helpers ####################
     275
     276
     277#ifdef __CFA_DEBUG__
     278static size_t allocUnfreed;                                                             // running total of allocations minus frees
     279
     280static void prtUnfreed() {
     281        if ( allocUnfreed != 0 ) {
     282                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
     283                char helpText[512];
     284                __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
     285                                                                        "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n"
     286                                                                        "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
     287                                                                        (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid
     288        } // if
     289} // prtUnfreed
     290
     291extern int cfa_main_returned;                                                   // from interpose.cfa
     292extern "C" {
     293        void heapAppStart() {                                                           // called by __cfaabi_appready_startup
     294                allocUnfreed = 0;
     295        } // heapAppStart
     296
     297        void heapAppStop() {                                                            // called by __cfaabi_appready_startdown
     298                fclose( stdin ); fclose( stdout );
     299                if ( cfa_main_returned ) prtUnfreed();                  // do not check unfreed storage if exit called
     300        } // heapAppStop
     301} // extern "C"
     302#endif // __CFA_DEBUG__
     303
     304
     305#ifdef __STATISTICS__
    310306static HeapStatistics stats;                                                    // zero filled
    311307static unsigned int sbrk_calls;
     
    387383
    388384
     385// statically allocated variables => zero filled.
     386static size_t heapExpand;                                                               // sbrk advance
     387static size_t mmapStart;                                                                // cross over point for mmap
     388static unsigned int maxBucketsUsed;                                             // maximum number of buckets in use
     389// extern visibility, used by runtime kernel
     390// would be cool to remove libcfa_public but it's needed for libcfathread
     391libcfa_public size_t __page_size;                                                       // architecture pagesize
     392libcfa_public int __map_prot;                                                           // common mmap/mprotect protection
     393
     394
    389395// thunk problem
    390396size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) {
     
    490496        } else {
    491497                fakeHeader( header, alignment );
    492                 if ( unlikely( MmappedBit( header ) ) ) {
    493                         assert( addr < heapBegin || heapEnd < addr );
     498                if ( unlikely( MmappedBit( header ) ) ) {               // mmapped ?
     499                        verify( addr < heapBegin || heapEnd < addr );
    494500                        size = ClearStickyBits( header->kind.real.blockSize ); // mmap size
    495501                        return true;
     
    503509        checkHeader( header < (Heap.Storage.Header *)heapBegin || (Heap.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -)
    504510
    505         if ( freeHead < &freeLists[0] || &freeLists[NoBucketSizes] <= freeHead ) {
    506                 abort( "Attempt to %s storage %p with corrupted header.\n"
    507                            "Possible cause is duplicate free on same block or overwriting of header information.",
    508                            name, addr );
    509         } // if
     511        Heap * homeManager;
     512        if ( unlikely( freeHead == 0p || // freed and only free-list node => null link
     513                                   // freed and link points at another free block not to a bucket in the bucket array.
     514                                   freeHead < &freeLists[0] || &freeLists[NoBucketSizes] <= freeHead ) ) {
     515                abort( "**** Error **** attempt to %s storage %p with corrupted header.\n"
     516                           "Possible cause is duplicate free on same block or overwriting of header information.",
     517                           name, addr );
     518        } // if
    510519        #endif // __CFA_DEBUG__
    511520
     
    560569                sbrk_storage += increase;
    561570                #endif // __STATISTICS__
     571
    562572                #ifdef __CFA_DEBUG__
    563573                // Set new memory to garbage so subsequent uninitialized usages might fail.
     
    565575                //Memset( (char *)heapEnd + heapRemaining, increase );
    566576                #endif // __CFA_DEBUG__
     577
    567578                rem = heapRemaining + increase - size;
    568579        } // if
     
    651662        __atomic_add_fetch( &allocUnfreed, tsize, __ATOMIC_SEQ_CST );
    652663        if ( traceHeap() ) {
    653                 enum { BufferSize = 64 };
    654                 char helpText[BufferSize];
    655                 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize );
    656                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     664                char helpText[64];
     665                __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
     666                                                                        "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize ); // print debug/nodebug
    657667        } // if
    658668        #endif // __CFA_DEBUG__
     
    711721        if ( traceHeap() ) {
    712722                char helpText[64];
    713                 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    714                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     723                __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
     724                                                                        "Free( %p ) size:%zu\n", addr, size ); // print debug/nodebug
    715725        } // if
    716726        #endif // __CFA_DEBUG__
     
    718728
    719729
    720 size_t prtFree( Heap & manager ) with( manager ) {
     730static size_t prtFree( Heap & manager ) with( manager ) {
    721731        size_t total = 0;
    722732        #ifdef __STATISTICS__
     
    870880        // Allocates size bytes and returns a pointer to the allocated memory.  The contents are undefined. If size is 0,
    871881        // then malloc() returns a unique pointer value that can later be successfully passed to free().
    872         void * malloc( size_t size ) {
     882        void * malloc( size_t size ) libcfa_public {
    873883                #ifdef __STATISTICS__
    874884                if ( likely( size > 0 ) ) {
     
    885895
    886896        // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes.
    887         void * aalloc( size_t dim, size_t elemSize ) {
     897        void * aalloc( size_t dim, size_t elemSize ) libcfa_public {
    888898                size_t size = dim * elemSize;
    889899                #ifdef __STATISTICS__
     
    901911
    902912        // Same as aalloc() with memory set to zero.
    903         void * calloc( size_t dim, size_t elemSize ) {
     913        void * calloc( size_t dim, size_t elemSize ) libcfa_public {
    904914                size_t size = dim * elemSize;
    905915          if ( unlikely( size ) == 0 ) {                        // 0 BYTE ALLOCATION RETURNS NULL POINTER
     
    942952        // not 0p, then the call is equivalent to free(oaddr). Unless oaddr is 0p, it must have been returned by an earlier
    943953        // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
    944         void * resize( void * oaddr, size_t size ) {
     954        void * resize( void * oaddr, size_t size ) libcfa_public {
    945955                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    946956          if ( unlikely( size == 0 ) ) {                                        // special cases
     
    987997        // Same as resize() but the contents are unchanged in the range from the start of the region up to the minimum of
    988998        // the old and new sizes.
    989         void * realloc( void * oaddr, size_t size ) {
     999        void * realloc( void * oaddr, size_t size ) libcfa_public {
    9901000                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    9911001          if ( unlikely( size == 0 ) ) {                                        // special cases
     
    10511061
    10521062        // Same as realloc() except the new allocation size is large enough for an array of nelem elements of size elsize.
    1053         void * reallocarray( void * oaddr, size_t dim, size_t elemSize ) {
     1063        void * reallocarray( void * oaddr, size_t dim, size_t elemSize ) libcfa_public {
    10541064                return realloc( oaddr, dim * elemSize );
    10551065        } // reallocarray
     
    10571067
    10581068        // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete)
    1059         void * memalign( size_t alignment, size_t size ) {
     1069        void * memalign( size_t alignment, size_t size ) libcfa_public {
    10601070                #ifdef __STATISTICS__
    10611071                if ( likely( size > 0 ) ) {
     
    10721082
    10731083        // Same as aalloc() with memory alignment.
    1074         void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
     1084        void * amemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public {
    10751085                size_t size = dim * elemSize;
    10761086                #ifdef __STATISTICS__
     
    10881098
    10891099        // Same as calloc() with memory alignment.
    1090         void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) {
     1100        void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public {
    10911101                size_t size = dim * elemSize;
    10921102          if ( unlikely( size ) == 0 ) {                                        // 0 BYTE ALLOCATION RETURNS NULL POINTER
     
    11271137        // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
    11281138        // of alignment. This requirement is universally ignored.
    1129         void * aligned_alloc( size_t alignment, size_t size ) {
     1139        void * aligned_alloc( size_t alignment, size_t size ) libcfa_public {
    11301140                return memalign( alignment, size );
    11311141        } // aligned_alloc
     
    11361146        // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to
    11371147        // free(3).
    1138         int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
     1148        int posix_memalign( void ** memptr, size_t alignment, size_t size ) libcfa_public {
    11391149          if ( unlikely( alignment < libAlign() || ! is_pow2( alignment ) ) ) return EINVAL; // check alignment
    11401150                *memptr = memalign( alignment, size );
     
    11451155        // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the
    11461156        // page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
    1147         void * valloc( size_t size ) {
     1157        void * valloc( size_t size ) libcfa_public {
    11481158                return memalign( __page_size, size );
    11491159        } // valloc
     
    11511161
    11521162        // Same as valloc but rounds size to multiple of page size.
    1153         void * pvalloc( size_t size ) {
     1163        void * pvalloc( size_t size ) libcfa_public {
    11541164                return memalign( __page_size, ceiling2( size, __page_size ) ); // round size to multiple of page size
    11551165        } // pvalloc
     
    11591169        // or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is
    11601170        // 0p, no operation is performed.
    1161         void free( void * addr ) {
     1171        void free( void * addr ) libcfa_public {
    11621172          if ( unlikely( addr == 0p ) ) {                                       // special case
    11631173                        #ifdef __STATISTICS__
     
    11801190
    11811191        // Returns the alignment of an allocation.
    1182         size_t malloc_alignment( void * addr ) {
     1192        size_t malloc_alignment( void * addr ) libcfa_public {
    11831193          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
    11841194                Heap.Storage.Header * header = HeaderAddr( addr );
     
    11921202
    11931203        // Returns true if the allocation is zero filled, e.g., allocated by calloc().
    1194         bool malloc_zero_fill( void * addr ) {
     1204        bool malloc_zero_fill( void * addr ) libcfa_public {
    11951205          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    11961206                Heap.Storage.Header * header = HeaderAddr( addr );
     
    12031213
    12041214        // Returns original total allocation size (not bucket size) => array size is dimension * sizeof(T).
    1205         size_t malloc_size( void * addr ) {
     1215        size_t malloc_size( void * addr ) libcfa_public {
    12061216          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has zero size
    12071217                Heap.Storage.Header * header = HeaderAddr( addr );
     
    12151225        // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by
    12161226        // malloc or a related function.
    1217         size_t malloc_usable_size( void * addr ) {
     1227        size_t malloc_usable_size( void * addr ) libcfa_public {
    12181228          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    12191229                Heap.Storage.Header * header;
     
    12271237
    12281238        // Prints (on default standard error) statistics about memory allocated by malloc and related functions.
    1229         void malloc_stats( void ) {
     1239        void malloc_stats( void ) libcfa_public {
    12301240                #ifdef __STATISTICS__
    12311241                printStats();
     
    12361246
    12371247        // Changes the file descriptor where malloc_stats() writes statistics.
    1238         int malloc_stats_fd( int fd __attribute__(( unused )) ) {
     1248        int malloc_stats_fd( int fd __attribute__(( unused )) ) libcfa_public {
    12391249                #ifdef __STATISTICS__
    12401250                int temp = stats_fd;
     
    12501260        // The string is printed on the file stream stream.  The exported string includes information about all arenas (see
    12511261        // malloc).
    1252         int malloc_info( int options, FILE * stream __attribute__(( unused )) ) {
     1262        int malloc_info( int options, FILE * stream __attribute__(( unused )) ) libcfa_public {
    12531263          if ( options != 0 ) { errno = EINVAL; return -1; }
    12541264                #ifdef __STATISTICS__
     
    12621272        // Adjusts parameters that control the behaviour of the memory-allocation functions (see malloc). The param argument
    12631273        // specifies the parameter to be modified, and value specifies the new value for that parameter.
    1264         int mallopt( int option, int value ) {
     1274        int mallopt( int option, int value ) libcfa_public {
    12651275          if ( value < 0 ) return 0;
    12661276                choose( option ) {
     
    12761286
    12771287        // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument).
    1278         int malloc_trim( size_t ) {
     1288        int malloc_trim( size_t ) libcfa_public {
    12791289                return 0;                                                                               // => impossible to release memory
    12801290        } // malloc_trim
     
    12851295        // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function
    12861296        // result.  (The caller must free this memory.)
    1287         void * malloc_get_state( void ) {
     1297        void * malloc_get_state( void ) libcfa_public {
    12881298                return 0p;                                                                              // unsupported
    12891299        } // malloc_get_state
     
    12921302        // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
    12931303        // structure pointed to by state.
    1294         int malloc_set_state( void * ) {
     1304        int malloc_set_state( void * ) libcfa_public {
    12951305                return 0;                                                                               // unsupported
    12961306        } // malloc_set_state
     
    12981308
    12991309        // Sets the amount (bytes) to extend the heap when there is insufficent free storage to service an allocation.
    1300         __attribute__((weak)) size_t malloc_expansion() { return __CFA_DEFAULT_HEAP_EXPANSION__; }
     1310        __attribute__((weak)) size_t malloc_expansion() libcfa_public { return __CFA_DEFAULT_HEAP_EXPANSION__; }
    13011311
    13021312        // Sets the crossover point between allocations occuring in the sbrk area or separately mmapped.
    1303         __attribute__((weak)) size_t malloc_mmap_start() { return __CFA_DEFAULT_MMAP_START__; }
     1313        __attribute__((weak)) size_t malloc_mmap_start() libcfa_public { return __CFA_DEFAULT_MMAP_START__; }
    13041314
    13051315        // Amount subtracted to adjust for unfreed program storage (debug only).
    1306         __attribute__((weak)) size_t malloc_unfreed() { return __CFA_DEFAULT_HEAP_UNFREED__; }
     1316        __attribute__((weak)) size_t malloc_unfreed() libcfa_public { return __CFA_DEFAULT_HEAP_UNFREED__; }
    13071317} // extern "C"
    13081318
    13091319
    13101320// Must have CFA linkage to overload with C linkage realloc.
    1311 void * resize( void * oaddr, size_t nalign, size_t size ) {
     1321void * resize( void * oaddr, size_t nalign, size_t size ) libcfa_public {
    13121322        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    13131323  if ( unlikely( size == 0 ) ) {                                                // special cases
     
    13711381
    13721382
    1373 void * realloc( void * oaddr, size_t nalign, size_t size ) {
     1383void * realloc( void * oaddr, size_t nalign, size_t size ) libcfa_public {
    13741384        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    13751385  if ( unlikely( size == 0 ) ) {                                                // special cases
  • libcfa/src/interpose.cfa

    r29d8c02 r74ec742  
    3636//=============================================================================================
    3737
    38 void preload_libgcc(void) {
     38static void preload_libgcc(void) {
    3939        dlopen( "libgcc_s.so.1", RTLD_NOW );
    4040        if ( const char * error = dlerror() ) abort( "interpose_symbol : internal error pre-loading libgcc, %s\n", error );
     
    4242
    4343typedef void (* generic_fptr_t)(void);
    44 generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
     44static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
    4545        const char * error;
    4646
     
    8383//=============================================================================================
    8484
    85 void sigHandler_segv( __CFA_SIGPARMS__ );
    86 void sigHandler_ill ( __CFA_SIGPARMS__ );
    87 void sigHandler_fpe ( __CFA_SIGPARMS__ );
    88 void sigHandler_abrt( __CFA_SIGPARMS__ );
    89 void sigHandler_term( __CFA_SIGPARMS__ );
    90 
    91 struct {
     85static void sigHandler_segv( __CFA_SIGPARMS__ );
     86static void sigHandler_ill ( __CFA_SIGPARMS__ );
     87static void sigHandler_fpe ( __CFA_SIGPARMS__ );
     88static void sigHandler_abrt( __CFA_SIGPARMS__ );
     89static void sigHandler_term( __CFA_SIGPARMS__ );
     90
     91static struct {
    9292        void (* exit)( int ) __attribute__(( __noreturn__ ));
    9393        void (* abort)( void ) __attribute__(( __noreturn__ ));
    9494} __cabi_libc;
    9595
    96 int cfa_main_returned;
     96libcfa_public int cfa_main_returned;
    9797
    9898extern "C" {
     
    148148
    149149// Forward declare abort after the __typeof__ call to avoid ambiguities
    150 void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
    151 void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
    152 void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
    153 void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ ));
     150libcfa_public void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
     151libcfa_public void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
     152libcfa_public void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
     153libcfa_public void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ ));
    154154
    155155extern "C" {
    156         void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
     156        libcfa_public void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
    157157                abort( false, "%s", "" );
    158158        }
    159159
    160         void __cabi_abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) {
     160        libcfa_public void __cabi_abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) {
    161161                va_list argp;
    162162                va_start( argp, fmt );
     
    165165        }
    166166
    167         void exit( int status ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
     167        libcfa_public void exit( int status ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
    168168                __cabi_libc.exit( status );
    169169        }
  • libcfa/src/iostream.cfa

    r29d8c02 r74ec742  
    3232#include "bitmanip.hfa"                                                                 // high1
    3333
     34#pragma GCC visibility push(default)
    3435
    3536// *********************************** ostream ***********************************
  • libcfa/src/limits.cfa

    r29d8c02 r74ec742  
    2020#include <complex.h>
    2121#include "limits.hfa"
     22
     23#pragma GCC visibility push(default)
    2224
    2325// Integral Constants
  • libcfa/src/memory.cfa

    r29d8c02 r74ec742  
    1616#include "memory.hfa"
    1717#include "stdlib.hfa"
     18
     19#pragma GCC visibility push(default)
    1820
    1921// Internal data object.
  • libcfa/src/parseargs.cfa

    r29d8c02 r74ec742  
    2424#include "common.hfa"
    2525#include "limits.hfa"
     26
     27#pragma GCC visibility push(default)
    2628
    2729extern int cfa_args_argc __attribute__((weak));
     
    208210        }
    209211
     212        if(strcmp(arg, "Y") == 0) {
     213                value = true;
     214                return true;
     215        }
     216
     217        if(strcmp(arg, "y") == 0) {
     218                value = true;
     219                return true;
     220        }
     221
    210222        if(strcmp(arg, "no") == 0) {
     223                value = false;
     224                return true;
     225        }
     226
     227        if(strcmp(arg, "N") == 0) {
     228                value = false;
     229                return true;
     230        }
     231
     232        if(strcmp(arg, "n") == 0) {
    211233                value = false;
    212234                return true;
  • libcfa/src/parseconfig.cfa

    r29d8c02 r74ec742  
    1414
    1515
     16#pragma GCC visibility push(default)
     17
    1618// *********************************** exceptions ***********************************
    1719
    1820
    1921// TODO: Add names of missing config entries to exception (see further below)
    20 static vtable(Missing_Config_Entries) Missing_Config_Entries_vt;
     22vtable(Missing_Config_Entries) Missing_Config_Entries_vt;
    2123
    2224[ void ] ?{}( & Missing_Config_Entries this, unsigned int num_missing ) {
     
    3133
    3234
    33 static vtable(Parse_Failure) Parse_Failure_vt;
     35vtable(Parse_Failure) Parse_Failure_vt;
    3436
    3537[ void ] ?{}( & Parse_Failure this, [] char failed_key, [] char failed_value ) {
     
    5355
    5456
    55 static vtable(Validation_Failure) Validation_Failure_vt;
     57vtable(Validation_Failure) Validation_Failure_vt;
    5658
    5759[ void ] ?{}( & Validation_Failure this, [] char failed_key, [] char failed_value ) {
     
    110112
    111113
    112 [ bool ] comments( & ifstream in, [] char name ) {
     114static [ bool ] comments( & ifstream in, [] char name ) {
    113115        while () {
    114116                in | name;
  • libcfa/src/rational.cfa

    r29d8c02 r74ec742  
    1717#include "fstream.hfa"
    1818#include "stdlib.hfa"
     19
     20#pragma GCC visibility push(default)
    1921
    2022forall( T | Arithmetic( T ) ) {
  • libcfa/src/startup.cfa

    r29d8c02 r74ec742  
    4141        } // __cfaabi_appready_shutdown
    4242
    43         void disable_interrupts() __attribute__(( weak )) {}
    44         void enable_interrupts() __attribute__(( weak )) {}
     43        void disable_interrupts() __attribute__(( weak )) libcfa_public {}
     44        void enable_interrupts() __attribute__(( weak )) libcfa_public {}
    4545
    4646
     
    6464struct __spinlock_t;
    6565extern "C" {
    66         void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) {}
     66        void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) libcfa_public {}
    6767}
    6868
  • libcfa/src/stdlib.cfa

    r29d8c02 r74ec742  
    2525#include <complex.h>                                                                    // _Complex_I
    2626#include <assert.h>
     27
     28#pragma GCC visibility push(default)
    2729
    2830//---------------------------------------
     
    225227#define GENERATOR LCG
    226228
    227 uint32_t __global_random_seed;                                                  // sequential/concurrent
    228 uint32_t __global_random_state;                                                 // sequential only
     229// would be cool to make hidden but it's needed for libcfathread
     230__attribute__((visibility("default"))) uint32_t __global_random_seed;                                                   // sequential/concurrent
     231__attribute__((visibility("hidden"))) uint32_t __global_random_state;                                                   // sequential only
    229232
    230233void set_seed( PRNG & prng, uint32_t seed_ ) with( prng ) { state = seed = seed_; GENERATOR( state ); } // set seed
  • libcfa/src/strstream.cfa

    r29d8c02 r74ec742  
    1 // 
     1//
    22// Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
    3 // 
     3//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // strstream.cfa -- 
    8 // 
     7// strstream.cfa --
     8//
    99// Author           : Peter A. Buhr
    1010// Created On       : Thu Apr 22 22:24:35 2021
     
    1212// Last Modified On : Sun Oct 10 16:13:20 2021
    1313// Update Count     : 101
    14 // 
     14//
    1515
    1616#include "strstream.hfa"
     
    2424#include <unistd.h>                                                                             // sbrk, sysconf
    2525
     26#pragma GCC visibility push(default)
    2627
    2728// *********************************** strstream ***********************************
  • libcfa/src/time.cfa

    r29d8c02 r74ec742  
    1818#include <stdio.h>                                                                              // snprintf
    1919#include <assert.h>
     20
     21#pragma GCC visibility push(default)
    2022
    2123static char * nanomsd( long int ns, char * buf ) {              // most significant digits
  • libcfa/src/virtual.c

    r29d8c02 r74ec742  
    1616#include "virtual.h"
    1717#include "assert.h"
     18
     19#pragma GCC visibility push(default)
    1820
    1921int __cfavir_is_parent(
  • src/AST/Convert.cpp

    r29d8c02 r74ec742  
    9393        };
    9494
    95     template<typename T>
    96     Getter<T> get() {
    97         return Getter<T>{ *this };
    98     }
     95        template<typename T>
     96        Getter<T> get() {
     97                return Getter<T>{ *this };
     98        }
    9999
    100100        Label makeLabel(Statement * labelled, const ast::Label& label) {
     
    16511651                        // GET_ACCEPT_1(type, FunctionType),
    16521652                        std::move(forall),
     1653                        std::move(assertions),
    16531654                        std::move(paramVars),
    16541655                        std::move(returnVars),
     
    16641665                cache.emplace( old, decl );
    16651666
    1666                 decl->assertions = std::move(assertions);
    16671667                decl->withExprs = GET_ACCEPT_V(withExprs, Expr);
    16681668                decl->stmts = GET_ACCEPT_1(statements, CompoundStmt);
     
    17301730        }
    17311731
    1732         // Convert SynTree::EnumDecl to AST::EnumDecl
     1732
    17331733        virtual void visit( const EnumDecl * old ) override final {
    17341734                if ( inCache( old ) ) return;
     
    27292729                        ty->forall.emplace_back(new ast::TypeInstType(param));
    27302730                        for (auto asst : param->assertions) {
    2731                                 ty->assertions.emplace_back(new ast::VariableExpr({}, asst));
     2731                                ty->assertions.emplace_back(
     2732                                        new ast::VariableExpr(param->location, asst));
    27322733                        }
    27332734                }
  • src/AST/Copy.cpp

    r29d8c02 r74ec742  
    1010// Created On       : Thr Nov 11  9:16:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Nov 11  9:28:00 2021
    13 // Update Count     : 0
     12// Last Modified On : Tue May  3 16:28:00 2022
     13// Update Count     : 1
    1414//
    1515
     
    7777        }
    7878
     79        void postvisit( const UniqueExpr * node ) {
     80                readonlyInsert( &node->object );
     81        }
     82
    7983        void postvisit( const MemberExpr * node ) {
    8084                readonlyInsert( &node->member );
  • src/AST/Decl.cpp

    r29d8c02 r74ec742  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jan 12 16:54:55 2021
    13 // Update Count     : 23
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu May  5 12:10:00 2022
     13// Update Count     : 24
    1414//
    1515
     
    5353// --- FunctionDecl
    5454
    55 FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name, 
     55FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name,
    5656        std::vector<ptr<TypeDecl>>&& forall,
    5757        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     
    7474        }
    7575        this->type = ftype;
     76}
     77
     78FunctionDecl::FunctionDecl( const CodeLocation & location, const std::string & name,
     79        std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions,
     80        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     81        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
     82        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
     83: DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),
     84                params( std::move(params) ), returns( std::move(returns) ),
     85                type_params( std::move( forall) ), assertions( std::move( assertions ) ),
     86                type( nullptr ), stmts( stmts ) {
     87        FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );
     88        for ( auto & param : this->params ) {
     89                type->params.emplace_back( param->get_type() );
     90        }
     91        for ( auto & ret : this->returns ) {
     92                type->returns.emplace_back( ret->get_type() );
     93        }
     94        for ( auto & param : this->type_params ) {
     95                type->forall.emplace_back( new TypeInstType( param ) );
     96        }
     97        for ( auto & assertion : this->assertions ) {
     98                type->assertions.emplace_back(
     99                        new VariableExpr( assertion->location, assertion ) );
     100        }
     101        this->type = type;
    76102}
    77103
  • src/AST/Decl.hpp

    r29d8c02 r74ec742  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:25:05 2021
    13 // Update Count     : 32
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu May  5 12:09:00 2022
     13// Update Count     : 33
    1414//
    1515
     
    135135        std::vector< ptr<Expr> > withExprs;
    136136
     137        // The difference between the two constructors is in how they handle
     138        // assertions. The first constructor uses the assertions from the type
     139        // parameters, in the style of the old ast, and puts them on the type.
     140        // The second takes an explicite list of assertions and builds a list of
     141        // references to them on the type.
     142
    137143        FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
    138144                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    139145                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
    140146                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
    141         // : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
    142         //  stmts( stmts ) {}
     147
     148        FunctionDecl( const CodeLocation & location, const std::string & name,
     149                std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions,
     150                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     151                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
     152                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
    143153
    144154        const Type * get_type() const override;
  • src/AST/Expr.cpp

    r29d8c02 r74ec742  
    1010// Created On       : Wed May 15 17:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Created On       : Tue Nov 30 14:23:00 2021
    13 // Update Count     : 7
     12// Created On       : Wed May 18 13:56:00 2022
     13// Update Count     : 8
    1414//
    1515
     
    2121
    2222#include "Copy.hpp"                // for shallowCopy
    23 #include "Eval.hpp"                // for call
    2423#include "GenericSubstitution.hpp"
    2524#include "LinkageSpec.hpp"
     
    6766// --- UntypedExpr
    6867
     68bool UntypedExpr::get_lvalue() const {
     69        std::string fname = InitTweak::getFunctionName( this );
     70        return lvalueFunctionNames.count( fname );
     71}
     72
    6973UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) {
    7074        assert( arg );
    7175
    72         UntypedExpr * ret = call( loc, "*?", arg );
     76        UntypedExpr * ret = createCall( loc, "*?", { arg } );
    7377        if ( const Type * ty = arg->result ) {
    7478                const Type * base = InitTweak::getPointerBase( ty );
     
    8791}
    8892
    89 bool UntypedExpr::get_lvalue() const {
    90         std::string fname = InitTweak::getFunctionName( this );
    91         return lvalueFunctionNames.count( fname );
    92 }
    93 
    9493UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) {
    9594        assert( lhs && rhs );
    9695
    97         UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
     96        UntypedExpr * ret = createCall( loc, "?=?", { lhs, rhs } );
    9897        if ( lhs->result && rhs->result ) {
    9998                // if both expressions are typed, assumes that this assignment is a C bitwise assignment,
     
    102101        }
    103102        return ret;
     103}
     104
     105UntypedExpr * UntypedExpr::createCall( const CodeLocation & loc,
     106                const std::string & name, std::vector<ptr<Expr>> && args ) {
     107        return new UntypedExpr( loc,
     108                        new NameExpr( loc, name ), std::move( args ) );
    104109}
    105110
  • src/AST/Expr.hpp

    r29d8c02 r74ec742  
    230230        /// Creates a new assignment expression
    231231        static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs );
     232        /// Creates a new call of a variable.
     233        static UntypedExpr * createCall( const CodeLocation & loc,
     234                const std::string & name, std::vector<ptr<Expr>> && args );
    232235
    233236        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    784787public:
    785788        ptr<Expr> expr;
    786         ptr<ObjectDecl> object;
     789        readonly<ObjectDecl> object;
    787790        ptr<VariableExpr> var;
    788791        unsigned long long id;
  • src/AST/Label.hpp

    r29d8c02 r74ec742  
    3434        std::vector< ptr<Attribute> > attributes;
    3535
    36         Label( CodeLocation loc, const std::string& name = "",
     36        Label( const CodeLocation& loc, const std::string& name = "",
    3737                std::vector<ptr<Attribute>> && attrs = std::vector<ptr<Attribute>>{} )
    3838        : location( loc ), name( name ), attributes( attrs ) {}
  • src/AST/Node.hpp

    r29d8c02 r74ec742  
    1010// Created On       : Wed May 8 10:27:04 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 25 10:33:00 2022
    13 // Update Count     : 7
     12// Last Modified On : Mon May  9 10:20:00 2022
     13// Update Count     : 8
    1414//
    1515
     
    4949
    5050        bool unique() const { return strong_count == 1; }
    51         bool isManaged() const {return strong_count > 0; }
     51        bool isManaged() const { return strong_count > 0; }
     52        bool isReferenced() const { return weak_count > 0; }
     53        bool isStable() const {
     54                return (1 == strong_count || (1 < strong_count && 0 == weak_count));
     55        }
    5256
    5357private:
  • src/AST/Pass.proto.hpp

    r29d8c02 r74ec742  
    131131        template< typename node_t >
    132132        struct result1 {
    133                 bool differs;
    134                 const node_t * value;
     133                bool differs = false;
     134                const node_t * value = nullptr;
    135135
    136136                template< typename object_t, typename super_t, typename field_t >
     
    151151                };
    152152
    153                 bool differs;
     153                bool differs = false;
    154154                container_t< delta > values;
    155155
     
    167167        template< template<class...> class container_t, typename node_t >
    168168        struct resultN {
    169                 bool differs;
     169                bool differs = false;
    170170                container_t<ptr<node_t>> values;
    171171
  • src/AST/Stmt.cpp

    r29d8c02 r74ec742  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed May  8 13:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  2 19:01:20 2022
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue May  3 15:18:20 2022
     13// Update Count     : 4
    1414//
    1515
    1616#include "Stmt.hpp"
    1717
    18 
     18#include "Copy.hpp"
    1919#include "DeclReplacer.hpp"
    2020#include "Type.hpp"
     
    2323
    2424// --- CompoundStmt
    25 CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids(other.kids) {
     25CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids() {
     26        // Statements can have weak references to them, if that happens inserting
     27        // the original node into the new list will put the original node in a
     28        // bad state, where it cannot be mutated. To avoid this, just perform an
     29        // additional shallow copy on the statement.
     30        for ( const Stmt * kid : other.kids ) {
     31                if ( kid->isReferenced() ) {
     32                        kids.emplace_back( ast::shallowCopy( kid ) );
     33                } else {
     34                        kids.emplace_back( kid );
     35                }
     36        }
     37
    2638        // when cloning a compound statement, we may end up cloning declarations which
    2739        // are referred to by VariableExprs throughout the block. Cloning a VariableExpr
  • src/AST/Stmt.hpp

    r29d8c02 r74ec742  
    5858        // cannot be, they are sub-types of this type, for organization.
    5959
    60     StmtClause( const CodeLocation & loc )
     60        StmtClause( const CodeLocation & loc )
    6161                : ParseNode(loc) {}
    6262
     
    396396class WaitForClause final : public StmtClause {
    397397  public:
    398     ptr<Expr> target_func;
    399     std::vector<ptr<Expr>> target_args;
    400     ptr<Stmt> stmt;
    401     ptr<Expr> cond;
    402 
    403     WaitForClause( const CodeLocation & loc )
     398        ptr<Expr> target_func;
     399        std::vector<ptr<Expr>> target_args;
     400        ptr<Stmt> stmt;
     401        ptr<Expr> cond;
     402
     403        WaitForClause( const CodeLocation & loc )
    404404                : StmtClause( loc ) {}
    405405
    406406        const WaitForClause * accept( Visitor & v ) const override { return v.visit( this ); }
    407407  private:
    408     WaitForClause * clone() const override { return new WaitForClause{ *this }; }
    409     MUTATE_FRIEND
     408        WaitForClause * clone() const override { return new WaitForClause{ *this }; }
     409        MUTATE_FRIEND
    410410};
    411411
  • src/AST/Util.cpp

    r29d8c02 r74ec742  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Util.hpp -- General utilities for working with the AST.
     7// Util.cpp -- General utilities for working with the AST.
    88//
    99// Author           : Andrew Beach
    1010// Created On       : Wed Jan 19  9:46:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 11 18:07:00 2022
    13 // Update Count     : 1
     12// Last Modified On : Wed May 11 16:16:00 2022
     13// Update Count     : 3
    1414//
    1515
     
    4646
    4747/// Check that every note that can has a set CodeLocation.
    48 struct SetCodeLocationsCore {
    49         void previsit( const ParseNode * node ) {
    50                 assert( node->location.isSet() );
     48void isCodeLocationSet( const ParseNode * node ) {
     49        assert( node->location.isSet() );
     50}
     51
     52void areLabelLocationsSet( const Stmt * stmt ) {
     53        for ( const Label& label : stmt->labels ) {
     54                assert( label.location.isSet() );
    5155        }
    52 };
     56}
     57
     58/// Make sure the reference counts are in a valid combination.
     59void isStable( const Node * node ) {
     60        assert( node->isStable() );
     61}
     62
     63/// Check that a FunctionDecl is synchronized with it's FunctionType.
     64void functionDeclMatchesType( const FunctionDecl * decl ) {
     65        // The type is a cache of sorts, if it is missing that is only a
     66        // problem if isTypeFixed is set.
     67        if ( decl->isTypeFixed ) {
     68                assert( decl->type );
     69        } else if ( !decl->type ) {
     70                return;
     71        }
     72
     73        const FunctionType * type = decl->type;
     74
     75        // Check that `type->forall` corresponds with `decl->type_params`.
     76        assert( type->forall.size() == decl->type_params.size() );
     77        // Check that `type->assertions` corresponds with `decl->assertions`.
     78        assert( type->assertions.size() == decl->assertions.size() );
     79        // Check that `type->params` corresponds with `decl->params`.
     80        assert( type->params.size() == decl->params.size() );
     81        // Check that `type->returns` corresponds with `decl->returns`.
     82        assert( type->returns.size() == decl->returns.size() );
     83}
    5384
    5485struct InvariantCore {
     
    5687        // None of the passes should make changes so ordering doesn't matter.
    5788        NoStrongCyclesCore no_strong_cycles;
    58         SetCodeLocationsCore set_code_locations;
    5989
    6090        void previsit( const Node * node ) {
    6191                no_strong_cycles.previsit( node );
     92                isStable( node );
    6293        }
    6394
    6495        void previsit( const ParseNode * node ) {
    65                 no_strong_cycles.previsit( node );
    66                 set_code_locations.previsit( node );
     96                previsit( (const Node *)node );
     97                isCodeLocationSet( node );
     98        }
     99
     100        void previsit( const FunctionDecl * node ) {
     101                previsit( (const ParseNode *)node );
     102                functionDeclMatchesType( node );
     103        }
     104
     105        void previsit( const Stmt * node ) {
     106                previsit( (const ParseNode *)node );
     107                areLabelLocationsSet( node );
    67108        }
    68109
  • src/AST/module.mk

    r29d8c02 r74ec742  
    2929        AST/DeclReplacer.cpp \
    3030        AST/DeclReplacer.hpp \
    31         AST/Eval.hpp \
    3231        AST/Expr.cpp \
    3332        AST/Expr.hpp \
  • src/CodeGen/CodeGenerator.cc

    r29d8c02 r74ec742  
    12381238} // namespace CodeGen
    12391239
    1240 
    1241 unsigned Indenter::tabsize = 2;
    1242 
    1243 std::ostream & operator<<( std::ostream & out, const BaseSyntaxNode * node ) {
    1244         if ( node ) {
    1245                 node->print( out );
    1246         } else {
    1247                 out << "nullptr";
    1248         }
    1249         return out;
    1250 }
    1251 
    12521240// Local Variables: //
    12531241// tab-width: 4 //
  • src/CodeGen/FixMain.cc

    r29d8c02 r74ec742  
    4949
    5050}
    51 
    52         bool FixMain::replace_main = false;
    5351
    5452        template<typename container>
  • src/CodeGen/LinkOnce.cc

    r29d8c02 r74ec742  
    5353                                new ConstantExpr( Constant::from_string( section_name ) )
    5454                        );
     55
     56                        // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce
     57                        // visibility is a mess otherwise
     58                        attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )}));
     59
    5560                }
    5661                visit_children = false;
  • src/CodeGen/module.mk

    r29d8c02 r74ec742  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Dec 14 07:29:42 2019
    14 ## Update Count     : 4
     12## Last Modified By : Andrew Beach
     13## Last Modified On : Tue May 17 14:26:00 2022
     14## Update Count     : 5
    1515###############################################################################
    1616
    17 #SRC +=  ArgTweak/Rewriter.cc \
    18 #       ArgTweak/Mutate.cc
     17SRC_CODEGEN = \
     18        CodeGen/FixMain2.cc \
     19        CodeGen/FixMain.h \
     20        CodeGen/OperatorTable.cc \
     21        CodeGen/OperatorTable.h
    1922
    20 SRC_CODEGEN = \
     23SRC += $(SRC_CODEGEN) \
    2124        CodeGen/CodeGenerator.cc \
    2225        CodeGen/CodeGenerator.h \
     26        CodeGen/Generate.cc \
     27        CodeGen/Generate.h \
    2328        CodeGen/FixMain.cc \
    24         CodeGen/FixMain.h \
     29        CodeGen/FixNames.cc \
     30        CodeGen/FixNames.h \
    2531        CodeGen/GenType.cc \
    2632        CodeGen/GenType.h \
    2733        CodeGen/LinkOnce.cc \
    2834        CodeGen/LinkOnce.h \
    29         CodeGen/OperatorTable.cc \
    30         CodeGen/OperatorTable.h \
    3135        CodeGen/Options.h
    3236
    33 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/Generate.h CodeGen/FixNames.cc CodeGen/FixNames.h
    3437SRCDEMANGLE += $(SRC_CODEGEN)
  • src/Common/CodeLocationTools.cpp

    r29d8c02 r74ec742  
    1010// Created On       : Fri Dec  4 15:42:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Mar 14 15:14:00 2022
    13 // Update Count     : 4
     12// Last Modified On : Wed May 11 16:16:00 2022
     13// Update Count     : 5
    1414//
    1515
     
    2424namespace {
    2525
    26 // There are a lot of helpers in this file that could be used much more
    27 // generally if anyone has another use for them.
    28 
    29 // Check if a node type has a code location.
    30 template<typename node_t>
    31 struct has_code_location : public std::is_base_of<ast::ParseNode, node_t> {};
    32 
    33 template<typename node_t, bool has_location>
    34 struct __GetCL;
    35 
    36 template<typename node_t>
    37 struct __GetCL<node_t, true> {
    38         static inline CodeLocation const * get( node_t const * node ) {
    39                 return &node->location;
    40         }
    41 
    42         static inline CodeLocation * get( node_t * node ) {
    43                 return &node->location;
    44         }
    45 };
    46 
    47 template<typename node_t>
    48 struct __GetCL<node_t, false> {
    49         static inline CodeLocation * get( node_t const * ) {
    50                 return nullptr;
    51         }
    52 };
    53 
    54 template<typename node_t>
    55 CodeLocation const * get_code_location( node_t const * node ) {
    56         return __GetCL< node_t, has_code_location< node_t >::value >::get( node );
    57 }
    58 
    59 template<typename node_t>
    60 CodeLocation * get_code_location( node_t * node ) {
    61         return __GetCL< node_t, has_code_location< node_t >::value >::get( node );
    62 }
    63 
    6426// Fill every location with a nearby (parent) location.
    6527class FillCore : public ast::WithGuards {
    6628        CodeLocation const * parent;
     29
     30        template<typename node_t>
     31        node_t const * parse_visit( node_t const * node ) {
     32                if ( node->location.isUnset() ) {
     33                        assert( parent );
     34                        node_t * newNode = ast::mutate( node );
     35                        newNode->location = *parent;
     36                        return newNode;
     37                }
     38                GuardValue( parent ) = &node->location;
     39                return node;
     40        }
     41
     42        bool hasUnsetLabels( const ast::Stmt * stmt ) {
     43                for ( const ast::Label& label : stmt->labels ) {
     44                        if ( label.location.isUnset() ) {
     45                                return true;
     46                        }
     47                }
     48                return false;
     49        }
     50
     51        template<typename node_t>
     52        node_t const * stmt_visit( node_t const * node ) {
     53                assert( node->location.isSet() );
     54
     55                if ( hasUnsetLabels( node ) ) {
     56                        node_t * newNode = ast::mutate( node );
     57                        for ( ast::Label& label : newNode->labels ) {
     58                                if ( label.location.isUnset() ) {
     59                                        label.location = newNode->location;
     60                                }
     61                        }
     62                        return newNode;
     63                }
     64                return node;
     65        }
     66
     67        template<typename node_t>
     68        auto visit( node_t const * node, long ) {
     69                return node;
     70        }
     71
     72        template<typename node_t>
     73        auto visit( node_t const * node, int ) -> typename
     74                        std::remove_reference< decltype( node->location, node ) >::type {
     75                return parse_visit( node );
     76        }
     77
     78        template<typename node_t>
     79        auto visit( node_t const * node, char ) -> typename
     80                        std::remove_reference< decltype( node->labels, node ) >::type {
     81                return stmt_visit( parse_visit( node ) );
     82        }
     83
    6784public:
    6885        FillCore() : parent( nullptr ) {}
     86        FillCore( const CodeLocation& location ) : parent( &location ) {
     87                assert( location.isSet() );
     88        }
    6989
    7090        template<typename node_t>
    7191        node_t const * previsit( node_t const * node ) {
    72                 GuardValue( parent );
    73                 CodeLocation const * location = get_code_location( node );
    74                 if ( location && location->isUnset() ) {
    75                         assert( parent );
    76                         node_t * newNode = ast::mutate( node );
    77                         CodeLocation * newLocation = get_code_location( newNode );
    78                         assert( newLocation );
    79                         *newLocation = *parent;
    80                         parent = newLocation;
    81                         return newNode;
    82                 } else if ( location ) {
    83                         parent = location;
    84                 }
    85                 return node;
     92                return visit( node, '\0' );
    8693        }
    8794};
     
    233240
    234241        template<typename node_t>
    235         void previsit( node_t const * node ) {
    236                 CodeLocation const * location = get_code_location( node );
    237                 if ( location && location->isUnset() ) {
     242        auto previsit( node_t const * node ) -> decltype( node->location, void() ) {
     243                if ( node->location.isUnset() ) {
    238244                        unset.push_back( node );
    239                 }
    240         }
    241 };
    242 
    243 class LocalFillCore : public ast::WithGuards {
    244         CodeLocation const * parent;
    245 public:
    246         LocalFillCore( CodeLocation const & location ) : parent( &location ) {
    247                 assert( location.isSet() );
    248         }
    249 
    250         template<typename node_t>
    251         auto previsit( node_t const * node )
    252                         -> typename std::enable_if<has_code_location<node_t>::value, node_t const *>::type {
    253                 if ( node->location.isSet() ) {
    254                         GuardValue( parent ) = &node->location;
    255                         return node;
    256                 } else {
    257                         node_t * mut = ast::mutate( node );
    258                         mut->location = *parent;
    259                         return mut;
    260245                }
    261246        }
     
    304289ast::Node const * localFillCodeLocations(
    305290                CodeLocation const & location , ast::Node const * node ) {
    306         ast::Pass<LocalFillCore> visitor( location );
     291        ast::Pass<FillCore> visitor( location );
    307292        return node->accept( visitor );
    308293}
  • src/Common/Indenter.h

    r29d8c02 r74ec742  
    1010// Created On       : Fri Jun 30 16:55:23 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Aug 11 11:15:00 2017
    13 // Update Count     : 1
     12// Last Modified On : Fri May 13 14:10:00 2022
     13// Update Count     : 2
    1414//
    1515
    16 #ifndef INDENTER_H
    17 #define INDENTER_H
     16#pragma once
     17
     18#include <ostream>
    1819
    1920struct Indenter {
     
    3738        return out << std::string(indent.indent * indent.amt, ' ');
    3839}
    39 
    40 #endif // INDENTER_H
  • src/Common/SemanticError.h

    r29d8c02 r74ec742  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 19 10:09:17 2018
    13 // Update Count     : 31
     12// Last Modified On : Wed May  4 14:08:26 2022
     13// Update Count     : 35
    1414//
    1515
     
    5959        {"aggregate-forward-decl" , Severity::Warn    , "forward declaration of nested aggregate: %s"                },
    6060        {"superfluous-decl"       , Severity::Warn    , "declaration does not allocate storage: %s"                  },
     61        {"superfluous-else"       , Severity::Warn    , "else clause never executed for empty loop conditional"      },
    6162        {"gcc-attributes"         , Severity::Warn    , "invalid attribute: %s"                                      },
    6263        {"c++-like-copy"          , Severity::Warn    , "Constructor from reference is not a valid copy constructor" },
     
    6970        AggrForwardDecl,
    7071        SuperfluousDecl,
     72        SuperfluousElse,
    7173        GccAttributes,
    7274        CppCopy,
     
    7981);
    8082
    81 #define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id].message, __VA_ARGS__)
     83#define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id].message, ##__VA_ARGS__)
    8284
    8385void SemanticWarningImpl (CodeLocation loc, Warning warn, const char * const fmt, ...) __attribute__((format(printf, 3, 4)));
  • src/Common/module.mk

    r29d8c02 r74ec742  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Tue Sep 27 11:06:38 2016
    14 ## Update Count     : 4
     12## Last Modified By : Andrew Beach
     13## Last Modified On : Tue May 17 14:27:00 2022
     14## Update Count     : 5
    1515###############################################################################
    1616
    1717SRC_COMMON = \
    18       Common/Assert.cc \
    19       Common/CodeLocation.h \
    20       Common/CodeLocationTools.hpp \
    21       Common/CodeLocationTools.cpp \
    22       Common/CompilerError.h \
    23       Common/Debug.h \
    24       Common/DeclStats.hpp \
    25       Common/DeclStats.cpp \
    26       Common/ErrorObjects.h \
    27       Common/Eval.cc \
    28       Common/Examine.cc \
    29       Common/Examine.h \
    30       Common/FilterCombos.h \
    31       Common/Indenter.h \
    32       Common/PassVisitor.cc \
    33       Common/PassVisitor.h \
    34       Common/PassVisitor.impl.h \
    35       Common/PassVisitor.proto.h \
    36       Common/PersistentMap.h \
    37       Common/ResolvProtoDump.hpp \
    38       Common/ResolvProtoDump.cpp \
    39       Common/ScopedMap.h \
    40       Common/SemanticError.cc \
    41       Common/SemanticError.h \
    42       Common/Stats.h \
    43       Common/Stats/Base.h \
    44       Common/Stats/Counter.cc \
    45       Common/Stats/Counter.h \
    46       Common/Stats/Heap.cc \
    47       Common/Stats/Heap.h \
    48       Common/Stats/ResolveTime.cc \
    49       Common/Stats/ResolveTime.h \
    50       Common/Stats/Stats.cc \
    51       Common/Stats/Time.cc \
    52       Common/Stats/Time.h \
    53       Common/UnimplementedError.h \
    54       Common/UniqueName.cc \
    55       Common/UniqueName.h \
    56       Common/utility.h \
    57       Common/VectorMap.h
     18        Common/Assert.cc \
     19        Common/CodeLocation.h \
     20        Common/CodeLocationTools.hpp \
     21        Common/CodeLocationTools.cpp \
     22        Common/CompilerError.h \
     23        Common/Debug.h \
     24        Common/DeclStats.hpp \
     25        Common/DeclStats.cpp \
     26        Common/ErrorObjects.h \
     27        Common/Eval.cc \
     28        Common/Examine.cc \
     29        Common/Examine.h \
     30        Common/FilterCombos.h \
     31        Common/Indenter.h \
     32        Common/Indenter.cc \
     33        Common/PassVisitor.cc \
     34        Common/PassVisitor.h \
     35        Common/PassVisitor.impl.h \
     36        Common/PassVisitor.proto.h \
     37        Common/PersistentMap.h \
     38        Common/ResolvProtoDump.hpp \
     39        Common/ResolvProtoDump.cpp \
     40        Common/ScopedMap.h \
     41        Common/SemanticError.cc \
     42        Common/SemanticError.h \
     43        Common/Stats.h \
     44        Common/Stats/Base.h \
     45        Common/Stats/Counter.cc \
     46        Common/Stats/Counter.h \
     47        Common/Stats/Heap.cc \
     48        Common/Stats/Heap.h \
     49        Common/Stats/ResolveTime.cc \
     50        Common/Stats/ResolveTime.h \
     51        Common/Stats/Stats.cc \
     52        Common/Stats/Time.cc \
     53        Common/Stats/Time.h \
     54        Common/UnimplementedError.h \
     55        Common/UniqueName.cc \
     56        Common/UniqueName.h \
     57        Common/utility.h \
     58        Common/VectorMap.h
    5859
    59 SRC += $(SRC_COMMON) Common/DebugMalloc.cc
     60SRC += $(SRC_COMMON) \
     61        Common/DebugMalloc.cc
     62
    6063SRCDEMANGLE += $(SRC_COMMON)
  • src/Common/utility.h

    r29d8c02 r74ec742  
    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 : Tue Feb 11 13:00:36 2020
    13 // Update Count     : 50
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Apr 25 14:26:00 2022
     13// Update Count     : 51
    1414//
    1515
     
    230230}
    231231
     232template<typename Container, typename Pred>
     233void erase_if( Container & cont, Pred && pred ) {
     234        auto keep_end = std::remove_if( cont.begin(), cont.end(), pred );
     235        cont.erase( keep_end, cont.end() );
     236}
     237
    232238template< typename... Args >
    233239auto zip(Args&&... args) -> decltype(zipWith(std::forward<Args>(args)..., std::make_pair)) {
  • src/Concurrency/module.mk

    r29d8c02 r74ec742  
    1010## Author           : Thierry Delisle
    1111## Created On       : Mon Mar 13 12:48:40 2017
    12 ## Last Modified By :
    13 ## Last Modified On :
    14 ## Update Count     : 0
     12## Last Modified By : Andrew Beach
     13## Last Modified On : Tue May 17 13:28:00 2022
     14## Update Count     : 1
    1515###############################################################################
    1616
    17 SRC_CONCURRENCY = \
     17SRC += \
    1818        Concurrency/KeywordsNew.cpp \
    19         Concurrency/Keywords.cc
    20 
    21 SRC += $(SRC_CONCURRENCY) \
     19        Concurrency/Keywords.cc \
    2220        Concurrency/Keywords.h \
    2321        Concurrency/Waitfor.cc \
    2422        Concurrency/Waitfor.h
    25 
    26 SRCDEMANGLE += $(SRC_CONCURRENCY)
    27 
  • src/ControlStruct/LabelGeneratorNew.hpp

    r29d8c02 r74ec742  
    1818#include <string>                                                                               // for string
    1919
    20 class CodeLocation;
     20struct CodeLocation;
    2121
    2222namespace ast {
  • src/ControlStruct/MultiLevelExit.cpp

    r29d8c02 r74ec742  
    1818#include "AST/Pass.hpp"
    1919#include "AST/Stmt.hpp"
     20#include "Common/CodeLocationTools.hpp"
    2021#include "LabelGeneratorNew.hpp"
    2122
     
    228229        // Labels on different stmts require different approaches to access
    229230        switch ( stmt->kind ) {
    230           case BranchStmt::Goto:
     231        case BranchStmt::Goto:
    231232                return stmt;
    232           case BranchStmt::Continue:
    233           case BranchStmt::Break: {
    234                   bool isContinue = stmt->kind == BranchStmt::Continue;
    235                   // Handle unlabeled break and continue.
    236                   if ( stmt->target.empty() ) {
    237                           if ( isContinue ) {
    238                                   targetEntry = findEnclosingControlStructure( isContinueTarget );
    239                           } else {
    240                                   if ( enclosing_control_structures.empty() ) {
     233        case BranchStmt::Continue:
     234        case BranchStmt::Break: {
     235                bool isContinue = stmt->kind == BranchStmt::Continue;
     236                // Handle unlabeled break and continue.
     237                if ( stmt->target.empty() ) {
     238                        if ( isContinue ) {
     239                                targetEntry = findEnclosingControlStructure( isContinueTarget );
     240                        } else {
     241                                if ( enclosing_control_structures.empty() ) {
    241242                                          SemanticError( stmt->location,
    242243                                                                         "'break' outside a loop, 'switch', or labelled block" );
    243                                   }
    244                                   targetEntry = findEnclosingControlStructure( isBreakTarget );
    245                           }
    246                           // Handle labeled break and continue.
    247                   } else {
    248                           // Lookup label in table to find attached control structure.
    249                           targetEntry = findEnclosingControlStructure(
    250                                   [ targetStmt = target_table.at(stmt->target) ](auto entry){
     244                                }
     245                                targetEntry = findEnclosingControlStructure( isBreakTarget );
     246                        }
     247                        // Handle labeled break and continue.
     248                } else {
     249                        // Lookup label in table to find attached control structure.
     250                        targetEntry = findEnclosingControlStructure(
     251                                [ targetStmt = target_table.at(stmt->target) ](auto entry){
    251252                                          return entry.stmt == targetStmt;
    252                                   } );
    253                   }
    254                   // Ensure that selected target is valid.
    255                   if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) {
    256                           SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"),
     253                                } );
     254                }
     255                // Ensure that selected target is valid.
     256                if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) {
     257                        SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"),
    257258                                                        " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "),
    258259                                                        stmt->originalTarget ) );
    259                   }
    260                   break;
    261           }
    262           // handle fallthrough in case/switch stmts
    263           case BranchStmt::FallThrough: {
    264                   targetEntry = findEnclosingControlStructure( isFallthroughTarget );
    265                   // Check that target is valid.
    266                   if ( targetEntry == enclosing_control_structures.rend() ) {
    267                           SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
    268                   }
    269                   if ( ! stmt->target.empty() ) {
    270                           // Labelled fallthrough: target must be a valid fallthough label.
    271                           if ( ! fallthrough_labels.count( stmt->target ) ) {
    272                                   SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ",
     260                }
     261                break;
     262        }
     263        // handle fallthrough in case/switch stmts
     264        case BranchStmt::FallThrough: {
     265                targetEntry = findEnclosingControlStructure( isFallthroughTarget );
     266                // Check that target is valid.
     267                if ( targetEntry == enclosing_control_structures.rend() ) {
     268                        SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
     269                }
     270                if ( ! stmt->target.empty() ) {
     271                        // Labelled fallthrough: target must be a valid fallthough label.
     272                        if ( ! fallthrough_labels.count( stmt->target ) ) {
     273                                SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ",
    273274                                                                                                                   stmt->originalTarget ) );
    274                           }
    275                           return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget );
    276                   }
    277                   break;
    278           }
    279           case BranchStmt::FallThroughDefault: {
    280                   targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget );
    281 
    282                   // Check if in switch or choose statement.
    283                   if ( targetEntry == enclosing_control_structures.rend() ) {
    284                           SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
    285                   }
    286 
    287                   // Check if switch or choose has default clause.
    288                   auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt );
    289                   bool foundDefault = false;
    290                   for ( auto caseStmt : switchStmt->cases ) {
    291                           if ( caseStmt->isDefault() ) {
    292                                   foundDefault = true;
    293                                   break;
    294                           }
    295                   }
    296                   if ( ! foundDefault ) {
    297                           SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'"
    298                                                         "control structure with a 'default' clause" );
    299                   }
    300                   break;
    301           }
    302           default:
     275                        }
     276                        return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget );
     277                }
     278                break;
     279        }
     280        case BranchStmt::FallThroughDefault: {
     281                targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget );
     282
     283                // Check if in switch or choose statement.
     284                if ( targetEntry == enclosing_control_structures.rend() ) {
     285                        SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
     286                }
     287
     288                // Check if switch or choose has default clause.
     289                auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt );
     290                bool foundDefault = false;
     291                for ( auto caseStmt : switchStmt->cases ) {
     292                        if ( caseStmt->isDefault() ) {
     293                                foundDefault = true;
     294                                break;
     295                        }
     296                }
     297                if ( ! foundDefault ) {
     298                        SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'"
     299                                                  "control structure with a 'default' clause" );
     300                }
     301                break;
     302        }
     303        default:
    303304                assert( false );
    304305        }
     
    307308        Label exitLabel( CodeLocation(), "" );
    308309        switch ( stmt->kind ) {
    309           case BranchStmt::Break:
     310        case BranchStmt::Break:
    310311                assert( ! targetEntry->useBreakExit().empty() );
    311312                exitLabel = targetEntry->useBreakExit();
    312313                break;
    313           case BranchStmt::Continue:
     314        case BranchStmt::Continue:
    314315                assert( ! targetEntry->useContExit().empty() );
    315316                exitLabel = targetEntry->useContExit();
    316317                break;
    317           case BranchStmt::FallThrough:
     318        case BranchStmt::FallThrough:
    318319                assert( ! targetEntry->useFallExit().empty() );
    319320                exitLabel = targetEntry->useFallExit();
    320321                break;
    321           case BranchStmt::FallThroughDefault:
     322        case BranchStmt::FallThroughDefault:
    322323                assert( ! targetEntry->useFallDefaultExit().empty() );
    323324                exitLabel = targetEntry->useFallDefaultExit();
     
    327328                }
    328329                break;
    329           default:
     330        default:
    330331                assert(0);
    331332        }
     
    588589                }
    589590
     591                ptr<Stmt> else_stmt = nullptr;
     592                Stmt * loop_kid = nullptr;
     593                // check if loop node and if so add else clause if it exists
     594                const WhileDoStmt * whilePtr = dynamic_cast<const WhileDoStmt *>(kid.get());
     595                if ( whilePtr && whilePtr->else_) {
     596                        else_stmt = whilePtr->else_;
     597                        WhileDoStmt * mutate_ptr = mutate(whilePtr);
     598                        mutate_ptr->else_ = nullptr;
     599                        loop_kid = mutate_ptr;
     600                }
     601                const ForStmt * forPtr = dynamic_cast<const ForStmt *>(kid.get());
     602                if ( forPtr && forPtr->else_) {
     603                        else_stmt = forPtr->else_;
     604                        ForStmt * mutate_ptr = mutate(forPtr);
     605                        mutate_ptr->else_ = nullptr;
     606                        loop_kid = mutate_ptr;
     607                }
     608
    590609                try {
    591                         ret.push_back( kid->accept( *visitor ) );
     610                        if (else_stmt) ret.push_back( loop_kid->accept( *visitor ) );
     611                        else ret.push_back( kid->accept( *visitor ) );
    592612                } catch ( SemanticErrorException & e ) {
    593613                        errors.append( e );
    594614                }
     615
     616                if (else_stmt) ret.push_back(else_stmt);
    595617
    596618                if ( ! break_label.empty() ) {
     
    612634        Pass<MultiLevelExitCore> visitor( labelTable );
    613635        const CompoundStmt * ret = stmt->accept( visitor );
    614         return ret;
     636        // There are some unset code locations slipping in, possibly by Labels.
     637        const Node * node = localFillCodeLocations( ret->location, ret );
     638        return strict_dynamic_cast<const CompoundStmt *>( node );
    615639}
    616640} // namespace ControlStruct
  • src/ControlStruct/module.mk

    r29d8c02 r74ec742  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Jan 29 12:04:19 2022
    14 ## Update Count     : 7
     12## Last Modified By : Andrew Beach
     13## Last Modified On : Tue May 17 14:30:00 2022
     14## Update Count     : 8
    1515###############################################################################
    1616
    17 SRC_CONTROLSTRUCT = \
     17SRC += \
    1818        ControlStruct/ExceptDecl.cc \
    1919        ControlStruct/ExceptDecl.h \
     20        ControlStruct/ExceptTranslateNew.cpp \
     21        ControlStruct/ExceptTranslate.cc \
     22        ControlStruct/ExceptTranslate.h \
    2023        ControlStruct/FixLabels.cpp \
    2124        ControlStruct/FixLabels.hpp \
     
    3740        ControlStruct/Mutate.h
    3841
    39 SRC += $(SRC_CONTROLSTRUCT) \
    40         ControlStruct/ExceptTranslateNew.cpp \
    41         ControlStruct/ExceptTranslate.cc \
    42         ControlStruct/ExceptTranslate.h
    43 
    44 SRCDEMANGLE += $(SRC_CONTROLSTRUCT)
    45 
  • src/GenPoly/Lvalue.cc

    r29d8c02 r74ec742  
    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 Dec 13 23:14:38 2019
    13 // Update Count     : 7
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon May 16 14:09:00 2022
     13// Update Count     : 8
    1414//
    1515
     
    125125        } // namespace
    126126
    127         static bool referencesEliminated = false;
    128         // used by UntypedExpr::createDeref to determine whether result type of dereference should be ReferenceType or value type.
    129         bool referencesPermissable() {
    130                 return ! referencesEliminated;
    131         }
     127        // Stored elsewhere (Lvalue2, initially false).
     128        extern bool referencesEliminated;
    132129
    133130        void convertLvalue( std::list< Declaration* > & translationUnit ) {
  • src/GenPoly/module.mk

    r29d8c02 r74ec742  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Jun  1 17:52:30 2015
    14 ## Update Count     : 1
     12## Last Modified By : Andrew Beach
     13## Last Modified On : Tue May 17 14:31:00 2022
     14## Update Count     : 2
    1515###############################################################################
    1616
    17 SRC += GenPoly/Box.cc \
    18        GenPoly/Box.h \
    19        GenPoly/ErasableScopedMap.h \
    20        GenPoly/FindFunction.cc \
    21        GenPoly/FindFunction.h \
    22        GenPoly/GenPoly.cc \
    23        GenPoly/GenPoly.h \
    24        GenPoly/InstantiateGeneric.cc \
    25        GenPoly/InstantiateGeneric.h \
    26        GenPoly/Lvalue.cc \
    27        GenPoly/Lvalue.h \
    28        GenPoly/ScopedSet.h \
    29        GenPoly/ScrubTyVars.cc \
    30        GenPoly/ScrubTyVars.h \
    31        GenPoly/Specialize.cc \
    32        GenPoly/Specialize.h
     17SRC_GENPOLY = \
     18        GenPoly/GenPoly.cc \
     19        GenPoly/GenPoly.h \
     20        GenPoly/Lvalue2.cc \
     21        GenPoly/Lvalue.h
    3322
    34 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/GenPoly.h GenPoly/Lvalue.cc GenPoly/Lvalue.h
     23SRC += $(SRC_GENPOLY) \
     24        GenPoly/Box.cc \
     25        GenPoly/Box.h \
     26        GenPoly/ErasableScopedMap.h \
     27        GenPoly/FindFunction.cc \
     28        GenPoly/FindFunction.h \
     29        GenPoly/InstantiateGeneric.cc \
     30        GenPoly/InstantiateGeneric.h \
     31        GenPoly/Lvalue.cc \
     32        GenPoly/ScopedSet.h \
     33        GenPoly/ScrubTyVars.cc \
     34        GenPoly/ScrubTyVars.h \
     35        GenPoly/Specialize.cc \
     36        GenPoly/Specialize.h
    3537
     38SRCDEMANGLE += $(SRC_GENPOLY)
  • src/InitTweak/FixInitNew.cpp

    r29d8c02 r74ec742  
    454454
    455455                auto expr = new ast::ImplicitCopyCtorExpr( appExpr->location, mutExpr );
    456                 // Move the type substitution to the new top-level, if it is attached to the appExpr.
    457                 // Ensure it is not deleted with the ImplicitCopyCtorExpr by removing it before deletion.
    458                 // The substitution is needed to obtain the type of temporary variables so that copy constructor
    459                 // calls can be resolved.
     456                // Move the type substitution to the new top-level. The substitution
     457                // is needed to obtain the type of temporary variables so that copy
     458                // constructor calls can be resolved.
    460459                assert( typeSubs );
    461                 // assert (mutExpr->env);
    462460                expr->env = tmp;
    463                 // mutExpr->env = nullptr;
    464                 //std::swap( expr->env, appExpr->env );
    465461                return expr;
    466462        }
    467463
    468464        void ResolveCopyCtors::previsit(const ast::Expr * expr) {
    469                 if (expr->env) {
    470                         GuardValue(env);
    471                         GuardValue(envModified);
    472                         env = expr->env->clone();
    473                         envModified = false;
    474                 }
     465                if ( nullptr == expr->env ) {
     466                        return;
     467                }
     468                GuardValue( env ) = expr->env->clone();
     469                GuardValue( envModified ) = false;
    475470        }
    476471
    477472        const ast::Expr * ResolveCopyCtors::postvisit(const ast::Expr * expr) {
    478                 if (expr->env) {
    479                         if (envModified) {
    480                                 auto mutExpr = mutate(expr);
    481                                 mutExpr->env = env;
    482                                 return mutExpr;
    483                         }
    484                         else {
    485                                 // env was not mutated, skip and delete the shallow copy
    486                                 delete env;
    487                                 return expr;
    488                         }
    489                 }
    490                 else {
     473                // No local environment, skip.
     474                if ( nullptr == expr->env ) {
     475                        return expr;
     476                // Environment was modified, mutate and replace.
     477                } else if ( envModified ) {
     478                        auto mutExpr = mutate(expr);
     479                        mutExpr->env = env;
     480                        return mutExpr;
     481                // Environment was not mutated, delete the shallow copy before guard.
     482                } else {
     483                        delete env;
    491484                        return expr;
    492485                }
     
    497490        const ast::Expr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg ) {
    498491                assert( var );
    499                 assert (var->isManaged());
    500                 assert (!cpArg || cpArg->isManaged());
     492                assert( var->isManaged() );
     493                assert( !cpArg || cpArg->isManaged() );
    501494                // arrays are not copy constructed, so this should always be an ExprStmt
    502495                ast::ptr< ast::Stmt > stmt = genCtorDtor(var->location, fname, var, cpArg );
     
    504497                auto exprStmt = stmt.strict_as<ast::ImplicitCtorDtorStmt>()->callStmt.strict_as<ast::ExprStmt>();
    505498                ast::ptr<ast::Expr> untyped = exprStmt->expr; // take ownership of expr
    506                 // exprStmt->expr = nullptr;
    507499
    508500                // resolve copy constructor
     
    516508                        env->add( *resolved->env );
    517509                        envModified = true;
    518                         // delete resolved->env;
    519510                        auto mut = mutate(resolved.get());
    520511                        assertf(mut == resolved.get(), "newly resolved expression must be unique");
    521512                        mut->env = nullptr;
    522513                } // if
    523                 // delete stmt;
    524514                if ( auto assign = resolved.as<ast::TupleAssignExpr>() ) {
    525515                        // fix newly generated StmtExpr
  • src/InitTweak/module.mk

    r29d8c02 r74ec742  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Rob Schluntz
    13 ## Last Modified On : Fri May 13 11:36:24 2016
    14 ## Update Count     : 3
     12## Last Modified By : Andrew Beach
     13## Last Modified On : Tue May 17 14:31:00 2022
     14## Update Count     : 4
    1515###############################################################################
    1616
    17 SRC += \
    18         InitTweak/FixGlobalInit.cc \
    19         InitTweak/FixGlobalInit.h \
    20         InitTweak/FixInit.cc \
    21         InitTweak/FixInit.h \
    22         InitTweak/GenInit.cc \
    23         InitTweak/GenInit.h \
    24         InitTweak/InitTweak.cc \
    25         InitTweak/InitTweak.h \
    26         InitTweak/FixInitNew.cpp
    27 
    28 SRCDEMANGLE += \
     17SRC_INITTWEAK = \
    2918        InitTweak/GenInit.cc \
    3019        InitTweak/GenInit.h \
     
    3221        InitTweak/InitTweak.h
    3322
     23SRC += $(SRC_INITTWEAK) \
     24        InitTweak/FixGlobalInit.cc \
     25        InitTweak/FixGlobalInit.h \
     26        InitTweak/FixInit.cc \
     27        InitTweak/FixInit.h \
     28        InitTweak/FixInitNew.cpp
     29
     30SRCDEMANGLE += $(SRC_INITTWEAK)
  • src/Parser/DeclarationNode.cc

    r29d8c02 r74ec742  
    253253} // DeclarationNode::newAggregate
    254254
    255 DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body) {
     255DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body, DeclarationNode * base) {
    256256        DeclarationNode * newnode = new DeclarationNode;
    257257        newnode->type = new TypeData( TypeData::Enum );
     
    260260        newnode->type->enumeration.body = body;
    261261        newnode->type->enumeration.anon = name == nullptr;
     262        if ( base && base->type)  {
     263                newnode->type->base = base->type;       
     264        } // if
     265
     266        // Check: if base has TypeData
    262267        return newnode;
    263268} // DeclarationNode::newEnum
     
    290295                return newName( name ); // Not explicitly inited enum value;
    291296        } // if
    292 } // DeclarationNode::newEnumGeneric
     297} // DeclarationNode::newEnumValueGeneric
    293298
    294299DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) {
  • src/Parser/ParseNode.h

    r29d8c02 r74ec742  
    235235        static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
    236236        static DeclarationNode * newAggregate( AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
    237         static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body );
     237        static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, DeclarationNode * base = nullptr );
    238238        static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );
    239239        static DeclarationNode * newEnumValueGeneric( const std::string * name, InitializerNode * init );
  • src/Parser/TypeData.cc

    r29d8c02 r74ec742  
    388388                if ( enumeration.body ) {
    389389                        os << string( indent + 2, ' ' ) << " with body" << endl;
     390                } // if
     391                if ( base ) {
     392                        os << "for ";
     393                        base->print( os, indent + 2 );
    390394                } // if
    391395                break;
     
    926930                        ObjectDecl * member = dynamic_cast< ObjectDecl * >(* members);
    927931                        member->set_init( new SingleInit( maybeMoveBuild< Expression >( cur->consume_enumeratorValue() ) ) );
    928                 } else {
     932                } else if ( !cur->initializer ) {
    929933                        if ( baseType && (!dynamic_cast<BasicType *>(baseType) || !dynamic_cast<BasicType *>(baseType)->isWholeNumber())) {
    930934                                SemanticError( td->location, "A non whole number enum value decl must be explicitly initialized." );
    931935                        }
    932                 } // if
     936                }
     937                // else cur is a List Initializer and has been set as init in buildList()
     938                // if
    933939        } // for
    934         ret->set_body( td->enumeration.body ); // Boolean; if it has body
     940        ret->set_body( td->enumeration.body );
    935941        return ret;
    936942} // buildEnum
  • src/Parser/parser.yy

    r29d8c02 r74ec742  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 14 16:35:29 2022
    13 // Update Count     : 5276
     12// Last Modified On : Sat May 14 09:16:22 2022
     13// Update Count     : 5401
    1414//
    1515
     
    5454#include "Common/SemanticError.h"                                               // error_str
    5555#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
     56
     57#include "SynTree/Attribute.h"     // for Attribute
    5658
    5759extern DeclarationNode * parseTree;
     
    9395} // appendStr
    9496
    95 DeclarationNode * distAttr( DeclarationNode * specifier, DeclarationNode * declList ) {
    96         // distribute declaration_specifier across all declared variables, e.g., static, const, __attribute__.
    97         DeclarationNode * cur = declList, * cl = (new DeclarationNode)->addType( specifier );
     97DeclarationNode * distAttr( DeclarationNode * typeSpec, DeclarationNode * declList ) {
     98        // distribute declaration_specifier across all declared variables, e.g., static, const, but not __attribute__.
     99        assert( declList );
     100//      printf( "distAttr1 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout );
     101        DeclarationNode * cur = declList, * cl = (new DeclarationNode)->addType( typeSpec );
     102//      printf( "distAttr2 cl %p\n", cl ); cl->type->print( std::cout );
     103//      cl->type->aggregate.name = cl->type->aggInst.aggregate->aggregate.name;
     104
    98105        for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {
    99106                cl->cloneBaseType( cur );
    100107        } // for
    101108        declList->addType( cl );
     109//      printf( "distAttr3 declList %p\n", declList ); declList->print( std::cout, 0 );
    102110        return declList;
    103111} // distAttr
     
    111119
    112120void distInl( DeclarationNode * declaration ) {
    113         // distribute EXTENSION across all declarations
     121        // distribute INLINE across all declarations
    114122        for ( DeclarationNode *iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) {
    115123                iter->set_inLine( true );
     
    171179                if ( ! ( typeSpec->type && (typeSpec->type->kind == TypeData::Aggregate || typeSpec->type->kind == TypeData::Enum) ) ) {
    172180                        stringstream ss;
    173                         typeSpec->type->print( ss );
     181                        // printf( "fieldDecl1 typeSpec %p\n", typeSpec ); typeSpec->type->print( std::cout );
    174182                        SemanticWarning( yylloc, Warning::SuperfluousDecl, ss.str().c_str() );
    175183                        return nullptr;
    176184                } // if
     185                // printf( "fieldDecl2 typeSpec %p\n", typeSpec ); typeSpec->type->print( std::cout );
    177186                fieldList = DeclarationNode::newName( nullptr );
    178187        } // if
    179         return distAttr( typeSpec, fieldList );                         // mark all fields in list
     188//      return distAttr( typeSpec, fieldList );                         // mark all fields in list
     189
     190        // printf( "fieldDecl3 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout, 0 );
     191        DeclarationNode * temp = distAttr( typeSpec, fieldList );                               // mark all fields in list
     192        // printf( "fieldDecl4 temp %p\n", temp ); temp->print( std::cout, 0 );
     193        return temp;
    180194} // fieldDecl
    181195
     
    12211235
    12221236iteration_statement:
    1223         WHILE '(' ')' statement                                                         // CFA => while ( 1 )
     1237        WHILE '(' ')' statement                                                         %prec THEN // CFA => while ( 1 )
    12241238                { $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
     1239        | WHILE '(' ')' statement ELSE statement                        // CFA
     1240                {
     1241                        $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) );
     1242                        SemanticWarning( yylloc, Warning::SuperfluousElse );
     1243                }
    12251244        | WHILE '(' conditional_declaration ')' statement       %prec THEN
    12261245                { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); }
     
    12291248        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    12301249                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
    1231         | DO statement WHILE '(' comma_expression ')' ';'       %prec THEN
     1250        | DO statement WHILE '(' ')' ELSE statement                     // CFA
     1251                {
     1252                        $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) );
     1253                        SemanticWarning( yylloc, Warning::SuperfluousElse );
     1254                }
     1255        | DO statement WHILE '(' comma_expression ')' ';'
    12321256                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
    12331257        | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA
    12341258                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ), $8 ) ); }
    1235         | FOR '(' ')' statement                                                         // CFA => for ( ;; )
     1259        | FOR '(' ')' statement                                                         %prec THEN // CFA => for ( ;; )
    12361260                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
     1261        | FOR '(' ')' statement ELSE statement                          // CFA
     1262                {
     1263                        $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) );
     1264                        SemanticWarning( yylloc, Warning::SuperfluousElse );
     1265                }
    12371266        | FOR '(' for_control_expression_list ')' statement     %prec THEN
    12381267                { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }
     
    16051634declaration:                                                                                    // old & new style declarations
    16061635        c_declaration ';'
     1636                {
     1637                        // printf( "C_DECLARATION1 %p %s\n", $$, $$->name ? $$->name->c_str() : "(nil)" );
     1638                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     1639                        //   printf( "\tattr %s\n", attr->name.c_str() );
     1640                        // } // for
     1641                }
    16071642        | cfa_declaration ';'                                                           // CFA
    16081643        | static_assert                                                                         // C11
     
    18101845        basic_type_specifier
    18111846        | sue_type_specifier
     1847                {
     1848                        // printf( "sue_type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
     1849                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     1850                        //   printf( "\tattr %s\n", attr->name.c_str() );
     1851                        // } // for
     1852                }
    18121853        | type_type_specifier
    18131854        ;
     
    20262067sue_declaration_specifier:                                                              // struct, union, enum + storage class + type specifier
    20272068        sue_type_specifier
     2069                {
     2070                        // printf( "sue_declaration_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
     2071                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2072                        //   printf( "\tattr %s\n", attr->name.c_str() );
     2073                        // } // for
     2074                }
    20282075        | declaration_qualifier_list sue_type_specifier
    20292076                { $$ = $2->addQualifiers( $1 ); }
     
    20362083sue_type_specifier:                                                                             // struct, union, enum + type specifier
    20372084        elaborated_type
     2085                {
     2086                        // printf( "sue_type_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
     2087                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2088                        //   printf( "\tattr %s\n", attr->name.c_str() );
     2089                        // } // for
     2090                }
    20382091        | type_qualifier_list
    20392092                { if ( $1->type != nullptr && $1->type->forall ) forall = true; } // remember generic type
     
    21082161elaborated_type:                                                                                // struct, union, enum
    21092162        aggregate_type
     2163                {
     2164                        // printf( "elaborated_type %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
     2165                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2166                        //   printf( "\tattr %s\n", attr->name.c_str() );
     2167                        // } // for
     2168                }
    21102169        | enum_type
    21112170        ;
     
    21272186                }
    21282187          '{' field_declaration_list_opt '}' type_parameters_opt
    2129                 { $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); }
     2188                {
     2189                        // printf( "aggregate_type1 %s\n", $3.str->c_str() );
     2190                        // if ( $2 )
     2191                        //      for ( Attribute * attr: reverseIterate( $2->attributes ) ) {
     2192                        //              printf( "copySpecifiers12 %s\n", attr->name.c_str() );
     2193                        //      } // for
     2194                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     2195                        // printf( "aggregate_type2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
     2196                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2197                        //      printf( "aggregate_type3 %s\n", attr->name.c_str() );
     2198                        // } // for
     2199                }
    21302200        | aggregate_key attribute_list_opt TYPEDEFname          // unqualified type name
    21312201                {
     
    21352205          '{' field_declaration_list_opt '}' type_parameters_opt
    21362206                {
     2207                        // printf( "AGG3\n" );
    21372208                        DeclarationNode::newFromTypedef( $3 );
    21382209                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    21452216          '{' field_declaration_list_opt '}' type_parameters_opt
    21462217                {
     2218                        // printf( "AGG4\n" );
    21472219                        DeclarationNode::newFromTypeGen( $3, nullptr );
    21482220                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    22212293field_declaration:
    22222294        type_specifier field_declaring_list_opt ';'
    2223                 { $$ = fieldDecl( $1, $2 ); }
     2295                {
     2296                        // printf( "type_specifier1 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
     2297                        $$ = fieldDecl( $1, $2 );
     2298                        // printf( "type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
     2299                        // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
     2300                        //   printf( "\tattr %s\n", attr->name.c_str() );
     2301                        // } // for
     2302                }
    22242303        | EXTENSION type_specifier field_declaring_list_opt ';' // GCC
    22252304                { $$ = fieldDecl( $2, $3 ); distExt( $$ ); }
     
    23032382        ;
    23042383
    2305 enum_type: // static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, bool typed );                                                                                         // enum
     2384enum_type:
    23062385        ENUM attribute_list_opt '{' enumerator_list comma_opt '}'
    23072386                { $$ = DeclarationNode::newEnum( nullptr, $4, true )->addQualifiers( $2 ); }
     
    23182397                        { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    23192398
    2320                         $$ = DeclarationNode::newEnum( nullptr, $7, true ) ->addQualifiers( $5 )  -> addEnumBase( $3 );
    2321                 }
    2322         | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt // Question: why attributes/qualifier after identifier
     2399                        $$ = DeclarationNode::newEnum( nullptr, $7, true, $3 )->addQualifiers( $5 );
     2400                }
     2401        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
    23232402                {
    23242403                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
     
    23272406          '{' enumerator_list comma_opt '}'
    23282407                {
    2329                         $$ = DeclarationNode::newEnum( $6, $10, true ) -> addQualifiers( $5 ) -> addQualifiers( $7 ) -> addEnumBase( $3 );
     2408                        $$ = DeclarationNode::newEnum( $6, $10, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
    23302409                }
    23312410        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}'
     
    23332412                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    23342413                        typedefTable.makeTypedef( *$6->name );
    2335                         $$ = DeclarationNode::newEnum( $6->name, $9, true ) -> addQualifiers( $5 ) -> addQualifiers( $7 ) -> addEnumBase( $3 );
     2414                        $$ = DeclarationNode::newEnum( $6->name, $9, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
    23362415                }
    23372416        | enum_type_nobody
     
    28302909        // empty
    28312910                { $$ = nullptr; forall = false; }
    2832         | WITH '(' tuple_expression_list ')'
    2833                 { $$ = $3; forall = false; }
     2911        | WITH '(' tuple_expression_list ')' attribute_list_opt
     2912                {
     2913                        $$ = $3; forall = false;
     2914                        if ( $5 ) {
     2915                                SemanticError( yylloc, "Attributes cannot be associated with function body. Move attribute(s) before \"with\" clause." );
     2916                                $$ = nullptr;
     2917                        } // if
     2918                }
    28342919        ;
    28352920
  • src/ResolvExpr/AlternativeFinder.cc

    r29d8c02 r74ec742  
    4242#include "SymTab/Indexer.h"        // for Indexer
    4343#include "SymTab/Mangler.h"        // for Mangler
    44 #include "SymTab/Validate.h"       // for validateType
     44#include "SymTab/ValidateType.h"   // for validateType
    4545#include "SynTree/Constant.h"      // for Constant
    4646#include "SynTree/Declaration.h"   // for DeclarationWithType, TypeDecl, Dec...
  • src/ResolvExpr/Resolver.cc

    r29d8c02 r74ec742  
    427427                        // enumerator initializers should not use the enum type to initialize, since
    428428                        // the enum type is still incomplete at this point. Use signed int instead.
     429                        // TODO: BasicType::SignedInt may not longer be true
    429430                        currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    430431                }
     
    14771478                        // enum type is still incomplete at this point. Use `int` instead.
    14781479
    1479                         if (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base) { // const ast::PointerType &
    1480                                 // const ast::Type * enumBase =  (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base.get());
    1481                                 // const ast::PointerType * enumBaseAsPtr = dynamic_cast<const ast::PointerType *>(enumBase);
    1482 
    1483                                 // if ( enumBaseAsPtr ) {
    1484                                 //      const ast::Type * pointerBase = enumBaseAsPtr->base.get();
    1485                                 //      if ( dynamic_cast<const ast::BasicType *>(pointerBase) ) {
    1486                                 //              objectDecl = fixObjectType(objectDecl, context);
    1487                                 //              if (dynamic_cast<const ast::BasicType *>(pointerBase)->kind == ast::BasicType::Char)
    1488                                 //              currentObject = ast::CurrentObject{
    1489                                 //                      objectDecl->location,  new ast::PointerType{
    1490                                 //                              new ast::BasicType{ ast::BasicType::Char }
    1491                                 //                      } };
    1492                                 //      } else {
    1493                                 //              objectDecl = fixObjectType(objectDecl, context);
    1494                                 //              currentObject = ast::CurrentObject{objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
    1495                                 //      }
    1496                                 // }
     1480                        if (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base) {
    14971481                                objectDecl = fixObjectType( objectDecl, context );
    14981482                                const ast::Type * enumBase =  (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base.get());
  • src/SymTab/Autogen.h

    r29d8c02 r74ec742  
    2121
    2222#include "AST/Decl.hpp"
    23 #include "AST/Eval.hpp"
    2423#include "AST/Expr.hpp"
    2524#include "AST/Init.hpp"
     
    7170        template< typename OutIter >
    7271        ast::ptr< ast::Stmt > genCall(
    73                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
    74                 const CodeLocation & loc, const std::string & fname, OutIter && out, 
     72                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     73                const CodeLocation & loc, const std::string & fname, OutIter && out,
    7574                const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
    7675
     
    128127        }
    129128
    130         /// inserts into out a generated call expression to function fname with arguments dstParam and 
     129        /// inserts into out a generated call expression to function fname with arguments dstParam and
    131130        /// srcParam. Should only be called with non-array types.
    132         /// optionally returns a statement which must be inserted prior to the containing loop, if 
     131        /// optionally returns a statement which must be inserted prior to the containing loop, if
    133132        /// there is one
    134133        template< typename OutIter >
    135         ast::ptr< ast::Stmt > genScalarCall( 
    136                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
    137                 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type, 
     134        ast::ptr< ast::Stmt > genScalarCall(
     135                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     136                const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
    138137                const ast::Type * addCast = nullptr
    139138        ) {
     
    153152
    154153                if ( addCast ) {
    155                         // cast to T& with qualifiers removed, so that qualified objects can be constructed and 
    156                         // destructed with the same functions as non-qualified objects. Unfortunately, lvalue 
    157                         // is considered a qualifier - for AddressExpr to resolve, its argument must have an 
     154                        // cast to T& with qualifiers removed, so that qualified objects can be constructed and
     155                        // destructed with the same functions as non-qualified objects. Unfortunately, lvalue
     156                        // is considered a qualifier - for AddressExpr to resolve, its argument must have an
    158157                        // lvalue-qualified type, so remove all qualifiers except lvalue.
    159158                        // xxx -- old code actually removed lvalue too...
    160159                        ast::ptr< ast::Type > guard = addCast;  // prevent castType from mutating addCast
    161160                        ast::ptr< ast::Type > castType = addCast;
    162                         ast::remove_qualifiers( 
    163                                 castType, 
     161                        ast::remove_qualifiers(
     162                                castType,
    164163                                ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );
    165164                        dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };
     
    181180
    182181                srcParam.clearArrayIndices();
    183                
     182
    184183                return listInit;
    185184        }
     
    249248        }
    250249
    251         /// Store in out a loop which calls fname on each element of the array with srcParam and 
     250        /// Store in out a loop which calls fname on each element of the array with srcParam and
    252251        /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
    253252        template< typename OutIter >
    254253        void genArrayCall(
    255                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
    256                 const CodeLocation & loc, const std::string & fname, OutIter && out, 
    257                 const ast::ArrayType * array, const ast::Type * addCast = nullptr, 
    258                 LoopDirection forward = LoopForward 
     254                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     255                const CodeLocation & loc, const std::string & fname, OutIter && out,
     256                const ast::ArrayType * array, const ast::Type * addCast = nullptr,
     257                LoopDirection forward = LoopForward
    259258        ) {
    260259                static UniqueName indexName( "_index" );
     
    279278                } else {
    280279                        // generate: for ( int i = N-1; i >= 0; --i )
    281                         begin = ast::call(
    282                                 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
     280                        begin = ast::UntypedExpr::createCall( loc, "?-?",
     281                                { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
    283282                        end = ast::ConstantExpr::from_int( loc, 0 );
    284283                        cmp = "?>=?";
     
    286285                }
    287286
    288                 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{ 
    289                         loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 
     287                ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{
     288                        loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
    290289                        new ast::SingleInit{ loc, begin } };
    291290                ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
    292                
    293                 ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
    294                
    295                 ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
    296                
    297                 ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
    298                
    299                 // srcParam must keep track of the array indices to build the source parameter and/or
     291
     292                ast::ptr< ast::Expr > cond = ast::UntypedExpr::createCall(
     293                        loc, cmp, { indexVar, end } );
     294
     295                ast::ptr< ast::Expr > inc = ast::UntypedExpr::createCall(
     296                        loc, update, { indexVar } );
     297
     298                ast::ptr< ast::Expr > dstIndex = ast::UntypedExpr::createCall(
     299                        loc, "?[?]", { dstParam, indexVar } );
     300
     301                // srcParam must keep track of the array indices to build the source parameter and/or
    300302                // array list initializer
    301303                srcParam.addArrayIndex( indexVar, array->dimension );
     
    303305                // for stmt's body, eventually containing call
    304306                ast::CompoundStmt * body = new ast::CompoundStmt{ loc };
    305                 ast::ptr< ast::Stmt > listInit = genCall( 
    306                         srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast, 
     307                ast::ptr< ast::Stmt > listInit = genCall(
     308                        srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast,
    307309                        forward );
    308                
     310
    309311                // block containing the stmt and index variable
    310312                ast::CompoundStmt * block = new ast::CompoundStmt{ loc };
     
    328330        template< typename OutIter >
    329331        ast::ptr< ast::Stmt > genCall(
    330                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
    331                 const CodeLocation & loc, const std::string & fname, OutIter && out, 
     332                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     333                const CodeLocation & loc, const std::string & fname, OutIter && out,
    332334                const ast::Type * type, const ast::Type * addCast, LoopDirection forward
    333335        ) {
    334336                if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
    335                         genArrayCall( 
    336                                 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast, 
     337                        genArrayCall(
     338                                srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,
    337339                                forward );
    338340                        return {};
    339341                } else {
    340                         return genScalarCall( 
     342                        return genScalarCall(
    341343                                srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
    342344                }
     
    377379        }
    378380
    379         static inline ast::ptr< ast::Stmt > genImplicitCall( 
    380                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
    381                 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 
    382                 LoopDirection forward = LoopForward 
     381        static inline ast::ptr< ast::Stmt > genImplicitCall(
     382                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     383                const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
     384                LoopDirection forward = LoopForward
    383385        ) {
    384386                // unnamed bit fields are not copied as they cannot be accessed
     
    392394
    393395                std::vector< ast::ptr< ast::Stmt > > stmts;
    394                 genCall( 
     396                genCall(
    395397                        srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
    396398
     
    400402                        const ast::Stmt * callStmt = stmts.front();
    401403                        if ( addCast ) {
    402                                 // implicitly generated ctor/dtor calls should be wrapped so that later passes are 
     404                                // implicitly generated ctor/dtor calls should be wrapped so that later passes are
    403405                                // aware they were generated.
    404406                                callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt };
     
    417419// compile-command: "make install" //
    418420// End: //
    419 
  • src/SymTab/Demangle.cc

    r29d8c02 r74ec742  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Demangler.cc --
     7// Demangle.cc -- Convert a mangled name into a human readable name.
    88//
    99// Author           : Rob Schluntz
  • src/SymTab/Mangler.h

    r29d8c02 r74ec742  
    111111}
    112112
    113 extern "C" {
    114         char * cforall_demangle(const char *, int);
    115 }
    116 
    117113// Local Variables: //
    118114// tab-width: 4 //
  • src/SymTab/Validate.cc

    r29d8c02 r74ec742  
    1010// Created On       : Sun May 17 21:50:04 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Nov 12 11:00:00 2021
    13 // Update Count     : 364
     12// Last Modified On : Tue May 17 14:36:00 2022
     13// Update Count     : 366
    1414//
    1515
     
    7474#include "ResolvExpr/ResolveTypeof.h"  // for resolveTypeof
    7575#include "SymTab/Autogen.h"            // for SizeType
     76#include "SymTab/ValidateType.h"       // for decayEnumsAndPointers, decayFo...
    7677#include "SynTree/LinkageSpec.h"       // for C
    7778#include "SynTree/Attribute.h"         // for noAttributes, Attribute
     
    134135        };
    135136
    136         /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers.
    137         struct EnumAndPointerDecay_old {
    138                 void previsit( EnumDecl * aggregateDecl );
    139                 void previsit( FunctionType * func );
    140         };
    141 
    142         /// Associates forward declarations of aggregates with their definitions
    143         struct LinkReferenceToTypes_old final : public WithIndexer, public WithGuards, public WithVisitorRef<LinkReferenceToTypes_old>, public WithShortCircuiting {
    144                 LinkReferenceToTypes_old( const Indexer * indexer );
    145                 void postvisit( TypeInstType * typeInst );
    146 
    147                 void postvisit( EnumInstType * enumInst );
    148                 void postvisit( StructInstType * structInst );
    149                 void postvisit( UnionInstType * unionInst );
    150                 void postvisit( TraitInstType * traitInst );
    151                 void previsit( QualifiedType * qualType );
    152                 void postvisit( QualifiedType * qualType );
    153 
    154                 void postvisit( EnumDecl * enumDecl );
    155                 void postvisit( StructDecl * structDecl );
    156                 void postvisit( UnionDecl * unionDecl );
    157                 void postvisit( TraitDecl * traitDecl );
    158 
    159                 void previsit( StructDecl * structDecl );
    160                 void previsit( UnionDecl * unionDecl );
    161 
    162                 void renameGenericParams( std::list< TypeDecl * > & params );
    163 
    164           private:
    165                 const Indexer * local_indexer;
    166 
    167                 typedef std::map< std::string, std::list< EnumInstType * > > ForwardEnumsType;
    168                 typedef std::map< std::string, std::list< StructInstType * > > ForwardStructsType;
    169                 typedef std::map< std::string, std::list< UnionInstType * > > ForwardUnionsType;
    170                 ForwardEnumsType forwardEnums;
    171                 ForwardStructsType forwardStructs;
    172                 ForwardUnionsType forwardUnions;
    173                 /// true if currently in a generic type body, so that type parameter instances can be renamed appropriately
    174                 bool inGeneric = false;
    175         };
    176 
    177137        /// Does early resolution on the expressions that give enumeration constants their values
    178138        struct ResolveEnumInitializers final : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveEnumInitializers>, public WithShortCircuiting {
     
    192152                void previsit( StructDecl * aggrDecl );
    193153                void previsit( UnionDecl * aggrDecl );
    194         };
    195 
    196         // These structs are the sub-sub-passes of ForallPointerDecay_old.
    197 
    198         struct TraitExpander_old final {
    199                 void previsit( FunctionType * );
    200                 void previsit( StructDecl * );
    201                 void previsit( UnionDecl * );
    202         };
    203 
    204         struct AssertionFixer_old final {
    205                 void previsit( FunctionType * );
    206                 void previsit( StructDecl * );
    207                 void previsit( UnionDecl * );
    208         };
    209 
    210         struct CheckOperatorTypes_old final {
    211                 void previsit( ObjectDecl * );
    212         };
    213 
    214         struct FixUniqueIds_old final {
    215                 void previsit( DeclarationWithType * );
    216154        };
    217155
     
    357295
    358296        void validate_A( std::list< Declaration * > & translationUnit ) {
    359                 PassVisitor<EnumAndPointerDecay_old> epc;
    360297                PassVisitor<HoistTypeDecls> hoistDecls;
    361298                {
     
    366303                        ReplaceTypedef::replaceTypedef( translationUnit );
    367304                        ReturnTypeFixer::fix( translationUnit ); // must happen before autogen
    368                         acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling
     305                        decayEnumsAndPointers( translationUnit ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling
    369306                }
    370307        }
    371308
    372309        void validate_B( std::list< Declaration * > & translationUnit ) {
    373                 PassVisitor<LinkReferenceToTypes_old> lrt( nullptr );
    374310                PassVisitor<FixQualifiedTypes> fixQual;
    375311                {
    376312                        Stats::Heap::newPass("validate-B");
    377313                        Stats::Time::BlockGuard guard("validate-B");
    378                         acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions
     314                        //linkReferenceToTypes( translationUnit );
    379315                        mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes_old, because aggregate members are accessed
    380316                        HoistStruct::hoistStruct( translationUnit );
     
    407343                        });
    408344                }
    409         }
    410 
    411         static void decayForallPointers( std::list< Declaration * > & translationUnit ) {
    412                 PassVisitor<TraitExpander_old> te;
    413                 acceptAll( translationUnit, te );
    414                 PassVisitor<AssertionFixer_old> af;
    415                 acceptAll( translationUnit, af );
    416                 PassVisitor<CheckOperatorTypes_old> cot;
    417                 acceptAll( translationUnit, cot );
    418                 PassVisitor<FixUniqueIds_old> fui;
    419                 acceptAll( translationUnit, fui );
    420345        }
    421346
     
    496421        }
    497422
    498         void validateType( Type * type, const Indexer * indexer ) {
    499                 PassVisitor<EnumAndPointerDecay_old> epc;
    500                 PassVisitor<LinkReferenceToTypes_old> lrt( indexer );
    501                 PassVisitor<TraitExpander_old> te;
    502                 PassVisitor<AssertionFixer_old> af;
    503                 PassVisitor<CheckOperatorTypes_old> cot;
    504                 PassVisitor<FixUniqueIds_old> fui;
    505                 type->accept( epc );
    506                 type->accept( lrt );
    507                 type->accept( te );
    508                 type->accept( af );
    509                 type->accept( cot );
    510                 type->accept( fui );
    511         }
    512 
    513423        void HoistTypeDecls::handleType( Type * type ) {
    514424                // some type declarations are buried in expressions and not easy to hoist during parsing; hoist them here
     
    703613        }
    704614
    705         void EnumAndPointerDecay_old::previsit( EnumDecl * enumDecl ) {
    706                 // Set the type of each member of the enumeration to be EnumConstant
    707                 for ( std::list< Declaration * >::iterator i = enumDecl->members.begin(); i != enumDecl->members.end(); ++i ) {
    708                         ObjectDecl * obj = dynamic_cast< ObjectDecl * >( * i );
    709                         assert( obj );
    710                         obj->set_type( new EnumInstType( Type::Qualifiers( Type::Const ), enumDecl->name ) );
    711                 } // for
    712         }
    713 
    714         namespace {
    715                 template< typename DWTList >
    716                 void fixFunctionList( DWTList & dwts, bool isVarArgs, FunctionType * func ) {
    717                         auto nvals = dwts.size();
    718                         bool containsVoid = false;
    719                         for ( auto & dwt : dwts ) {
    720                                 // fix each DWT and record whether a void was found
    721                                 containsVoid |= fixFunction( dwt );
    722                         }
    723 
    724                         // the only case in which "void" is valid is where it is the only one in the list
    725                         if ( containsVoid && ( nvals > 1 || isVarArgs ) ) {
    726                                 SemanticError( func, "invalid type void in function type " );
    727                         }
    728 
    729                         // one void is the only thing in the list; remove it.
    730                         if ( containsVoid ) {
    731                                 delete dwts.front();
    732                                 dwts.clear();
    733                         }
    734                 }
    735         }
    736 
    737         void EnumAndPointerDecay_old::previsit( FunctionType * func ) {
    738                 // Fix up parameters and return types
    739                 fixFunctionList( func->parameters, func->isVarArgs, func );
    740                 fixFunctionList( func->returnVals, false, func );
    741         }
    742 
    743         LinkReferenceToTypes_old::LinkReferenceToTypes_old( const Indexer * other_indexer ) : WithIndexer( false ) {
    744                 if ( other_indexer ) {
    745                         local_indexer = other_indexer;
    746                 } else {
    747                         local_indexer = &indexer;
    748                 } // if
    749         }
    750 
    751         void LinkReferenceToTypes_old::postvisit( EnumInstType * enumInst ) {
    752                 const EnumDecl * st = local_indexer->lookupEnum( enumInst->name );
    753                 // it's not a semantic error if the enum is not found, just an implicit forward declaration
    754                 if ( st ) {
    755                         enumInst->baseEnum = const_cast<EnumDecl *>(st); // Just linking in the node
    756                 } // if
    757                 if ( ! st || ! st->body ) {
    758                         // use of forward declaration
    759                         forwardEnums[ enumInst->name ].push_back( enumInst );
    760                 } // if
    761         }
    762 
    763         void LinkReferenceToTypes_old::postvisit( StructInstType * structInst ) {
    764                 const StructDecl * st = local_indexer->lookupStruct( structInst->name );
    765                 // it's not a semantic error if the struct is not found, just an implicit forward declaration
    766                 if ( st ) {
    767                         structInst->baseStruct = const_cast<StructDecl *>(st); // Just linking in the node
    768                 } // if
    769                 if ( ! st || ! st->body ) {
    770                         // use of forward declaration
    771                         forwardStructs[ structInst->name ].push_back( structInst );
    772                 } // if
    773         }
    774 
    775         void LinkReferenceToTypes_old::postvisit( UnionInstType * unionInst ) {
    776                 const UnionDecl * un = local_indexer->lookupUnion( unionInst->name );
    777                 // it's not a semantic error if the union is not found, just an implicit forward declaration
    778                 if ( un ) {
    779                         unionInst->baseUnion = const_cast<UnionDecl *>(un); // Just linking in the node
    780                 } // if
    781                 if ( ! un || ! un->body ) {
    782                         // use of forward declaration
    783                         forwardUnions[ unionInst->name ].push_back( unionInst );
    784                 } // if
    785         }
    786 
    787         void LinkReferenceToTypes_old::previsit( QualifiedType * ) {
    788                 visit_children = false;
    789         }
    790 
    791         void LinkReferenceToTypes_old::postvisit( QualifiedType * qualType ) {
    792                 // linking only makes sense for the 'oldest ancestor' of the qualified type
    793                 qualType->parent->accept( * visitor );
    794         }
    795 
    796         template< typename Decl >
    797         void normalizeAssertions( std::list< Decl * > & assertions ) {
    798                 // ensure no duplicate trait members after the clone
    799                 auto pred = [](Decl * d1, Decl * d2) {
    800                         // only care if they're equal
    801                         DeclarationWithType * dwt1 = dynamic_cast<DeclarationWithType *>( d1 );
    802                         DeclarationWithType * dwt2 = dynamic_cast<DeclarationWithType *>( d2 );
    803                         if ( dwt1 && dwt2 ) {
    804                                 if ( dwt1->name == dwt2->name && ResolvExpr::typesCompatible( dwt1->get_type(), dwt2->get_type(), SymTab::Indexer() ) ) {
    805                                         // std::cerr << "=========== equal:" << std::endl;
    806                                         // std::cerr << "d1: " << d1 << std::endl;
    807                                         // std::cerr << "d2: " << d2 << std::endl;
    808                                         return false;
    809                                 }
    810                         }
    811                         return d1 < d2;
    812                 };
    813                 std::set<Decl *, decltype(pred)> unique_members( assertions.begin(), assertions.end(), pred );
    814                 // if ( unique_members.size() != assertions.size() ) {
    815                 //      std::cerr << "============different" << std::endl;
    816                 //      std::cerr << unique_members.size() << " " << assertions.size() << std::endl;
    817                 // }
    818 
    819                 std::list< Decl * > order;
    820                 order.splice( order.end(), assertions );
    821                 std::copy_if( order.begin(), order.end(), back_inserter( assertions ), [&]( Decl * decl ) {
    822                         return unique_members.count( decl );
    823                 });
    824         }
    825 
    826615        // expand assertions from trait instance, performing the appropriate type variable substitutions
    827616        template< typename Iterator >
     
    834623                // substitute trait decl parameters for instance parameters
    835624                applySubstitution( inst->baseTrait->parameters.begin(), inst->baseTrait->parameters.end(), inst->parameters.begin(), asserts.begin(), asserts.end(), out );
    836         }
    837 
    838         void LinkReferenceToTypes_old::postvisit( TraitDecl * traitDecl ) {
    839                 if ( traitDecl->name == "sized" ) {
    840                         // "sized" is a special trait - flick the sized status on for the type variable
    841                         assertf( traitDecl->parameters.size() == 1, "Built-in trait 'sized' has incorrect number of parameters: %zd", traitDecl->parameters.size() );
    842                         TypeDecl * td = traitDecl->parameters.front();
    843                         td->set_sized( true );
    844                 }
    845 
    846                 // move assertions from type parameters into the body of the trait
    847                 for ( TypeDecl * td : traitDecl->parameters ) {
    848                         for ( DeclarationWithType * assert : td->assertions ) {
    849                                 if ( TraitInstType * inst = dynamic_cast< TraitInstType * >( assert->get_type() ) ) {
    850                                         expandAssertions( inst, back_inserter( traitDecl->members ) );
    851                                 } else {
    852                                         traitDecl->members.push_back( assert->clone() );
    853                                 }
    854                         }
    855                         deleteAll( td->assertions );
    856                         td->assertions.clear();
    857                 } // for
    858         }
    859 
    860         void LinkReferenceToTypes_old::postvisit( TraitInstType * traitInst ) {
    861                 // handle other traits
    862                 const TraitDecl * traitDecl = local_indexer->lookupTrait( traitInst->name );
    863                 if ( ! traitDecl ) {
    864                         SemanticError( traitInst->location, "use of undeclared trait " + traitInst->name );
    865                 } // if
    866                 if ( traitDecl->parameters.size() != traitInst->parameters.size() ) {
    867                         SemanticError( traitInst, "incorrect number of trait parameters: " );
    868                 } // if
    869                 traitInst->baseTrait = const_cast<TraitDecl *>(traitDecl); // Just linking in the node
    870 
    871                 // need to carry over the 'sized' status of each decl in the instance
    872                 for ( auto p : group_iterate( traitDecl->parameters, traitInst->parameters ) ) {
    873                         TypeExpr * expr = dynamic_cast< TypeExpr * >( std::get<1>(p) );
    874                         if ( ! expr ) {
    875                                 SemanticError( std::get<1>(p), "Expression parameters for trait instances are currently unsupported: " );
    876                         }
    877                         if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( expr->get_type() ) ) {
    878                                 TypeDecl * formalDecl = std::get<0>(p);
    879                                 TypeDecl * instDecl = inst->baseType;
    880                                 if ( formalDecl->get_sized() ) instDecl->set_sized( true );
    881                         }
    882                 }
    883                 // normalizeAssertions( traitInst->members );
    884         }
    885 
    886         void LinkReferenceToTypes_old::postvisit( EnumDecl * enumDecl ) {
    887                 // visit enum members first so that the types of self-referencing members are updated properly
    888                 if ( enumDecl->body ) {
    889                         ForwardEnumsType::iterator fwds = forwardEnums.find( enumDecl->name );
    890                         if ( fwds != forwardEnums.end() ) {
    891                                 for ( std::list< EnumInstType * >::iterator inst = fwds->second.begin(); inst != fwds->second.end(); ++inst ) {
    892                                         (* inst)->baseEnum = enumDecl;
    893                                 } // for
    894                                 forwardEnums.erase( fwds );
    895                         } // if
    896                 } // if
    897         }
    898 
    899         void LinkReferenceToTypes_old::renameGenericParams( std::list< TypeDecl * > & params ) {
    900                 // rename generic type parameters uniquely so that they do not conflict with user-defined function forall parameters, e.g.
    901                 //   forall(otype T)
    902                 //   struct Box {
    903                 //     T x;
    904                 //   };
    905                 //   forall(otype T)
    906                 //   void f(Box(T) b) {
    907                 //     ...
    908                 //   }
    909                 // The T in Box and the T in f are different, so internally the naming must reflect that.
    910                 GuardValue( inGeneric );
    911                 inGeneric = ! params.empty();
    912                 for ( TypeDecl * td : params ) {
    913                         td->name = "__" + td->name + "_generic_";
    914                 }
    915         }
    916 
    917         void LinkReferenceToTypes_old::previsit( StructDecl * structDecl ) {
    918                 renameGenericParams( structDecl->parameters );
    919         }
    920 
    921         void LinkReferenceToTypes_old::previsit( UnionDecl * unionDecl ) {
    922                 renameGenericParams( unionDecl->parameters );
    923         }
    924 
    925         void LinkReferenceToTypes_old::postvisit( StructDecl * structDecl ) {
    926                 // visit struct members first so that the types of self-referencing members are updated properly
    927                 // xxx - need to ensure that type parameters match up between forward declarations and definition (most importantly, number of type parameters and their defaults)
    928                 if ( structDecl->body ) {
    929                         ForwardStructsType::iterator fwds = forwardStructs.find( structDecl->name );
    930                         if ( fwds != forwardStructs.end() ) {
    931                                 for ( std::list< StructInstType * >::iterator inst = fwds->second.begin(); inst != fwds->second.end(); ++inst ) {
    932                                         (* inst)->baseStruct = structDecl;
    933                                 } // for
    934                                 forwardStructs.erase( fwds );
    935                         } // if
    936                 } // if
    937         }
    938 
    939         void LinkReferenceToTypes_old::postvisit( UnionDecl * unionDecl ) {
    940                 if ( unionDecl->body ) {
    941                         ForwardUnionsType::iterator fwds = forwardUnions.find( unionDecl->name );
    942                         if ( fwds != forwardUnions.end() ) {
    943                                 for ( std::list< UnionInstType * >::iterator inst = fwds->second.begin(); inst != fwds->second.end(); ++inst ) {
    944                                         (* inst)->baseUnion = unionDecl;
    945                                 } // for
    946                                 forwardUnions.erase( fwds );
    947                         } // if
    948                 } // if
    949         }
    950 
    951         void LinkReferenceToTypes_old::postvisit( TypeInstType * typeInst ) {
    952                 // ensure generic parameter instances are renamed like the base type
    953                 if ( inGeneric && typeInst->baseType ) typeInst->name = typeInst->baseType->name;
    954                 if ( const NamedTypeDecl * namedTypeDecl = local_indexer->lookupType( typeInst->name ) ) {
    955                         if ( const TypeDecl * typeDecl = dynamic_cast< const TypeDecl * >( namedTypeDecl ) ) {
    956                                 typeInst->set_isFtype( typeDecl->kind == TypeDecl::Ftype );
    957                         } // if
    958                 } // if
    959625        }
    960626
     
    985651                                                }
    986652                                        }
    987                                        
    988653                                }
    989654                        }
     
    1073738        void ForallPointerDecay_old::previsit( UnionDecl * aggrDecl ) {
    1074739                forallFixer( aggrDecl->parameters, aggrDecl );
    1075         }
    1076 
    1077         void TraitExpander_old::previsit( FunctionType * ftype ) {
    1078                 expandTraits( ftype->forall );
    1079         }
    1080 
    1081         void TraitExpander_old::previsit( StructDecl * aggrDecl ) {
    1082                 expandTraits( aggrDecl->parameters );
    1083         }
    1084 
    1085         void TraitExpander_old::previsit( UnionDecl * aggrDecl ) {
    1086                 expandTraits( aggrDecl->parameters );
    1087         }
    1088 
    1089         void AssertionFixer_old::previsit( FunctionType * ftype ) {
    1090                 fixAssertions( ftype->forall, ftype );
    1091         }
    1092 
    1093         void AssertionFixer_old::previsit( StructDecl * aggrDecl ) {
    1094                 fixAssertions( aggrDecl->parameters, aggrDecl );
    1095         }
    1096 
    1097         void AssertionFixer_old::previsit( UnionDecl * aggrDecl ) {
    1098                 fixAssertions( aggrDecl->parameters, aggrDecl );
    1099         }
    1100 
    1101         void CheckOperatorTypes_old::previsit( ObjectDecl * object ) {
    1102                 // ensure that operator names only apply to functions or function pointers
    1103                 if ( CodeGen::isOperator( object->name ) && ! dynamic_cast< FunctionType * >( object->type->stripDeclarator() ) ) {
    1104                         SemanticError( object->location, toCString( "operator ", object->name.c_str(), " is not a function or function pointer." )  );
    1105                 }
    1106         }
    1107 
    1108         void FixUniqueIds_old::previsit( DeclarationWithType * decl ) {
    1109                 decl->fixUniqueId();
    1110740        }
    1111741
  • src/SymTab/Validate.h

    r29d8c02 r74ec742  
    1010// Author           : Richard C. Bilson
    1111// Created On       : Sun May 17 21:53:34 2015
    12 // Last Modified By : Peter A. Buhr
    13 // Last Modified On : Sat Jul 22 09:46:07 2017
    14 // Update Count     : 4
     12// Last Modified By : Andrew Beach
     13// Last Modified On : Tue May 17 14:35:00 2022
     14// Update Count     : 5
    1515//
    1616
     
    3333        /// Normalizes struct and function declarations
    3434        void validate( std::list< Declaration * > &translationUnit, bool doDebug = false );
    35         void validateType( Type *type, const Indexer *indexer );
    3635
    3736        // Sub-passes of validate.
     
    4241        void validate_E( std::list< Declaration * > &translationUnit );
    4342        void validate_F( std::list< Declaration * > &translationUnit );
    44 
    45         const ast::Type * validateType(
    46                 const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab );
    4743} // namespace SymTab
    4844
  • src/SymTab/demangler.cc

    r29d8c02 r74ec742  
    1 #include "Mangler.h"
     1#include "Demangle.h"
    22#include <iostream>
    33#include <fstream>
  • src/SymTab/module.mk

    r29d8c02 r74ec742  
    1111## Created On       : Mon Jun  1 17:49:17 2015
    1212## Last Modified By : Andrew Beach
    13 ## Last Modified On : Thr Aug 10 16:08:00 2017
    14 ## Update Count     : 4
     13## Last Modified On : Tue May 17 14:46:00 2022
     14## Update Count     : 5
    1515###############################################################################
    1616
    1717SRC_SYMTAB = \
    18       SymTab/Autogen.cc \
    19       SymTab/Autogen.h \
    20       SymTab/FixFunction.cc \
    21       SymTab/FixFunction.h \
    22       SymTab/Indexer.cc \
    23       SymTab/Indexer.h \
    24       SymTab/Mangler.cc \
    25       SymTab/ManglerCommon.cc \
    26       SymTab/Mangler.h \
    27       SymTab/Validate.cc \
    28       SymTab/Validate.h
     18        SymTab/Autogen.cc \
     19        SymTab/Autogen.h \
     20        SymTab/FixFunction.cc \
     21        SymTab/FixFunction.h \
     22        SymTab/Indexer.cc \
     23        SymTab/Indexer.h \
     24        SymTab/Mangler.cc \
     25        SymTab/ManglerCommon.cc \
     26        SymTab/Mangler.h \
     27        SymTab/ValidateType.cc \
     28        SymTab/ValidateType.h
    2929
    30 SRC += $(SRC_SYMTAB)
    31 SRCDEMANGLE += $(SRC_SYMTAB) SymTab/Demangle.cc
     30SRC += $(SRC_SYMTAB) \
     31        SymTab/Validate.cc \
     32        SymTab/Validate.h
     33
     34SRCDEMANGLE += $(SRC_SYMTAB) \
     35        SymTab/Demangle.cc \
     36        SymTab/Demangle.h
  • src/SynTree/module.mk

    r29d8c02 r74ec742  
    2424      SynTree/AttrType.cc \
    2525      SynTree/BaseSyntaxNode.h \
     26      SynTree/BaseSyntaxNode.cc \
    2627      SynTree/BasicType.cc \
    2728      SynTree/CommaExpr.cc \
  • src/Tuples/TupleExpansion.cc

    r29d8c02 r74ec742  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:45:51 2019
    13 // Update Count     : 24
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue May 17 15:02:00 2022
     13// Update Count     : 25
    1414//
    1515
     
    367367                return nullptr;
    368368        }
    369 
    370         namespace {
    371                 /// determines if impurity (read: side-effects) may exist in a piece of code. Currently gives a very crude approximation, wherein any function call expression means the code may be impure
    372                 struct ImpurityDetector : public WithShortCircuiting {
    373                         ImpurityDetector( bool ignoreUnique ) : ignoreUnique( ignoreUnique ) {}
    374 
    375                         void previsit( const ApplicationExpr * appExpr ) {
    376                                 visit_children = false;
    377                                 if ( const DeclarationWithType * function = InitTweak::getFunction( appExpr ) ) {
    378                                         if ( function->linkage == LinkageSpec::Intrinsic ) {
    379                                                 if ( function->name == "*?" || function->name == "?[?]" ) {
    380                                                         // intrinsic dereference, subscript are pure, but need to recursively look for impurity
    381                                                         visit_children = true;
    382                                                         return;
    383                                                 }
    384                                         }
    385                                 }
    386                                 maybeImpure = true;
    387                         }
    388                         void previsit( const UntypedExpr * ) { maybeImpure = true; visit_children = false; }
    389                         void previsit( const UniqueExpr * ) {
    390                                 if ( ignoreUnique ) {
    391                                         // bottom out at unique expression.
    392                                         // The existence of a unique expression doesn't change the purity of an expression.
    393                                         // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.
    394                                         visit_children = false;
    395                                         return;
    396                                 }
    397                         }
    398 
    399                         bool maybeImpure = false;
    400                         bool ignoreUnique;
    401                 };
    402         } // namespace
    403 
    404         bool maybeImpure( const Expression * expr ) {
    405                 PassVisitor<ImpurityDetector> detector( false );
    406                 expr->accept( detector );
    407                 return detector.pass.maybeImpure;
    408         }
    409 
    410         bool maybeImpureIgnoreUnique( const Expression * expr ) {
    411                 PassVisitor<ImpurityDetector> detector( true );
    412                 expr->accept( detector );
    413                 return detector.pass.maybeImpure;
    414         }
    415369} // namespace Tuples
    416370
  • src/Tuples/Tuples.cc

    r29d8c02 r74ec742  
    1010// Created On       : Mon Jun 17 14:41:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Jun 18  9:31:00 2019
    13 // Update Count     : 1
     12// Last Modified On : Mon May 16 16:15:00 2022
     13// Update Count     : 2
    1414//
    1515
     
    1818#include "AST/Pass.hpp"
    1919#include "AST/LinkageSpec.hpp"
     20#include "Common/PassVisitor.h"
    2021#include "InitTweak/InitTweak.h"
    2122
     
    2324
    2425namespace {
     26        /// Checks if impurity (read: side-effects) may exist in a piece of code.
     27        /// Currently gives a very crude approximation, wherein any function
     28        /// call expression means the code may be impure.
     29        struct ImpurityDetector_old : public WithShortCircuiting {
     30                bool const ignoreUnique;
     31                bool maybeImpure;
     32
     33                ImpurityDetector_old( bool ignoreUnique ) :
     34                        ignoreUnique( ignoreUnique ), maybeImpure( false )
     35                {}
     36
     37                void previsit( const ApplicationExpr * appExpr ) {
     38                        visit_children = false;
     39                        if ( const DeclarationWithType * function =
     40                                        InitTweak::getFunction( appExpr ) ) {
     41                                if ( function->linkage == LinkageSpec::Intrinsic ) {
     42                                        if ( function->name == "*?" || function->name == "?[?]" ) {
     43                                                // intrinsic dereference, subscript are pure,
     44                                                // but need to recursively look for impurity
     45                                                visit_children = true;
     46                                                return;
     47                                        }
     48                                }
     49                        }
     50                        maybeImpure = true;
     51                }
     52
     53                void previsit( const UntypedExpr * ) {
     54                        maybeImpure = true;
     55                        visit_children = false;
     56                }
     57
     58                void previsit( const UniqueExpr * ) {
     59                        if ( ignoreUnique ) {
     60                                // bottom out at unique expression.
     61                                // The existence of a unique expression doesn't change the purity of an expression.
     62                                // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.
     63                                visit_children = false;
     64                                return;
     65                        }
     66                }
     67        };
     68
     69        bool detectImpurity( const Expression * expr, bool ignoreUnique ) {
     70                PassVisitor<ImpurityDetector_old> detector( ignoreUnique );
     71                expr->accept( detector );
     72                return detector.pass.maybeImpure;
     73        }
     74
    2575        /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives
    2676        /// a very crude approximation, wherein any function call expression means the code may be
    2777        /// impure.
    2878    struct ImpurityDetector : public ast::WithShortCircuiting {
    29                 bool maybeImpure = false;
     79                bool result = false;
    3080
    3181                void previsit( ast::ApplicationExpr const * appExpr ) {
     
    3686                                }
    3787                        }
    38                         maybeImpure = true; visit_children = false;
     88                        result = true; visit_children = false;
    3989                }
    4090                void previsit( ast::UntypedExpr const * ) {
    41                         maybeImpure = true; visit_children = false;
     91                        result = true; visit_children = false;
    4292                }
    4393        };
     94
    4495        struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
    4596                using ImpurityDetector::previsit;
     
    4899                }
    49100        };
    50 
    51         template<typename Detector>
    52         bool detectImpurity( const ast::Expr * expr ) {
    53                 ast::Pass<Detector> detector;
    54                 expr->accept( detector );
    55                 return detector.core.maybeImpure;
    56         }
    57101} // namespace
    58102
    59103bool maybeImpure( const ast::Expr * expr ) {
    60         return detectImpurity<ImpurityDetector>( expr );
     104        return ast::Pass<ImpurityDetector>::read( expr );
    61105}
    62106
    63107bool maybeImpureIgnoreUnique( const ast::Expr * expr ) {
    64         return detectImpurity<ImpurityDetectorIgnoreUnique>( expr );
     108        return ast::Pass<ImpurityDetectorIgnoreUnique>::read( expr );
     109}
     110
     111bool maybeImpure( const Expression * expr ) {
     112        return detectImpurity( expr, false );
     113}
     114
     115bool maybeImpureIgnoreUnique( const Expression * expr ) {
     116        return detectImpurity( expr, true );
    65117}
    66118
  • src/Tuples/module.mk

    r29d8c02 r74ec742  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Henry Xue
    13 ## Last Modified On : Mon Aug 23 15:36:09 2021
    14 ## Update Count     : 2
     12## Last Modified By : Andrew Beach
     13## Last Modified On : Mon May 17 15:00:00 2022
     14## Update Count     : 3
    1515###############################################################################
    1616
     
    2424        Tuples/Tuples.h
    2525
     26SRC += $(SRC_TUPLES)
    2627
    27 SRC += $(SRC_TUPLES)
    2828SRCDEMANGLE += $(SRC_TUPLES)
  • src/Validate/Autogen.cpp

    r29d8c02 r74ec742  
    350350                name,
    351351                std::move( type_params ),
     352                std::move( assertions ),
    352353                std::move( params ),
    353354                std::move( returns ),
     
    360361                // Auto-generated routines are inline to avoid conflicts.
    361362                ast::Function::Specs( ast::Function::Inline ) );
    362         decl->assertions = std::move( assertions );
    363363        decl->fixUniqueId();
    364364        return decl;
  • src/Validate/ForallPointerDecay.cpp

    r29d8c02 r74ec742  
    1010// Created On       : Tue Dec  7 16:15:00 2021
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Feb 11 10:59:00 2022
    13 // Update Count     : 0
     12// Last Modified On : Sat Apr 23 13:10:00 2022
     13// Update Count     : 1
    1414//
    1515
     
    237237}
    238238
     239std::vector<ast::ptr<ast::DeclWithType>> expandAssertions(
     240                std::vector<ast::ptr<ast::DeclWithType>> const & old ) {
     241        return TraitExpander::expandAssertions( old );
     242}
     243
    239244} // namespace Validate
    240245
  • src/Validate/ForallPointerDecay.hpp

    r29d8c02 r74ec742  
    1010// Created On       : Tue Dec  7 16:15:00 2021
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Dec  8 11:50:00 2021
    13 // Update Count     : 0
     12// Last Modified On : Sat Apr 23 13:13:00 2022
     13// Update Count     : 1
    1414//
    1515
    1616#pragma once
    1717
     18#include <vector>
     19#include "AST/Node.hpp"
     20
    1821namespace ast {
     22        class DeclWithType;
    1923        class TranslationUnit;
    2024}
     
    2731void decayForallPointers( ast::TranslationUnit & transUnit );
    2832
     33/// Expand all traits in an assertion list.
     34std::vector<ast::ptr<ast::DeclWithType>> expandAssertions(
     35        std::vector<ast::ptr<ast::DeclWithType>> const & );
     36
    2937}
    3038
  • src/Validate/GenericParameter.cpp

    r29d8c02 r74ec742  
    1010// Created On       : Fri Mar 21 10:02:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr 13 10:09:00 2022
    13 // Update Count     : 0
     12// Last Modified On : Fri Apr 22 16:43:00 2022
     13// Update Count     : 1
    1414//
    1515
     
    2222#include "AST/TranslationUnit.hpp"
    2323#include "AST/Type.hpp"
     24#include "Validate/NoIdSymbolTable.hpp"
    2425
    2526namespace Validate {
     
    138139// --------------------------------------------------------------------------
    139140
    140 // A SymbolTable that only has the operations used in the Translate Dimension
    141 // pass. More importantly, it doesn't have some methods that should no be
    142 // called by the Pass template (lookupId and addId).
    143 class NoIdSymbolTable {
    144         ast::SymbolTable base;
    145 public:
    146 #       define FORWARD_X( func, types_and_names, just_names ) \
    147         inline auto func types_and_names -> decltype( base.func just_names ) { \
    148                 return base.func just_names ; \
    149         }
    150 #       define FORWARD_0( func )         FORWARD_X( func, (),             () )
    151 #       define FORWARD_1( func, type )   FORWARD_X( func, (type arg),     (arg) )
    152 #       define FORWARD_2( func, t0, t1 ) FORWARD_X( func, (t0 a0, t1 a1), (a0, a1) )
    153 
    154         FORWARD_0( enterScope )
    155         FORWARD_0( leaveScope )
    156         FORWARD_1( lookupType, const std::string &        )
    157         FORWARD_1( addType   , const ast::NamedTypeDecl * )
    158         FORWARD_1( addStruct , const ast::StructDecl *    )
    159         FORWARD_1( addEnum   , const ast::EnumDecl *      )
    160         FORWARD_1( addUnion  , const ast::UnionDecl *     )
    161         FORWARD_1( addTrait  , const ast::TraitDecl *     )
    162         FORWARD_2( addWith   , const std::vector< ast::ptr<ast::Expr> > &, const ast::Decl * )
    163 };
    164 
    165 struct TranslateDimensionCore : public ast::WithGuards {
    166         NoIdSymbolTable symtab;
     141struct TranslateDimensionCore :
     142                public WithNoIdSymbolTable, public ast::WithGuards {
    167143
    168144        // SUIT: Struct- or Union- InstType
  • src/Validate/module.mk

    r29d8c02 r74ec742  
    1010## Author           : Rob Schluntz
    1111## Created On       : Fri Jul 27 10:10:10 2018
    12 ## Last Modified By : Rob Schluntz
    13 ## Last Modified On : Fri Jul 27 10:10:26 2018
    14 ## Update Count     : 2
     12## Last Modified By : Andrew Beach
     13## Last Modified On : Tue May 17 14:59:00 2022
     14## Update Count     : 3
    1515###############################################################################
    1616
    1717SRC_VALIDATE = \
     18        Validate/FindSpecialDecls.cc \
     19        Validate/FindSpecialDecls.h
     20
     21SRC += $(SRC_VALIDATE) \
    1822        Validate/Autogen.cpp \
    1923        Validate/Autogen.hpp \
    2024        Validate/CompoundLiteral.cpp \
    2125        Validate/CompoundLiteral.hpp \
     26        Validate/EliminateTypedef.cpp \
     27        Validate/EliminateTypedef.hpp \
     28        Validate/FindSpecialDeclsNew.cpp \
     29        Validate/FixQualifiedTypes.cpp \
     30        Validate/FixQualifiedTypes.hpp \
    2231        Validate/ForallPointerDecay.cpp \
    2332        Validate/ForallPointerDecay.hpp \
     
    2635        Validate/HandleAttributes.cc \
    2736        Validate/HandleAttributes.h \
     37        Validate/HoistStruct.cpp \
     38        Validate/HoistStruct.hpp \
    2839        Validate/InitializerLength.cpp \
    2940        Validate/InitializerLength.hpp \
    3041        Validate/LabelAddressFixer.cpp \
    3142        Validate/LabelAddressFixer.hpp \
     43        Validate/NoIdSymbolTable.hpp \
    3244        Validate/ReturnCheck.cpp \
    33         Validate/ReturnCheck.hpp \
    34         Validate/FindSpecialDeclsNew.cpp \
    35         Validate/FindSpecialDecls.cc \
    36         Validate/FindSpecialDecls.h
     45        Validate/ReturnCheck.hpp
    3746
    38 SRC += $(SRC_VALIDATE)
    3947SRCDEMANGLE += $(SRC_VALIDATE)
  • src/Virtual/module.mk

    r29d8c02 r74ec742  
    1111## Created On       : Tus Jul 25 10:18:00 2017
    1212## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tus Jul 25 10:18:00 2017
    14 ## Update Count     : 0
     13## Last Modified On : Tus May 17 14:59:00 2022
     14## Update Count     : 1
    1515###############################################################################
    1616
    17 SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h \
    18         Virtual/Tables.cc Virtual/Tables.h
    19 
    20 SRCDEMANGLE += Virtual/Tables.cc
     17SRC += \
     18        Virtual/ExpandCasts.cc \
     19        Virtual/ExpandCasts.h \
     20        Virtual/Tables.cc \
     21        Virtual/Tables.h
  • src/main.cc

    r29d8c02 r74ec742  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr 13 11:11:00 2022
    13 // Update Count     : 672
     12// Last Modified On : Fri Apr 29  9:52:00 2022
     13// Update Count     : 673
    1414//
    1515
     
    7070#include "ResolvExpr/Resolver.h"            // for resolve
    7171#include "SymTab/Validate.h"                // for validate
     72#include "SymTab/ValidateType.h"            // for linkReferenceToTypes
    7273#include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
    7374#include "SynTree/Declaration.h"            // for Declaration
     
    7576#include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
    7677#include "Validate/Autogen.hpp"             // for autogenerateRoutines
     78#include "Validate/CompoundLiteral.hpp"     // for handleCompoundLiterals
     79#include "Validate/EliminateTypedef.hpp"    // for eliminateTypedef
     80#include "Validate/FindSpecialDecls.h"      // for findGlobalDecls
     81#include "Validate/FixQualifiedTypes.hpp"   // for fixQualifiedTypes
     82#include "Validate/ForallPointerDecay.hpp"  // for decayForallPointers
    7783#include "Validate/GenericParameter.hpp"    // for fillGenericParameters, tr...
    78 #include "Validate/FindSpecialDecls.h"      // for findGlobalDecls
    79 #include "Validate/ForallPointerDecay.hpp"  // for decayForallPointers
    80 #include "Validate/CompoundLiteral.hpp"     // for handleCompoundLiterals
     84#include "Validate/HoistStruct.hpp"         // for hoistStruct
    8185#include "Validate/InitializerLength.hpp"   // for setLengthFromInitializer
    8286#include "Validate/LabelAddressFixer.hpp"   // for fixLabelAddresses
     
    328332                // add the assignment statement after the initialization of a type parameter
    329333                PASS( "Validate-A", SymTab::validate_A( translationUnit ) );
    330                 PASS( "Validate-B", SymTab::validate_B( translationUnit ) );
     334
     335                // Must happen before auto-gen, because it uses the sized flag.
     336                PASS( "Link Reference To Types", SymTab::linkReferenceToTypes( translationUnit ) );
    331337
    332338                CodeTools::fillLocations( translationUnit );
     
    342348
    343349                        forceFillCodeLocations( transUnit );
     350
     351                        // Must happen after Link References To Types,
     352                        // because aggregate members are accessed.
     353                        PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) );
     354
     355                        PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) );
     356                        PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) );
    344357
    345358                        // Check as early as possible. Can't happen before
     
    438451                        translationUnit = convert( move( transUnit ) );
    439452                } else {
     453                        PASS( "Validate-B", SymTab::validate_B( translationUnit ) );
    440454                        PASS( "Validate-C", SymTab::validate_C( translationUnit ) );
    441455                        PASS( "Validate-D", SymTab::validate_D( translationUnit ) );
  • tests/.expect/forall.txt

    r29d8c02 r74ec742  
    1 forall.cfa:242:25: warning: Compiled
     1forall.cfa:244:25: warning: Compiled
  • tests/forall.cfa

    r29d8c02 r74ec742  
    1 // 
     1//
    22// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
    33//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 // 
    7 // forall.cfa -- 
    8 // 
     6//
     7// forall.cfa --
     8//
    99// Author           : Peter A. Buhr
    1010// Created On       : Wed May  9 08:48:15 2018
     
    1212// Last Modified On : Sat Jun  5 10:06:08 2021
    1313// Update Count     : 36
    14 // 
     14//
    1515
    1616void g1() {
     
    4545}
    4646
    47 typedef forall ( T ) int (* f)( int );
     47// commented this out since it is not clearly meaningful
     48// and not really representable in the ast
     49// typedef forall ( T ) int (* f)( int );
    4850
    4951forall( T )
     
    170172}
    171173
    172 forall( T | { T ?+?( T, T ); } ) forall( S | { T ?+?( T, S ); } ) 
     174forall( T | { T ?+?( T, T ); } ) forall( S | { T ?+?( T, S ); } )
    173175struct XW { T t; };
    174176XW(int,int) xww;
  • tests/include/.expect/includes.nast.txt

    r29d8c02 r74ec742  
    1 include/includes.cfa:153:25: warning: Compiled
     1include/includes.cfa:169:25: warning: Compiled
  • tests/include/includes.cfa

    r29d8c02 r74ec742  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  3 22:06:07 2022
    13 // Update Count     : 774
     12// Last Modified On : Tue May 10 16:36:44 2022
     13// Update Count     : 776
    1414//
    1515
     
    3232#include <crypt.h>
    3333#include <ctype.h>
    34 //#include <curses.h>                                                                           // may not be installed
     34#if __has_include( "curses.h" )
     35#include <curses.h>                                                                             // may not be installed
     36#endif
    3537#include <dirent.h>
    3638#include <dlfcn.h>
     
    4143#include <errno.h>
    4244#include <error.h>
    43 //#include <eti.h>                                                                              // may not be installed, comes with ncurses
     45#if __has_include( "eti.h" )
     46#include <eti.h>                                                                                // may not be installed, comes with ncurses
     47#endif
    4448#include <execinfo.h>
    4549#include <expat.h>
     
    5054#include <fmtmsg.h>
    5155#include <fnmatch.h>
    52 //#include <form.h>                                                                             // may not be installed, comes with ncurses
     56#if __has_include( "form.h" )
     57#include <form.h>                                                                               // may not be installed, comes with ncurses
     58#endif
    5359#include <fstab.h>
    5460#include <fts.h>
     
    7884#include <mcheck.h>
    7985#include <memory.h>
    80 //#include <menu.h>                                                                             // may not be installed, comes with ncurses
     86#if __has_include( "menu.h" )
     87#include <menu.h>                                                                               // may not be installed, comes with ncurses
     88#endif
    8189#include <mntent.h>
    8290#include <monetary.h>
    8391#include <mqueue.h>
    84 //#include <ncurses_dll.h>                                                              // may not be installed, comes with ncurses
     92#if __has_include( "ncurses_dll.h" )
     93#include <ncurses_dll.h>                                                                // may not be installed, comes with ncurses
     94#endif
    8595#include <netdb.h>
    8696#include <nl_types.h>
    8797#include <nss.h>
    8898#include <obstack.h>
    89 //#include <panel.h>                                                                            // may not be installed, comes with ncurses
     99#if __has_include( "panel.h" )
     100#include <panel.h>                                                                              // may not be installed, comes with ncurses
     101#endif
    90102#include <paths.h>
    91103#include <poll.h>
     
    118130#include <syslog.h>
    119131#include <tar.h>
    120 //#include <term.h>                                                                             // may not be installed, comes with ncurses
    121 //#include <termcap.h>                                                                  // may not be installed, comes with ncurses
     132#if __has_include( "term.h" )
     133#include <term.h>                                                                               // may not be installed, comes with ncurses
     134#include <termcap.h>                                                                    // may not be installed, comes with ncurses
     135#endif
    122136#include <termio.h>
    123137#include <termios.h>
     
    131145#include <ucontext.h>
    132146#include <ulimit.h>
    133 //#include <unctrl.h>                                                                           // may not be installed, comes with ncurses
     147#if __has_include( "unctrl.h" )
     148#include <unctrl.h>                                                                             // may not be installed, comes with ncurses
     149#endif
    134150#include <unistd.h>
    135151#include <utime.h>
  • tests/pybin/settings.py

    r29d8c02 r74ec742  
    201201        global output_width
    202202        output_width = max(map(lambda t: len(t.target()), tests))
     203        # 35 is the maximum width of the name field before we get line wrapping.
     204        output_width = min(output_width, 35)
  • tests/pybin/test_run.py

    r29d8c02 r74ec742  
    4343                return os.path.normpath( os.path.join(settings.BUILDDIR, self.path, self.name) )
    4444
     45        def format_target(self, width):
     46                target = self.target()
     47                length = len(target)
     48                if length < width:
     49                        return '{0:{width}}'.format(target, width=width)
     50                elif length == width:
     51                        return target
     52                else:
     53                        return '...' + target[3-width:]
     54
    4555        @staticmethod
    4656        def valid_name(name):
  • tests/test.py

    r29d8c02 r74ec742  
    132132        parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no')
    133133        parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_')
    134         parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=120)
     134        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=180)
    135135        parser.add_argument('--global-timeout', help='Maximum cumulative duration in seconds after the ALL tests are considered to have timed out', type=int, default=7200)
    136136        parser.add_argument('--timeout-with-gdb', help='Instead of killing the command when it times out, orphan it and print process id to allow gdb to attach', type=yes_no, default="no")
     
    252252        try :
    253253                # print formated name
    254                 name_txt = '{0:{width}}  '.format(t.target(), width=settings.output_width)
     254                name_txt = t.format_target(width=settings.output_width) + '  '
    255255
    256256                retcode, error, duration = run_single_test(t)
  • tests/unified_locking/.expect/locks.txt

    r29d8c02 r74ec742  
    2323Start Test 12: locked condition variable wait/notify with front()
    2424Done Test 12
     25Start Test 13: fast block lock and fast cond var single wait/notify
     26Done Test 13
  • tests/unified_locking/locks.cfa

    r29d8c02 r74ec742  
    1818condition_variable( linear_backoff_then_block_lock ) c_l;
    1919
     20fast_block_lock f;
     21fast_cond_var( fast_block_lock ) f_c_f;
     22
    2023thread T_C_M_WS1 {};
    2124
     
    99102                }
    100103                unlock(l);
     104        }
     105}
     106
     107thread T_F_C_F_WS1 {};
     108
     109void main( T_F_C_F_WS1 & this ) {
     110        for (unsigned int i = 0; i < num_times; i++) {
     111                lock(f);
     112                if(empty(f_c_f) && i != num_times - 1) {
     113                        wait(f_c_f,f);
     114                }else{
     115                        notify_one(f_c_f);
     116                        unlock(f);
     117                }
    101118        }
    102119}
     
    322339        }
    323340        printf("Done Test 12\n");
    324 }
     341
     342        printf("Start Test 13: fast block lock and fast cond var single wait/notify\n");
     343        {
     344                T_F_C_F_WS1 t1[2];
     345        }
     346        printf("Done Test 13\n");
     347       
     348}
Note: See TracChangeset for help on using the changeset viewer.