Changes in / [f5a51db:97c215f]


Ignore:
Files:
8 deleted
75 edited

Legend:

Unmodified
Added
Removed
  • benchmark/io/http/Makefile.am

    rf5a51db r97c215f  
    2121include $(top_srcdir)/tools/build/cfa.make
    2222
    23 AM_CFLAGS = -O3 -Wall -Wextra -I$(srcdir) -lrt -pthread # -Werror
     23AM_CFLAGS = -O2 -Wall -Wextra -I$(srcdir) -lrt -pthread # -Werror
    2424AM_CFAFLAGS = -quiet -nodebug
    2525AM_LDFLAGS = -quiet -nodebug
  • benchmark/io/http/main.cfa

    rf5a51db r97c215f  
    1 #define _GNU_SOURCE
     1#define __USE_GNU
    22
    33#include <errno.h>
     
    66#include <unistd.h>
    77extern "C" {
    8         #include <sched.h>
    98        #include <signal.h>
    109        #include <sys/socket.h>
     
    6867        (this.self){ "Server Cluster", options.clopts.params };
    6968
    70         cpu_set_t fullset;
    71         CPU_ZERO(&fullset);
    72         int ret = sched_getaffinity(getpid(), sizeof(fullset), &fullset);
    73         if( ret != 0 ) abort | "sched_getaffinity failed with" | errno | strerror( errno );
    74         int cnt = CPU_COUNT(&fullset);
    75 
    7669        this.procs = alloc(options.clopts.nprocs);
    7770        for(i; options.clopts.nprocs) {
    7871                (this.procs[i]){ "Benchmark Processor", this.self };
    79 
    80                 int c = 0;
    81                 int n = 1 + (i % cnt);
    82                 for(int j = 0; j < CPU_SETSIZE; j++) {
    83                         if(CPU_ISSET(j, &fullset)) n--;
    84                         if(n == 0) {
    85                                 c = j;
    86                                 break;
    87                         }
    88                 }
    89                 cpu_set_t localset;
    90                 CPU_ZERO(&localset);
    91                 CPU_SET(c, &localset);
    92                 ret = pthread_setaffinity_np(this.procs[i].kernel_thread, sizeof(localset), &localset);
    93                 if( ret != 0 ) abort | "sched_getaffinity failed with" | ret | strerror( ret );
    9472
    9573                #if !defined(__CFA_NO_STATISTICS__)
     
    168146        int waited = 0;
    169147        for() {
    170                 int sockfd = server_fd;
    171                 __CONST_SOCKADDR_ARG addr;
    172                 addr.__sockaddr__ = (struct sockaddr *)&address;
    173                 socklen_t addrlen = sizeof(address);
    174                 ret = bind( sockfd, addr, addrlen );
     148                ret = bind( server_fd, (struct sockaddr *)&address, sizeof(address) );
    175149                if(ret < 0) {
    176150                        if(errno == EADDRINUSE) {
  • doc/theses/thierry_delisle_PhD/thesis/Makefile

    rf5a51db r97c215f  
    4848## Define the documents that need to be made.
    4949all: thesis.pdf
    50 thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} thesis.tex glossary.tex local.bib ../../../LaTeXmacros/common.tex ../../../LaTeXmacros/common.sty
     50thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} thesis.tex glossary.tex local.bib
    5151
    5252DOCUMENT = thesis.pdf
  • doc/theses/thierry_delisle_PhD/thesis/fig/base.fig

    rf5a51db r97c215f  
    12121 3 0 1 0 0 50 -1 20 0.000 1 0.0000 6900 4200 20 20 6900 4200 6920 4200
    13131 3 0 1 0 0 50 -1 20 0.000 1 0.0000 6975 4200 20 20 6975 4200 6995 4200
    14 -6
    15 6 6375 5100 6675 5250
    16 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 6450 5175 20 20 6450 5175 6470 5175
    17 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 6525 5175 20 20 6525 5175 6545 5175
    18 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 6600 5175 20 20 6600 5175 6620 5175
    1914-6
    20151 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3900 2400 300 300 3900 2400 4200 2400
     
    80752 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    8176         2400 2475 3000 2475
    82 2 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
    83          3300 5210 3150 4950 2850 4950 2700 5210 2850 5470 3150 5470
    84          3300 5210
    85 2 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
    86          4500 5210 4350 4950 4050 4950 3900 5210 4050 5470 4350 5470
    87          4500 5210
    88 2 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
    89          5700 5210 5550 4950 5250 4950 5100 5210 5250 5470 5550 5470
    90          5700 5210
    91774 2 -1 50 -1 0 12 0.0000 2 135 630 2100 3075 Threads\001
    92784 2 -1 50 -1 0 12 0.0000 2 165 450 2100 2850 Ready\001
     
    96824 1 -1 50 -1 0 11 0.0000 2 135 180 2700 3550 TS\001
    97834 1 -1 50 -1 0 11 0.0000 2 135 180 2700 2650 TS\001
    98 4 2 -1 50 -1 0 12 0.0000 2 135 900 2100 5175 Processors\001
  • doc/theses/thierry_delisle_PhD/thesis/glossary.tex

    rf5a51db r97c215f  
    4040
    4141\textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.}
    42 }
    43 
    44 \longnewglossaryentry{rmr}
    45 {name={remote memory reference}}
    46 {
    47 
    4842}
    4943
  • doc/theses/thierry_delisle_PhD/thesis/text/core.tex

    rf5a51db r97c215f  
    4949
    5050\section{Design}
    51 In general, a na\"{i}ve \glsxtrshort{fifo} ready-queue does not scale with increased parallelism from \glspl{hthrd}, resulting in decreased performance. The problem is adding/removing \glspl{thrd} is a single point of contention. As shown in the evaluation sections, most production schedulers do scale when adding \glspl{hthrd}. The solution to this problem is to shard the ready-queue : create multiple sub-ready-queues that multiple \glspl{hthrd} can access and modify without interfering.
     51In general, a na\"{i}ve \glsxtrshort{fifo} ready-queue does not scale with increased parallelism from \glspl{hthrd}, resulting in decreased performance. The problem is adding/removing \glspl{thrd} is a single point of contention. As shown in the evaluation sections, most production schedulers do scale when adding \glspl{hthrd}. The common solution to the single point of contention is to shard the ready-queue so each \gls{hthrd} can access the ready-queue without contention, increasing performance.
    5252
    53 Before going into the design of \CFA's scheduler proper, I want to discuss two sharding solutions which served as the inspiration scheduler in this thesis.
     53\subsection{Sharding} \label{sec:sharding}
     54An interesting approach to sharding a queue is presented in \cit{Trevors paper}. This algorithm presents a queue with a relaxed \glsxtrshort{fifo} guarantee using an array of strictly \glsxtrshort{fifo} sublists as shown in Figure~\ref{fig:base}. Each \emph{cell} of the array has a timestamp for the last operation and a pointer to a linked-list with a lock. Each node in the list is marked with a timestamp indicating when it is added to the list. A push operation is done by picking a random cell, acquiring the list lock, and pushing to the list. If the cell is locked, the operation is simply retried on another random cell until a lock is acquired. A pop operation is done in a similar fashion except two random cells are picked. If both cells are unlocked with non-empty lists, the operation pops the node with the oldest timestamp. If one of the cells is unlocked and non-empty, the operation pops from that cell. If both cells are either locked or empty, the operation picks two new random cells and tries again.
    5455
    55 \subsection{Work-Stealing}
    56 
    57 As I mentioned in \ref{existing:workstealing}, a popular pattern shard the ready-queue is work-stealing. As mentionned, in this pattern each \gls{proc} has its own ready-queue and \glspl{proc} only access each other's ready-queue if they run out of work.
    58 The interesting aspect of workstealing happen in easier scheduling cases, \ie enough work for everyone but no more and no load balancing needed. In these cases, work-stealing is close to optimal scheduling: it can achieve perfect locality and have no contention.
    59 On the other hand, work-stealing schedulers only attempt to do load-balancing when a \gls{proc} runs out of work.
    60 This means that the scheduler may never balance unfairness that does not result in a \gls{proc} running out of work.
    61 Chapter~\ref{microbench} shows that in pathological cases this problem can lead to indefinite starvation.
    62 
    63 
    64 Based on these observation, I conclude that \emph{perfect} scheduler should behave very similarly to work-stealing in the easy cases, but should have more proactive load-balancing if the need arises.
    65 
    66 \subsection{Relaxed-Fifo}
    67 An entirely different scheme is to create a ``relaxed-FIFO'' queue as in \todo{cite Trevor's paper}. This approach forgos any ownership between \gls{proc} and ready-queue, and simply creates a pool of ready-queues from which the \glspl{proc} can pick from.
    68 \Glspl{proc} choose ready-queus at random, but timestamps are added to all elements of the queue and dequeues are done by picking two queues and dequeing the oldest element.
    69 The result is a queue that has both decent scalability and sufficient fairness.
    70 The lack of ownership means that as long as one \gls{proc} is still able to repeatedly dequeue elements, it is unlikely that any element will stay on the queue for much longer than any other element.
    71 This contrasts with work-stealing, where \emph{any} \gls{proc} busy for an extended period of time results in all the elements on its local queue to have to wait. Unless another \gls{proc} runs out of work.
    72 
    73 An important aspects of this scheme's fairness approach is that the timestamps make it possible to evaluate how long elements have been on the queue.
    74 However, another major aspect is that \glspl{proc} will eagerly search for these older elements instead of focusing on specific queues.
    75 
    76 While the fairness, of this scheme is good, it does suffer in terms of performance.
    77 It requires very wide sharding, \eg at least 4 queues per \gls{hthrd}, and the randomness means locality can suffer significantly and finding non-empty queues can be difficult.
    78 
    79 \section{\CFA}
    80 The \CFA is effectively attempting to merge these two approaches, keeping the best of both.
    81 It is based on the
    8256\begin{figure}
    8357        \centering
    8458        \input{base.pstex_t}
    85         \caption[Base \CFA design]{Base \CFA design \smallskip\newline A list of sub-ready queues offers the sharding, two per \glspl{proc}. However, \glspl{proc} can access any of the sub-queues.}
     59        \caption[Relaxed FIFO list]{Relaxed FIFO list \smallskip\newline List at the base of the scheduler: an array of strictly FIFO lists. The timestamp is in all nodes and cell arrays.}
    8660        \label{fig:base}
    8761\end{figure}
    8862
     63\subsection{Finding threads}
     64Once threads have been distributed onto multiple queues, identifying empty queues becomes a problem. Indeed, if the number of \glspl{thrd} does not far exceed the number of queues, it is probable that several of the cell queues are empty. Figure~\ref{fig:empty} shows an example with 2 \glspl{thrd} running on 8 queues, where the chances of getting an empty queue is 75\% per pick, meaning two random picks yield a \gls{thrd} only half the time. This scenario leads to performance problems since picks that do not yield a \gls{thrd} are not useful and do not necessarily help make more informed guesses.
    8965
     66\begin{figure}
     67        \centering
     68        \input{empty.pstex_t}
     69        \caption[``More empty'' Relaxed FIFO list]{``More empty'' Relaxed FIFO list \smallskip\newline Emptier state of the queue: the array contains many empty cells, that is strictly FIFO lists containing no elements.}
     70        \label{fig:empty}
     71\end{figure}
    9072
    91 % The common solution to the single point of contention is to shard the ready-queue so each \gls{hthrd} can access the ready-queue without contention, increasing performance.
     73There are several solutions to this problem, but they ultimately all have to encode if a cell has an empty list. My results show the density and locality of this encoding is generally the dominating factor in these scheme. Classic solutions to this problem use one of three techniques to encode the information:
    9274
    93 % \subsection{Sharding} \label{sec:sharding}
    94 % An interesting approach to sharding a queue is presented in \cit{Trevors paper}. This algorithm presents a queue with a relaxed \glsxtrshort{fifo} guarantee using an array of strictly \glsxtrshort{fifo} sublists as shown in Figure~\ref{fig:base}. Each \emph{cell} of the array has a timestamp for the last operation and a pointer to a linked-list with a lock. Each node in the list is marked with a timestamp indicating when it is added to the list. A push operation is done by picking a random cell, acquiring the list lock, and pushing to the list. If the cell is locked, the operation is simply retried on another random cell until a lock is acquired. A pop operation is done in a similar fashion except two random cells are picked. If both cells are unlocked with non-empty lists, the operation pops the node with the oldest timestamp. If one of the cells is unlocked and non-empty, the operation pops from that cell. If both cells are either locked or empty, the operation picks two new random cells and tries again.
     75\paragraph{Dense Information} Figure~\ref{fig:emptybit} shows a dense bitmask to identify the cell queues currently in use. This approach means processors can often find \glspl{thrd} in constant time, regardless of how many underlying queues are empty. Furthermore, modern x86 CPUs have extended bit manipulation instructions (BMI2) that allow searching the bitmask with very little overhead compared to the randomized selection approach for a filled ready queue, offering good performance even in cases with many empty inner queues. However, this technique has its limits: with a single word\footnote{Word refers here to however many bits can be written atomically.} bitmask, the total amount of ready-queue sharding is limited to the number of bits in the word. With a multi-word bitmask, this maximum limit can be increased arbitrarily, but the look-up time increases. Finally, a dense bitmap, either single or multi-word, causes additional contention problems that reduces performance because of cache misses after updates. This central update bottleneck also means the information in the bitmask is more often stale before a processor can use it to find an item, \ie mask read says there are available \glspl{thrd} but none on queue when the subsequent atomic check is done.
    9576
    96 % \begin{figure}
    97 %       \centering
    98 %       \input{base.pstex_t}
    99 %       \caption[Relaxed FIFO list]{Relaxed FIFO list \smallskip\newline List at the base of the scheduler: an array of strictly FIFO lists. The timestamp is in all nodes and cell arrays.}
    100 %       \label{fig:base}
    101 % \end{figure}
     77\begin{figure}
     78        \centering
     79        \vspace*{-5pt}
     80        {\resizebox{0.75\textwidth}{!}{\input{emptybit.pstex_t}}}
     81        \vspace*{-5pt}
     82        \caption[Underloaded queue with bitmask]{Underloaded queue with bitmask indicating array cells with items.}
     83        \label{fig:emptybit}
    10284
    103 % \subsection{Finding threads}
    104 % Once threads have been distributed onto multiple queues, identifying empty queues becomes a problem. Indeed, if the number of \glspl{thrd} does not far exceed the number of queues, it is probable that several of the cell queues are empty. Figure~\ref{fig:empty} shows an example with 2 \glspl{thrd} running on 8 queues, where the chances of getting an empty queue is 75\% per pick, meaning two random picks yield a \gls{thrd} only half the time. This scenario leads to performance problems since picks that do not yield a \gls{thrd} are not useful and do not necessarily help make more informed guesses.
     85        \vspace*{10pt}
     86        {\resizebox{0.75\textwidth}{!}{\input{emptytree.pstex_t}}}
     87        \vspace*{-5pt}
     88        \caption[Underloaded queue with binary search-tree]{Underloaded queue with binary search-tree indicating array cells with items.}
     89        \label{fig:emptytree}
    10590
    106 % \begin{figure}
    107 %       \centering
    108 %       \input{empty.pstex_t}
    109 %       \caption[``More empty'' Relaxed FIFO list]{``More empty'' Relaxed FIFO list \smallskip\newline Emptier state of the queue: the array contains many empty cells, that is strictly FIFO lists containing no elements.}
    110 %       \label{fig:empty}
    111 % \end{figure}
     91        \vspace*{10pt}
     92        {\resizebox{0.95\textwidth}{!}{\input{emptytls.pstex_t}}}
     93        \vspace*{-5pt}
     94        \caption[Underloaded queue with per processor bitmask]{Underloaded queue with per processor bitmask indicating array cells with items.}
     95        \label{fig:emptytls}
     96\end{figure}
    11297
    113 % There are several solutions to this problem, but they ultimately all have to encode if a cell has an empty list. My results show the density and locality of this encoding is generally the dominating factor in these scheme. Classic solutions to this problem use one of three techniques to encode the information:
     98\paragraph{Sparse Information} Figure~\ref{fig:emptytree} shows an approach using a hierarchical tree data-structure to reduce contention and has been shown to work in similar cases~\cite{ellen2007snzi}. However, this approach may lead to poorer performance due to the inherent pointer chasing cost while still allowing significant contention on the nodes of the tree if the tree is shallow.
    11499
    115 % \paragraph{Dense Information} Figure~\ref{fig:emptybit} shows a dense bitmask to identify the cell queues currently in use. This approach means processors can often find \glspl{thrd} in constant time, regardless of how many underlying queues are empty. Furthermore, modern x86 CPUs have extended bit manipulation instructions (BMI2) that allow searching the bitmask with very little overhead compared to the randomized selection approach for a filled ready queue, offering good performance even in cases with many empty inner queues. However, this technique has its limits: with a single word\footnote{Word refers here to however many bits can be written atomically.} bitmask, the total amount of ready-queue sharding is limited to the number of bits in the word. With a multi-word bitmask, this maximum limit can be increased arbitrarily, but the look-up time increases. Finally, a dense bitmap, either single or multi-word, causes additional contention problems that reduces performance because of cache misses after updates. This central update bottleneck also means the information in the bitmask is more often stale before a processor can use it to find an item, \ie mask read says there are available \glspl{thrd} but none on queue when the subsequent atomic check is done.
     100\paragraph{Local Information} Figure~\ref{fig:emptytls} shows an approach using dense information, similar to the bitmap, but each \gls{hthrd} keeps its own independent copy. While this approach can offer good scalability \emph{and} low latency, the liveliness and discovery of the information can become a problem. This case is made worst in systems with few processors where even blind random picks can find \glspl{thrd} in a few tries.
    116101
    117 % \begin{figure}
    118 %       \centering
    119 %       \vspace*{-5pt}
    120 %       {\resizebox{0.75\textwidth}{!}{\input{emptybit.pstex_t}}}
    121 %       \vspace*{-5pt}
    122 %       \caption[Underloaded queue with bitmask]{Underloaded queue with bitmask indicating array cells with items.}
    123 %       \label{fig:emptybit}
     102I built a prototype of these approaches and none of these techniques offer satisfying performance when few threads are present. All of these approach hit the same 2 problems. First, randomly picking sub-queues is very fast. That speed means any improvement to the hit rate can easily be countered by a slow-down in look-up speed, whether or not there are empty lists. Second, the array is already sharded to avoid contention bottlenecks, so any denser data structure tends to become a bottleneck. In all cases, these factors meant the best cases scenario, \ie many threads, would get worst throughput, and the worst-case scenario, few threads, would get a better hit rate, but an equivalent poor throughput. As a result I tried an entirely different approach.
    124103
    125 %       \vspace*{10pt}
    126 %       {\resizebox{0.75\textwidth}{!}{\input{emptytree.pstex_t}}}
    127 %       \vspace*{-5pt}
    128 %       \caption[Underloaded queue with binary search-tree]{Underloaded queue with binary search-tree indicating array cells with items.}
    129 %       \label{fig:emptytree}
     104\subsection{Dynamic Entropy}\cit{https://xkcd.com/2318/}
     105In the worst-case scenario there are only few \glspl{thrd} ready to run, or more precisely given $P$ \glspl{proc}\footnote{For simplicity, this assumes there is a one-to-one match between \glspl{proc} and \glspl{hthrd}.}, $T$ \glspl{thrd} and $\epsilon$ a very small number, than the worst case scenario can be represented by $T = P + \epsilon$, with $\epsilon \ll P$. It is important to note in this case that fairness is effectively irrelevant. Indeed, this case is close to \emph{actually matching} the model of the ``Ideal multi-tasking CPU'' on page \pageref{q:LinuxCFS}. In this context, it is possible to use a purely internal-locality based approach and still meet the fairness requirements. This approach simply has each \gls{proc} running a single \gls{thrd} repeatedly. Or from the shared ready-queue viewpoint, each \gls{proc} pushes to a given sub-queue and then pops from the \emph{same} subqueue. The challenge is for the the scheduler to achieve good performance in both the $T = P + \epsilon$ case and the $T \gg P$ case, without affecting the fairness guarantees in the later.
    130106
    131 %       \vspace*{10pt}
    132 %       {\resizebox{0.95\textwidth}{!}{\input{emptytls.pstex_t}}}
    133 %       \vspace*{-5pt}
    134 %       \caption[Underloaded queue with per processor bitmask]{Underloaded queue with per processor bitmask indicating array cells with items.}
    135 %       \label{fig:emptytls}
    136 % \end{figure}
     107To handle this case, I use a \glsxtrshort{prng}\todo{Fix missing long form} in a novel way. There exist \glsxtrshort{prng}s that are fast, compact and can be run forward \emph{and} backwards.  Linear congruential generators~\cite{wiki:lcg} are an example of \glsxtrshort{prng}s of such \glsxtrshort{prng}s. The novel approach is to use the ability to run backwards to ``replay'' the \glsxtrshort{prng}. The scheduler uses an exclusive \glsxtrshort{prng} instance per \gls{proc}, the random-number seed effectively starts an encoding that produces a list of all accessed subqueues, from latest to oldest. Replaying the \glsxtrshort{prng} to identify cells accessed recently and which probably have data still cached.
    137108
    138 % \paragraph{Sparse Information} Figure~\ref{fig:emptytree} shows an approach using a hierarchical tree data-structure to reduce contention and has been shown to work in similar cases~\cite{ellen2007snzi}. However, this approach may lead to poorer performance due to the inherent pointer chasing cost while still allowing significant contention on the nodes of the tree if the tree is shallow.
     109The algorithm works as follows:
     110\begin{itemize}
     111        \item Each \gls{proc} has two \glsxtrshort{prng} instances, $F$ and $B$.
     112        \item Push and Pop operations occur as discussed in Section~\ref{sec:sharding} with the following exceptions:
     113        \begin{itemize}
     114                \item Push operations use $F$ going forward on each try and on success $F$ is copied into $B$.
     115                \item Pop operations use $B$ going backwards on each try.
     116        \end{itemize}
     117\end{itemize}
    139118
    140 % \paragraph{Local Information} Figure~\ref{fig:emptytls} shows an approach using dense information, similar to the bitmap, but each \gls{hthrd} keeps its own independent copy. While this approach can offer good scalability \emph{and} low latency, the liveliness and discovery of the information can become a problem. This case is made worst in systems with few processors where even blind random picks can find \glspl{thrd} in a few tries.
     119The main benefit of this technique is that it basically respects the desired properties of Figure~\ref{fig:fair}. When looking for work, a \gls{proc} first looks at the last cell they pushed to, if any, and then move backwards through its accessed cells. As the \gls{proc} continues looking for work, $F$ moves backwards and $B$ stays in place. As a result, the relation between the two becomes weaker, which means that the probablisitic fairness of the algorithm reverts to normal. Chapter~\ref{proofs} discusses more formally the fairness guarantees of this algorithm.
    141120
    142 % I built a prototype of these approaches and none of these techniques offer satisfying performance when few threads are present. All of these approach hit the same 2 problems. First, randomly picking sub-queues is very fast. That speed means any improvement to the hit rate can easily be countered by a slow-down in look-up speed, whether or not there are empty lists. Second, the array is already sharded to avoid contention bottlenecks, so any denser data structure tends to become a bottleneck. In all cases, these factors meant the best cases scenario, \ie many threads, would get worst throughput, and the worst-case scenario, few threads, would get a better hit rate, but an equivalent poor throughput. As a result I tried an entirely different approach.
    143 
    144 % \subsection{Dynamic Entropy}\cit{https://xkcd.com/2318/}
    145 % In the worst-case scenario there are only few \glspl{thrd} ready to run, or more precisely given $P$ \glspl{proc}\footnote{For simplicity, this assumes there is a one-to-one match between \glspl{proc} and \glspl{hthrd}.}, $T$ \glspl{thrd} and $\epsilon$ a very small number, than the worst case scenario can be represented by $T = P + \epsilon$, with $\epsilon \ll P$. It is important to note in this case that fairness is effectively irrelevant. Indeed, this case is close to \emph{actually matching} the model of the ``Ideal multi-tasking CPU'' on page \pageref{q:LinuxCFS}. In this context, it is possible to use a purely internal-locality based approach and still meet the fairness requirements. This approach simply has each \gls{proc} running a single \gls{thrd} repeatedly. Or from the shared ready-queue viewpoint, each \gls{proc} pushes to a given sub-queue and then pops from the \emph{same} subqueue. The challenge is for the the scheduler to achieve good performance in both the $T = P + \epsilon$ case and the $T \gg P$ case, without affecting the fairness guarantees in the later.
    146 
    147 % To handle this case, I use a \glsxtrshort{prng}\todo{Fix missing long form} in a novel way. There exist \glsxtrshort{prng}s that are fast, compact and can be run forward \emph{and} backwards.  Linear congruential generators~\cite{wiki:lcg} are an example of \glsxtrshort{prng}s of such \glsxtrshort{prng}s. The novel approach is to use the ability to run backwards to ``replay'' the \glsxtrshort{prng}. The scheduler uses an exclusive \glsxtrshort{prng} instance per \gls{proc}, the random-number seed effectively starts an encoding that produces a list of all accessed subqueues, from latest to oldest. Replaying the \glsxtrshort{prng} to identify cells accessed recently and which probably have data still cached.
    148 
    149 % The algorithm works as follows:
    150 % \begin{itemize}
    151 %       \item Each \gls{proc} has two \glsxtrshort{prng} instances, $F$ and $B$.
    152 %       \item Push and Pop operations occur as discussed in Section~\ref{sec:sharding} with the following exceptions:
    153 %       \begin{itemize}
    154 %               \item Push operations use $F$ going forward on each try and on success $F$ is copied into $B$.
    155 %               \item Pop operations use $B$ going backwards on each try.
    156 %       \end{itemize}
    157 % \end{itemize}
    158 
    159 % The main benefit of this technique is that it basically respects the desired properties of Figure~\ref{fig:fair}. When looking for work, a \gls{proc} first looks at the last cell they pushed to, if any, and then move backwards through its accessed cells. As the \gls{proc} continues looking for work, $F$ moves backwards and $B$ stays in place. As a result, the relation between the two becomes weaker, which means that the probablisitic fairness of the algorithm reverts to normal. Chapter~\ref{proofs} discusses more formally the fairness guarantees of this algorithm.
    160 
    161 % \section{Details}
     121\section{Details}
  • doc/theses/thierry_delisle_PhD/thesis/text/eval_macro.tex

    rf5a51db r97c215f  
    44
    55In Memory Plain Text
     6
     7Networked Plain Text
    68
    79Networked ZIPF
  • doc/theses/thierry_delisle_PhD/thesis/text/eval_micro.tex

    rf5a51db r97c215f  
    22
    33The first step of evaluation is always to test-out small controlled cases, to ensure that the basics are working properly.
    4 This sections presents five different experimental setup, evaluating some of the basic features of \CFA's scheduler.
     4This sections presents four different experimental setup, evaluating some of the basic features of \CFA's scheduler.
    55
    66\section{Cycling latency}
    77The most basic evaluation of any ready queue is to evaluate the latency needed to push and pop one element from the ready-queue.
    8 Since these two operation also describe a \texttt{yield} operation, many systems use this as the most basic benchmark.
    9 However, yielding can be treated as a special case, since it also carries the information that the number of the ready \glspl{at} will not change.
     8While these two operation also describe a \texttt{yield} operation, many systems use this as the most basic benchmark.
     9However, yielding can be treated as a special case, since it also carries the information that the length of the ready queue will not change.
    1010Not all systems use this information, but those which do may appear to have better performance than they would for disconnected push/pop pairs.
    1111For this reason, I chose a different first benchmark, which I call the Cycle Benchmark.
    12 This benchmark arranges many \glspl{at} into multiple rings of \glspl{at}.
     12This benchmark arranges many threads into multiple rings of threads.
    1313Each ring is effectively a circular singly-linked list.
    14 At runtime, each \gls{at} unparks the next \gls{at} before parking itself.
     14At runtime, each thread unparks the next thread before parking itself.
    1515This corresponds to the desired pair of ready queue operations.
    16 Unparking the next \gls{at} requires pushing that \gls{at} onto the ready queue and the ensuing park will cause the runtime to pop a \gls{at} from the ready-queue.
     16Unparking the next thread requires pushing that thread onto the ready queue and the ensuing park will cause the runtime to pop a thread from the ready-queue.
    1717Figure~\ref{fig:cycle} shows a visual representation of this arrangement.
    1818
    19 The goal of this ring is that the underlying runtime cannot rely on the guarantee that the number of ready \glspl{at} will stay constant over the duration of the experiment.
    20 In fact, the total number of \glspl{at} waiting on the ready queue is expected to vary because of the race between the next \gls{at} unparking and the current \gls{at} parking.
    21 The size of the cycle is also decided based on this race: cycles that are too small may see the chain of unparks go full circle before the first \gls{at} can park.
     19The goal of this ring is that the underlying runtime cannot rely on the guarantee that the number of ready threads will stay constant over the duration of the experiment.
     20In fact, the total number of threads waiting on the ready is expected to vary a little because of the race between the next thread unparking and the current thread parking.
     21The size of the cycle is also decided based on this race: cycles that are too small may see the
     22chain of unparks go full circle before the first thread can park.
    2223While this would not be a correctness problem, every runtime system must handle that race, it could lead to pushes and pops being optimized away.
    23 Since silently omitting ready-queue operations would throw off the measuring of these operations, the ring of \glspl{at} must be big enough so the \glspl{at} have the time to fully park before they are unparked.
     24Since silently omitting ready-queue operations would throw off the measuring of these operations.
     25Therefore the ring of threads must be big enough so the threads have the time to fully park before they are unparked.
    2426Note that this problem is only present on SMP machines and is significantly mitigated by the fact that there are multiple rings in the system.
    2527
     
    2729        \centering
    2830        \input{cycle.pstex_t}
    29         \caption[Cycle benchmark]{Cycle benchmark\smallskip\newline Each \gls{at} unparks the next \gls{at} in the cycle before parking itself.}
     31        \caption[Cycle benchmark]{Cycle benchmark\smallskip\newline Each thread unparks the next thread in the cycle before parking itself.}
    3032        \label{fig:cycle}
    3133\end{figure}
    3234
    3335\todo{check term ``idle sleep handling''}
    34 To 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.
     36To 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 processors available.
    3537Beyond this point, adding more rings serves to mitigate even more the idle sleep handling.
    36 This is to avoid the case where one of the worker \glspl{at} runs out of work because of the variation on the number of ready \glspl{at} mentionned above.
     38This is to avoid the case where one of the worker threads runs out of work because of the variation on the number of ready threads mentionned above.
    3739
    3840The 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.
    3941
    40 \todo{code, setup, results}
    41 \begin{lstlisting}
    42         Thread.main() {
    43                 count := 0
    44                 for {
    45                         wait()
    46                         this.next.wake()
    47                         count ++
    48                         if must_stop() { break }
    49                 }
    50                 global.count += count
    51         }
    52 \end{lstlisting}
    53 
     42\todo{mention where to get the code.}
    5443
    5544\section{Yield}
    5645For completion, I also include the yield benchmark.
    57 This benchmark is much simpler than the cycle tests, it simply creates many \glspl{at} that call \texttt{yield}.
    58 As mentionned in the previous section, this benchmark may be less representative of usages that only make limited use of \texttt{yield}, due to potential shortcuts in the routine.
    59 Its 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.
    60 This sometimes puts more strain on the idle sleep handling, compared to scenarios where there is clearly plenty of work to be done.
    61 
    62 \todo{code, setup, results}
    63 
    64 \begin{lstlisting}
    65         Thread.main() {
    66                 count := 0
    67                 while !stop {
    68                         yield()
    69                         count ++
    70                 }
    71                 global.count += count
    72         }
    73 \end{lstlisting}
    74 
    75 
    76 \section{Churn}
    77 The Cycle and Yield benchmark represents an ``easy'' scenario for a scheduler, \eg, an embarrassingly parallel application.
    78 In these benchmarks, \glspl{at} can be easily partitioned over the different \glspl{proc} up-front and none of the \glspl{at} communicate with each other.
    79 
    80 The Churn benchmark represents more chaotic usages, where there is no relation between the last \gls{proc} on which a \gls{at} ran and the \gls{proc} that unblocked it.
    81 When a \gls{at} is unblocked from a different \gls{proc} than the one on which it last ran, the unblocking \gls{proc} must either ``steal'' the \gls{at} or place it on a remote queue.
    82 This results can result in either contention on the remote queue or \glspl{rmr} on \gls{at} data structure.
    83 In 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.
    84 
    85 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}.
    86 When a \gls{at} attempts to block on the chair, it must first unblocked the \gls{at} currently blocked on said chair, if any.
    87 This creates a flow where \glspl{at} push each other out of the chairs before being pushed out themselves.
    88 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}.
    89 
    90 \todo{code, setup, results}
    91 \begin{lstlisting}
    92         Thread.main() {
    93                 count := 0
    94                 for {
    95                         r := random() % len(spots)
    96                         next := xchg(spots[r], this)
    97                         if next { next.wake() }
    98                         wait()
    99                         count ++
    100                         if must_stop() { break }
    101                 }
    102                 global.count += count
    103         }
    104 \end{lstlisting}
     46This benchmark is much simpler than the cycle tests, it simply creates many threads that call \texttt{yield}.
    10547
    10648\section{Locality}
    10749
    108 \todo{code, setup, results}
    109 
    11050\section{Transfer}
    111 The last benchmark is more exactly characterize as an experiment than a benchmark.
    112 It tests the behavior of the schedulers for a particularly misbehaved workload.
    113 In this workload, one of the \gls{at} is selected at random to be the leader.
    114 The leader then spins in a tight loop until it has observed that all other \glspl{at} have acknowledged its leadership.
    115 The leader \gls{at} then picks a new \gls{at} to be the ``spinner'' and the cycle repeats.
    116 
    117 The benchmark comes in two flavours for the behavior of the non-leader \glspl{at}:
    118 once they acknowledged the leader, they either block on a semaphore or yield repeatadly.
    119 
    120 This experiment is designed to evaluate the short term load balancing of the scheduler.
    121 Indeed, schedulers where the runnable \glspl{at} are partitioned on the \glspl{proc} may need to balance the \glspl{at} for this experient to terminate.
    122 This is because the spinning \gls{at} is effectively preventing the \gls{proc} from runnning any other \glspl{thrd}.
    123 In the semaphore flavour, the number of runnable \glspl{at} will eventually dwindle down to only the leader.
    124 This is a simpler case to handle for schedulers since \glspl{proc} eventually run out of work.
    125 In the yielding flavour, the number of runnable \glspl{at} stays constant.
    126 This is a harder case to handle because corrective measures must be taken even if work is still available.
    127 Note that languages that have mandatory preemption do circumvent this problem by forcing the spinner to yield.
    128 
    129 \todo{code, setup, results}
    130 \begin{lstlisting}
    131         Thread.lead() {
    132                 this.idx_seen = ++lead_idx
    133                 if lead_idx > stop_idx {
    134                         done := true
    135                         return
    136                 }
    137 
    138                 // Wait for everyone to acknowledge my leadership
    139                 start: = timeNow()
    140                 for t in threads {
    141                         while t.idx_seen != lead_idx {
    142                                 asm pause
    143                                 if (timeNow() - start) > 5 seconds { error() }
    144                         }
    145                 }
    146 
    147                 // pick next leader
    148                 leader := threads[ prng() % len(threads) ]
    149 
    150                 // wake every one
    151                 if !exhaust {
    152                         for t in threads {
    153                                 if t != me { t.wake() }
    154                         }
    155                 }
    156         }
    157 
    158         Thread.wait() {
    159                 this.idx_seen := lead_idx
    160                 if exhaust { wait() }
    161                 else { yield() }
    162         }
    163 
    164         Thread.main() {
    165                 while !done  {
    166                         if leader == me { this.lead() }
    167                         else { this.wait() }
    168                 }
    169         }
    170 \end{lstlisting}
  • doc/theses/thierry_delisle_PhD/thesis/text/existing.tex

    rf5a51db r97c215f  
    3333
    3434
    35 \section{Work Stealing}\label{existing:workstealing}
     35\section{Work Stealing}
    3636One of the most popular scheduling algorithm in practice (see~\ref{existing:prod}) is work-stealing. This idea, introduce by \cite{DBLP:conf/fpca/BurtonS81}, effectively has each worker work on its local tasks first, but allows the possibility for other workers to steal local tasks if they run out of tasks. \cite{DBLP:conf/focs/Blumofe94} introduced the more familiar incarnation of this, where each workers has queue of tasks to accomplish and workers without tasks steal tasks from random workers. (The Burton and Sleep algorithm had trees of tasks and stole only among neighbours). Blumofe and Leiserson also prove worst case space and time requirements for well-structured computations.
    3737
  • libcfa/src/concurrency/io.cfa

    rf5a51db r97c215f  
    306306                ctx->proc->io.pending = true;
    307307                ctx->proc->io.dirty   = true;
    308                 if(sq.to_submit > 30) {
    309                         __tls_stats()->io.flush.full++;
    310                         __cfa_io_flush( ctx->proc, 0 );
    311                 }
    312                 if(!lazy) {
    313                         __tls_stats()->io.flush.eager++;
     308                if(sq.to_submit > 30 || !lazy) {
    314309                        __cfa_io_flush( ctx->proc, 0 );
    315310                }
  • libcfa/src/concurrency/kernel.cfa

    rf5a51db r97c215f  
    4242
    4343#if !defined(__CFA_NO_STATISTICS__)
    44         #define __STATS_DEF( ...) __VA_ARGS__
     44        #define __STATS( ...) __VA_ARGS__
    4545#else
    46         #define __STATS_DEF( ...)
     46        #define __STATS( ...)
    4747#endif
    4848
     
    122122static thread$ * __next_thread(cluster * this);
    123123static thread$ * __next_thread_slow(cluster * this);
    124 static thread$ * __next_thread_search(cluster * this);
    125124static inline bool __must_unpark( thread$ * thrd ) __attribute((nonnull(1)));
    126125static void __run_thread(processor * this, thread$ * dst);
     
    188187                MAIN_LOOP:
    189188                for() {
     189                        #define OLD_MAIN 1
     190                        #if OLD_MAIN
    190191                        // Check if there is pending io
    191192                        __maybe_io_drain( this );
     
    195196
    196197                        if( !readyThread ) {
    197                                 __IO_STATS__(true, io.flush.idle++; )
    198198                                __cfa_io_flush( this, 0 );
    199199
    200                                 readyThread = __next_thread( this->cltr );
    201                         }
    202 
    203                         if( !readyThread ) for(5) {
    204                                 __IO_STATS__(true, io.flush.idle++; )
    205 
    206200                                readyThread = __next_thread_slow( this->cltr );
    207 
    208                                 if( readyThread ) break;
    209 
    210                                 __cfa_io_flush( this, 0 );
    211201                        }
    212202
     
    216206                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    217207
     208                                #if !defined(__CFA_NO_STATISTICS__)
     209                                        __tls_stats()->ready.sleep.halts++;
     210                                #endif
     211
    218212                                // Push self to idle stack
    219213                                if(!mark_idle(this->cltr->procs, * this)) continue MAIN_LOOP;
    220214
    221215                                // Confirm the ready-queue is empty
    222                                 readyThread = __next_thread_search( this->cltr );
     216                                readyThread = __next_thread_slow( this->cltr );
    223217                                if( readyThread ) {
    224218                                        // A thread was found, cancel the halt
    225219                                        mark_awake(this->cltr->procs, * this);
    226220
    227                                         __STATS__(true, ready.sleep.cancels++; )
     221                                        #if !defined(__CFA_NO_STATISTICS__)
     222                                                __tls_stats()->ready.sleep.cancels++;
     223                                        #endif
    228224
    229225                                        // continue the mai loop
     
    252248
    253249                        if(this->io.pending && !this->io.dirty) {
    254                                 __IO_STATS__(true, io.flush.dirty++; )
    255250                                __cfa_io_flush( this, 0 );
    256251                        }
     252
     253                        #else
     254                                #warning new kernel loop
     255                        SEARCH: {
     256                                /* paranoid */ verify( ! __preemption_enabled() );
     257
     258                                // First, lock the scheduler since we are searching for a thread
     259                                ready_schedule_lock();
     260
     261                                // Try to get the next thread
     262                                readyThread = pop_fast( this->cltr );
     263                                if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     264
     265                                // If we can't find a thread, might as well flush any outstanding I/O
     266                                if(this->io.pending) { __cfa_io_flush( this, 0 ); }
     267
     268                                // Spin a little on I/O, just in case
     269                                for(5) {
     270                                        __maybe_io_drain( this );
     271                                        readyThread = pop_fast( this->cltr );
     272                                        if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     273                                }
     274
     275                                // no luck, try stealing a few times
     276                                for(5) {
     277                                        if( __maybe_io_drain( this ) ) {
     278                                                readyThread = pop_fast( this->cltr );
     279                                        } else {
     280                                                readyThread = pop_slow( this->cltr );
     281                                        }
     282                                        if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     283                                }
     284
     285                                // still no luck, search for a thread
     286                                readyThread = pop_search( this->cltr );
     287                                if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     288
     289                                // Don't block if we are done
     290                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) {
     291                                        ready_schedule_unlock();
     292                                        break MAIN_LOOP;
     293                                }
     294
     295                                __STATS( __tls_stats()->ready.sleep.halts++; )
     296
     297                                // Push self to idle stack
     298                                ready_schedule_unlock();
     299                                if(!mark_idle(this->cltr->procs, * this)) goto SEARCH;
     300                                ready_schedule_lock();
     301
     302                                // Confirm the ready-queue is empty
     303                                __maybe_io_drain( this );
     304                                readyThread = pop_search( this->cltr );
     305                                ready_schedule_unlock();
     306
     307                                if( readyThread ) {
     308                                        // A thread was found, cancel the halt
     309                                        mark_awake(this->cltr->procs, * this);
     310
     311                                        __STATS( __tls_stats()->ready.sleep.cancels++; )
     312
     313                                        // continue the main loop
     314                                        break SEARCH;
     315                                }
     316
     317                                __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
     318                                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd);
     319
     320                                {
     321                                        eventfd_t val;
     322                                        ssize_t ret = read( this->idle_fd, &val, sizeof(val) );
     323                                        if(ret < 0) {
     324                                                switch((int)errno) {
     325                                                case EAGAIN:
     326                                                #if EAGAIN != EWOULDBLOCK
     327                                                        case EWOULDBLOCK:
     328                                                #endif
     329                                                case EINTR:
     330                                                        // No need to do anything special here, just assume it's a legitimate wake-up
     331                                                        break;
     332                                                default:
     333                                                        abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
     334                                                }
     335                                        }
     336                                }
     337
     338                                        __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )
     339
     340                                // We were woken up, remove self from idle
     341                                mark_awake(this->cltr->procs, * this);
     342
     343                                // DON'T just proceed, start looking again
     344                                continue MAIN_LOOP;
     345                        }
     346
     347                RUN_THREAD:
     348                        /* paranoid */ verify( ! __preemption_enabled() );
     349                        /* paranoid */ verify( readyThread );
     350
     351                        // Reset io dirty bit
     352                        this->io.dirty = false;
     353
     354                        // We found a thread run it
     355                        __run_thread(this, readyThread);
     356
     357                        // Are we done?
     358                        if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     359
     360                        if(this->io.pending && !this->io.dirty) {
     361                                __cfa_io_flush( this, 0 );
     362                        }
     363
     364                        ready_schedule_lock();
     365                        __maybe_io_drain( this );
     366                        ready_schedule_unlock();
     367                        #endif
    257368                }
    258369
     
    365476                                break RUNNING;
    366477                        case TICKET_UNBLOCK:
    367                                 __STATS__(true, ready.threads.threads++; )
     478                                #if !defined(__CFA_NO_STATISTICS__)
     479                                        __tls_stats()->ready.threads.threads++;
     480                                #endif
    368481                                // This is case 2, the racy case, someone tried to run this thread before it finished blocking
    369482                                // In this case, just run it again.
     
    380493        __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst);
    381494
    382         __STATS__(true, ready.threads.threads--; )
     495        #if !defined(__CFA_NO_STATISTICS__)
     496                __tls_stats()->ready.threads.threads--;
     497        #endif
    383498
    384499        /* paranoid */ verify( ! __preemption_enabled() );
     
    391506        thread$ * thrd_src = kernelTLS().this_thread;
    392507
    393         __STATS_DEF( thrd_src->last_proc = kernelTLS().this_processor; )
     508        __STATS( thrd_src->last_proc = kernelTLS().this_processor; )
    394509
    395510        // Run the thread on this processor
     
    443558        // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
    444559        struct cluster * cl = thrd->curr_cluster;
    445         __STATS_DEF(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
     560        __STATS(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
    446561
    447562        // push the thread to the cluster ready-queue
     
    494609
    495610        ready_schedule_lock();
    496                 thread$ * thrd = pop_slow( this );
    497         ready_schedule_unlock();
    498 
    499         /* paranoid */ verify( ! __preemption_enabled() );
    500         return thrd;
    501 }
    502 
    503 // KERNEL ONLY
    504 static inline thread$ * __next_thread_search(cluster * this) with( *this ) {
    505         /* paranoid */ verify( ! __preemption_enabled() );
    506 
    507         ready_schedule_lock();
    508                 thread$ * thrd = pop_search( this );
     611                thread$ * thrd;
     612                for(25) {
     613                        thrd = pop_slow( this );
     614                        if(thrd) goto RET;
     615                }
     616                thrd = pop_search( this );
     617
     618                RET:
    509619        ready_schedule_unlock();
    510620
     
    622732// Wake a thread from the front if there are any
    623733static void __wake_one(cluster * this) {
     734        /* paranoid */ verify( ! __preemption_enabled() );
     735        /* paranoid */ verify( ready_schedule_islocked() );
     736
     737        // Check if there is a sleeping processor
     738        // int fd = __atomic_load_n(&this->procs.fd, __ATOMIC_SEQ_CST);
     739        int fd = 0;
     740        if( __atomic_load_n(&this->procs.fd, __ATOMIC_SEQ_CST) != 0 ) {
     741                fd = __atomic_exchange_n(&this->procs.fd, 0, __ATOMIC_RELAXED);
     742        }
     743
     744        // If no one is sleeping, we are done
     745        if( fd == 0 ) return;
     746
     747        // We found a processor, wake it up
    624748        eventfd_t val;
    625 
    626         /* paranoid */ verify( ! __preemption_enabled() );
    627         /* paranoid */ verify( ready_schedule_islocked() );
    628 
    629         // Check if there is a sleeping processor
    630         struct __fd_waitctx * fdp = __atomic_load_n(&this->procs.fdw, __ATOMIC_SEQ_CST);
    631 
    632         // If no one is sleeping: we are done
    633         if( fdp == 0p ) return;
    634 
    635         int fd = 1;
    636         if( __atomic_load_n(&fdp->fd, __ATOMIC_SEQ_CST) != 1 ) {
    637                 fd = __atomic_exchange_n(&fdp->fd, 1, __ATOMIC_RELAXED);
    638         }
    639 
    640         switch(fd) {
    641         case 0:
    642                 // If the processor isn't ready to sleep then the exchange will already wake it up
    643                 #if !defined(__CFA_NO_STATISTICS__)
    644                         if( kernelTLS().this_stats ) { __tls_stats()->ready.sleep.early++;
    645                         } else { __atomic_fetch_add(&this->stats->ready.sleep.early, 1, __ATOMIC_RELAXED); }
    646                 #endif
    647                 break;
    648         case 1:
    649                 // If someone else already said they will wake them: we are done
    650                 #if !defined(__CFA_NO_STATISTICS__)
    651                         if( kernelTLS().this_stats ) { __tls_stats()->ready.sleep.seen++;
    652                         } else { __atomic_fetch_add(&this->stats->ready.sleep.seen, 1, __ATOMIC_RELAXED); }
    653                 #endif
    654                 break;
    655         default:
    656                 // If the processor was ready to sleep, we need to wake it up with an actual write
    657                 val = 1;
    658                 eventfd_write( fd, val );
    659 
    660                 #if !defined(__CFA_NO_STATISTICS__)
    661                         if( kernelTLS().this_stats ) { __tls_stats()->ready.sleep.wakes++;
    662                         } else { __atomic_fetch_add(&this->stats->ready.sleep.wakes, 1, __ATOMIC_RELAXED); }
    663                 #endif
    664                 break;
    665         }
     749        val = 1;
     750        eventfd_write( fd, val );
     751
     752        #if !defined(__CFA_NO_STATISTICS__)
     753                if( kernelTLS().this_stats ) {
     754                        __tls_stats()->ready.sleep.wakes++;
     755                }
     756                else {
     757                        __atomic_fetch_add(&this->stats->ready.sleep.wakes, 1, __ATOMIC_RELAXED);
     758                }
     759        #endif
    666760
    667761        /* paranoid */ verify( ready_schedule_islocked() );
     
    676770
    677771        __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
    678 
    679         this->idle_wctx.fd = 1;
    680772
    681773        eventfd_t val;
     
    687779
    688780static void idle_sleep(processor * this, io_future_t & future, iovec & iov) {
    689         // Tell everyone we are ready to go do sleep
    690         for() {
    691                 int expected = this->idle_wctx.fd;
    692 
    693                 // Someone already told us to wake-up! No time for a nap.
    694                 if(expected == 1) { return; }
    695 
    696                 // Try to mark that we are going to sleep
    697                 if(__atomic_compare_exchange_n(&this->idle_wctx.fd, &expected, this->idle_fd, false,  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) {
    698                         // Every one agreed, taking a nap
    699                         break;
    700                 }
    701         }
    702 
    703 
    704781        #if !defined(CFA_WITH_IO_URING_IDLE)
    705782                #if !defined(__CFA_NO_STATISTICS__)
     
    748825
    749826static bool mark_idle(__cluster_proc_list & this, processor & proc) {
    750         __STATS__(true, ready.sleep.halts++; )
    751 
    752         proc.idle_wctx.fd = 0;
    753 
    754827        /* paranoid */ verify( ! __preemption_enabled() );
    755828        if(!try_lock( this )) return false;
     
    759832                insert_first(this.idles, proc);
    760833
    761                 __atomic_store_n(&this.fdw, &proc.idle_wctx, __ATOMIC_SEQ_CST);
     834                __atomic_store_n(&this.fd, proc.idle_fd, __ATOMIC_SEQ_CST);
    762835        unlock( this );
    763836        /* paranoid */ verify( ! __preemption_enabled() );
     
    775848
    776849                {
    777                         struct __fd_waitctx * wctx = 0;
    778                         if(!this.idles`isEmpty) wctx = &this.idles`first.idle_wctx;
    779                         __atomic_store_n(&this.fdw, wctx, __ATOMIC_SEQ_CST);
     850                        int fd = 0;
     851                        if(!this.idles`isEmpty) fd = this.idles`first.idle_fd;
     852                        __atomic_store_n(&this.fd, fd, __ATOMIC_SEQ_CST);
    780853                }
    781854
     
    841914                unsigned tail = *ctx->cq.tail;
    842915                if(head == tail) return false;
    843                 ready_schedule_lock();
    844                 ret = __cfa_io_drain( proc );
    845                 ready_schedule_unlock();
     916                #if OLD_MAIN
     917                        ready_schedule_lock();
     918                        ret = __cfa_io_drain( proc );
     919                        ready_schedule_unlock();
     920                #else
     921                        ret = __cfa_io_drain( proc );
     922                #endif
    846923        #endif
    847924        return ret;
  • libcfa/src/concurrency/kernel.hfa

    rf5a51db r97c215f  
    5353coroutine processorCtx_t {
    5454        struct processor * proc;
    55 };
    56 
    57 
    58 struct __fd_waitctx {
    59         volatile int fd;
    6055};
    6156
     
    106101        int idle_fd;
    107102
    108         // Idle waitctx
    109         struct __fd_waitctx idle_wctx;
    110 
    111103        // Termination synchronisation (user semaphore)
    112104        oneshot terminated;
     
    215207
    216208        // FD to use to wake a processor
    217         struct __fd_waitctx * volatile fdw;
     209        volatile int fd;
    218210
    219211        // Total number of processors
  • libcfa/src/concurrency/kernel/fwd.hfa

    rf5a51db r97c215f  
    396396                                if( !(in_kernel) ) enable_interrupts(); \
    397397                        }
    398                         #if defined(CFA_HAVE_LINUX_IO_URING_H)
    399                                 #define __IO_STATS__(in_kernel, ...) { \
    400                                         if( !(in_kernel) ) disable_interrupts(); \
    401                                         with( *__tls_stats() ) { \
    402                                                 __VA_ARGS__ \
    403                                         } \
    404                                         if( !(in_kernel) ) enable_interrupts(); \
    405                                 }
    406                         #else
    407                                 #define __IO_STATS__(in_kernel, ...)
    408                         #endif
    409398                #else
    410399                        #define __STATS__(in_kernel, ...)
    411                         #define __IO_STATS__(in_kernel, ...)
    412400                #endif
    413401        }
  • libcfa/src/concurrency/kernel/startup.cfa

    rf5a51db r97c215f  
    537537        }
    538538
    539         this.idle_wctx.fd = 0;
    540 
    541         // I'm assuming these two are reserved for standard input and output
    542         // so I'm using them as sentinels with idle_wctx.
    543         /* paranoid */ verify( this.idle_fd != 0 );
    544         /* paranoid */ verify( this.idle_fd != 1 );
    545 
    546539        #if !defined(__CFA_NO_STATISTICS__)
    547540                print_stats = 0;
     
    597590// Cluster
    598591static void ?{}(__cluster_proc_list & this) {
    599         this.fdw   = 0p;
     592        this.fd    = 0;
    600593        this.idle  = 0;
    601594        this.total = 0;
  • libcfa/src/concurrency/mutex_stmt.hfa

    rf5a51db r97c215f  
    3838    }
    3939
    40     struct scoped_lock {
    41         L * internal_lock;
    42     };
    43 
    44     static inline void ?{}( scoped_lock(L) & this, L & internal_lock ) {
    45         this.internal_lock = &internal_lock;
    46         lock(internal_lock);
    47     }
    48    
    49     static inline void ^?{}( scoped_lock(L) & this ) with(this) {
    50         unlock(*internal_lock);
    51     }
    52 
    5340    static inline L * __get_ptr( L & this ) {
    5441        return &this;
  • libcfa/src/concurrency/preemption.cfa

    rf5a51db r97c215f  
    251251        bool enabled = __cfaabi_tls.preemption_state.enabled;
    252252
    253         // Check if there is a pending preemption
    254         processor   * proc = __cfaabi_tls.this_processor;
    255         bool pending = proc ? proc->pending_preemption : false;
    256         if( enabled && pending ) proc->pending_preemption = false;
    257 
    258253        // create a assembler label after
    259254        // marked as clobber all to avoid movement
    260255        __cfaasm_label(check, after);
    261 
    262         // If we can preempt and there is a pending one
    263         // this is a good time to yield
    264         if( enabled && pending ) {
    265                 force_yield( __POLL_PREEMPTION );
    266         }
    267256        return enabled;
    268257}
     
    293282        // marked as clobber all to avoid movement
    294283        __cfaasm_label(get, after);
    295 
    296         // This is used everywhere, to avoid cost, we DO NOT poll pending preemption
    297284        return val;
    298285}
     
    371358        if(!ready) { abort("Preemption should be ready"); }
    372359
    373         sigset_t oldset;
    374         int ret;
    375         ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
    376         if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    377 
    378         ret = sigismember(&oldset, SIGUSR1);
    379         if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
    380         if(ret == 1) { abort("ERROR SIGUSR1 is disabled"); }
    381 
    382         ret = sigismember(&oldset, SIGALRM);
    383         if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
    384         if(ret == 0) { abort("ERROR SIGALRM is enabled"); }
    385 
    386         ret = sigismember(&oldset, SIGTERM);
    387         if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
    388         if(ret == 1) { abort("ERROR SIGTERM is disabled"); }
     360        __cfaasm_label(debug, before);
     361
     362                sigset_t oldset;
     363                int ret;
     364                ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
     365                if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
     366
     367                ret = sigismember(&oldset, SIGUSR1);
     368                if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
     369                if(ret == 1) { abort("ERROR SIGUSR1 is disabled"); }
     370
     371                ret = sigismember(&oldset, SIGALRM);
     372                if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
     373                if(ret == 0) { abort("ERROR SIGALRM is enabled"); }
     374
     375                ret = sigismember(&oldset, SIGTERM);
     376                if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
     377                if(ret == 1) { abort("ERROR SIGTERM is disabled"); }
     378
     379        __cfaasm_label(debug, after);
    389380}
    390381
     
    557548        __cfaasm_label( check  );
    558549        __cfaasm_label( dsable );
    559         // __cfaasm_label( debug  );
     550        __cfaasm_label( debug  );
    560551
    561552        // Check if preemption is safe
     
    564555        if( __cfaasm_in( ip, check  ) ) { ready = false; goto EXIT; };
    565556        if( __cfaasm_in( ip, dsable ) ) { ready = false; goto EXIT; };
    566         // if( __cfaasm_in( ip, debug  ) ) { ready = false; goto EXIT; };
     557        if( __cfaasm_in( ip, debug  ) ) { ready = false; goto EXIT; };
    567558        if( !__cfaabi_tls.preemption_state.enabled) { ready = false; goto EXIT; };
    568559        if( __cfaabi_tls.preemption_state.in_progress ) { ready = false; goto EXIT; };
     
    670661
    671662        // Check if it is safe to preempt here
    672         if( !preemption_ready( ip ) ) {
    673                 #if !defined(__CFA_NO_STATISTICS__)
    674                         __cfaabi_tls.this_stats->ready.threads.preempt.rllfwd++;
    675                 #endif
    676                 return;
    677         }
     663        if( !preemption_ready( ip ) ) { return; }
    678664
    679665        __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", __cfaabi_tls.this_processor, __cfaabi_tls.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) );
     
    694680
    695681        // Preemption can occur here
    696 
    697         #if !defined(__CFA_NO_STATISTICS__)
    698                 __cfaabi_tls.this_stats->ready.threads.preempt.yield++;
    699         #endif
    700682
    701683        force_yield( __ALARM_PREEMPTION ); // Do the actual __cfactx_switch
  • libcfa/src/concurrency/ready_queue.cfa

    rf5a51db r97c215f  
    201201uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
    202202        /* paranoid */ verify( ! __preemption_enabled() );
     203        /* paranoid */ verify( ! kernelTLS().sched_lock );
    203204
    204205        // Step 1 : lock global lock
     
    206207        //   to simply lock their own lock and enter.
    207208        __atomic_acquire( &write_lock );
    208 
    209         // Make sure we won't deadlock ourself
    210         // Checking before acquiring the writer lock isn't safe
    211         // because someone else could have locked us.
    212         /* paranoid */ verify( ! kernelTLS().sched_lock );
    213209
    214210        // Step 2 : lock per-proc lock
  • libcfa/src/concurrency/stats.cfa

    rf5a51db r97c215f  
    2929                stats->ready.threads.threads   = 0;
    3030                stats->ready.threads.cthreads  = 0;
    31                 stats->ready.threads.preempt.yield  = 0;
    32                 stats->ready.threads.preempt.rllfwd = 0;
    3331                stats->ready.sleep.halts   = 0;
    3432                stats->ready.sleep.cancels = 0;
    35                 stats->ready.sleep.early   = 0;
    3633                stats->ready.sleep.wakes   = 0;
    37                 stats->ready.sleep.seen    = 0;
    3834                stats->ready.sleep.exits   = 0;
    3935
     
    4743                        stats->io.submit.slow       = 0;
    4844                        stats->io.flush.external    = 0;
    49                         stats->io.flush.dirty       = 0;
    50                         stats->io.flush.full        = 0;
    51                         stats->io.flush.idle        = 0;
    52                         stats->io.flush.eager       = 0;
    5345                        stats->io.calls.flush       = 0;
    5446                        stats->io.calls.submitted   = 0;
     
    7971
    8072        void __tally_stats( struct __stats_t * cltr, struct __stats_t * proc ) {
    81                 tally_one( &cltr->ready.push.local.attempt    , &proc->ready.push.local.attempt     );
    82                 tally_one( &cltr->ready.push.local.success    , &proc->ready.push.local.success     );
    83                 tally_one( &cltr->ready.push.share.attempt    , &proc->ready.push.share.attempt     );
    84                 tally_one( &cltr->ready.push.share.success    , &proc->ready.push.share.success     );
    85                 tally_one( &cltr->ready.push.extrn.attempt    , &proc->ready.push.extrn.attempt     );
    86                 tally_one( &cltr->ready.push.extrn.success    , &proc->ready.push.extrn.success     );
    87                 tally_one( &cltr->ready.pop.local .attempt    , &proc->ready.pop.local .attempt     );
    88                 tally_one( &cltr->ready.pop.local .success    , &proc->ready.pop.local .success     );
    89                 tally_one( &cltr->ready.pop.help  .attempt    , &proc->ready.pop.help  .attempt     );
    90                 tally_one( &cltr->ready.pop.help  .success    , &proc->ready.pop.help  .success     );
    91                 tally_one( &cltr->ready.pop.steal .attempt    , &proc->ready.pop.steal .attempt     );
    92                 tally_one( &cltr->ready.pop.steal .success    , &proc->ready.pop.steal .success     );
    93                 tally_one( &cltr->ready.pop.search.attempt    , &proc->ready.pop.search.attempt     );
    94                 tally_one( &cltr->ready.pop.search.success    , &proc->ready.pop.search.success     );
    95                 tally_one( &cltr->ready.threads.migration     , &proc->ready.threads.migration      );
    96                 tally_one( &cltr->ready.threads.extunpark     , &proc->ready.threads.extunpark      );
    97                 tally_one( &cltr->ready.threads.threads       , &proc->ready.threads.threads        );
    98                 tally_one( &cltr->ready.threads.cthreads      , &proc->ready.threads.cthreads       );
    99                 tally_one( &cltr->ready.threads.preempt.yield , &proc->ready.threads.preempt.yield  );
    100                 tally_one( &cltr->ready.threads.preempt.rllfwd, &proc->ready.threads.preempt.rllfwd );
    101                 tally_one( &cltr->ready.sleep.halts           , &proc->ready.sleep.halts            );
    102                 tally_one( &cltr->ready.sleep.cancels         , &proc->ready.sleep.cancels          );
    103                 tally_one( &cltr->ready.sleep.early           , &proc->ready.sleep.early            );
    104                 tally_one( &cltr->ready.sleep.wakes           , &proc->ready.sleep.wakes            );
    105                 tally_one( &cltr->ready.sleep.seen            , &proc->ready.sleep.wakes            );
    106                 tally_one( &cltr->ready.sleep.exits           , &proc->ready.sleep.exits            );
     73                tally_one( &cltr->ready.push.local.attempt, &proc->ready.push.local.attempt );
     74                tally_one( &cltr->ready.push.local.success, &proc->ready.push.local.success );
     75                tally_one( &cltr->ready.push.share.attempt, &proc->ready.push.share.attempt );
     76                tally_one( &cltr->ready.push.share.success, &proc->ready.push.share.success );
     77                tally_one( &cltr->ready.push.extrn.attempt, &proc->ready.push.extrn.attempt );
     78                tally_one( &cltr->ready.push.extrn.success, &proc->ready.push.extrn.success );
     79                tally_one( &cltr->ready.pop.local .attempt, &proc->ready.pop.local .attempt );
     80                tally_one( &cltr->ready.pop.local .success, &proc->ready.pop.local .success );
     81                tally_one( &cltr->ready.pop.help  .attempt, &proc->ready.pop.help  .attempt );
     82                tally_one( &cltr->ready.pop.help  .success, &proc->ready.pop.help  .success );
     83                tally_one( &cltr->ready.pop.steal .attempt, &proc->ready.pop.steal .attempt );
     84                tally_one( &cltr->ready.pop.steal .success, &proc->ready.pop.steal .success );
     85                tally_one( &cltr->ready.pop.search.attempt, &proc->ready.pop.search.attempt );
     86                tally_one( &cltr->ready.pop.search.success, &proc->ready.pop.search.success );
     87                tally_one( &cltr->ready.threads.migration , &proc->ready.threads.migration  );
     88                tally_one( &cltr->ready.threads.extunpark , &proc->ready.threads.extunpark  );
     89                tally_one( &cltr->ready.threads.threads   , &proc->ready.threads.threads    );
     90                tally_one( &cltr->ready.threads.cthreads  , &proc->ready.threads.cthreads   );
     91                tally_one( &cltr->ready.sleep.halts       , &proc->ready.sleep.halts        );
     92                tally_one( &cltr->ready.sleep.cancels     , &proc->ready.sleep.cancels      );
     93                tally_one( &cltr->ready.sleep.wakes       , &proc->ready.sleep.wakes        );
     94                tally_one( &cltr->ready.sleep.exits       , &proc->ready.sleep.exits        );
    10795
    10896                #if defined(CFA_HAVE_LINUX_IO_URING_H)
     
    115103                        tally_one( &cltr->io.submit.slow      , &proc->io.submit.slow       );
    116104                        tally_one( &cltr->io.flush.external   , &proc->io.flush.external    );
    117                         tally_one( &cltr->io.flush.dirty      , &proc->io.flush.dirty       );
    118                         tally_one( &cltr->io.flush.full       , &proc->io.flush.full        );
    119                         tally_one( &cltr->io.flush.idle       , &proc->io.flush.idle        );
    120                         tally_one( &cltr->io.flush.eager      , &proc->io.flush.eager       );
    121105                        tally_one( &cltr->io.calls.flush      , &proc->io.calls.flush       );
    122106                        tally_one( &cltr->io.calls.submitted  , &proc->io.calls.submitted   );
     
    169153                             | " (" | eng3(ready.pop.search.attempt) | " try)";
    170154
    171                         sstr | "- Idle Slp : " | eng3(ready.sleep.halts) | "halt," | eng3(ready.sleep.cancels) | "cancel,"
    172                              | eng3(ready.sleep.wakes + ready.sleep.early) | '(' | eng3(ready.sleep.early) | ',' | eng3(ready.sleep.seen) | ')' | " wake(early, seen),"
    173                              | eng3(ready.sleep.exits) | "exit";
    174                         sstr | "- Preemption : " | eng3(ready.threads.preempt.yield) | "yields," | eng3(ready.threads.preempt.rllfwd) | "delayed";
     155                        sstr | "- Idle Slp : " | eng3(ready.sleep.halts) | "halt," | eng3(ready.sleep.cancels) | "cancel," | eng3(ready.sleep.wakes) | "wake," | eng3(ready.sleep.exits) | "exit";
    175156                        sstr | nl;
    176157                }
     
    197178                                if(io.alloc.fail || io.alloc.revoke || io.alloc.block)
    198179                                        sstr | "-     failures      : " | eng3(io.alloc.fail) | "oom, " | eng3(io.alloc.revoke) | "rvk, " | eng3(io.alloc.block) | "blk";
    199                                 // if(io.flush.external)
    200                                 //      sstr | "- flush external    : " | eng3(io.flush.external);
     180                                if(io.flush.external)
     181                                        sstr | "- flush external    : " | eng3(io.flush.external);
    201182
    202183                                double avgsubs = ((double)io.calls.submitted) / io.calls.flush;
    203184                                double avgcomp = ((double)io.calls.completed) / io.calls.drain;
    204185                                sstr | "- syscll : "
    205                                      |   " sub " | eng3(io.calls.submitted) | "/" | eng3(io.calls.flush) | "(" | ws(3, 3, avgsubs) | "/flush)"
    206                                      | " - cmp " | eng3(io.calls.completed) | "/" | eng3(io.calls.drain) | "(" | ws(3, 3, avgcomp) | "/drain)"
     186                                     |   " sub " | eng3(io.calls.flush) | "/" | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)"
     187                                     | " - cmp " | eng3(io.calls.drain) | "/" | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)"
    207188                                     | " - " | eng3(io.calls.errors.busy) | " EBUSY";
    208                                 sstr | " - sub: " | eng3(io.flush.full) | "full, " | eng3(io.flush.dirty) | "drty, " | eng3(io.flush.idle) | "idle, " | eng3(io.flush.eager) | "eagr, " | eng3(io.flush.external) | "ext";
    209189                                sstr | "- ops blk: "
    210190                                     |   " sk rd: " | eng3(io.ops.sockread)  | "epll: " | eng3(io.ops.epllread)
  • libcfa/src/concurrency/stats.hfa

    rf5a51db r97c215f  
    6565                        volatile  int64_t threads;  // number of threads in the system, includes only local change
    6666                        volatile  int64_t cthreads; // number of threads in the system, includes only local change
    67                         struct {
    68                                 volatile uint64_t yield;
    69                                 volatile uint64_t rllfwd;
    70                         } preempt;
    7167                } threads;
    7268                struct {
    7369                        volatile uint64_t halts;
    7470                        volatile uint64_t cancels;
    75                         volatile uint64_t early;
    7671                        volatile uint64_t wakes;
    77                         volatile uint64_t seen;
    7872                        volatile uint64_t exits;
    7973                } sleep;
     
    9589                        struct {
    9690                                volatile uint64_t external;
    97                                 volatile uint64_t dirty;
    98                                 volatile uint64_t full;
    99                                 volatile uint64_t idle;
    100                                 volatile uint64_t eager;
    10191                        } flush;
    10292                        struct {
  • libcfa/src/stdhdr/pthread.h

    rf5a51db r97c215f  
    1010// Created On       : Wed Jun 16 13:39:06 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  3 21:53:26 2022
    13 // Update Count     : 13
     12// Last Modified On : Wed Jun 16 13:39:42 2021
     13// Update Count     : 1
    1414//
    1515
    16 // pthread.h and setjmp.h cannot agree on the type of __sigsetjmp:
    17 //
    18 //   extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __attribute__ ((__nothrow__));
    19 //   extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) __attribute__ ((__nothrow__));
    20 //
    21 // With -Wall, gcc-11 warns about the disagreement unless the CPP directive
    22 //
    23 //    # 1 "/usr/include/pthread.h" 1 3 4
    24 //
    25 // appears, which appears to be witchcraft. Unfortunately, this directive is removed by the CFA preprocessor, so the
    26 // batchtest fails because of the spurious warning message. Hence, the warning is elided.
    27 
    2816extern "C" {
    29 #if defined(__GNUC__) && __GNUC__ == 11
    30         #pragma GCC diagnostic push
    31         #pragma GCC diagnostic ignored "-Warray-parameter"
    32 #endif // defined(__GNUC__) && __GNUC__ == 11
    33 
    3417#include_next <pthread.h>                                                               // has internal check for multiple expansion
    35 
    36 #if defined(__GNUC__) && __GNUC__ == 11
    37         #pragma GCC diagnostic pop
    38 #endif // defined(__GNUC__) && __GNUC__ == 11
    3918} // extern "C"
    4019
    4120// Local Variables: //
     21// tab-width: 4 //
    4222// mode: c++ //
     23// compile-command: "make install" //
    4324// End: //
  • libcfa/src/stdhdr/setjmp.h

    rf5a51db r97c215f  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  3 21:53:28 2022
    13 // Update Count     : 18
     12// Last Modified On : Tue Jul  5 20:38:33 2016
     13// Update Count     : 12
    1414//
    1515
    16 // pthread.h and setjmp.h cannot agree on the type of __sigsetjmp:
    17 //
    18 //   extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __attribute__ ((__nothrow__));
    19 //   extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) __attribute__ ((__nothrow__));
    20 //
    21 // With -Wall, gcc-11 warns about the disagreement unless the CPP directive
    22 //
    23 //    # 1 "/usr/include/pthread.h" 1 3 4
    24 //
    25 // appears, which appears to be witchcraft. Unfortunately, this directive is removed by the CFA preprocessor, so the
    26 // batchtest fails because of the spurious warning message. Hence, the warning is elided.
    27 
    2816extern "C" {
    29 #if defined(__GNUC__) && __GNUC__ == 11
    30         #pragma GCC diagnostic push
    31         #pragma GCC diagnostic ignored "-Warray-parameter"
    32 #endif // defined(__GNUC__) && __GNUC__ == 11
    33 
    3417#include_next <setjmp.h>                                                                // has internal check for multiple expansion
    35 
    36 #if defined(__GNUC__) && __GNUC__ == 11
    37         #pragma GCC diagnostic pop
    38 #endif // defined(__GNUC__) && __GNUC__ == 11
    3918} // extern "C"
    4019
    4120// Local Variables: //
     21// tab-width: 4 //
    4222// mode: c++ //
     23// compile-command: "make install" //
    4324// End: //
  • src/AST/Convert.cpp

    rf5a51db r97c215f  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 09 15::37::05 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  2 13:19:22 2022
    13 // Update Count     : 41
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jul 14 16:15:00 2021
     13// Update Count     : 37
    1414//
    1515
     
    393393                auto stmt = new IfStmt(
    394394                        get<Expression>().accept1( node->cond ),
    395                         get<Statement>().accept1( node->then ),
    396                         get<Statement>().accept1( node->else_ ),
     395                        get<Statement>().accept1( node->thenPart ),
     396                        get<Statement>().accept1( node->elsePart ),
    397397                        get<Statement>().acceptL( node->inits )
    398398                );
     
    419419        }
    420420
    421         const ast::Stmt * visit( const ast::WhileDoStmt * node ) override final {
     421        const ast::Stmt * visit( const ast::WhileStmt * node ) override final {
    422422                if ( inCache( node ) ) return nullptr;
    423423                auto inits = get<Statement>().acceptL( node->inits );
    424                 auto stmt = new WhileDoStmt(
     424                auto stmt = new WhileStmt(
    425425                        get<Expression>().accept1( node->cond ),
    426426                        get<Statement>().accept1( node->body ),
    427                         get<Statement>().accept1( node->else_ ),
    428427                        inits,
    429428                        node->isDoWhile
     
    438437                        get<Expression>().accept1( node->cond ),
    439438                        get<Expression>().accept1( node->inc ),
    440                         get<Statement>().accept1( node->body ),
    441                         get<Statement>().accept1( node->else_ )
     439                        get<Statement>().accept1( node->body )
    442440                );
    443441                return stmtPostamble( stmt, node );
     
    18741872                        old->location,
    18751873                        GET_ACCEPT_1(condition, Expr),
    1876                         GET_ACCEPT_1(then, Stmt),
    1877                         GET_ACCEPT_1(else_, Stmt),
     1874                        GET_ACCEPT_1(thenPart, Stmt),
     1875                        GET_ACCEPT_1(elsePart, Stmt),
    18781876                        GET_ACCEPT_V(initialization, Stmt),
    18791877                        GET_LABELS_V(old->labels)
     
    19041902        }
    19051903
    1906         virtual void visit( const WhileDoStmt * old ) override final {
     1904        virtual void visit( const WhileStmt * old ) override final {
    19071905                if ( inCache( old ) ) return;
    1908                 this->node = new ast::WhileDoStmt(
     1906                this->node = new ast::WhileStmt(
    19091907                        old->location,
    19101908                        GET_ACCEPT_1(condition, Expr),
    19111909                        GET_ACCEPT_1(body, Stmt),
    1912                         GET_ACCEPT_1(else_, Stmt),
    19131910                        GET_ACCEPT_V(initialization, Stmt),
    19141911                        old->isDoWhile,
     
    19261923                        GET_ACCEPT_1(increment, Expr),
    19271924                        GET_ACCEPT_1(body, Stmt),
    1928                         GET_ACCEPT_1(else_, Stmt),
    19291925                        GET_LABELS_V(old->labels)
    19301926                );
  • src/AST/Copy.hpp

    rf5a51db r97c215f  
    1010// Created On       : Wed Jul 10 16:13:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Dec 15 11:07:00 2021
    13 // Update Count     : 3
     12// Last Modified On : Thr Nov 11  9:22:00 2021
     13// Update Count     : 2
    1414//
    1515
     
    5252Node * deepCopy<Node>( const Node * localRoot );
    5353
    54 template<typename node_t, enum Node::ref_type ref_t>
    55 node_t * shallowCopy( const ptr_base<node_t, ref_t> & localRoot ) {
    56         return shallowCopy( localRoot.get() );
    57 }
    58 
    59 template<typename node_t, enum Node::ref_type ref_t>
    60 node_t * deepCopy( const ptr_base<node_t, ref_t> & localRoot ) {
    61         return deepCopy( localRoot.get() );
    62 }
    63 
    6454}
    6555
  • src/AST/Fwd.hpp

    rf5a51db r97c215f  
    1010// Created On       : Wed May  8 16:05:00 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:08:33 2022
    13 // Update Count     : 5
     12// Last Modified On : Fri Mar 12 18:37:39 2021
     13// Update Count     : 4
    1414//
    1515
     
    4444class DirectiveStmt;
    4545class IfStmt;
    46 class WhileDoStmt;
     46class WhileStmt;
    4747class ForStmt;
    4848class SwitchStmt;
  • src/AST/Node.cpp

    rf5a51db r97c215f  
    1010// Created On       : Thu May 16 14:16:00 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:09:39 2022
    13 // Update Count     : 3
     12// Last Modified On : Fri Mar 12 18:25:06 2021
     13// Update Count     : 2
    1414//
    1515
     
    146146template class ast::ptr_base< ast::IfStmt, ast::Node::ref_type::weak >;
    147147template class ast::ptr_base< ast::IfStmt, ast::Node::ref_type::strong >;
    148 template class ast::ptr_base< ast::WhileDoStmt, ast::Node::ref_type::weak >;
    149 template class ast::ptr_base< ast::WhileDoStmt, ast::Node::ref_type::strong >;
     148template class ast::ptr_base< ast::WhileStmt, ast::Node::ref_type::weak >;
     149template class ast::ptr_base< ast::WhileStmt, ast::Node::ref_type::strong >;
    150150template class ast::ptr_base< ast::ForStmt, ast::Node::ref_type::weak >;
    151151template class ast::ptr_base< ast::ForStmt, ast::Node::ref_type::strong >;
  • src/AST/Node.hpp

    rf5a51db r97c215f  
    188188        }
    189189
    190         ptr_base & operator=( const node_t * node ) {
    191                 assign( node );
    192                 return *this;
    193         }
    194 
    195190        template<typename o_node_t>
    196191        ptr_base & operator=( const o_node_t * node ) {
  • src/AST/Pass.hpp

    rf5a51db r97c215f  
    146146        const ast::Stmt *             visit( const ast::DirectiveStmt        * ) override final;
    147147        const ast::Stmt *             visit( const ast::IfStmt               * ) override final;
    148         const ast::Stmt *             visit( const ast::WhileDoStmt          * ) override final;
     148        const ast::Stmt *             visit( const ast::WhileStmt            * ) override final;
    149149        const ast::Stmt *             visit( const ast::ForStmt              * ) override final;
    150150        const ast::Stmt *             visit( const ast::SwitchStmt           * ) override final;
     
    238238
    239239private:
    240 
    241         // Regular nodes
     240        const ast::Stmt * call_accept( const ast::Stmt * );
     241        const ast::Expr * call_accept( const ast::Expr * );
     242
     243        // requests WithStmtsToAdd directly add to this statement, as if it is a compound.
     244
     245        const ast::Stmt * call_accept_as_compound(const ast::Stmt *);
     246
    242247        template< typename node_t >
    243         struct result1 {
    244                 bool differs;
    245                 const node_t * value;
    246 
    247                 template< typename object_t, typename super_t, typename field_t >
    248                 void apply(object_t *, field_t super_t::* field);
    249         };
    250 
    251         result1<ast::Stmt> call_accept( const ast::Stmt * );
    252         result1<ast::Expr> call_accept( const ast::Expr * );
    253 
    254         template< typename node_t >
    255         auto call_accept( const node_t * node )
    256                 -> typename std::enable_if<
     248        auto call_accept( const node_t * node ) -> typename std::enable_if<
    257249                                !std::is_base_of<ast::Expr, node_t>::value &&
    258250                                !std::is_base_of<ast::Stmt, node_t>::value
    259                         , result1<
    260                                 typename std::remove_pointer< decltype( node->accept(*this) ) >::type
    261                         >
     251                        , decltype( node->accept(*this) )
    262252                >::type;
    263253
    264         // requests WithStmtsToAdd directly add to this statement, as if it is a compound.
    265         result1<ast::Stmt> call_accept_as_compound(const ast::Stmt *);
    266 
    267         template<typename it_t, template <class...> class container_t>
    268                 static inline void take_all_delta( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) {
    269                         if(empty(decls)) return;
    270 
    271                         std::transform(decls->begin(), decls->end(), it, [](ast::ptr<ast::Decl>&& decl) -> auto {
    272                                         auto loc = decl->location;
    273                                         auto stmt = new DeclStmt( loc, decl.release() );
    274                                         return { {stmt}, -1, false };
    275                                 });
    276                         decls->clear();
    277                         if(mutated) *mutated = true;
    278                 }
    279 
    280         // Container of statements
    281254        template< template <class...> class container_t >
    282         struct resultNstmt {
    283                 struct delta {
    284                         ptr<Stmt> nval;
    285                         ssize_t old_idx;
    286                         bool is_old;
    287 
    288                         delta(const Stmt * s, ssize_t i, bool old) : nval{s}, old_idx{i}, is_old{old} {}
    289                 };
    290 
    291                 bool differs;
    292                 container_t< delta > values;
    293 
    294                 resultNstmt() : differs(false), values{} {}
    295                 resultNstmt(bool diff, container_t< delta > && vals) : differs(diff), values(vals) {}
    296 
    297                 template< typename object_t, typename super_t, typename field_t >
    298                 void apply(object_t *, field_t super_t::* field);
    299 
    300                 template< template <class...> class incontainer_t >
    301                 void take_all( incontainer_t<ast::ptr<ast::Stmt>> * stmts ) {
    302                         if(!stmts || stmts->empty()) return;
    303 
    304                         std::transform(stmts->begin(), stmts->end(), std::back_inserter( values ), [](ast::ptr<ast::Stmt>& decl) -> delta {
    305                                         return delta( decl.release(), -1, false );
    306                                 });
    307                         stmts->clear();
    308                         differs = true;
    309                 }
    310 
    311                 template< template <class...> class incontainer_t >
    312                 void take_all( incontainer_t<ast::ptr<ast::Decl>> * decls ) {
    313                         if(!decls || decls->empty()) return;
    314 
    315                         std::transform(decls->begin(), decls->end(), std::back_inserter( values ), [](ast::ptr<ast::Decl>& decl) -> auto {
    316                                         auto loc = decl->location;
    317                                         auto stmt = new DeclStmt( loc, decl.release() );
    318                                         return delta( stmt, -1, false );
    319                                 });
    320                         decls->clear();
    321                         differs = true;
    322                 }
    323         };
    324 
    325         template< template <class...> class container_t >
    326         resultNstmt<container_t> call_accept( const container_t< ptr<Stmt> > & );
    327 
    328         // Container of something
     255        container_t< ptr<Stmt> > call_accept( const container_t< ptr<Stmt> > & );
     256
    329257        template< template <class...> class container_t, typename node_t >
    330         struct resultN {
    331                 bool differs;
    332                 container_t<ptr<node_t>> values;
    333 
    334                 template< typename object_t, typename super_t, typename field_t >
    335                 void apply(object_t *, field_t super_t::* field);
    336         };
    337 
    338         template< template <class...> class container_t, typename node_t >
    339         resultN< container_t, node_t > call_accept( const container_t< ptr<node_t> > & container );
     258        container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
    340259
    341260public:
    342261        /// Logic to call the accept and mutate the parent if needed, delegates call to accept
    343         template<typename node_t, typename parent_t, typename field_t>
    344         void maybe_accept(const node_t * &, field_t parent_t::* field);
    345 
    346         template<typename node_t, typename parent_t, typename field_t>
    347         void maybe_accept_as_compound(const node_t * &, field_t parent_t::* field);
     262        template<typename node_t, typename parent_t, typename child_t>
     263        void maybe_accept(const node_t * &, child_t parent_t::* child);
     264
     265        template<typename node_t, typename parent_t, typename child_t>
     266        void maybe_accept_as_compound(const node_t * &, child_t parent_t::* child);
    348267
    349268private:
  • src/AST/Pass.impl.hpp

    rf5a51db r97c215f  
    3434        __pass::previsit( core, node, 0 );
    3535
     36#define VISIT( code... ) \
     37        /* if this node should visit its children */ \
     38        if ( __visit_children() ) { \
     39                /* visit the children */ \
     40                code \
     41        }
     42
    3643#define VISIT_END( type, node ) \
    3744        /* call the implementation of the postvisit of this pass */ \
     
    7986
    8087                template<typename it_t, template <class...> class container_t>
    81                 static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * stmts, bool * mutated = nullptr ) {
    82                         if(empty(stmts)) return;
    83 
    84                         std::move(stmts->begin(), stmts->end(), it);
    85                         stmts->clear();
     88                static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * decls, bool * mutated = nullptr ) {
     89                        if(empty(decls)) return;
     90
     91                        std::move(decls->begin(), decls->end(), it);
     92                        decls->clear();
    8693                        if(mutated) *mutated = true;
    8794                }
     
    123130                        return !new_val.empty();
    124131                }
    125         }
    126 
    127 
    128         template< typename core_t >
    129         template< typename node_t >
    130         template< typename object_t, typename super_t, typename field_t >
    131         void ast::Pass< core_t >::result1< node_t >::apply(object_t * object, field_t super_t::* field) {
    132                 object->*field = value;
    133132        }
    134133
     
    139138                                !std::is_base_of<ast::Expr, node_t>::value &&
    140139                                !std::is_base_of<ast::Stmt, node_t>::value
    141                         , ast::Pass< core_t >::result1<
    142                                 typename std::remove_pointer< decltype( node->accept(*this) ) >::type
    143                         >
     140                        , decltype( node->accept(*this) )
    144141                >::type
    145142        {
     
    150147                static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR");
    151148
    152                 auto nval = node->accept( *this );
    153                 ast::Pass< core_t >::result1<
    154                         typename std::remove_pointer< decltype( node->accept(*this) ) >::type
    155                 > res;
    156                 res.differs = nval != node;
    157                 res.value = nval;
    158                 return res;
     149                return node->accept( *this );
    159150        }
    160151
    161152        template< typename core_t >
    162         ast::Pass< core_t >::result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
     153        const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
    163154                __pedantic_pass_assert( __visit_children() );
    164155                __pedantic_pass_assert( expr );
     
    169160                }
    170161
    171                 auto nval = expr->accept( *this );
    172                 return { nval != expr, nval };
     162                return expr->accept( *this );
    173163        }
    174164
    175165        template< typename core_t >
    176         ast::Pass< core_t >::result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
     166        const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
    177167                __pedantic_pass_assert( __visit_children() );
    178168                __pedantic_pass_assert( stmt );
    179169
    180                 const ast::Stmt * nval = stmt->accept( *this );
    181                 return { nval != stmt, nval };
     170                return stmt->accept( *this );
    182171        }
    183172
    184173        template< typename core_t >
    185         ast::Pass< core_t >::result1<ast::Stmt> ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) {
     174        const ast::Stmt * ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) {
    186175                __pedantic_pass_assert( __visit_children() );
    187176                __pedantic_pass_assert( stmt );
     
    208197                // If the pass doesn't want to add anything then we are done
    209198                if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
    210                         return { nstmt != stmt, nstmt };
     199                        return nstmt;
    211200                }
    212201
     
    230219                __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
    231220
    232                 return {true, compound};
     221                return compound;
    233222        }
    234223
    235224        template< typename core_t >
    236225        template< template <class...> class container_t >
    237         template< typename object_t, typename super_t, typename field_t >
    238         void ast::Pass< core_t >::resultNstmt<container_t>::apply(object_t * object, field_t super_t::* field) {
    239                 auto & container = object->*field;
    240                 __pedantic_pass_assert( container.size() <= values.size() );
    241 
    242                 auto cit = enumerate(container).begin();
    243 
    244                 container_t<ptr<Stmt>> nvals;
    245                 for(delta & d : values) {
    246                         if( d.is_old ) {
    247                                 __pedantic_pass_assert( cit.idx <= d.old_idx );
    248                                 std::advance( cit, d.old_idx - cit.idx );
    249                                 nvals.push_back( std::move( (*cit).val) );
    250                         } else {
    251                                 nvals.push_back( std::move(d.nval) );
    252                         }
    253                 }
    254 
    255                 object->*field = std::move(nvals);
    256         }
    257 
    258         template< typename core_t >
    259         template< template <class...> class container_t >
    260         ast::Pass< core_t >::resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     226        container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    261227                __pedantic_pass_assert( __visit_children() );
    262228                if( statements.empty() ) return {};
     
    285251                pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    286252
    287                 resultNstmt<container_t> new_kids;
    288                 for( auto value : enumerate( statements ) ) {
     253                bool mutated = false;
     254                container_t< ptr<Stmt> > new_kids;
     255                for( const Stmt * stmt : statements ) {
    289256                        try {
    290                                 size_t i = value.idx;
    291                                 const Stmt * stmt = value.val;
    292257                                __pedantic_pass_assert( stmt );
    293258                                const ast::Stmt * new_stmt = stmt->accept( *this );
    294259                                assert( new_stmt );
    295                                 if(new_stmt != stmt ) { new_kids.differs = true; }
     260                                if(new_stmt != stmt ) mutated = true;
    296261
    297262                                // Make sure that it is either adding statements or declartions but not both
     
    303268
    304269                                // Take all the statements which should have gone after, N/A for first iteration
    305                                 new_kids.take_all( decls_before );
    306                                 new_kids.take_all( stmts_before );
     270                                __pass::take_all( std::back_inserter( new_kids ), decls_before, &mutated );
     271                                __pass::take_all( std::back_inserter( new_kids ), stmts_before, &mutated );
    307272
    308273                                // Now add the statement if there is one
    309                                 if(new_stmt != stmt) {
    310                                         new_kids.values.emplace_back( new_stmt, i, false );
    311                                 } else {
    312                                         new_kids.values.emplace_back( nullptr, i, true );
    313                                 }
     274                                new_kids.emplace_back( new_stmt );
    314275
    315276                                // Take all the declarations that go before
    316                                 new_kids.take_all( decls_after );
    317                                 new_kids.take_all( stmts_after );
     277                                __pass::take_all( std::back_inserter( new_kids ), decls_after, &mutated );
     278                                __pass::take_all( std::back_inserter( new_kids ), stmts_after, &mutated );
    318279                        }
    319280                        catch ( SemanticErrorException &e ) {
     
    324285                if ( !errors.isEmpty() ) { throw errors; }
    325286
    326                 return new_kids;
     287                return mutated ? new_kids : container_t< ptr<Stmt> >();
    327288        }
    328289
    329290        template< typename core_t >
    330291        template< template <class...> class container_t, typename node_t >
    331         template< typename object_t, typename super_t, typename field_t >
    332         void ast::Pass< core_t >::resultN<container_t, node_t>::apply(object_t * object, field_t super_t::* field) {
    333                 auto & container = object->*field;
    334                 __pedantic_pass_assert( container.size() == values.size() );
    335 
    336                 for(size_t i = 0; i < container.size(); i++) {
    337                         // Take all the elements that are different in 'values'
    338                         // and swap them into 'container'
    339                         if( values[i] != nullptr ) std::swap(container[i], values[i]);
    340                 }
    341 
    342                 // Now the original containers should still have the unchanged values
    343                 // but also contain the new values
    344         }
    345 
    346         template< typename core_t >
    347         template< template <class...> class container_t, typename node_t >
    348         ast::Pass< core_t >::resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
     292        container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    349293                __pedantic_pass_assert( __visit_children() );
    350294                if( container.empty() ) return {};
     
    356300
    357301                bool mutated = false;
    358                 container_t<ptr<node_t>> new_kids;
     302                container_t< ast::ptr<node_t> > new_kids;
    359303                for ( const node_t * node : container ) {
    360304                        try {
    361305                                __pedantic_pass_assert( node );
    362306                                const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
    363                                 if(new_stmt != node ) {
    364                                         mutated = true;
    365                                         new_kids.emplace_back( new_stmt );
    366                                 } else {
    367                                         new_kids.emplace_back( nullptr );
    368                                 }
    369 
     307                                if(new_stmt != node ) mutated = true;
     308
     309                                new_kids.emplace_back( new_stmt );
    370310                        }
    371311                        catch( SemanticErrorException &e ) {
     
    373313                        }
    374314                }
    375 
    376                 __pedantic_pass_assert( new_kids.size() == container.size() );
    377315                pass_visitor_stats.depth--;
    378316                if ( ! errors.isEmpty() ) { throw errors; }
    379317
    380                 return ast::Pass< core_t >::resultN<container_t, node_t>{ mutated,  new_kids };
     318                return mutated ? new_kids : container_t< ast::ptr<node_t> >();
    381319        }
    382320
     
    396334                auto new_val = call_accept( old_val );
    397335
    398                 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR");
    399 
    400                 if( new_val.differs ) {
     336                static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
     337
     338                if( __pass::differs(old_val, new_val) ) {
    401339                        auto new_parent = __pass::mutate<core_t>(parent);
    402                         new_val.apply(new_parent, child);
     340                        new_parent->*child = new_val;
    403341                        parent = new_parent;
    404342                }
     
    422360                static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
    423361
    424                 if( new_val.differs ) {
     362                if( __pass::differs(old_val, new_val) ) {
    425363                        auto new_parent = __pass::mutate<core_t>(parent);
    426                         new_val.apply( new_parent, child );
     364                        new_parent->*child = new_val;
    427365                        parent = new_parent;
    428366                }
     
    514452        VISIT_START( node );
    515453
    516         if ( __visit_children() ) {
     454        VISIT(
    517455                {
    518456                        guard_symtab guard { *this };
     
    522460                maybe_accept( node, &ObjectDecl::bitfieldWidth );
    523461                maybe_accept( node, &ObjectDecl::attributes    );
    524         }
     462        )
    525463
    526464        __pass::symtab::addId( core, 0, node );
     
    537475        __pass::symtab::addId( core, 0, node );
    538476
    539         if ( __visit_children() ) {
    540                 maybe_accept( node, &FunctionDecl::withExprs );
    541         }
     477        VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
    542478        {
    543479                // with clause introduces a level of scope (for the with expression members).
     
    557493                        } };
    558494                        __pass::symtab::addId( core, 0, func );
    559                         if ( __visit_children() ) {
     495                        VISIT(
    560496                                // parameter declarations
    561497                                maybe_accept( node, &FunctionDecl::params );
     
    573509                                maybe_accept( node, &FunctionDecl::stmts );
    574510                                maybe_accept( node, &FunctionDecl::attributes );
    575                         }
     511                        )
    576512                }
    577513        }
     
    590526        __pass::symtab::addStructFwd( core, 0, node );
    591527
    592         if ( __visit_children() ) {
     528        VISIT({
    593529                guard_symtab guard { * this };
    594530                maybe_accept( node, &StructDecl::params     );
    595531                maybe_accept( node, &StructDecl::members    );
    596532                maybe_accept( node, &StructDecl::attributes );
    597         }
     533        })
    598534
    599535        // this addition replaces the forward declaration
     
    612548        __pass::symtab::addUnionFwd( core, 0, node );
    613549
    614         if ( __visit_children() ) {
     550        VISIT({
    615551                guard_symtab guard { * this };
    616552                maybe_accept( node, &UnionDecl::params     );
    617553                maybe_accept( node, &UnionDecl::members    );
    618554                maybe_accept( node, &UnionDecl::attributes );
    619         }
     555        })
    620556
    621557        __pass::symtab::addUnion( core, 0, node );
     
    632568        __pass::symtab::addEnum( core, 0, node );
    633569
    634         if ( __visit_children() ) {
     570        VISIT(
    635571                // unlike structs, traits, and unions, enums inject their members into the global scope
    636572                maybe_accept( node, &EnumDecl::params     );
    637573                maybe_accept( node, &EnumDecl::members    );
    638574                maybe_accept( node, &EnumDecl::attributes );
    639         }
     575        )
    640576
    641577        VISIT_END( Decl, node );
     
    648584        VISIT_START( node );
    649585
    650         if ( __visit_children() ) {
     586        VISIT({
    651587                guard_symtab guard { *this };
    652588                maybe_accept( node, &TraitDecl::params     );
    653589                maybe_accept( node, &TraitDecl::members    );
    654590                maybe_accept( node, &TraitDecl::attributes );
    655         }
     591        })
    656592
    657593        __pass::symtab::addTrait( core, 0, node );
     
    666602        VISIT_START( node );
    667603
    668         if ( __visit_children() ) {
     604        VISIT({
    669605                guard_symtab guard { *this };
    670606                maybe_accept( node, &TypeDecl::base   );
    671         }
     607        })
    672608
    673609        // see A NOTE ON THE ORDER OF TRAVERSAL, above
     
    676612        __pass::symtab::addType( core, 0, node );
    677613
    678         if ( __visit_children() ) {
     614        VISIT(
    679615                maybe_accept( node, &TypeDecl::assertions );
    680616
     
    683619                        maybe_accept( node, &TypeDecl::init );
    684620                }
    685         }
     621        )
    686622
    687623        VISIT_END( Decl, node );
     
    694630        VISIT_START( node );
    695631
    696         if ( __visit_children() ) {
     632        VISIT({
    697633                guard_symtab guard { *this };
    698634                maybe_accept( node, &TypedefDecl::base   );
    699         }
     635        })
    700636
    701637        __pass::symtab::addType( core, 0, node );
    702638
    703         if ( __visit_children() ) {
    704                 maybe_accept( node, &TypedefDecl::assertions );
    705         }
     639        VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
    706640
    707641        VISIT_END( Decl, node );
     
    714648        VISIT_START( node );
    715649
    716         if ( __visit_children() ) {
     650        VISIT(
    717651                maybe_accept( node, &AsmDecl::stmt );
    718         }
     652        )
    719653
    720654        VISIT_END( AsmDecl, node );
     
    727661        VISIT_START( node );
    728662
    729         if ( __visit_children() ) {
     663        VISIT(
    730664                maybe_accept( node, &DirectiveDecl::stmt );
    731         }
     665        )
    732666
    733667        VISIT_END( DirectiveDecl, node );
     
    740674        VISIT_START( node );
    741675
    742         if ( __visit_children() ) {
     676        VISIT(
    743677                maybe_accept( node, &StaticAssertDecl::cond );
    744678                maybe_accept( node, &StaticAssertDecl::msg  );
    745         }
     679        )
    746680
    747681        VISIT_END( StaticAssertDecl, node );
     
    753687const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
    754688        VISIT_START( node );
    755 
    756         if ( __visit_children() ) {
     689        VISIT(
    757690                // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result.
    758691                auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() {
     
    771704                guard_scope guard3 { *this };
    772705                maybe_accept( node, &CompoundStmt::kids );
    773         }
    774 
     706        )
    775707        VISIT_END( CompoundStmt, node );
    776708}
     
    782714        VISIT_START( node );
    783715
    784         if ( __visit_children() ) {
     716        VISIT(
    785717                maybe_accept( node, &ExprStmt::expr );
    786         }
     718        )
    787719
    788720        VISIT_END( Stmt, node );
     
    795727        VISIT_START( node )
    796728
    797         if ( __visit_children() ) {
     729        VISIT(
    798730                maybe_accept( node, &AsmStmt::instruction );
    799731                maybe_accept( node, &AsmStmt::output      );
    800732                maybe_accept( node, &AsmStmt::input       );
    801733                maybe_accept( node, &AsmStmt::clobber     );
    802         }
     734        )
    803735
    804736        VISIT_END( Stmt, node );
     
    820752        VISIT_START( node );
    821753
    822         if ( __visit_children() ) {
     754        VISIT({
    823755                // if statements introduce a level of scope (for the initialization)
    824756                guard_symtab guard { *this };
    825757                maybe_accept( node, &IfStmt::inits    );
    826758                maybe_accept( node, &IfStmt::cond     );
    827                 maybe_accept_as_compound( node, &IfStmt::then );
    828                 maybe_accept_as_compound( node, &IfStmt::else_ );
    829         }
     759                maybe_accept_as_compound( node, &IfStmt::thenPart );
     760                maybe_accept_as_compound( node, &IfStmt::elsePart );
     761        })
    830762
    831763        VISIT_END( Stmt, node );
     
    833765
    834766//--------------------------------------------------------------------------
    835 // WhileDoStmt
    836 template< typename core_t >
    837 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileDoStmt * node ) {
    838         VISIT_START( node );
    839 
    840         if ( __visit_children() ) {
     767// WhileStmt
     768template< typename core_t >
     769const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) {
     770        VISIT_START( node );
     771
     772        VISIT({
    841773                // while statements introduce a level of scope (for the initialization)
    842774                guard_symtab guard { *this };
    843                 maybe_accept( node, &WhileDoStmt::inits );
    844                 maybe_accept( node, &WhileDoStmt::cond  );
    845                 maybe_accept_as_compound( node, &WhileDoStmt::body  );
    846         }
     775                maybe_accept( node, &WhileStmt::inits );
     776                maybe_accept( node, &WhileStmt::cond  );
     777                maybe_accept_as_compound( node, &WhileStmt::body  );
     778        })
    847779
    848780        VISIT_END( Stmt, node );
     
    855787        VISIT_START( node );
    856788
    857         if ( __visit_children() ) {
     789        VISIT({
    858790                // for statements introduce a level of scope (for the initialization)
    859791                guard_symtab guard { *this };
     
    863795                maybe_accept( node, &ForStmt::inc   );
    864796                maybe_accept_as_compound( node, &ForStmt::body  );
    865         }
     797        })
    866798
    867799        VISIT_END( Stmt, node );
     
    874806        VISIT_START( node );
    875807
    876         if ( __visit_children() ) {
     808        VISIT(
    877809                maybe_accept( node, &SwitchStmt::cond  );
    878810                maybe_accept( node, &SwitchStmt::stmts );
    879         }
     811        )
    880812
    881813        VISIT_END( Stmt, node );
     
    888820        VISIT_START( node );
    889821
    890         if ( __visit_children() ) {
     822        VISIT(
    891823                maybe_accept( node, &CaseStmt::cond  );
    892824                maybe_accept( node, &CaseStmt::stmts );
    893         }
     825        )
    894826
    895827        VISIT_END( Stmt, node );
     
    910842        VISIT_START( node );
    911843
    912         if ( __visit_children() ) {
     844        VISIT(
    913845                maybe_accept( node, &ReturnStmt::expr );
    914         }
     846        )
    915847
    916848        VISIT_END( Stmt, node );
     
    923855        VISIT_START( node );
    924856
    925         if ( __visit_children() ) {
     857        VISIT(
    926858                maybe_accept( node, &ThrowStmt::expr   );
    927859                maybe_accept( node, &ThrowStmt::target );
    928         }
     860        )
    929861
    930862        VISIT_END( Stmt, node );
     
    937869        VISIT_START( node );
    938870
    939         if ( __visit_children() ) {
     871        VISIT(
    940872                maybe_accept( node, &TryStmt::body     );
    941873                maybe_accept( node, &TryStmt::handlers );
    942874                maybe_accept( node, &TryStmt::finally  );
    943         }
     875        )
    944876
    945877        VISIT_END( Stmt, node );
     
    952884        VISIT_START( node );
    953885
    954         if ( __visit_children() ) {
     886        VISIT({
    955887                // catch statements introduce a level of scope (for the caught exception)
    956888                guard_symtab guard { *this };
     
    958890                maybe_accept( node, &CatchStmt::cond );
    959891                maybe_accept_as_compound( node, &CatchStmt::body );
    960         }
     892        })
    961893
    962894        VISIT_END( Stmt, node );
     
    969901        VISIT_START( node );
    970902
    971         if ( __visit_children() ) {
     903        VISIT(
    972904                maybe_accept( node, &FinallyStmt::body );
    973         }
     905        )
    974906
    975907        VISIT_END( Stmt, node );
     
    982914        VISIT_START( node );
    983915
    984         if ( __visit_children() ) {
     916        VISIT(
    985917                maybe_accept( node, &SuspendStmt::then   );
    986         }
     918        )
    987919
    988920        VISIT_END( Stmt, node );
     
    1002934                // }
    1003935
    1004         if ( __visit_children() ) {
     936        VISIT({
    1005937                std::vector<WaitForStmt::Clause> new_clauses;
    1006938                new_clauses.reserve( node->clauses.size() );
     
    1010942                        const Expr * func = clause.target.func ? clause.target.func->accept(*this) : nullptr;
    1011943                        if(func != clause.target.func) mutated = true;
    1012                         else func = nullptr;
    1013944
    1014945                        std::vector<ptr<Expr>> new_args;
     
    1016947                        for( const auto & arg : clause.target.args ) {
    1017948                                auto a = arg->accept(*this);
    1018                                 if( a != arg ) {
    1019                                         mutated = true;
    1020                                         new_args.push_back( a );
    1021                                 } else
    1022                                         new_args.push_back( nullptr );
     949                                new_args.push_back( a );
     950                                if( a != arg ) mutated = true;
    1023951                        }
    1024952
    1025953                        const Stmt * stmt = clause.stmt ? clause.stmt->accept(*this) : nullptr;
    1026954                        if(stmt != clause.stmt) mutated = true;
    1027                         else stmt = nullptr;
    1028955
    1029956                        const Expr * cond = clause.cond ? clause.cond->accept(*this) : nullptr;
    1030957                        if(cond != clause.cond) mutated = true;
    1031                         else cond = nullptr;
    1032958
    1033959                        new_clauses.push_back( WaitForStmt::Clause{ {func, std::move(new_args) }, stmt, cond } );
     
    1036962                if(mutated) {
    1037963                        auto n = __pass::mutate<core_t>(node);
    1038                         for(size_t i = 0; i < new_clauses.size(); i++) {
    1039                                 if(new_clauses.at(i).target.func != nullptr) std::swap(n->clauses.at(i).target.func, new_clauses.at(i).target.func);
    1040 
    1041                                 for(size_t j = 0; j < new_clauses.at(i).target.args.size(); j++) {
    1042                                         if(new_clauses.at(i).target.args.at(j) != nullptr) std::swap(n->clauses.at(i).target.args.at(j), new_clauses.at(i).target.args.at(j));
    1043                                 }
    1044 
    1045                                 if(new_clauses.at(i).stmt != nullptr) std::swap(n->clauses.at(i).stmt, new_clauses.at(i).stmt);
    1046                                 if(new_clauses.at(i).cond != nullptr) std::swap(n->clauses.at(i).cond, new_clauses.at(i).cond);
    1047                         }
     964                        n->clauses = std::move( new_clauses );
    1048965                        node = n;
    1049966                }
    1050         }
     967        })
    1051968
    1052969        #define maybe_accept(field) \
    1053970                if(node->field) { \
    1054971                        auto nval = call_accept( node->field ); \
    1055                         if(nval.differs ) { \
     972                        if(nval != node->field ) { \
    1056973                                auto nparent = __pass::mutate<core_t>(node); \
    1057                                 nparent->field = nval.value; \
     974                                nparent->field = nval; \
    1058975                                node = nparent; \
    1059976                        } \
    1060977                }
    1061978
    1062         if ( __visit_children() ) {
     979        VISIT(
    1063980                maybe_accept( timeout.time );
    1064981                maybe_accept( timeout.stmt );
     
    1066983                maybe_accept( orElse.stmt  );
    1067984                maybe_accept( orElse.cond  );
    1068         }
     985        )
    1069986
    1070987        #undef maybe_accept
     
    1079996        VISIT_START( node );
    1080997
    1081         if ( __visit_children() ) {
     998        VISIT(
    1082999                maybe_accept( node, &WithStmt::exprs );
    10831000                {
     
    10871004                        maybe_accept( node, &WithStmt::stmt );
    10881005                }
    1089         }
    1090 
     1006        )
    10911007        VISIT_END( Stmt, node );
    10921008}
     
    11061022        VISIT_START( node );
    11071023
    1108         if ( __visit_children() ) {
     1024        VISIT(
    11091025                maybe_accept( node, &DeclStmt::decl );
    1110         }
     1026        )
    11111027
    11121028        VISIT_END( Stmt, node );
     
    11211037        // For now this isn't visited, it is unclear if this causes problem
    11221038        // if all tests are known to pass, remove this code
    1123         if ( __visit_children() ) {
     1039        VISIT(
    11241040                maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
    1125         }
     1041        )
    11261042
    11271043        VISIT_END( Stmt, node );
     
    11341050        VISIT_START( node );
    11351051
    1136         if ( __visit_children() ) {
     1052        VISIT({
    11371053                // mutex statements introduce a level of scope (for the initialization)
    11381054                guard_symtab guard { *this };
    11391055                maybe_accept( node, &MutexStmt::stmt );
    11401056                maybe_accept( node, &MutexStmt::mutexObjs );
    1141         }
     1057        })
    11421058
    11431059        VISIT_END( Stmt, node );
     
    11501066        VISIT_START( node );
    11511067
    1152         if ( __visit_children() ) {
     1068        VISIT(
    11531069                {
    11541070                        guard_symtab guard { *this };
     
    11571073                maybe_accept( node, &ApplicationExpr::func );
    11581074                maybe_accept( node, &ApplicationExpr::args );
    1159         }
     1075        )
    11601076
    11611077        VISIT_END( Expr, node );
     
    11681084        VISIT_START( node );
    11691085
    1170         if ( __visit_children() ) {
     1086        VISIT(
    11711087                {
    11721088                        guard_symtab guard { *this };
     
    11751091
    11761092                maybe_accept( node, &UntypedExpr::args );
    1177         }
     1093        )
    11781094
    11791095        VISIT_END( Expr, node );
     
    11861102        VISIT_START( node );
    11871103
    1188         if ( __visit_children() ) {
     1104        VISIT({
    11891105                guard_symtab guard { *this };
    11901106                maybe_accept( node, &NameExpr::result );
    1191         }
     1107        })
    11921108
    11931109        VISIT_END( Expr, node );
     
    12001116        VISIT_START( node );
    12011117
    1202         if ( __visit_children() ) {
    1203                 {
     1118        VISIT({
    12041119                        guard_symtab guard { *this };
    12051120                        maybe_accept( node, &CastExpr::result );
    12061121                }
    12071122                maybe_accept( node, &CastExpr::arg );
    1208         }
     1123        )
    12091124
    12101125        VISIT_END( Expr, node );
     
    12171132        VISIT_START( node );
    12181133
    1219         if ( __visit_children() ) {
    1220                 {
     1134        VISIT({
    12211135                        guard_symtab guard { *this };
    12221136                        maybe_accept( node, &KeywordCastExpr::result );
    12231137                }
    12241138                maybe_accept( node, &KeywordCastExpr::arg );
    1225         }
     1139        )
    12261140
    12271141        VISIT_END( Expr, node );
     
    12341148        VISIT_START( node );
    12351149
    1236         if ( __visit_children() ) {
    1237                 {
     1150        VISIT({
    12381151                        guard_symtab guard { *this };
    12391152                        maybe_accept( node, &VirtualCastExpr::result );
    12401153                }
    12411154                maybe_accept( node, &VirtualCastExpr::arg );
    1242         }
     1155        )
    12431156
    12441157        VISIT_END( Expr, node );
     
    12511164        VISIT_START( node );
    12521165
    1253         if ( __visit_children() ) {
    1254                 {
     1166        VISIT({
    12551167                        guard_symtab guard { *this };
    12561168                        maybe_accept( node, &AddressExpr::result );
    12571169                }
    12581170                maybe_accept( node, &AddressExpr::arg );
    1259         }
     1171        )
    12601172
    12611173        VISIT_END( Expr, node );
     
    12681180        VISIT_START( node );
    12691181
    1270         if ( __visit_children() ) {
     1182        VISIT({
    12711183                guard_symtab guard { *this };
    12721184                maybe_accept( node, &LabelAddressExpr::result );
    1273         }
     1185        })
    12741186
    12751187        VISIT_END( Expr, node );
     
    12821194        VISIT_START( node );
    12831195
    1284         if ( __visit_children() ) {
    1285                 {
     1196        VISIT({
    12861197                        guard_symtab guard { *this };
    12871198                        maybe_accept( node, &UntypedMemberExpr::result );
     
    12891200                maybe_accept( node, &UntypedMemberExpr::aggregate );
    12901201                maybe_accept( node, &UntypedMemberExpr::member    );
    1291         }
     1202        )
    12921203
    12931204        VISIT_END( Expr, node );
     
    13001211        VISIT_START( node );
    13011212
    1302         if ( __visit_children() ) {
    1303                 {
     1213        VISIT({
    13041214                        guard_symtab guard { *this };
    13051215                        maybe_accept( node, &MemberExpr::result );
    13061216                }
    13071217                maybe_accept( node, &MemberExpr::aggregate );
    1308         }
     1218        )
    13091219
    13101220        VISIT_END( Expr, node );
     
    13171227        VISIT_START( node );
    13181228
    1319         if ( __visit_children() ) {
     1229        VISIT({
    13201230                guard_symtab guard { *this };
    13211231                maybe_accept( node, &VariableExpr::result );
    1322         }
     1232        })
    13231233
    13241234        VISIT_END( Expr, node );
     
    13311241        VISIT_START( node );
    13321242
    1333         if ( __visit_children() ) {
     1243        VISIT({
    13341244                guard_symtab guard { *this };
    13351245                maybe_accept( node, &ConstantExpr::result );
    1336         }
     1246        })
    13371247
    13381248        VISIT_END( Expr, node );
     
    13451255        VISIT_START( node );
    13461256
    1347         if ( __visit_children() ) {
    1348                 {
     1257        VISIT({
    13491258                        guard_symtab guard { *this };
    13501259                        maybe_accept( node, &SizeofExpr::result );
     
    13551264                        maybe_accept( node, &SizeofExpr::expr );
    13561265                }
    1357         }
     1266        )
    13581267
    13591268        VISIT_END( Expr, node );
     
    13661275        VISIT_START( node );
    13671276
    1368         if ( __visit_children() ) {
    1369                 {
     1277        VISIT({
    13701278                        guard_symtab guard { *this };
    13711279                        maybe_accept( node, &AlignofExpr::result );
     
    13761284                        maybe_accept( node, &AlignofExpr::expr );
    13771285                }
    1378         }
     1286        )
    13791287
    13801288        VISIT_END( Expr, node );
     
    13871295        VISIT_START( node );
    13881296
    1389         if ( __visit_children() ) {
    1390                 {
     1297        VISIT({
    13911298                        guard_symtab guard { *this };
    13921299                        maybe_accept( node, &UntypedOffsetofExpr::result );
    13931300                }
    13941301                maybe_accept( node, &UntypedOffsetofExpr::type   );
    1395         }
     1302        )
    13961303
    13971304        VISIT_END( Expr, node );
     
    14041311        VISIT_START( node );
    14051312
    1406         if ( __visit_children() ) {
    1407                 {
     1313        VISIT({
    14081314                        guard_symtab guard { *this };
    14091315                        maybe_accept( node, &OffsetofExpr::result );
    14101316                }
    14111317                maybe_accept( node, &OffsetofExpr::type   );
    1412         }
     1318        )
    14131319
    14141320        VISIT_END( Expr, node );
     
    14211327        VISIT_START( node );
    14221328
    1423         if ( __visit_children() ) {
    1424                 {
     1329        VISIT({
    14251330                        guard_symtab guard { *this };
    14261331                        maybe_accept( node, &OffsetPackExpr::result );
    14271332                }
    14281333                maybe_accept( node, &OffsetPackExpr::type   );
    1429         }
     1334        )
    14301335
    14311336        VISIT_END( Expr, node );
     
    14381343        VISIT_START( node );
    14391344
    1440         if ( __visit_children() ) {
    1441                 {
     1345        VISIT({
    14421346                        guard_symtab guard { *this };
    14431347                        maybe_accept( node, &LogicalExpr::result );
     
    14451349                maybe_accept( node, &LogicalExpr::arg1 );
    14461350                maybe_accept( node, &LogicalExpr::arg2 );
    1447         }
     1351        )
    14481352
    14491353        VISIT_END( Expr, node );
     
    14561360        VISIT_START( node );
    14571361
    1458         if ( __visit_children() ) {
    1459                 {
     1362        VISIT({
    14601363                        guard_symtab guard { *this };
    14611364                        maybe_accept( node, &ConditionalExpr::result );
     
    14641367                maybe_accept( node, &ConditionalExpr::arg2 );
    14651368                maybe_accept( node, &ConditionalExpr::arg3 );
    1466         }
     1369        )
    14671370
    14681371        VISIT_END( Expr, node );
     
    14751378        VISIT_START( node );
    14761379
    1477         if ( __visit_children() ) {
    1478                 {
     1380        VISIT({
    14791381                        guard_symtab guard { *this };
    14801382                        maybe_accept( node, &CommaExpr::result );
     
    14821384                maybe_accept( node, &CommaExpr::arg1 );
    14831385                maybe_accept( node, &CommaExpr::arg2 );
    1484         }
     1386        )
    14851387
    14861388        VISIT_END( Expr, node );
     
    14931395        VISIT_START( node );
    14941396
    1495         if ( __visit_children() ) {
    1496                 {
     1397        VISIT({
    14971398                        guard_symtab guard { *this };
    14981399                        maybe_accept( node, &TypeExpr::result );
    14991400                }
    15001401                maybe_accept( node, &TypeExpr::type );
    1501         }
     1402        )
    15021403
    15031404        VISIT_END( Expr, node );
     
    15101411        VISIT_START( node );
    15111412
    1512         if ( __visit_children() ) {
    1513                 {
     1413        VISIT({
    15141414                        guard_symtab guard { *this };
    15151415                        maybe_accept( node, &AsmExpr::result );
     
    15171417                maybe_accept( node, &AsmExpr::constraint );
    15181418                maybe_accept( node, &AsmExpr::operand    );
    1519         }
     1419        )
    15201420
    15211421        VISIT_END( Expr, node );
     
    15281428        VISIT_START( node );
    15291429
    1530         if ( __visit_children() ) {
    1531                 {
     1430        VISIT({
    15321431                        guard_symtab guard { *this };
    15331432                        maybe_accept( node, &ImplicitCopyCtorExpr::result );
    15341433                }
    15351434                maybe_accept( node, &ImplicitCopyCtorExpr::callExpr    );
    1536         }
     1435        )
    15371436
    15381437        VISIT_END( Expr, node );
     
    15451444        VISIT_START( node );
    15461445
    1547         if ( __visit_children() ) {
    1548                 {
     1446        VISIT({
    15491447                        guard_symtab guard { *this };
    15501448                        maybe_accept( node, &ConstructorExpr::result );
    15511449                }
    15521450                maybe_accept( node, &ConstructorExpr::callExpr );
    1553         }
     1451        )
    15541452
    15551453        VISIT_END( Expr, node );
     
    15621460        VISIT_START( node );
    15631461
    1564         if ( __visit_children() ) {
    1565                 {
     1462        VISIT({
    15661463                        guard_symtab guard { *this };
    15671464                        maybe_accept( node, &CompoundLiteralExpr::result );
    15681465                }
    15691466                maybe_accept( node, &CompoundLiteralExpr::init );
    1570         }
     1467        )
    15711468
    15721469        VISIT_END( Expr, node );
     
    15791476        VISIT_START( node );
    15801477
    1581         if ( __visit_children() ) {
    1582                 {
     1478        VISIT({
    15831479                        guard_symtab guard { *this };
    15841480                        maybe_accept( node, &RangeExpr::result );
     
    15861482                maybe_accept( node, &RangeExpr::low    );
    15871483                maybe_accept( node, &RangeExpr::high   );
    1588         }
     1484        )
    15891485
    15901486        VISIT_END( Expr, node );
     
    15971493        VISIT_START( node );
    15981494
    1599         if ( __visit_children() ) {
    1600                 {
     1495        VISIT({
    16011496                        guard_symtab guard { *this };
    16021497                        maybe_accept( node, &UntypedTupleExpr::result );
    16031498                }
    16041499                maybe_accept( node, &UntypedTupleExpr::exprs  );
    1605         }
     1500        )
    16061501
    16071502        VISIT_END( Expr, node );
     
    16141509        VISIT_START( node );
    16151510
    1616         if ( __visit_children() ) {
    1617                 {
     1511        VISIT({
    16181512                        guard_symtab guard { *this };
    16191513                        maybe_accept( node, &TupleExpr::result );
    16201514                }
    16211515                maybe_accept( node, &TupleExpr::exprs  );
    1622         }
     1516        )
    16231517
    16241518        VISIT_END( Expr, node );
     
    16311525        VISIT_START( node );
    16321526
    1633         if ( __visit_children() ) {
    1634                 {
     1527        VISIT({
    16351528                        guard_symtab guard { *this };
    16361529                        maybe_accept( node, &TupleIndexExpr::result );
    16371530                }
    16381531                maybe_accept( node, &TupleIndexExpr::tuple  );
    1639         }
     1532        )
    16401533
    16411534        VISIT_END( Expr, node );
     
    16481541        VISIT_START( node );
    16491542
    1650         if ( __visit_children() ) {
    1651                 {
     1543        VISIT({
    16521544                        guard_symtab guard { *this };
    16531545                        maybe_accept( node, &TupleAssignExpr::result );
    16541546                }
    16551547                maybe_accept( node, &TupleAssignExpr::stmtExpr );
    1656         }
     1548        )
    16571549
    16581550        VISIT_END( Expr, node );
     
    16651557        VISIT_START( node );
    16661558
    1667         if ( __visit_children() ) {
    1668                 // don't want statements from outer CompoundStmts to be added to this StmtExpr
     1559        VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr
    16691560                // get the stmts that will need to be spliced in
    16701561                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     
    16831574                maybe_accept( node, &StmtExpr::returnDecls );
    16841575                maybe_accept( node, &StmtExpr::dtors       );
    1685         }
     1576        )
    16861577
    16871578        VISIT_END( Expr, node );
     
    16941585        VISIT_START( node );
    16951586
    1696         if ( __visit_children() ) {
    1697                 {
     1587        VISIT({
    16981588                        guard_symtab guard { *this };
    16991589                        maybe_accept( node, &UniqueExpr::result );
    17001590                }
    17011591                maybe_accept( node, &UniqueExpr::expr   );
    1702         }
     1592        )
    17031593
    17041594        VISIT_END( Expr, node );
     
    17111601        VISIT_START( node );
    17121602
    1713         if ( __visit_children() ) {
    1714                 {
     1603        VISIT({
    17151604                        guard_symtab guard { *this };
    17161605                        maybe_accept( node, &UntypedInitExpr::result );
     
    17181607                maybe_accept( node, &UntypedInitExpr::expr   );
    17191608                // not currently visiting initAlts, but this doesn't matter since this node is only used in the resolver.
    1720         }
     1609        )
    17211610
    17221611        VISIT_END( Expr, node );
     
    17291618        VISIT_START( node );
    17301619
    1731         if ( __visit_children() ) {
    1732                 {
     1620        VISIT({
    17331621                        guard_symtab guard { *this };
    17341622                        maybe_accept( node, &InitExpr::result );
     
    17361624                maybe_accept( node, &InitExpr::expr   );
    17371625                maybe_accept( node, &InitExpr::designation );
    1738         }
     1626        )
    17391627
    17401628        VISIT_END( Expr, node );
     
    17471635        VISIT_START( node );
    17481636
    1749         if ( __visit_children() ) {
    1750                 {
     1637        VISIT({
    17511638                        guard_symtab guard { *this };
    17521639                        maybe_accept( node, &DeletedExpr::result );
     
    17541641                maybe_accept( node, &DeletedExpr::expr );
    17551642                // don't visit deleteStmt, because it is a pointer to somewhere else in the tree.
    1756         }
     1643        )
    17571644
    17581645        VISIT_END( Expr, node );
     
    17651652        VISIT_START( node );
    17661653
    1767         if ( __visit_children() ) {
    1768                 {
     1654        VISIT({
    17691655                        guard_symtab guard { *this };
    17701656                        maybe_accept( node, &DefaultArgExpr::result );
    17711657                }
    17721658                maybe_accept( node, &DefaultArgExpr::expr );
    1773         }
     1659        )
    17741660
    17751661        VISIT_END( Expr, node );
     
    17821668        VISIT_START( node );
    17831669
    1784         if ( __visit_children() ) {
    1785                 {
     1670        VISIT({
    17861671                        guard_symtab guard { *this };
    17871672                        maybe_accept( node, &GenericExpr::result );
     
    18121697                        node = n;
    18131698                }
    1814         }
     1699        )
    18151700
    18161701        VISIT_END( Expr, node );
     
    18411726        VISIT_START( node );
    18421727
    1843         if ( __visit_children() ) {
     1728        VISIT(
    18441729                // xxx - should PointerType visit/mutate dimension?
    18451730                maybe_accept( node, &PointerType::base );
    1846         }
     1731        )
    18471732
    18481733        VISIT_END( Type, node );
     
    18551740        VISIT_START( node );
    18561741
    1857         if ( __visit_children() ) {
     1742        VISIT(
    18581743                maybe_accept( node, &ArrayType::dimension );
    18591744                maybe_accept( node, &ArrayType::base );
    1860         }
     1745        )
    18611746
    18621747        VISIT_END( Type, node );
     
    18691754        VISIT_START( node );
    18701755
    1871         if ( __visit_children() ) {
     1756        VISIT(
    18721757                maybe_accept( node, &ReferenceType::base );
    1873         }
     1758        )
    18741759
    18751760        VISIT_END( Type, node );
     
    18821767        VISIT_START( node );
    18831768
    1884         if ( __visit_children() ) {
     1769        VISIT(
    18851770                maybe_accept( node, &QualifiedType::parent );
    18861771                maybe_accept( node, &QualifiedType::child );
    1887         }
     1772        )
    18881773
    18891774        VISIT_END( Type, node );
     
    18961781        VISIT_START( node );
    18971782
    1898         if ( __visit_children() ) {
     1783        VISIT({
    18991784                // guard_forall_subs forall_guard { *this, node };
    19001785                // mutate_forall( node );
     
    19021787                maybe_accept( node, &FunctionType::returns );
    19031788                maybe_accept( node, &FunctionType::params  );
    1904         }
     1789        })
    19051790
    19061791        VISIT_END( Type, node );
     
    19151800        __pass::symtab::addStruct( core, 0, node->name );
    19161801
    1917         if ( __visit_children() ) {
     1802        VISIT({
    19181803                guard_symtab guard { *this };
    19191804                maybe_accept( node, &StructInstType::params );
    1920         }
     1805        })
    19211806
    19221807        VISIT_END( Type, node );
     
    19311816        __pass::symtab::addUnion( core, 0, node->name );
    19321817
    1933         if ( __visit_children() ) {
     1818        VISIT({
    19341819                guard_symtab guard { *this };
    19351820                maybe_accept( node, &UnionInstType::params );
    1936         }
     1821        })
    19371822
    19381823        VISIT_END( Type, node );
     
    19451830        VISIT_START( node );
    19461831
    1947         if ( __visit_children() ) {
     1832        VISIT({
    19481833                maybe_accept( node, &EnumInstType::params );
    1949         }
     1834        })
    19501835
    19511836        VISIT_END( Type, node );
     
    19581843        VISIT_START( node );
    19591844
    1960         if ( __visit_children() ) {
     1845        VISIT({
    19611846                maybe_accept( node, &TraitInstType::params );
    1962         }
     1847        })
    19631848
    19641849        VISIT_END( Type, node );
     
    19711856        VISIT_START( node );
    19721857
    1973         if ( __visit_children() ) {
     1858        VISIT(
    19741859                {
    19751860                        maybe_accept( node, &TypeInstType::params );
     
    19771862                // ensure that base re-bound if doing substitution
    19781863                __pass::forall::replace( core, 0, node );
    1979         }
     1864        )
    19801865
    19811866        VISIT_END( Type, node );
     
    19881873        VISIT_START( node );
    19891874
    1990         if ( __visit_children() ) {
     1875        VISIT(
    19911876                maybe_accept( node, &TupleType::types );
    19921877                maybe_accept( node, &TupleType::members );
    1993         }
     1878        )
    19941879
    19951880        VISIT_END( Type, node );
     
    20021887        VISIT_START( node );
    20031888
    2004         if ( __visit_children() ) {
     1889        VISIT(
    20051890                maybe_accept( node, &TypeofType::expr );
    2006         }
     1891        )
    20071892
    20081893        VISIT_END( Type, node );
     
    20151900        VISIT_START( node );
    20161901
    2017         if ( __visit_children() ) {
     1902        VISIT(
    20181903                maybe_accept( node, &VTableType::base );
    2019         }
     1904        )
    20201905
    20211906        VISIT_END( Type, node );
     
    20651950        VISIT_START( node );
    20661951
    2067         if ( __visit_children() ) {
    2068                 maybe_accept( node, &Designation::designators );
    2069         }
     1952        VISIT( maybe_accept( node, &Designation::designators ); )
    20701953
    20711954        VISIT_END( Designation, node );
     
    20781961        VISIT_START( node );
    20791962
    2080         if ( __visit_children() ) {
     1963        VISIT(
    20811964                maybe_accept( node, &SingleInit::value );
    2082         }
     1965        )
    20831966
    20841967        VISIT_END( Init, node );
     
    20911974        VISIT_START( node );
    20921975
    2093         if ( __visit_children() ) {
     1976        VISIT(
    20941977                maybe_accept( node, &ListInit::designations );
    20951978                maybe_accept( node, &ListInit::initializers );
    2096         }
     1979        )
    20971980
    20981981        VISIT_END( Init, node );
     
    21051988        VISIT_START( node );
    21061989
    2107         if ( __visit_children() ) {
     1990        VISIT(
    21081991                maybe_accept( node, &ConstructorInit::ctor );
    21091992                maybe_accept( node, &ConstructorInit::dtor );
    21101993                maybe_accept( node, &ConstructorInit::init );
    2111         }
     1994        )
    21121995
    21131996        VISIT_END( Init, node );
     
    21202003        VISIT_START( node );
    21212004
    2122         if ( __visit_children() ) {
     2005        VISIT(
    21232006                maybe_accept( node, &Attribute::params );
    2124         }
     2007        )
    21252008
    21262009        VISIT_END( Attribute, node );
     
    21332016        VISIT_START( node );
    21342017
    2135         if ( __visit_children() ) {
     2018        VISIT(
    21362019                {
    21372020                        bool mutated = false;
     
    21492032                        }
    21502033                }
    2151         }
     2034        )
    21522035
    21532036        VISIT_END( TypeSubstitution, node );
     
    21552038
    21562039#undef VISIT_START
     2040#undef VISIT
    21572041#undef VISIT_END
  • src/AST/Print.cpp

    rf5a51db r97c215f  
    333333                print( node->funcSpec );
    334334
    335 
    336 
    337                 if ( node->type && node->isTypeFixed ) {
     335                if ( node->type ) {
    338336                        node->type->accept( *this );
    339337                } else {
    340                         if (!node->type_params.empty()) {
    341                                 os << "forall" << endl;
    342                                 ++indent;
    343                                 printAll(node->type_params);
    344                                 os << indent;
    345                                 --indent;
    346 
    347                                 if (!node->assertions.empty()) {
    348                                         os << "with assertions" << endl;
    349                                         ++indent;
    350                                         printAll(node->assertions);
    351                                         os << indent;
    352                                         --indent;
    353                                 }
    354                         }
    355 
    356                         os << "function" << endl;
    357                         if ( ! node->params.empty() ) {
    358                                 os << indent << "... with parameters" << endl;
    359                                 ++indent;
    360                                 printAll( node->params );
    361                                 if ( node->type->isVarArgs ) {
    362                                         os << indent << "and a variable number of other arguments" << endl;
    363                                 }
    364                                 --indent;
    365                         } else if ( node->type->isVarArgs ) {
    366                                 os << indent+1 << "accepting unspecified arguments" << endl;
    367                         }
    368 
    369                         os << indent << "... returning";
    370                         if ( node->returns.empty() ) {
    371                                 os << " nothing" << endl;
    372                         } else {
    373                                 os << endl;
    374                                 ++indent;
    375                                 printAll( node->returns );
    376                                 --indent;
    377                         }
     338                        os << "untyped entity";
    378339                }
    379340
     
    511472                ++indent;
    512473                os << indent;
    513                 safe_print( node->then );
    514                 --indent;
    515 
    516                 if ( node->else_ != 0 ) {
     474                safe_print( node->thenPart );
     475                --indent;
     476
     477                if ( node->elsePart != 0 ) {
    517478                        os << indent << "... else:" << endl;
    518479                        ++indent;
    519480                        os << indent;
    520                         node->else_->accept( *this );
     481                        node->elsePart->accept( *this );
    521482                        --indent;
    522483                } // if
     
    524485        }
    525486
    526         virtual const ast::Stmt * visit( const ast::WhileDoStmt * node ) override final {
     487        virtual const ast::Stmt * visit( const ast::WhileStmt * node ) override final {
    527488                if ( node->isDoWhile ) { os << "Do-"; }
    528489                os << "While on condition:" << endl;
  • src/AST/Stmt.cpp

    rf5a51db r97c215f  
    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 : Wed May 15 15:53:00 2019
     13// Update Count     : 2
    1414//
    1515
     
    5656
    5757// --- BranchStmt
    58 BranchStmt::BranchStmt( const CodeLocation& loc, Kind kind, Label target, const std::vector<Label>&& labels )
    59                 : Stmt(loc, std::move(labels)), originalTarget(target), target(target), kind(kind) {
     58BranchStmt::BranchStmt( const CodeLocation& loc, Kind kind, Label target, std::vector<Label>&& labels )
     59: Stmt(loc, std::move(labels)), originalTarget(target), target(target), kind(kind) {
    6060        // Make sure a syntax error hasn't slipped through.
    6161        assert( Goto != kind || !target.empty() );
  • src/AST/Stmt.hpp

    rf5a51db r97c215f  
    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 20:06:41 2022
    13 // Update Count     : 34
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri May 17 12:45:00 2019
     13// Update Count     : 5
    1414//
    1515
     
    1717
    1818#include <list>
    19 #include <utility>                                                                              // for move
     19#include <utility>                // for move
    2020#include <vector>
    2121
    2222#include "Label.hpp"
    23 #include "Node.hpp"                                                                             // for node, ptr
     23#include "Node.hpp"               // for node, ptr
    2424#include "ParseNode.hpp"
    2525#include "Visitor.hpp"
     
    2727
    2828// Must be included in *all* AST classes; should be #undef'd at the end of the file
    29 #define MUTATE_FRIEND                                                                                                   \
     29#define MUTATE_FRIEND \
    3030    template<typename node_t> friend node_t * mutate(const node_t * node); \
    3131        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3232
    3333namespace ast {
     34
    3435class Expr;
    3536
    36 // Base statement node
     37/// Base statement node
    3738class Stmt : public ParseNode {
    38   public:
     39public:
    3940        std::vector<Label> labels;
    4041
    41         Stmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    42                 : ParseNode(loc), labels(std::move(labels)) {}
    43 
    44         Stmt(const Stmt & o) : ParseNode(o), labels(o.labels) {}
     42        Stmt( const CodeLocation & loc, std::vector<Label> && labels = {} )
     43        : ParseNode(loc), labels(std::move(labels)) {}
     44
     45        Stmt(const Stmt& o) : ParseNode(o), labels(o.labels) {}
    4546
    4647        const Stmt * accept( Visitor & v ) const override = 0;
    47   private:
     48private:
    4849        Stmt * clone() const override = 0;
    4950        MUTATE_FRIEND
    5051};
    5152
    52 // Compound statement: { ... }
     53/// Compound statement `{ ... }`
    5354class CompoundStmt final : public Stmt {
    54   public:
     55public:
    5556        std::list<ptr<Stmt>> kids;
    5657
    57         CompoundStmt(const CodeLocation & loc, const std::list<ptr<Stmt>> && ks = {}, const std::vector<Label> && labels = {} )
    58                 : Stmt(loc, std::move(labels)), kids(std::move(ks)) {}
    59 
    60         CompoundStmt( const CompoundStmt & o );
    61         CompoundStmt( CompoundStmt && o ) = default;
     58        CompoundStmt(const CodeLocation & loc, std::list<ptr<Stmt>> && ks = {},
     59                std::vector<Label>&& labels = {} )
     60        : Stmt(loc, std::move(labels)), kids(std::move(ks)) {}
     61
     62        CompoundStmt( const CompoundStmt& o );
     63        CompoundStmt( CompoundStmt&& o ) = default;
    6264
    6365        void push_back( const Stmt * s ) { kids.emplace_back( s ); }
     
    6567
    6668        const CompoundStmt * accept( Visitor & v ) const override { return v.visit( this ); }
    67   private:
     69private:
    6870        CompoundStmt * clone() const override { return new CompoundStmt{ *this }; }
    6971        MUTATE_FRIEND
    7072};
    7173
    72 // Empty statment: ;
     74/// Empty statment `;`
    7375class NullStmt final : public Stmt {
    74   public:
    75         NullStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    76                 : Stmt(loc, std::move(labels)) {}
     76public:
     77        NullStmt( const CodeLocation & loc, std::vector<Label> && labels = {} )
     78        : Stmt(loc, std::move(labels)) {}
    7779
    7880        const NullStmt * accept( Visitor & v ) const override { return v.visit( this ); }
    79   private:
     81private:
    8082        NullStmt * clone() const override { return new NullStmt{ *this }; }
    8183        MUTATE_FRIEND
    8284};
    8385
    84 // Expression wrapped by statement
     86/// Expression wrapped by statement
    8587class ExprStmt final : public Stmt {
    86   public:
     88public:
    8789        ptr<Expr> expr;
    8890
    89         ExprStmt( const CodeLocation & loc, const Expr* e, const std::vector<Label> && labels = {} )
    90                 : Stmt(loc, std::move(labels)), expr(e) {}
    91 
    92         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    93   private:
     91        ExprStmt( const CodeLocation& loc, const Expr* e, std::vector<Label>&& labels = {} )
     92        : Stmt(loc, std::move(labels)), expr(e) {}
     93
     94        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     95private:
    9496        ExprStmt * clone() const override { return new ExprStmt{ *this }; }
    9597        MUTATE_FRIEND
    9698};
    9799
    98 // Assembly statement: asm ... ( "..." : ... )
     100/// Assembly statement `asm ... ( "..." : ... )`
    99101class AsmStmt final : public Stmt {
    100   public:
     102public:
    101103        bool isVolatile;
    102104        ptr<Expr> instruction;
     
    106108
    107109        AsmStmt( const CodeLocation & loc, bool isVolatile, const Expr * instruction,
    108                          const std::vector<ptr<Expr>> && output, const std::vector<ptr<Expr>> && input,
    109                          const std::vector<ptr<ConstantExpr>> && clobber, const std::vector<Label> && gotoLabels,
    110                          const std::vector<Label> && labels = {})
    111                 : Stmt(loc, std::move(labels)), isVolatile(isVolatile), instruction(instruction),
    112                   output(std::move(output)), input(std::move(input)), clobber(std::move(clobber)),
    113                   gotoLabels(std::move(gotoLabels)) {}
    114 
    115         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    116   private:
     110                std::vector<ptr<Expr>> && output, std::vector<ptr<Expr>> && input,
     111                std::vector<ptr<ConstantExpr>> && clobber, std::vector<Label> && gotoLabels,
     112                std::vector<Label> && labels = {})
     113        : Stmt(loc, std::move(labels)), isVolatile(isVolatile), instruction(instruction),
     114          output(std::move(output)), input(std::move(input)), clobber(std::move(clobber)),
     115          gotoLabels(std::move(gotoLabels)) {}
     116
     117        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     118private:
    117119        AsmStmt * clone() const override { return new AsmStmt{ *this }; }
    118120        MUTATE_FRIEND
    119121};
    120122
    121 // C-preprocessor directive: #...
     123/// C-preprocessor directive `#...`
    122124class DirectiveStmt final : public Stmt {
    123   public:
     125public:
    124126        std::string directive;
    125127
    126128        DirectiveStmt( const CodeLocation & loc, const std::string & directive,
    127                                    std::vector<Label> && labels = {} )
    128                 : Stmt(loc, std::move(labels)), directive(directive) {}
    129 
    130         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    131   private:
     129                std::vector<Label> && labels = {} )
     130        : Stmt(loc, std::move(labels)), directive(directive) {}
     131
     132        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     133private:
    132134        DirectiveStmt * clone() const override { return new DirectiveStmt{ *this }; }
    133135        MUTATE_FRIEND
    134136};
    135137
    136 // If statement: if (...) ... else ...
     138/// If conditional statement `if (...) ... else ...`
    137139class IfStmt final : public Stmt {
    138   public:
    139         ptr<Expr> cond;
    140         ptr<Stmt> then;
    141         ptr<Stmt> else_;
     140public:
     141        ptr<Expr> cond;
     142        ptr<Stmt> thenPart;
     143        ptr<Stmt> elsePart;
    142144        std::vector<ptr<Stmt>> inits;
    143145
    144         IfStmt( const CodeLocation & loc, const Expr * cond, const Stmt * then,
    145                         const Stmt * else_ = nullptr, const std::vector<ptr<Stmt>> && inits = {},
    146                         const std::vector<Label> && labels = {} )
    147                 : Stmt(loc, std::move(labels)), cond(cond), then(then), else_(else_),
    148                   inits(std::move(inits)) {}
    149 
    150         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    151   private:
     146        IfStmt( const CodeLocation & loc, const Expr * cond, const Stmt * thenPart,
     147                const Stmt * elsePart = nullptr, std::vector<ptr<Stmt>> && inits = {},
     148                std::vector<Label> && labels = {} )
     149        : Stmt(loc, std::move(labels)), cond(cond), thenPart(thenPart), elsePart(elsePart),
     150          inits(std::move(inits)) {}
     151
     152        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     153private:
    152154        IfStmt * clone() const override { return new IfStmt{ *this }; }
    153155        MUTATE_FRIEND
    154156};
    155157
    156 // Switch or choose statement: switch (...) { ... }
     158/// Switch or choose conditional statement `switch (...) { ... }`
    157159class SwitchStmt final : public Stmt {
    158   public:
     160public:
    159161        ptr<Expr> cond;
    160162        std::vector<ptr<Stmt>> stmts;
    161163
    162         SwitchStmt( const CodeLocation & loc, const Expr * cond, const std::vector<ptr<Stmt>> && stmts,
    163                                 const std::vector<Label> && labels = {} )
    164                 : Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {}
    165 
    166         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    167   private:
     164        SwitchStmt( const CodeLocation & loc, const Expr * cond, std::vector<ptr<Stmt>> && stmts,
     165                std::vector<Label> && labels = {} )
     166        : Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {}
     167
     168        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     169private:
    168170        SwitchStmt * clone() const override { return new SwitchStmt{ *this }; }
    169171        MUTATE_FRIEND
    170172};
    171173
    172 // Case label: case ...: or default:
     174/// Case label `case ...:` `default:`
    173175class CaseStmt final : public Stmt {
    174   public:
    175         // Null for the default label.
     176public:
     177        /// Null for the default label.
    176178        ptr<Expr> cond;
    177179        std::vector<ptr<Stmt>> stmts;
    178180
    179         CaseStmt( const CodeLocation & loc, const Expr * cond, const std::vector<ptr<Stmt>> && stmts,
    180                           const std::vector<Label> && labels = {} )
    181                 : Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {}
     181        CaseStmt( const CodeLocation & loc, const Expr * cond, std::vector<ptr<Stmt>> && stmts,
     182                std::vector<Label> && labels = {} )
     183        : Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {}
    182184
    183185        bool isDefault() const { return !cond; }
    184186
    185187        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    186   private:
     188private:
    187189        CaseStmt * clone() const override { return new CaseStmt{ *this }; }
    188190        MUTATE_FRIEND
    189191};
    190192
    191 // While loop: while (...) ... else ... or do ... while (...) else ...;
    192 class WhileDoStmt final : public Stmt {
    193   public:
     193/// While loop `while (...) ...` `do ... while (...);
     194class WhileStmt final : public Stmt {
     195public:
    194196        ptr<Expr> cond;
    195197        ptr<Stmt> body;
    196         ptr<Stmt> else_;
    197198        std::vector<ptr<Stmt>> inits;
    198199        bool isDoWhile;
    199200
    200         WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body,
    201                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
    202                 : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    203 
    204         WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, const Stmt * else_,
    205                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
    206                 : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    207 
    208         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    209   private:
    210         WhileDoStmt * clone() const override { return new WhileDoStmt{ *this }; }
    211         MUTATE_FRIEND
    212 };
    213 
    214 // For loop: for (... ; ... ; ...) ... else ...
     201        WhileStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body,
     202                std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, std::vector<Label> && labels = {} )
     203        : Stmt(loc, std::move(labels)), cond(cond), body(body), inits(std::move(inits)),
     204          isDoWhile(isDoWhile) {}
     205
     206        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     207private:
     208        WhileStmt * clone() const override { return new WhileStmt{ *this }; }
     209        MUTATE_FRIEND
     210};
     211
     212/// For loop `for (... ; ... ; ...) ...`
    215213class ForStmt final : public Stmt {
    216   public:
     214public:
    217215        std::vector<ptr<Stmt>> inits;
    218216        ptr<Expr> cond;
    219217        ptr<Expr> inc;
    220218        ptr<Stmt> body;
    221         ptr<Stmt> else_;
    222 
    223         ForStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits, const Expr * cond,
    224                          const Expr * inc, const Stmt * body, const std::vector<Label> && label = {} )
    225                 : Stmt(loc, std::move(label)), inits(std::move(inits)), cond(cond), inc(inc), body(body), else_(nullptr) {}
    226 
    227         ForStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits, const Expr * cond,
    228                          const Expr * inc, const Stmt * body, const Stmt * else_, const std::vector<Label> && labels = {} )
    229                 : Stmt(loc, std::move(labels)), inits(std::move(inits)), cond(cond), inc(inc), body(body), else_(else_) {}
    230 
    231         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    232   private:
     219
     220        ForStmt( const CodeLocation & loc, std::vector<ptr<Stmt>> && inits, const Expr * cond,
     221                const Expr * inc, const Stmt * body, std::vector<Label> && labels = {} )
     222        : Stmt(loc, std::move(labels)), inits(std::move(inits)), cond(cond), inc(inc),
     223          body(body) {}
     224
     225        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     226private:
    233227        ForStmt * clone() const override { return new ForStmt{ *this }; }
    234228        MUTATE_FRIEND
    235229};
    236230
    237 // Branch control flow statement: goto ... or break or continue or fallthru
     231/// Branch control flow statement `goto ...` `break` `continue` `fallthru`
    238232class BranchStmt final : public Stmt {
    239   public:
     233public:
    240234        enum Kind { Goto, Break, Continue, FallThrough, FallThroughDefault };
    241235        static constexpr size_t kindEnd = 1 + (size_t)FallThroughDefault;
     
    246240        Kind kind;
    247241
    248         BranchStmt( const CodeLocation & loc, Kind kind, Label target, const std::vector<Label> && labels = {} );
    249         BranchStmt( const CodeLocation & loc, const Expr * computedTarget, const std::vector<Label> && labels = {} )
    250                 : Stmt(loc, std::move(labels)), originalTarget(loc), target(loc), computedTarget(computedTarget), kind(Goto) {}
     242        BranchStmt( const CodeLocation & loc, Kind kind, Label target,
     243                std::vector<Label> && labels = {} );
     244        BranchStmt( const CodeLocation & loc, const Expr * computedTarget,
     245                std::vector<Label> && labels = {} )
     246        : Stmt(loc, std::move(labels)), originalTarget(loc), target(loc),
     247          computedTarget(computedTarget), kind(Goto) {}
    251248
    252249        const char * kindName() const { return kindNames[kind]; }
    253250
    254251        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    255   private:
     252private:
    256253        BranchStmt * clone() const override { return new BranchStmt{ *this }; }
    257254        MUTATE_FRIEND
     
    260257};
    261258
    262 // Return statement: return ...
     259/// Return statement `return ...`
    263260class ReturnStmt final : public Stmt {
    264   public:
     261public:
    265262        ptr<Expr> expr;
    266263
    267         ReturnStmt( const CodeLocation & loc, const Expr * expr, const std::vector<Label> && labels = {} )
    268                 : Stmt(loc, std::move(labels)), expr(expr) {}
    269 
    270         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    271   private:
     264        ReturnStmt( const CodeLocation & loc, const Expr * expr, std::vector<Label> && labels = {} )
     265        : Stmt(loc, std::move(labels)), expr(expr) {}
     266
     267        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     268private:
    272269        ReturnStmt * clone() const override { return new ReturnStmt{ *this }; }
    273270        MUTATE_FRIEND
    274271};
    275272
    276 // Kind of exception
     273/// Kind of exception
    277274enum ExceptionKind { Terminate, Resume };
    278275
    279 // Throw statement: throw ...
     276/// Throw statement `throw ...`
    280277class ThrowStmt final : public Stmt {
    281   public:
     278public:
    282279        ptr<Expr> expr;
    283280        ptr<Expr> target;
    284281        ExceptionKind kind;
    285282
    286         ThrowStmt( const CodeLocation & loc, ExceptionKind kind, const Expr * expr,
    287                            const Expr * target, const std::vector<Label> && labels = {} )
    288                 : Stmt(loc, std::move(labels)), expr(expr), target(target), kind(kind) {}
    289 
    290         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    291   private:
     283        ThrowStmt(
     284                const CodeLocation & loc, ExceptionKind kind, const Expr * expr, const Expr * target,
     285                std::vector<Label> && labels = {} )
     286        : Stmt(loc, std::move(labels)), expr(expr), target(target), kind(kind) {}
     287
     288        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     289private:
    292290        ThrowStmt * clone() const override { return new ThrowStmt{ *this }; }
    293291        MUTATE_FRIEND
    294292};
    295293
    296 // Try statement: try { ... } ...
     294/// Try statement `try { ... } ...`
    297295class TryStmt final : public Stmt {
    298   public:
     296public:
    299297        ptr<CompoundStmt> body;
    300298        std::vector<ptr<CatchStmt>> handlers;
    301299        ptr<FinallyStmt> finally;
    302300
    303         TryStmt( const CodeLocation & loc, const CompoundStmt * body,
    304                          const std::vector<ptr<CatchStmt>> && handlers, const FinallyStmt * finally,
    305                          const std::vector<Label> && labels = {} )
    306                 : Stmt(loc, std::move(labels)), body(body), handlers(std::move(handlers)), finally(finally) {}
    307 
    308         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    309   private:
     301        TryStmt(
     302                const CodeLocation & loc, const CompoundStmt * body,
     303                std::vector<ptr<CatchStmt>> && handlers, const FinallyStmt * finally,
     304                std::vector<Label> && labels = {} )
     305        : Stmt(loc, std::move(labels)), body(body), handlers(std::move(handlers)), finally(finally) {}
     306
     307        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     308private:
    310309        TryStmt * clone() const override { return new TryStmt{ *this }; }
    311310        MUTATE_FRIEND
    312311};
    313312
    314 // Catch clause of try statement
     313/// Catch clause of try statement
    315314class CatchStmt final : public Stmt {
    316   public:
     315public:
    317316        ptr<Decl> decl;
    318317        ptr<Expr> cond;
     
    320319        ExceptionKind kind;
    321320
    322         CatchStmt( const CodeLocation & loc, ExceptionKind kind, const Decl * decl, const Expr * cond,
    323                            const Stmt * body, const std::vector<Label> && labels = {} )
    324                 : Stmt(loc, std::move(labels)), decl(decl), cond(cond), body(body), kind(kind) {}
    325 
    326         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    327   private:
     321        CatchStmt(
     322                const CodeLocation & loc, ExceptionKind kind, const Decl * decl, const Expr * cond,
     323                const Stmt * body, std::vector<Label> && labels = {} )
     324        : Stmt(loc, std::move(labels)), decl(decl), cond(cond), body(body), kind(kind) {}
     325
     326        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     327private:
    328328        CatchStmt * clone() const override { return new CatchStmt{ *this }; }
    329329        MUTATE_FRIEND
    330330};
    331331
    332 // Finally clause of try statement
     332/// Finally clause of try statement
    333333class FinallyStmt final : public Stmt {
    334   public:
     334public:
    335335        ptr<CompoundStmt> body;
    336336
    337337        FinallyStmt( const CodeLocation & loc, const CompoundStmt * body,
    338                                  std::vector<Label> && labels = {} )
    339                 : Stmt(loc, std::move(labels)), body(body) {}
    340 
    341         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    342   private:
     338                std::vector<Label> && labels = {} )
     339        : Stmt(loc, std::move(labels)), body(body) {}
     340
     341        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     342private:
    343343        FinallyStmt * clone() const override { return new FinallyStmt{ *this }; }
    344344        MUTATE_FRIEND
    345345};
    346346
    347 // Suspend statement
     347/// Suspend statement
    348348class SuspendStmt final : public Stmt {
    349   public:
     349public:
    350350        ptr<CompoundStmt> then;
    351351        enum Type { None, Coroutine, Generator } type = None;
    352352
    353         SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, const std::vector<Label> && labels = {} )
    354                 : Stmt(loc, std::move(labels)), then(then), type(type) {}
    355 
    356         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    357   private:
     353        SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, std::vector<Label> && labels = {} )
     354        : Stmt(loc, std::move(labels)), then(then), type(type) {}
     355
     356        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     357private:
    358358        SuspendStmt * clone() const override { return new SuspendStmt{ *this }; }
    359359        MUTATE_FRIEND
    360360};
    361361
    362 // Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...
     362/// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...`
    363363class WaitForStmt final : public Stmt {
    364   public:
     364public:
    365365        struct Target {
    366366                ptr<Expr> func;
     
    389389        OrElse orElse;
    390390
    391         WaitForStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    392                 : Stmt(loc, std::move(labels)) {}
    393 
    394         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    395   private:
     391        WaitForStmt( const CodeLocation & loc, std::vector<Label> && labels = {} )
     392        : Stmt(loc, std::move(labels)) {}
     393
     394        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     395private:
    396396        WaitForStmt * clone() const override { return new WaitForStmt{ *this }; }
    397397        MUTATE_FRIEND
    398398};
    399399
    400 // Any declaration in a (compound) statement.
     400/// Any declaration in a (compound) statement.
    401401class DeclStmt final : public Stmt {
    402   public:
     402public:
    403403        ptr<Decl> decl;
    404404
    405         DeclStmt( const CodeLocation & loc, const Decl * decl, const std::vector<Label> && labels = {} )
    406                 : Stmt(loc, std::move(labels)), decl(decl) {}
    407 
    408         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    409   private:
     405        DeclStmt( const CodeLocation & loc, const Decl * decl, std::vector<Label> && labels = {} )
     406        : Stmt(loc, std::move(labels)), decl(decl) {}
     407
     408        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     409private:
    410410        DeclStmt * clone() const override { return new DeclStmt{ *this }; }
    411411        MUTATE_FRIEND
    412412};
    413413
    414 // Represents an implicit application of a constructor or destructor.
     414/// Represents an implicit application of a constructor or destructor.
    415415class ImplicitCtorDtorStmt final : public Stmt {
    416   public:
     416public:
    417417        ptr<Stmt> callStmt;
    418418
    419419        ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt,
    420                                                   std::vector<Label> && labels = {} )
    421                 : Stmt(loc, std::move(labels)), callStmt(callStmt) {}
    422 
    423         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    424   private:
     420                std::vector<Label> && labels = {} )
     421        : Stmt(loc, std::move(labels)), callStmt(callStmt) {}
     422
     423        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     424private:
    425425        ImplicitCtorDtorStmt * clone() const override { return new ImplicitCtorDtorStmt{ *this }; }
    426426        MUTATE_FRIEND
    427427};
    428428
    429 // Mutex Statement
     429/// Mutex Statement
    430430class MutexStmt final : public Stmt {
    431   public:
     431public:
    432432        ptr<Stmt> stmt;
    433433        std::vector<ptr<Expr>> mutexObjs;
    434434
    435435        MutexStmt( const CodeLocation & loc, const Stmt * stmt,
    436                            const std::vector<ptr<Expr>> && mutexes, const std::vector<Label> && labels = {} )
    437                 : Stmt(loc, std::move(labels)), stmt(stmt), mutexObjs(std::move(mutexes)) {}
    438 
    439         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    440   private:
     436                std::vector<ptr<Expr>> && mutexes, std::vector<Label> && labels = {} )
     437        : Stmt(loc, std::move(labels)), stmt(stmt), mutexObjs(std::move(mutexes)) {}
     438
     439        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     440private:
    441441        MutexStmt * clone() const override { return new MutexStmt{ *this }; }
    442442        MUTATE_FRIEND
    443443};
    444 } // namespace ast
     444
     445}
    445446
    446447#undef MUTATE_FRIEND
    447448
    448449// Local Variables: //
     450// tab-width: 4 //
    449451// mode: c++ //
     452// compile-command: "make install" //
    450453// End: //
  • src/AST/Visitor.hpp

    rf5a51db r97c215f  
    1010// Created On       : Thr May 9 15:28:00 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:09:34 2022
    13 // Update Count     : 2
     12// Last Modified On : Fri Mar 12 18:25:07 2021
     13// Update Count     : 1
    1414//
    1515
     
    3838    virtual const ast::Stmt *             visit( const ast::DirectiveStmt        * ) = 0;
    3939    virtual const ast::Stmt *             visit( const ast::IfStmt               * ) = 0;
    40     virtual const ast::Stmt *             visit( const ast::WhileDoStmt          * ) = 0;
     40    virtual const ast::Stmt *             visit( const ast::WhileStmt            * ) = 0;
    4141    virtual const ast::Stmt *             visit( const ast::ForStmt              * ) = 0;
    4242    virtual const ast::Stmt *             visit( const ast::SwitchStmt           * ) = 0;
  • src/CodeGen/CodeGenerator.cc

    rf5a51db r97c215f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  2 20:30:30 2022
    13 // Update Count     : 541
     12// Last Modified On : Fri Mar 12 19:00:42 2021
     13// Update Count     : 536
    1414//
    1515#include "CodeGenerator.h"
     
    4242        bool wantSpacing( Statement * stmt) {
    4343                return dynamic_cast< IfStmt * >( stmt ) || dynamic_cast< CompoundStmt * >( stmt ) ||
    44                         dynamic_cast< WhileDoStmt * >( stmt ) || dynamic_cast< ForStmt * >( stmt ) || dynamic_cast< SwitchStmt *>( stmt );
     44                        dynamic_cast< WhileStmt * >( stmt ) || dynamic_cast< ForStmt * >( stmt ) || dynamic_cast< SwitchStmt *>( stmt );
    4545        }
    4646
     
    955955                output << " ) ";
    956956
    957                 ifStmt->get_then()->accept( *visitor );
    958 
    959                 if ( ifStmt->get_else() != 0) {
     957                ifStmt->get_thenPart()->accept( *visitor );
     958
     959                if ( ifStmt->get_elsePart() != 0) {
    960960                        output << " else ";
    961                         ifStmt->get_else()->accept( *visitor );
     961                        ifStmt->get_elsePart()->accept( *visitor );
    962962                } // if
    963963        }
     
    10201020                        output << "fallthru";
    10211021                        break;
    1022                   default: ;                                                                    // prevent warning
    10231022                } // switch
    10241023                // print branch target for labelled break/continue/fallthru in debug mode
     
    11261125        }
    11271126
    1128         void CodeGenerator::postvisit( WhileDoStmt * whileDoStmt ) {
    1129                 if ( whileDoStmt->get_isDoWhile() ) {
     1127        void CodeGenerator::postvisit( WhileStmt * whileStmt ) {
     1128                if ( whileStmt->get_isDoWhile() ) {
    11301129                        output << "do";
    11311130                } else {
    11321131                        output << "while (";
    1133                         whileDoStmt->get_condition()->accept( *visitor );
     1132                        whileStmt->get_condition()->accept( *visitor );
    11341133                        output << ")";
    11351134                } // if
    11361135                output << " ";
    11371136
    1138                 output << CodeGenerator::printLabels( whileDoStmt->get_body()->get_labels() );
    1139                 whileDoStmt->get_body()->accept( *visitor );
     1137                output << CodeGenerator::printLabels( whileStmt->get_body()->get_labels() );
     1138                whileStmt->get_body()->accept( *visitor );
    11401139
    11411140                output << indent;
    11421141
    1143                 if ( whileDoStmt->get_isDoWhile() ) {
     1142                if ( whileStmt->get_isDoWhile() ) {
    11441143                        output << " while (";
    1145                         whileDoStmt->get_condition()->accept( *visitor );
     1144                        whileStmt->get_condition()->accept( *visitor );
    11461145                        output << ");";
    11471146                } // if
  • src/CodeGen/CodeGenerator.h

    rf5a51db r97c215f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:23:21 2022
    13 // Update Count     : 64
     12// Last Modified On : Fri Mar 12 18:35:38 2021
     13// Update Count     : 63
    1414//
    1515
     
    116116                void postvisit( WaitForStmt * );
    117117                void postvisit( WithStmt * );
    118                 void postvisit( WhileDoStmt * );
     118                void postvisit( WhileStmt * );
    119119                void postvisit( ForStmt * );
    120120                void postvisit( NullStmt * );
  • src/Common/CodeLocationTools.cpp

    rf5a51db r97c215f  
    1010// Created On       : Fri Dec  4 15:42:00 2020
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:14:39 2022
    13 // Update Count     : 3
     12// Last Modified On : Fri Mar 12 18:35:37 2021
     13// Update Count     : 2
    1414//
    1515
     
    109109    macro(DirectiveStmt, Stmt) \
    110110    macro(IfStmt, Stmt) \
    111     macro(WhileDoStmt, Stmt) \
     111    macro(WhileStmt, Stmt) \
    112112    macro(ForStmt, Stmt) \
    113113    macro(SwitchStmt, Stmt) \
  • src/Common/PassVisitor.h

    rf5a51db r97c215f  
    9292        virtual void visit( IfStmt * ifStmt ) override final;
    9393        virtual void visit( const IfStmt * ifStmt ) override final;
    94         virtual void visit( WhileDoStmt * whileDoStmt ) override final;
    95         virtual void visit( const WhileDoStmt * whileDoStmt ) override final;
     94        virtual void visit( WhileStmt * whileStmt ) override final;
     95        virtual void visit( const WhileStmt * whileStmt ) override final;
    9696        virtual void visit( ForStmt * forStmt ) override final;
    9797        virtual void visit( const ForStmt * forStmt ) override final;
     
    277277        virtual Statement * mutate( DirectiveStmt * dirStmt ) override final;
    278278        virtual Statement * mutate( IfStmt * ifStmt ) override final;
    279         virtual Statement * mutate( WhileDoStmt * whileDoStmt ) override final;
     279        virtual Statement * mutate( WhileStmt * whileStmt ) override final;
    280280        virtual Statement * mutate( ForStmt * forStmt ) override final;
    281281        virtual Statement * mutate( SwitchStmt * switchStmt ) override final;
  • src/Common/PassVisitor.impl.h

    rf5a51db r97c215f  
    11891189                maybeAccept_impl( node->initialization, *this );
    11901190                visitExpression ( node->condition );
    1191                 node->then = visitStatement( node->then );
    1192                 node->else_ = visitStatement( node->else_ );
     1191                node->thenPart = visitStatement( node->thenPart );
     1192                node->elsePart = visitStatement( node->elsePart );
    11931193        }
    11941194        VISIT_END( node );
     
    12031203                maybeAccept_impl( node->initialization, *this );
    12041204                visitExpression ( node->condition );
    1205                 visitStatement  ( node->then );
    1206                 visitStatement  ( node->else_ );
     1205                visitStatement  ( node->thenPart );
     1206                visitStatement  ( node->elsePart );
    12071207        }
    12081208        VISIT_END( node );
     
    12171217                maybeMutate_impl( node->initialization, *this );
    12181218                node->condition = mutateExpression( node->condition );
    1219                 node->then  = mutateStatement ( node->then  );
    1220                 node->else_  = mutateStatement ( node->else_  );
     1219                node->thenPart  = mutateStatement ( node->thenPart  );
     1220                node->elsePart  = mutateStatement ( node->elsePart  );
    12211221        }
    12221222        MUTATE_END( Statement, node );
     
    12241224
    12251225//--------------------------------------------------------------------------
    1226 // WhileDoStmt
    1227 template< typename pass_type >
    1228 void PassVisitor< pass_type >::visit( WhileDoStmt * node ) {
     1226// WhileStmt
     1227template< typename pass_type >
     1228void PassVisitor< pass_type >::visit( WhileStmt * node ) {
    12291229        VISIT_START( node );
    12301230
     
    12411241
    12421242template< typename pass_type >
    1243 void PassVisitor< pass_type >::visit( const WhileDoStmt * node ) {
     1243void PassVisitor< pass_type >::visit( const WhileStmt * node ) {
    12441244        VISIT_START( node );
    12451245
     
    12561256
    12571257template< typename pass_type >
    1258 Statement * PassVisitor< pass_type >::mutate( WhileDoStmt * node ) {
     1258Statement * PassVisitor< pass_type >::mutate( WhileStmt * node ) {
    12591259        MUTATE_START( node );
    12601260
  • src/Common/utility.h

    rf5a51db r97c215f  
    371371}
    372372
    373 template< typename T >
    374 struct enumerate_t {
    375         template<typename val_t>
    376         struct value_t {
    377                 val_t & val;
    378                 size_t idx;
    379         };
    380 
    381         template< typename iter_t, typename val_t >
    382         struct iterator_t {
    383                 iter_t it;
    384                 size_t idx;
    385 
    386                 iterator_t( iter_t _it, size_t _idx ) : it(_it), idx(_idx) {}
    387 
    388                 value_t<val_t> operator*() const { return value_t<val_t>{ *it, idx }; }
    389 
    390                 bool operator==(const iterator_t & o) const { return o.it == it; }
    391                 bool operator!=(const iterator_t & o) const { return o.it != it; }
    392 
    393                 iterator_t & operator++() {
    394                         it++;
    395                         idx++;
    396                         return *this;
    397                 }
    398 
    399                 using difference_type   = typename std::iterator_traits< iter_t >::difference_type;
    400                 using value_type        = value_t<val_t>;
    401                 using pointer           = value_t<val_t> *;
    402                 using reference         = value_t<val_t> &;
    403                 using iterator_category = std::forward_iterator_tag;
    404         };
    405 
    406         T & ref;
    407 
    408         using iterator = iterator_t< typename T::iterator, typename T::value_type >;
    409         using const_iterator = iterator_t< typename T::const_iterator, const typename T::value_type >;
    410 
    411         iterator begin() { return iterator( ref.begin(), 0 ); }
    412         iterator end()   { return iterator( ref.end(), ref.size() ); }
    413 
    414         const_iterator begin() const { return const_iterator( ref.cbegin(), 0 ); }
    415         const_iterator end()   const { return const_iterator( ref.cend(), ref.size() ); }
    416 
    417         const_iterator cbegin() const { return const_iterator( ref.cbegin(), 0 ); }
    418         const_iterator cend()   const { return const_iterator( ref.cend(), ref.size() ); }
    419 };
    420 
    421 template< typename T >
    422 enumerate_t<T> enumerate( T & ref ) {
    423         return enumerate_t< T >{ ref };
    424 }
    425 
    426 template< typename T >
    427 const enumerate_t< const T > enumerate( const T & ref ) {
    428         return enumerate_t< const T >{ ref };
    429 }
    430 
    431373template< typename OutType, typename Range, typename Functor >
    432374OutType map_range( const Range& range, Functor&& functor ) {
  • src/ControlStruct/ExceptTranslate.h

    rf5a51db r97c215f  
    3131
    3232        void translateTries( std::list< Declaration *> & translationUnit );
    33         void translateTries( ast::TranslationUnit & transUnit );
    3433        /* Replaces all try blocks (and their many clauses) with function definitions and calls.
    3534         * This uses the exception built-ins to produce typed output and should take place after
  • src/ControlStruct/ExceptTranslateNew.cpp

    rf5a51db r97c215f  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Nov  8 11:53:00 2021
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 31 18:49:58 2022
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  8 16:50:00 2021
     13// Update Count     : 0
    1414//
    1515
     
    2020#include "AST/Stmt.hpp"
    2121#include "AST/TranslationUnit.hpp"
    22 #include "AST/DeclReplacer.hpp"
    2322
    2423namespace ControlStruct {
    2524
    2625namespace {
    27 
    28         typedef std::list<ast::CatchStmt*> CatchList;
    29 
    30         void split( CatchList& allHandlers, CatchList& terHandlers,
    31                                 CatchList& resHandlers ) {
    32                 while ( !allHandlers.empty() ) {
    33                         ast::CatchStmt * stmt = allHandlers.front();
    34                         allHandlers.pop_front();
    35                         if (stmt->kind == ast::ExceptionKind::Terminate) {
    36                                 terHandlers.push_back(stmt);
    37                         } else {
    38                                 resHandlers.push_back(stmt);
    39                         }
    40                 }
    41         }
    42 
    43         void appendDeclStmt( ast::CompoundStmt * block, ast::DeclWithType * item ) {
    44                 block->push_back(new ast::DeclStmt(block->location, item));
    45         }
    4626
    4727class TranslateThrowsCore : public ast::WithGuards {
     
    148128}
    149129
    150 
    151 class TryMutatorCore {
    152         // The built in types used in translation.
    153         const ast::StructDecl * except_decl;
    154         const ast::StructDecl * node_decl;
    155         const ast::StructDecl * hook_decl;
    156 
    157         // The many helper functions for code/syntree generation.
    158         ast::CompoundStmt * take_try_block( ast::TryStmt * tryStmt );
    159         ast::FunctionDecl * create_try_wrapper( const ast::CompoundStmt * body );
    160         ast::FunctionDecl * create_terminate_catch( CatchList &handlers );
    161         ast::CompoundStmt * create_single_matcher(
    162                 const ast::DeclWithType * except_obj, ast::CatchStmt * modded_handler );
    163         ast::FunctionDecl * create_terminate_match( CatchList &handlers );
    164         ast::CompoundStmt * create_terminate_caller( CodeLocation loc, ast::FunctionDecl * try_wrapper,
    165                 ast::FunctionDecl * terminate_catch, ast::FunctionDecl * terminate_match );
    166         ast::FunctionDecl * create_resume_handler( CatchList &handlers );
    167         ast::CompoundStmt * create_resume_wrapper(
    168                 const ast::Stmt * wraps, const ast::FunctionDecl * resume_handler );
    169         ast::FunctionDecl * create_finally_wrapper( ast::TryStmt * tryStmt );
    170         ast::ObjectDecl * create_finally_hook( ast::FunctionDecl * finally_wrapper );
    171         ast::Stmt * create_resume_rethrow( const ast::ThrowStmt * throwStmt );
    172 
    173         // Types used in translation, make sure to use clone.
    174         // void (*function)();
    175         ast::FunctionDecl * try_func_t;
    176         // void (*function)(int, exception);
    177         ast::FunctionDecl * catch_func_t;
    178         // int (*function)(exception);
    179         ast::FunctionDecl * match_func_t;
    180         // bool (*function)(exception);
    181         ast::FunctionDecl * handle_func_t;
    182         // void (*function)(__attribute__((unused)) void *);
    183         ast::FunctionDecl * finally_func_t;
    184 
    185         ast::StructInstType * create_except_type() {
    186                 assert( except_decl );
    187                 return new ast::StructInstType( except_decl );
    188         }
    189         void init_func_types();
    190 
    191 public:
    192         TryMutatorCore() :
    193                 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr )
    194         {}
    195 
    196         void previsit( const ast::StructDecl *structDecl );
    197         ast::Stmt * postvisit( const ast::TryStmt *tryStmt );
    198         ast::Stmt * postvisit( const ast::ThrowStmt *throwStmt );
    199 };
    200 
    201 void TryMutatorCore::init_func_types() {
    202         assert( except_decl );
    203 
    204         ast::ObjectDecl index_obj(
    205                 {},
    206                 "__handler_index",
    207                 new ast::BasicType(ast::BasicType::SignedInt)
    208                 );
    209         ast::ObjectDecl exception_obj(
    210                 {},
    211                 "__exception_inst",
    212                 new ast::PointerType(
    213                         new ast::StructInstType( except_decl )
    214                         ),
    215                 NULL
    216                 );
    217         ast::ObjectDecl bool_obj(
    218                 {},
    219                 "__ret_bool",
    220                 new ast::BasicType( ast::BasicType::Bool ),
    221                 nullptr, //init
    222                 ast::Storage::Classes{},
    223                 ast::Linkage::Cforall,
    224                 nullptr, //width
    225                 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
    226                 );
    227         ast::ObjectDecl voidptr_obj(
    228                 {},
    229                 "__hook",
    230                 new ast::PointerType(
    231                         new ast::VoidType()
    232                 ),
    233                 nullptr, //init
    234                 ast::Storage::Classes{},
    235                 ast::Linkage::Cforall,
    236                 nullptr, //width
    237                 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
    238                 );
    239 
    240         ast::ObjectDecl unused_index_obj(
    241                 {},
    242                 "__handler_index",
    243                 new ast::BasicType(ast::BasicType::SignedInt),
    244                 nullptr,
    245                 ast::Storage::Classes{},
    246                 ast::Linkage::Cforall,
    247                 nullptr, //width
    248                 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
    249         );
    250         //unused_index_obj->attributes.push_back( new Attribute( "unused" ) );
    251 
    252         try_func_t = new ast::FunctionDecl(
    253                 {},
    254                 "try",
    255                 {}, //forall
    256                 {}, //no param
    257                 {}, //no return
    258                 nullptr,
    259                 ast::Storage::Classes{},
    260                 ast::Linkage::Cforall
    261         );
    262 
    263         catch_func_t = new ast::FunctionDecl(
    264                 {},
    265                 "catch",
    266                 {}, //forall
    267                 {ast::deepCopy(&index_obj), ast::deepCopy(&exception_obj)},//param
    268                 {}, //return void
    269                 nullptr,
    270                 ast::Storage::Classes{},
    271                 ast::Linkage::Cforall
    272         );
    273 
    274         match_func_t = new ast::FunctionDecl(
    275                 {},
    276                 "match",
    277                 {}, //forall
    278                 {ast::deepCopy(&exception_obj)},
    279                 {ast::deepCopy(&unused_index_obj)},
    280                 nullptr,
    281                 ast::Storage::Classes{},
    282                 ast::Linkage::Cforall
    283         );
    284 
    285         handle_func_t = new ast::FunctionDecl(
    286                 {},
    287                 "handle",
    288                 {}, //forall
    289                 {ast::deepCopy(&exception_obj)},
    290                 {ast::deepCopy(&bool_obj)},
    291                 nullptr,
    292                 ast::Storage::Classes{},
    293                 ast::Linkage::Cforall
    294         );
    295 
    296         finally_func_t = new ast::FunctionDecl(
    297                 {},
    298                 "finally",
    299                 {}, //forall
    300                 {ast::deepCopy(&voidptr_obj)},
    301                 {}, //return void
    302                 nullptr,
    303                 ast::Storage::Classes{},
    304                 ast::Linkage::Cforall
    305         );
    306 
    307         //catch_func_t.get_parameters().push_back( index_obj.clone() );
    308         //catch_func_t.get_parameters().push_back( exception_obj.clone() );
    309         //match_func_t.get_returnVals().push_back( unused_index_obj );
    310         //match_func_t.get_parameters().push_back( exception_obj.clone() );
    311         //handle_func_t.get_returnVals().push_back( bool_obj.clone() );
    312         //handle_func_t.get_parameters().push_back( exception_obj.clone() );
    313         //finally_func_t.get_parameters().push_back( voidptr_obj.clone() );
    314 }
    315 
    316 // TryStmt Mutation Helpers
    317 
    318 /*
    319 ast::CompoundStmt * TryMutatorCore::take_try_block( ast::TryStmt *tryStmt ) {
    320         ast::CompoundStmt * block = tryStmt->body;
    321         tryStmt->body = nullptr;
    322         return block;
    323 }
    324 */
    325 
    326 ast::FunctionDecl * TryMutatorCore::create_try_wrapper(
    327                 const ast::CompoundStmt *body ) {
    328 
    329         ast::FunctionDecl * ret = ast::deepCopy(try_func_t);
    330         ret->stmts = body;
    331         return ret;
    332 }
    333 
    334 ast::FunctionDecl * TryMutatorCore::create_terminate_catch(
    335                 CatchList &handlers ) {
    336         std::vector<ast::ptr<ast::Stmt>> handler_wrappers;
    337 
    338         assert (!handlers.empty());
    339         const CodeLocation loc = handlers.front()->location;
    340 
    341         ast::FunctionDecl * func_t = ast::deepCopy(catch_func_t);
    342         const ast::DeclWithType * index_obj = func_t->params.front();
    343         const ast::DeclWithType * except_obj = func_t->params.back();
    344 
    345         // Index 1..{number of handlers}
    346         int index = 0;
    347         CatchList::iterator it = handlers.begin();
    348         for ( ; it != handlers.end() ; ++it ) {
    349                 ++index;
    350                 ast::CatchStmt * handler = *it;
    351                 const CodeLocation loc = handler->location;
    352 
    353                 // case `index`:
    354                 // {
    355                 //     `handler.decl` = { (virtual `decl.type`)`except` };
    356                 //     `handler.body`;
    357                 // }
    358                 // return;
    359                 ast::CompoundStmt * block = new ast::CompoundStmt(loc);
    360 
    361                 // Just copy the exception value. (Post Validation)
    362                 const ast::ObjectDecl * handler_decl =
    363                         handler->decl.strict_as<ast::ObjectDecl>();
    364                 ast::ObjectDecl * local_except = ast::deepCopy(handler_decl);
    365                 ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
    366                         new ast::VariableExpr( loc, except_obj ),
    367                         local_except->get_type()
    368                         );
    369                 vcex->location = handler->location;
    370                 local_except->init = new ast::ListInit(loc, { new ast::SingleInit( loc, vcex ) });
    371                 block->push_back( new ast::DeclStmt( loc, local_except ) );
    372 
    373                 // Add the cleanup attribute.
    374                 local_except->attributes.push_back( new ast::Attribute(
    375                         "cleanup",
    376                         { new ast::NameExpr( loc, "__cfaehm_cleanup_terminate" ) }
    377                         ) );
    378 
    379                 ast::DeclReplacer::DeclMap mapping;
    380                 mapping[handler_decl] = local_except;
    381                 const ast::Stmt * mutBody = strict_dynamic_cast<const ast::Stmt *>(
    382                         ast::DeclReplacer::replace(handler->body, mapping));
    383 
    384 
    385                 block->push_back( mutBody );
    386                 // handler->body = nullptr;
    387 
    388                 handler_wrappers.push_back( new ast::CaseStmt(loc,
    389                         ast::ConstantExpr::from_int(loc, index) ,
    390                         { block, new ast::ReturnStmt( loc, nullptr ) }
    391                         ));
    392         }
    393         // TODO: Some sort of meaningful error on default perhaps?
    394 
    395         /*
    396         std::list<Statement*> stmt_handlers;
    397         while ( !handler_wrappers.empty() ) {
    398                 stmt_handlers.push_back( handler_wrappers.front() );
    399                 handler_wrappers.pop_front();
    400         }
    401         */
    402 
    403         ast::SwitchStmt * handler_lookup = new ast::SwitchStmt(loc,
    404                 new ast::VariableExpr( loc, index_obj ),
    405                 std::move(handler_wrappers)
    406                 );
    407         ast::CompoundStmt * body = new ast::CompoundStmt(loc,
    408                 {handler_lookup});
    409 
    410         func_t->stmts = body;
    411         return func_t;
    412 }
    413 
    414 // Create a single check from a moddified handler.
    415 // except_obj is referenced, modded_handler will be freed.
    416 ast::CompoundStmt * TryMutatorCore::create_single_matcher(
    417                 const ast::DeclWithType * except_obj, ast::CatchStmt * modded_handler ) {
    418         // {
    419         //     `modded_handler.decl`
    420         //     if ( `decl.name = (virtual `decl.type`)`except`
    421         //             [&& `modded_handler.cond`] ) {
    422         //         `modded_handler.body`
    423         //     }
    424         // }
    425 
    426         const CodeLocation loc = modded_handler->location;
    427         ast::CompoundStmt * block = new ast::CompoundStmt(loc);
    428 
    429         // Local Declaration
    430         const ast::ObjectDecl * local_except =
    431                 modded_handler->decl.strict_as<ast::ObjectDecl>();
    432         block->push_back( new ast::DeclStmt( loc,  local_except ) );
    433 
    434         // Check for type match.
    435         ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
    436                 new ast::VariableExpr(loc, except_obj ),
    437                 local_except->get_type()
    438                 );
    439         ast::Expr * cond = ast::UntypedExpr::createAssign(loc,
    440                 new ast::VariableExpr(loc, local_except ), vcex );
    441 
    442         // Add the check on the conditional if it is provided.
    443         if ( modded_handler->cond ) {
    444                 cond = new ast::LogicalExpr( loc, cond, modded_handler->cond, ast::LogicalFlag::AndExpr );
    445         }
    446         // Construct the match condition.
    447         block->push_back( new ast::IfStmt(loc,
    448                 cond, modded_handler->body, nullptr ) );
    449 
    450         // xxx - how does this work in new ast
    451         //modded_handler->set_decl( nullptr );
    452         //modded_handler->set_cond( nullptr );
    453         //modded_handler->set_body( nullptr );
    454         //delete modded_handler;
    455         return block;
    456 }
    457 
    458 ast::FunctionDecl * TryMutatorCore::create_terminate_match(
    459                 CatchList &handlers ) {
    460         // int match(exception * except) {
    461         //     HANDLER WRAPPERS { return `index`; }
    462         // }
    463 
    464         assert (!handlers.empty());
    465         const CodeLocation loc = handlers.front()->location;
    466 
    467         ast::CompoundStmt * body = new ast::CompoundStmt(loc);
    468 
    469         ast::FunctionDecl * func_t = ast::deepCopy(match_func_t);
    470         const ast::DeclWithType * except_obj = func_t->params.back();
    471 
    472         // Index 1..{number of handlers}
    473         int index = 0;
    474         CatchList::iterator it;
    475         for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
    476                 ++index;
    477                 ast::CatchStmt * handler = *it;
    478 
    479                 // Body should have been taken by create_terminate_catch.
    480                 // xxx - just ignore it?
    481                 // assert( nullptr == handler->get_body() );
    482 
    483                 // Create new body.
    484                 handler->body = new ast::ReturnStmt( handler->location,
    485                         ast::ConstantExpr::from_int( handler->location, index ) );
    486 
    487                 // Create the handler.
    488                 body->push_back( create_single_matcher( except_obj, handler ) );
    489                 *it = nullptr;
    490         }
    491 
    492         body->push_back( new ast::ReturnStmt(loc,
    493                 ast::ConstantExpr::from_int( loc, 0 ) ));
    494 
    495         func_t->stmts = body;
    496 
    497         return func_t;
    498 }
    499 
    500 ast::CompoundStmt * TryMutatorCore::create_terminate_caller(
    501                 CodeLocation loc,
    502                 ast::FunctionDecl * try_wrapper,
    503                 ast::FunctionDecl * terminate_catch,
    504                 ast::FunctionDecl * terminate_match ) {
    505         // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
    506 
    507         ast::UntypedExpr * caller = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
    508                 "__cfaehm_try_terminate" ) );
    509         caller->args.push_back( new ast::VariableExpr(loc, try_wrapper ) );
    510         caller->args.push_back( new ast::VariableExpr(loc, terminate_catch ) );
    511         caller->args.push_back( new ast::VariableExpr(loc, terminate_match ) );
    512 
    513         ast::CompoundStmt * callStmt = new ast::CompoundStmt(loc);
    514         callStmt->push_back( new ast::ExprStmt( loc, caller ) );
    515         return callStmt;
    516 }
    517 
    518 ast::FunctionDecl * TryMutatorCore::create_resume_handler(
    519                 CatchList &handlers ) {
    520         // bool handle(exception * except) {
    521         //     HANDLER WRAPPERS { `hander->body`; return true; }
    522         // }
    523         assert (!handlers.empty());
    524         const CodeLocation loc = handlers.front()->location;
    525         ast::CompoundStmt * body = new ast::CompoundStmt(loc);
    526 
    527         ast::FunctionDecl * func_t = ast::deepCopy(handle_func_t);
    528         const ast::DeclWithType * except_obj = func_t->params.back();
    529 
    530         CatchList::iterator it;
    531         for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
    532                 ast::CatchStmt * handler = *it;
    533                 const CodeLocation loc = handler->location;
    534                 // Modifiy body.
    535                 ast::CompoundStmt * handling_code;
    536                 if (handler->body.as<ast::CompoundStmt>()) {
    537                         handling_code =
    538                         strict_dynamic_cast<ast::CompoundStmt*>( handler->body.get_and_mutate() );
    539                 } else {
    540                         handling_code = new ast::CompoundStmt(loc);
    541                         handling_code->push_back( handler->body );
    542                 }
    543                 handling_code->push_back( new ast::ReturnStmt(loc,
    544                         ast::ConstantExpr::from_bool(loc, true ) ) );
    545                 handler->body = handling_code;
    546 
    547                 // Create the handler.
    548                 body->push_back( create_single_matcher( except_obj, handler ) );
    549                 *it = nullptr;
    550         }
    551 
    552         body->push_back( new ast::ReturnStmt(loc,
    553                 ast::ConstantExpr::from_bool(loc, false ) ) );
    554         func_t->stmts = body;
    555 
    556         return func_t;
    557 }
    558 
    559 ast::CompoundStmt * TryMutatorCore::create_resume_wrapper(
    560                 const ast::Stmt * wraps,
    561                 const ast::FunctionDecl * resume_handler ) {
    562         const CodeLocation loc = wraps->location;
    563         ast::CompoundStmt * body = new ast::CompoundStmt(loc);
    564 
    565         // struct __try_resume_node __resume_node
    566         //      __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
    567         // ** unwinding of the stack here could cause problems **
    568         // ** however I don't think that can happen currently **
    569         // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
    570 
    571         ast::ObjectDecl * obj = new ast::ObjectDecl(
    572                 loc,
    573                 "__resume_node",
    574                 new ast::StructInstType(
    575                         node_decl
    576                         ),
    577                 nullptr,
    578                 ast::Storage::Classes{},
    579                 ast::Linkage::Cforall,
    580                 nullptr,
    581                 {new ast::Attribute("cleanup", {new ast::NameExpr(loc, "__cfaehm_try_resume_cleanup")})}
    582                 );
    583         appendDeclStmt( body, obj );
    584 
    585         ast::UntypedExpr *setup = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
    586                 "__cfaehm_try_resume_setup" ) );
    587         setup->args.push_back( new ast::AddressExpr( loc, new ast::VariableExpr(loc, obj ) ) );
    588         setup->args.push_back( new ast::VariableExpr( loc, resume_handler ) );
    589 
    590         body->push_back( new ast::ExprStmt(loc, setup ) );
    591 
    592         body->push_back( wraps );
    593         return body;
    594 }
    595 
    596 ast::FunctionDecl * TryMutatorCore::create_finally_wrapper(
    597                 ast::TryStmt * tryStmt ) {
    598         // void finally() { `finally->block` }
    599         const ast::FinallyStmt * finally = tryStmt->finally;
    600         const ast::CompoundStmt * body = finally->body;
    601 
    602         ast::FunctionDecl * func_t = ast::deepCopy(finally_func_t);
    603         func_t->stmts = body;
    604 
    605         // finally->set_block( nullptr );
    606         // delete finally;
    607         tryStmt->finally = nullptr;
    608 
    609 
    610         return func_t;
    611 }
    612 
    613 ast::ObjectDecl * TryMutatorCore::create_finally_hook(
    614                 ast::FunctionDecl * finally_wrapper ) {
    615         // struct __cfaehm_cleanup_hook __finally_hook
    616         //      __attribute__((cleanup( `finally_wrapper` )));
    617 
    618         const CodeLocation loc = finally_wrapper->location;
    619         // Make Cleanup Attribute.
    620         /*
    621         std::list< ast::Attribute * > attributes;
    622         {
    623                 std::list<  > attr_params;
    624                 attr_params.push_back( nameOf( finally_wrapper ) );
    625                 attributes.push_back( new Attribute( "cleanup", attr_params ) );
    626         }
    627         */
    628 
    629         return new ast::ObjectDecl(
    630                 loc,
    631                 "__finally_hook",
    632                 new ast::StructInstType(
    633                         hook_decl
    634                         ),
    635                 nullptr,
    636                 ast::Storage::Classes{},
    637                 ast::Linkage::Cforall,
    638                 nullptr,
    639                 {new ast::Attribute("cleanup", {new ast::VariableExpr{loc, finally_wrapper}})}
    640                 );
    641 }
    642 
    643 ast::Stmt * TryMutatorCore::create_resume_rethrow( const ast::ThrowStmt *throwStmt ) {
    644         // return false;
    645         const CodeLocation loc = throwStmt->location;
    646         ast::Stmt * result = new ast::ReturnStmt(loc,
    647                 ast::ConstantExpr::from_bool( loc, false )
    648                 );
    649         result->labels = throwStmt->labels;
    650         // delete throwStmt; done by postvisit
    651         return result;
    652 }
    653 
    654 // Visiting/Mutating Functions
    655 void TryMutatorCore::previsit( const ast::StructDecl *structDecl ) {
    656         if ( !structDecl->body ) {
    657                 // Skip children?
    658                 return;
    659         } else if ( structDecl->name == "__cfaehm_base_exception_t" ) {
    660                 assert( nullptr == except_decl );
    661                 except_decl = structDecl;
    662                 init_func_types();
    663         } else if ( structDecl->name == "__cfaehm_try_resume_node" ) {
    664                 assert( nullptr == node_decl );
    665                 node_decl = structDecl;
    666         } else if ( structDecl->name == "__cfaehm_cleanup_hook" ) {
    667                 assert( nullptr == hook_decl );
    668                 hook_decl = structDecl;
    669         }
    670 }
    671 
    672 ast::Stmt * TryMutatorCore::postvisit( const ast::TryStmt *tryStmt ) {
    673         assert( except_decl );
    674         assert( node_decl );
    675         assert( hook_decl );
    676 
    677         const CodeLocation loc = tryStmt->location;
    678         ast::TryStmt * mutStmt = mutate(tryStmt);
    679         // Generate a prefix for the function names?
    680 
    681         ast::CompoundStmt * block = new ast::CompoundStmt( loc );
    682         // ast::CompoundStmt * inner = take_try_block( mutStmt );
    683         // this is never mutated so let node deletion do its job?
    684         const ast::CompoundStmt * inner = mutStmt->body;
    685 
    686         if ( mutStmt->finally ) {
    687                 // Define the helper function.
    688                 ast::FunctionDecl * finally_block =
    689                         create_finally_wrapper( mutStmt );
    690                 appendDeclStmt( block, finally_block );
    691                 // Create and add the finally cleanup hook.
    692                 appendDeclStmt( block, create_finally_hook( finally_block ) );
    693         }
    694 
    695         CatchList termination_handlers;
    696         CatchList resumption_handlers;
    697 
    698         for (auto & handler: mutStmt->handlers) {
    699                 // xxx - should always be unique? mutate as safe const-cast
    700                 assert(handler->unique());
    701                 if (handler->kind == ast::ExceptionKind::Resume) {
    702                         resumption_handlers.push_back(handler.get_and_mutate());
    703                 }
    704                 else {
    705                         termination_handlers.push_back(handler.get_and_mutate());
    706                 }
    707         }
    708         // split( mutStmt->handlers,
    709         //              termination_handlers, resumption_handlers );
    710 
    711         if ( resumption_handlers.size() ) {
    712                 // Define the helper function.
    713                 ast::FunctionDecl * resume_handler =
    714                         create_resume_handler( resumption_handlers );
    715                 appendDeclStmt( block, resume_handler );
    716                 // Prepare hooks
    717                 inner = create_resume_wrapper( inner, resume_handler );
    718         }
    719 
    720         if ( termination_handlers.size() ) {
    721                 // Define the three helper functions.
    722                 ast::FunctionDecl * try_wrapper = create_try_wrapper( inner );
    723                 appendDeclStmt( block, try_wrapper );
    724                 ast::FunctionDecl * terminate_catch =
    725                         create_terminate_catch( termination_handlers );
    726                 appendDeclStmt( block, terminate_catch );
    727                 ast::FunctionDecl * terminate_match =
    728                         create_terminate_match( termination_handlers );
    729                 appendDeclStmt( block, terminate_match );
    730                 // Build the call to the try wrapper.
    731                 inner = create_terminate_caller(inner->location,
    732                         try_wrapper, terminate_catch, terminate_match );
    733         }
    734 
    735         // Embed the try block.
    736         block->push_back( inner );
    737 
    738         return block;
    739 }
    740 
    741 ast::Stmt * TryMutatorCore::postvisit( const ast::ThrowStmt *throwStmt ) {
    742         // Only valid `throwResume;` statements should remain. (2/3 checks)
    743         assert( ast::ExceptionKind::Resume == throwStmt->kind && ! throwStmt->expr );
    744         return create_resume_rethrow( throwStmt );
    745 }
    746 
    747130} // namespace
    748131
    749132void translateThrows( ast::TranslationUnit & transUnit ) {
    750133        ast::Pass<TranslateThrowsCore>::run( transUnit );
    751 }
    752 
    753 void translateTries( ast::TranslationUnit & transUnit ) {
    754         ast::Pass<TryMutatorCore>::run(transUnit);
    755134}
    756135
  • src/ControlStruct/FixLabels.cpp

    rf5a51db r97c215f  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Nov  1 09:39:00 2021
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 31 22:19:17 2022
    13 // Update Count     : 9
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  8 10:53:00 2021
     13// Update Count     : 3
    1414//
    1515
     
    2020#include "AST/Stmt.hpp"
    2121#include "ControlStruct/MultiLevelExit.hpp"
    22 using namespace ast;
    2322
    2423namespace ControlStruct {
    25 class FixLabelsCore final : public WithGuards {
     24
     25namespace {
     26
     27class FixLabelsCore final : public ast::WithGuards {
    2628        LabelToStmt labelTable;
    27   public:
     29public:
    2830        FixLabelsCore() : labelTable() {}
    2931
    30         void previsit( const FunctionDecl * );
    31         const FunctionDecl * postvisit( const FunctionDecl * );
    32         void previsit( const Stmt * );
    33         void previsit( const BranchStmt * );
    34         void previsit( const LabelAddressExpr * );
     32        void previsit( const ast::FunctionDecl * );
     33        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
     34        void previsit( const ast::Stmt * );
     35        void previsit( const ast::BranchStmt * );
     36        void previsit( const ast::LabelAddressExpr * );
    3537
    36         void setLabelsDef( const std::vector<Label> &, const Stmt * );
    37         void setLabelsUsage( const Label & );
     38        void setLabelsDef( const std::vector<ast::Label> &, const ast::Stmt * );
     39        void setLabelsUsage( const ast::Label & );
    3840};
    3941
    40 void FixLabelsCore::previsit( const FunctionDecl * ) {
     42void FixLabelsCore::previsit( const ast::FunctionDecl * ) {
    4143        GuardValue( labelTable ).clear();
    4244}
    4345
    44 const FunctionDecl * FixLabelsCore::postvisit(
    45         const FunctionDecl * decl ) {
     46const ast::FunctionDecl * FixLabelsCore::postvisit(
     47                const ast::FunctionDecl * decl ) {
    4648        if ( nullptr == decl->stmts ) return decl;
    4749        for ( auto kvp : labelTable ) {
    4850                if ( nullptr == kvp.second ) {
    4951                        SemanticError( kvp.first.location,
    50                                                    "Use of undefined label: " + kvp.first.name );
     52                                "Use of undefined label: " + kvp.first.name );
    5153                }
    5254        }
    53         return mutate_field( decl, &FunctionDecl::stmts,
    54                                                  multiLevelExitUpdate( decl->stmts.get(), labelTable ) );
     55        return ast::mutate_field( decl, &ast::FunctionDecl::stmts,
     56                multiLevelExitUpdate( decl->stmts.get(), labelTable ) );
    5557}
    5658
    57 void FixLabelsCore::previsit( const Stmt * stmt ) {
     59void FixLabelsCore::previsit( const ast::Stmt * stmt ) {
    5860        if ( !stmt->labels.empty() ) {
    5961                setLabelsDef( stmt->labels, stmt );
     
    6163}
    6264
    63 void FixLabelsCore::previsit( const BranchStmt * stmt ) {
     65void FixLabelsCore::previsit( const ast::BranchStmt * stmt ) {
    6466        if ( !stmt->labels.empty() ) {
    6567                setLabelsDef( stmt->labels, stmt );
     
    7072}
    7173
    72 void FixLabelsCore::previsit( const LabelAddressExpr * expr ) {
     74void FixLabelsCore::previsit( const ast::LabelAddressExpr * expr ) {
    7375        assert( !expr->arg.empty() );
    7476        setLabelsUsage( expr->arg );
     
    7678
    7779void FixLabelsCore::setLabelsDef(
    78         const std::vector<Label> & labels, const Stmt * stmt ) {
     80                const std::vector<ast::Label> & labels, const ast::Stmt * stmt ) {
    7981        assert( !labels.empty() );
    8082        assert( stmt );
     
    8789                        // Duplicate definition, this is an error.
    8890                        SemanticError( label.location,
    89                                                    "Duplicate definition of label: " + label.name );
     91                                "Duplicate definition of label: " + label.name );
    9092                } else {
    9193                        // Perviously used, but not defined until now.
     
    9698
    9799// Label was used, if it is new add it to the table.
    98 void FixLabelsCore::setLabelsUsage( const Label & label ) {
     100void FixLabelsCore::setLabelsUsage( const ast::Label & label ) {
    99101        if ( labelTable.find( label ) == labelTable.end() ) {
    100102                labelTable[ label ] = nullptr;
     
    102104}
    103105
    104 void fixLabels( TranslationUnit & translationUnit ) {
    105         Pass<FixLabelsCore>::run( translationUnit );
     106} // namespace
     107
     108void fixLabels( ast::TranslationUnit & translationUnit ) {
     109        ast::Pass<FixLabelsCore>::run( translationUnit );
    106110}
     111
    107112} // namespace ControlStruct
    108113
  • src/ControlStruct/FixLabels.hpp

    rf5a51db r97c215f  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Nov  1 09:36:00 2021
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 31 22:18:43 2022
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  1 09:40:00 2021
     13// Update Count     : 0
    1414//
    1515
     
    1717
    1818namespace ast {
    19 class TranslationUnit;
     19        class TranslationUnit;
    2020}
    2121
    2222namespace ControlStruct {
    23 // normalizes label definitions and generates multi-level exit labels
     23
     24/// normalizes label definitions and generates multi-level exit labels
    2425void fixLabels( ast::TranslationUnit & translationUnit );
     26
    2527}
    2628
  • src/ControlStruct/ForExprMutator.cc

    rf5a51db r97c215f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:26:12 2022
    13 // Update Count     : 16
     12// Last Modified On : Mon Mar 11 22:26:52 2019
     13// Update Count     : 14
    1414//
    1515
     
    4545                return hoist( forStmt, forStmt->initialization );
    4646        }
    47         Statement * ForExprMutator::postmutate( WhileDoStmt * whileDoStmt ) {
    48                 return hoist( whileDoStmt, whileDoStmt->initialization );
     47        Statement * ForExprMutator::postmutate( WhileStmt * whileStmt ) {
     48                return hoist( whileStmt, whileStmt->initialization );
    4949        }
    5050} // namespace ControlStruct
  • src/ControlStruct/ForExprMutator.h

    rf5a51db r97c215f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:18:50 2022
    13 // Update Count     : 7
     12// Last Modified On : Thu Aug 17 15:32:48 2017
     13// Update Count     : 5
    1414//
    1515
     
    1818class IfStmt;
    1919class ForStmt;
    20 class WhileDoStmt;
     20class WhileStmt;
    2121class Statement;
    2222
     
    2424        class ForExprMutator {
    2525          public:
    26                 Statement * postmutate( IfStmt * );
    27                 Statement * postmutate( ForStmt * );
    28                 Statement * postmutate( WhileDoStmt * );
     26                Statement *postmutate( IfStmt * );
     27                Statement *postmutate( ForStmt * );
     28                Statement *postmutate( WhileStmt * );
    2929        };
    3030} // namespace ControlStruct
  • src/ControlStruct/LabelFixer.cc

    rf5a51db r97c215f  
    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 : Tue Feb  1 09:12:09 2022
    13 // Update Count     : 162
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Jan 21 10:32:00 2020
     13// Update Count     : 160
    1414//
    1515
     
    2727
    2828namespace ControlStruct {
    29 bool LabelFixer::Entry::insideLoop() {
    30         return ( dynamic_cast< ForStmt * > ( definition ) ||
    31                 dynamic_cast< WhileDoStmt * > ( definition )  );
    32 }
     29        bool LabelFixer::Entry::insideLoop() {
     30                return ( dynamic_cast< ForStmt * > ( definition ) ||
     31                        dynamic_cast< WhileStmt * > ( definition )  );
     32        }
    3333
    34 LabelFixer::LabelFixer( LabelGenerator * gen ) : generator ( gen ) {
    35         if ( generator == 0 )
    36                 generator = LabelGenerator::getGenerator();
    37 }
     34        LabelFixer::LabelFixer( LabelGenerator * gen ) : generator ( gen ) {
     35                if ( generator == 0 )
     36                        generator = LabelGenerator::getGenerator();
     37        }
    3838
    39 void LabelFixer::previsit( FunctionDecl * ) {
    40         // need to go into a nested function in a fresh state
    41         GuardValue( labelTable );
    42         labelTable.clear();
    43 }
     39        void LabelFixer::previsit( FunctionDecl * ) {
     40                // need to go into a nested function in a fresh state
     41                GuardValue( labelTable );
     42                labelTable.clear();
     43        }
    4444
    45 void LabelFixer::postvisit( FunctionDecl * functionDecl ) {
    46         PassVisitor<MultiLevelExitMutator> mlem( resolveJumps(), generator );
    47         // We start in the body so we can stop when we hit another FunctionDecl.
    48         maybeMutate( functionDecl->statements, mlem );
    49 }
     45        void LabelFixer::postvisit( FunctionDecl * functionDecl ) {
     46                PassVisitor<MultiLevelExitMutator> mlem( resolveJumps(), generator );
     47                // We start in the body so we can stop when we hit another FunctionDecl.
     48                maybeMutate( functionDecl->statements, mlem );
     49        }
    5050
    51 // prune to at most one label definition for each statement
    52 void LabelFixer::previsit( Statement * stmt ) {
    53         std::list< Label > &labels = stmt->get_labels();
     51        // prune to at most one label definition for each statement
     52        void LabelFixer::previsit( Statement * stmt ) {
     53                std::list< Label > &labels = stmt->get_labels();
    5454
    55         if ( ! labels.empty() ) {
    56                 // only remember one label for each statement
    57                 Label current = setLabelsDef( labels, stmt );
    58         } // if
    59 }
     55                if ( ! labels.empty() ) {
     56                        // only remember one label for each statement
     57                        Label current = setLabelsDef( labels, stmt );
     58                } // if
     59        }
    6060
    61 void LabelFixer::previsit( BranchStmt * branchStmt ) {
    62         previsit( ( Statement *)branchStmt );
     61        void LabelFixer::previsit( BranchStmt * branchStmt ) {
     62                previsit( ( Statement *)branchStmt );
    6363
    64         // for labeled branches, add an entry to the label table
    65         Label target = branchStmt->get_target();
    66         if ( target != "" ) {
    67                 setLabelsUsg( target, branchStmt );
     64                // for labeled branches, add an entry to the label table
     65                Label target = branchStmt->get_target();
     66                if ( target != "" ) {
     67                        setLabelsUsg( target, branchStmt );
     68                }
    6869        }
    69 }
    7070
    71 void LabelFixer::previsit( LabelAddressExpr * addrExpr ) {
    72         Label & target = addrExpr->arg;
    73         assert( target != "" );
    74         setLabelsUsg( target, addrExpr );
    75 }
     71        void LabelFixer::previsit( LabelAddressExpr * addrExpr ) {
     72                Label & target = addrExpr->arg;
     73                assert( target != "" );
     74                setLabelsUsg( target, addrExpr );
     75        }
    7676
    7777
    78 // Sets the definition of the labelTable entry to be the provided statement for every label in
    79 // the list parameter. Happens for every kind of statement.
    80 Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement * definition ) {
    81         assert( definition != 0 );
    82         assert( llabel.size() > 0 );
     78        // Sets the definition of the labelTable entry to be the provided statement for every label in
     79        // the list parameter. Happens for every kind of statement.
     80        Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement * definition ) {
     81                assert( definition != 0 );
     82                assert( llabel.size() > 0 );
    8383
    84         for ( std::list< Label >::iterator i = llabel.begin(); i != llabel.end(); i++ ) {
    85                 Label & l = *i;
    86                 l.set_statement( definition ); // attach statement to the label to be used later
    87                 if ( labelTable.find( l ) == labelTable.end() ) {
    88                         // All labels on this statement need to use the same entry,
    89                         // so this should only be created once.
    90                         // undefined and unused until now, add an entry
    91                         labelTable[ l ] = new Entry( definition );
    92                 } else if ( labelTable[ l ]->defined() ) {
    93                         // defined twice, error
    94                         SemanticError( l.get_statement()->location,
    95                                 "Duplicate definition of label: " + l.get_name() );
    96                 } else {
    97                         // used previously, but undefined until now -> link with this entry
    98                         // Question: Is changing objects important?
    99                         delete labelTable[ l ];
    100                         labelTable[ l ] = new Entry( definition );
    101                 } // if
    102         } // for
     84                for ( std::list< Label >::iterator i = llabel.begin(); i != llabel.end(); i++ ) {
     85                        Label & l = *i;
     86                        l.set_statement( definition ); // attach statement to the label to be used later
     87                        if ( labelTable.find( l ) == labelTable.end() ) {
     88                                // All labels on this statement need to use the same entry,
     89                                // so this should only be created once.
     90                                // undefined and unused until now, add an entry
     91                                labelTable[ l ] = new Entry( definition );
     92                        } else if ( labelTable[ l ]->defined() ) {
     93                                // defined twice, error
     94                                SemanticError( l.get_statement()->location,
     95                                        "Duplicate definition of label: " + l.get_name() );
     96                        } else {
     97                                // used previously, but undefined until now -> link with this entry
     98                                // Question: Is changing objects important?
     99                                delete labelTable[ l ];
     100                                labelTable[ l ] = new Entry( definition );
     101                        } // if
     102                } // for
    103103
    104         // Produce one of the labels attached to this statement to be temporarily used as the
    105         // canonical label.
    106         return labelTable[ llabel.front() ]->get_label();
    107 }
    108 
    109 // A label was used, add it to the table if it isn't already there
    110 template< typename UsageNode >
    111 void LabelFixer::setLabelsUsg( Label orgValue, UsageNode *use ) {
    112         assert( use != 0 );
    113 
    114         // add label with an unknown origin
    115         if ( labelTable.find( orgValue ) == labelTable.end() ) {
    116                 labelTable[ orgValue ] = new Entry( 0 );
    117         }
    118 }
    119 
    120 // Builds a table that maps a label to its defining statement.
    121 std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
    122         std::map< Label, Statement * > *ret = new std::map< Label, Statement * >();
    123         for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) {
    124                 if ( ! i->second->defined() ) {
    125                         SemanticError( i->first.get_statement()->location, "Use of undefined label: " + i->first.get_name() );
    126                 }
    127                 (*ret)[ i->first ] = i->second->get_definition();
     104                // Produce one of the labels attached to this statement to be temporarily used as the
     105                // canonical label.
     106                return labelTable[ llabel.front() ]->get_label();
    128107        }
    129108
    130         return ret;
    131 }
     109        // A label was used, add it to the table if it isn't already there
     110        template< typename UsageNode >
     111        void LabelFixer::setLabelsUsg( Label orgValue, UsageNode *use ) {
     112                assert( use != 0 );
     113
     114                // add label with an unknown origin
     115                if ( labelTable.find( orgValue ) == labelTable.end() ) {
     116                        labelTable[ orgValue ] = new Entry( 0 );
     117                }
     118        }
     119
     120        // Builds a table that maps a label to its defining statement.
     121        std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
     122                std::map< Label, Statement * > *ret = new std::map< Label, Statement * >();
     123                for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) {
     124                        if ( ! i->second->defined() ) {
     125                                SemanticError( i->first.get_statement()->location, "Use of undefined label: " + i->first.get_name() );
     126                        }
     127                        (*ret)[ i->first ] = i->second->get_definition();
     128                }
     129
     130                return ret;
     131        }
    132132}  // namespace ControlStruct
    133133
  • src/ControlStruct/LabelFixer.h

    rf5a51db r97c215f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 31 22:28:04 2022
    13 // Update Count     : 35
     12// Last Modified On : Sat Jul 22 09:17:24 2017
     13// Update Count     : 34
    1414//
    1515
     
    2626
    2727namespace ControlStruct {
    28 // normalizes label definitions and generates multi-level exit labels
    29 class LabelGenerator;
     28        /// normalizes label definitions and generates multi-level exit labels
     29        class LabelGenerator;
    3030
    31 class LabelFixer final : public WithGuards {
    32   public:
    33         LabelFixer( LabelGenerator *gen = 0 );
     31        class LabelFixer final : public WithGuards {
     32          public:
     33                LabelFixer( LabelGenerator *gen = 0 );
    3434
    35         std::map < Label, Statement * > *resolveJumps() throw ( SemanticErrorException );
     35                std::map < Label, Statement * > *resolveJumps() throw ( SemanticErrorException );
    3636
    37         // Declarations
    38         void previsit( FunctionDecl *functionDecl );
    39         void postvisit( FunctionDecl *functionDecl );
     37                // Declarations
     38                void previsit( FunctionDecl *functionDecl );
     39                void postvisit( FunctionDecl *functionDecl );
    4040
    41         // Statements
    42         void previsit( Statement *stmt );
    43         void previsit( BranchStmt *branchStmt );
     41                // Statements
     42                void previsit( Statement *stmt );
     43                void previsit( BranchStmt *branchStmt );
    4444
    45         // Expressions
    46         void previsit( LabelAddressExpr *addrExpr );
     45                // Expressions
     46                void previsit( LabelAddressExpr *addrExpr );
    4747
    48         Label setLabelsDef( std::list< Label > &, Statement *definition );
    49         template< typename UsageNode >
    50         void setLabelsUsg( Label, UsageNode *usage = 0 );
    51 
    52   private:
    53         class Entry {
    54                 public:
    55                 Entry( Statement *to ) : definition( to ) {}
    56                 bool defined() { return ( definition != 0 ); }
    57                 bool insideLoop();
    58 
    59                 Label get_label() const { return label; }
    60                 void set_label( Label lab ) { label = lab; }
    61 
    62                 Statement *get_definition() const { return definition; }
    63                 void set_definition( Statement *def ) { definition = def; }
     48                Label setLabelsDef( std::list< Label > &, Statement *definition );
     49                template< typename UsageNode >
     50                void setLabelsUsg( Label, UsageNode *usage = 0 );
    6451
    6552          private:
    66                 Label label;
    67                 Statement *definition;
     53                class Entry {
     54                        public:
     55                        Entry( Statement *to ) : definition( to ) {}
     56                        bool defined() { return ( definition != 0 ); }
     57                        bool insideLoop();
     58
     59                        Label get_label() const { return label; }
     60                        void set_label( Label lab ) { label = lab; }
     61
     62                        Statement *get_definition() const { return definition; }
     63                        void set_definition( Statement *def ) { definition = def; }
     64
     65                  private:
     66                        Label label;
     67                        Statement *definition;
     68                };
     69
     70                std::map < Label, Entry *> labelTable;
     71                LabelGenerator *generator;
    6872        };
    69 
    70         std::map < Label, Entry *> labelTable;
    71         LabelGenerator *generator;
    72 };
    7373} // namespace ControlStruct
    7474
  • src/ControlStruct/LabelGenerator.cc

    rf5a51db r97c215f  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 31 22:30:26 2022
    13 // Update Count     : 28
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  8 10:18:00 2021
     13// Update Count     : 17
    1414//
    1515
     
    1717#include <sstream>              // for ostringstream
    1818#include <list>                 // for list
    19 using namespace std;
    2019
    2120#include "LabelGenerator.h"
    2221
     22#include "AST/Attribute.hpp"
     23#include "AST/Label.hpp"
     24#include "AST/Stmt.hpp"
    2325#include "SynTree/Attribute.h"  // for Attribute
    2426#include "SynTree/Label.h"      // for Label, operator<<
     
    2628
    2729namespace ControlStruct {
     30
    2831int LabelGenerator::current = 0;
    2932LabelGenerator * LabelGenerator::labelGenerator = nullptr;
    3033
    31 LabelGenerator * LabelGenerator::getGenerator() {
    32         if ( LabelGenerator::labelGenerator == 0 )
    33                 LabelGenerator::labelGenerator = new LabelGenerator();
    34         return labelGenerator;
     34        LabelGenerator * LabelGenerator::getGenerator() {
     35                if ( LabelGenerator::labelGenerator == 0 )
     36                        LabelGenerator::labelGenerator = new LabelGenerator();
     37                return labelGenerator;
     38        }
     39
     40        Label LabelGenerator::newLabel( std::string suffix, Statement * stmt ) {
     41                std::ostringstream os;
     42                os << "__L" << current++ << "__" << suffix;
     43                if ( stmt && ! stmt->get_labels().empty() ) {
     44                        os << "_" << stmt->get_labels().front() << "__";
     45                } // if
     46                std::string ret = os.str();
     47                Label l( ret );
     48                l.get_attributes().push_back( new Attribute("unused") );
     49                return l;
     50        }
     51
     52ast::Label LabelGenerator::newLabel(
     53                const std::string & suffix, const ast::Stmt * stmt ) {
     54        assert( stmt );
     55
     56        std::ostringstream os;
     57        os << "__L" << current++ << "__" << suffix;
     58        if ( stmt && !stmt->labels.empty() ) {
     59                os << "_" << stmt->labels.front() << "__";
     60        }
     61        ast::Label ret_label( stmt->location, os.str() );
     62        ret_label.attributes.push_back( new ast::Attribute( "unused" ) );
     63        return ret_label;
    3564}
    3665
    37 Label LabelGenerator::newLabel( string suffix, Statement * stmt ) {
    38         ostringstream os;
    39         os << "__L_OLD" << current++ << "__" << suffix;
    40         if ( stmt && ! stmt->get_labels().empty() ) {
    41                 os << "_" << stmt->get_labels().front() << "__";
    42         } // if
    43         string ret = os.str();
    44         Label l( ret );
    45         l.get_attributes().push_back( new Attribute( "unused" ) );
    46         return l;
    47 }
    4866} // namespace ControlStruct
    4967
    5068// Local Variables: //
     69// tab-width: 4 //
    5170// mode: c++ //
     71// compile-command: "make install" //
    5272// End: //
  • src/ControlStruct/LabelGenerator.h

    rf5a51db r97c215f  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 31 22:30:10 2022
    13 // Update Count     : 16
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  8 10:16:00 2021
     13// Update Count     : 8
    1414//
    1515
     
    2121
    2222class Statement;
    23 
    2423namespace ast {
    25 class Stmt;
    26 class Label;
     24        class Stmt;
     25        class Label;
    2726}
    2827
    2928namespace ControlStruct {
     29
    3030class LabelGenerator {
    3131        static int current;
    3232        static LabelGenerator *labelGenerator;
    33   protected:
     33protected:
    3434        LabelGenerator() {}
    35   public:
     35public:
    3636        static LabelGenerator *getGenerator();
    3737        static Label newLabel(std::string suffix, Statement * stmt = nullptr);
     38        static ast::Label newLabel( const std::string&, const ast::Stmt * );
     39        static void reset() { current = 0; }
     40        static void rewind() { current--; }
    3841};
     42
    3943} // namespace ControlStruct
    4044
  • src/ControlStruct/MLEMutator.cc

    rf5a51db r97c215f  
    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 : Wed Feb  2 20:18:57 2022
    13 // Update Count     : 227
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jan 22 11:50:00 2020
     13// Update Count     : 223
    1414//
    1515
     
    3939        namespace {
    4040                bool isLoop( const MultiLevelExitMutator::Entry & e ) {
    41                         return dynamic_cast< WhileDoStmt * >( e.get_controlStructure() )
     41                        return dynamic_cast< WhileStmt * >( e.get_controlStructure() )
    4242                                || dynamic_cast< ForStmt * >( e.get_controlStructure() );
    4343                }
     
    136136                        }
    137137                }
    138                 assertf( false, "CFA internal error: could not find label '%s' on statement %s",
     138                assertf( false, "Could not find label '%s' on statement %s",
    139139                        originalTarget.get_name().c_str(), toString( stmt ).c_str() );
    140140        }
     
    295295        }
    296296
    297         void MultiLevelExitMutator::premutate( WhileDoStmt * whileDoStmt ) {
    298                 return prehandleLoopStmt( whileDoStmt );
     297        void MultiLevelExitMutator::premutate( WhileStmt * whileStmt ) {
     298                return prehandleLoopStmt( whileStmt );
    299299        }
    300300
     
    303303        }
    304304
    305         Statement * MultiLevelExitMutator::postmutate( WhileDoStmt * whileDoStmt ) {
    306                 return posthandleLoopStmt( whileDoStmt );
     305        Statement * MultiLevelExitMutator::postmutate( WhileStmt * whileStmt ) {
     306                return posthandleLoopStmt( whileStmt );
    307307        }
    308308
     
    395395                }
    396396                assert( ! enclosingControlStructures.empty() );
    397                 assertf( dynamic_cast<SwitchStmt *>( enclosingControlStructures.back().get_controlStructure() ),
    398                                  "CFA internal error: control structure enclosing a case clause must be a switch, but is: %s",
    399                                  toCString( enclosingControlStructures.back().get_controlStructure() ) );
     397                assertf( dynamic_cast<SwitchStmt *>( enclosingControlStructures.back().get_controlStructure() ), "Control structure enclosing a case clause must be a switch, but is: %s", toCString( enclosingControlStructures.back().get_controlStructure() ) );
    400398                if ( caseStmt->isDefault() ) {
    401399                        if ( enclosingControlStructures.back().isFallDefaultUsed() ) {
  • src/ControlStruct/MLEMutator.h

    rf5a51db r97c215f  
    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 : Tue Feb  1 09:27:24 2022
    13 // Update Count     : 50
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jan 22 11:50:00 2020
     13// Update Count     : 48
    1414//
    1515
     
    4242                void premutate( CompoundStmt *cmpndStmt );
    4343                Statement * postmutate( BranchStmt *branchStmt ) throw ( SemanticErrorException );
    44                 void premutate( WhileDoStmt *whileDoStmt );
    45                 Statement * postmutate( WhileDoStmt *whileDoStmt );
     44                void premutate( WhileStmt *whileStmt );
     45                Statement * postmutate( WhileStmt *whileStmt );
    4646                void premutate( ForStmt *forStmt );
    4747                Statement * postmutate( ForStmt *forStmt );
     
    6767                                stmt( stmt ), breakExit( breakExit ), contExit( contExit ) {}
    6868
    69                         explicit Entry( WhileDoStmt *stmt, Label breakExit, Label contExit ) :
     69                        explicit Entry( WhileStmt *stmt, Label breakExit, Label contExit ) :
    7070                                stmt( stmt ), breakExit( breakExit ), contExit( contExit ) {}
    7171
  • src/ControlStruct/MultiLevelExit.cpp

    rf5a51db r97c215f  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Nov  1 13:48:00 2021
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  2 23:07:54 2022
    13 // Update Count     : 33
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  8 10:56:00 2021
     13// Update Count     : 2
    1414//
    1515
     
    1818#include "AST/Pass.hpp"
    1919#include "AST/Stmt.hpp"
    20 #include "LabelGeneratorNew.hpp"
     20#include "ControlStruct/LabelGenerator.h"
    2121
    2222#include <set>
    23 using namespace std;
    24 using namespace ast;
    2523
    2624namespace ControlStruct {
     25
     26namespace {
     27
    2728class Entry {
    28   public:
    29         const Stmt * stmt;
    30   private:
     29public:
     30        const ast::Stmt * stmt;
     31private:
    3132        // Organized like a manual ADT. Avoids creating a bunch of dead data.
    3233        struct Target {
    33                 Label label;
     34                ast::Label label;
    3435                bool used = false;
    35                 Target( const Label & label ) : label( label ) {}
     36                Target( const ast::Label & label ) : label( label ) {}
    3637                Target() : label( CodeLocation() ) {}
    3738        };
     
    4041
    4142        enum Kind {
    42                 ForStmtK, WhileDoStmtK, CompoundStmtK, IfStmtK, CaseStmtK, SwitchStmtK, TryStmtK
     43                ForStmt, WhileStmt, CompoundStmt, IfStmt, CaseStmt, SwitchStmt, TryStmt
    4344        } kind;
    4445
    4546        bool fallDefaultValid = true;
    4647
    47         static Label & useTarget( Target & target ) {
     48        static ast::Label & useTarget( Target & target ) {
    4849                target.used = true;
    4950                return target.label;
    5051        }
    51   public:
    52         Entry( const ForStmt * stmt, Label breakExit, Label contExit ) :
    53                 stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( ForStmtK ) {}
    54         Entry( const WhileDoStmt * stmt, Label breakExit, Label contExit ) :
    55                 stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( WhileDoStmtK ) {}
    56         Entry( const CompoundStmt *stmt, Label breakExit ) :
    57                 stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( CompoundStmtK ) {}
    58         Entry( const IfStmt *stmt, Label breakExit ) :
    59                 stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( IfStmtK ) {}
    60         Entry( const CaseStmt *stmt, Label fallExit ) :
    61                 stmt( stmt ), firstTarget( fallExit ), secondTarget(), kind( CaseStmtK ) {}
    62         Entry( const SwitchStmt *stmt, Label breakExit, Label fallDefaultExit ) :
    63                 stmt( stmt ), firstTarget( breakExit ), secondTarget( fallDefaultExit ), kind( SwitchStmtK ) {}
    64         Entry( const TryStmt *stmt, Label breakExit ) :
    65                 stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( TryStmtK ) {}
    66 
    67         bool isContTarget() const { return kind <= WhileDoStmtK; }
    68         bool isBreakTarget() const { return kind != CaseStmtK; }
    69         bool isFallTarget() const { return kind == CaseStmtK; }
    70         bool isFallDefaultTarget() const { return kind == SwitchStmtK; }
    71 
    72         // These routines set a target as being "used" by a BranchStmt
    73         Label useContExit() { assert( kind <= WhileDoStmtK ); return useTarget(secondTarget); }
    74         Label useBreakExit() { assert( kind != CaseStmtK ); return useTarget(firstTarget); }
    75         Label useFallExit() { assert( kind == CaseStmtK );  return useTarget(firstTarget); }
    76         Label useFallDefaultExit() { assert( kind == SwitchStmtK ); return useTarget(secondTarget); }
    77 
    78         // These routines check if a specific label for a statement is used by a BranchStmt
    79         bool isContUsed() const { assert( kind <= WhileDoStmtK ); return secondTarget.used; }
    80         bool isBreakUsed() const { assert( kind != CaseStmtK ); return firstTarget.used; }
    81         bool isFallUsed() const { assert( kind == CaseStmtK ); return firstTarget.used; }
    82         bool isFallDefaultUsed() const { assert( kind == SwitchStmtK ); return secondTarget.used; }
     52
     53public:
     54        Entry( const ast::ForStmt * stmt, ast::Label breakExit, ast::Label contExit ) :
     55                stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( ForStmt ) {}
     56        Entry( const ast::WhileStmt * stmt, ast::Label breakExit, ast::Label contExit ) :
     57                stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( WhileStmt ) {}
     58        Entry( const ast::CompoundStmt *stmt, ast::Label breakExit ) :
     59                stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( CompoundStmt ) {}
     60        Entry( const ast::IfStmt *stmt, ast::Label breakExit ) :
     61                stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( IfStmt ) {}
     62        Entry( const ast::CaseStmt *stmt, ast::Label fallExit ) :
     63                stmt( stmt ), firstTarget( fallExit ), secondTarget(), kind( CaseStmt ) {}
     64        Entry( const ast::SwitchStmt *stmt, ast::Label breakExit, ast::Label fallDefaultExit ) :
     65                stmt( stmt ), firstTarget( breakExit ), secondTarget( fallDefaultExit ), kind( SwitchStmt ) {}
     66        Entry( const ast::TryStmt *stmt, ast::Label breakExit ) :
     67                stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( TryStmt ) {}
     68
     69        bool isContTarget() const { return kind <= WhileStmt; }
     70        bool isBreakTarget() const { return CaseStmt != kind; }
     71        bool isFallTarget() const { return CaseStmt == kind; }
     72        bool isFallDefaultTarget() const { return SwitchStmt == kind; }
     73
     74        ast::Label useContExit() { assert( kind <= WhileStmt ); return useTarget(secondTarget); }
     75        ast::Label useBreakExit() { assert( CaseStmt != kind ); return useTarget(firstTarget); }
     76        ast::Label useFallExit() { assert( CaseStmt == kind );  return useTarget(firstTarget); }
     77        ast::Label useFallDefaultExit() { assert( SwitchStmt == kind ); return useTarget(secondTarget); }
     78
     79        bool isContUsed() const { assert( kind <= WhileStmt ); return secondTarget.used; }
     80        bool isBreakUsed() const { assert( CaseStmt != kind ); return firstTarget.used; }
     81        bool isFallUsed() const { assert( CaseStmt == kind ); return firstTarget.used; }
     82        bool isFallDefaultUsed() const { assert( SwitchStmt == kind ); return secondTarget.used; }
    8383        void seenDefault() { fallDefaultValid = false; }
    8484        bool isFallDefaultValid() const { return fallDefaultValid; }
    8585};
    8686
    87 // Helper predicates used in find_if calls (it doesn't take methods):
     87// Helper predicates used in std::find_if calls (it doesn't take methods):
    8888bool isBreakTarget( const Entry & entry ) {
    8989        return entry.isBreakTarget();
     
    103103
    104104struct MultiLevelExitCore final :
    105         public WithVisitorRef<MultiLevelExitCore>,
    106         public WithShortCircuiting, public WithGuards {
     105                public ast::WithVisitorRef<MultiLevelExitCore>,
     106                public ast::WithShortCircuiting, public ast::WithGuards {
    107107        MultiLevelExitCore( const LabelToStmt & lt );
    108108
    109         void previsit( const FunctionDecl * );
    110 
    111         const CompoundStmt * previsit( const CompoundStmt * );
    112         const BranchStmt * postvisit( const BranchStmt * );
    113         void previsit( const WhileDoStmt * );
    114         const WhileDoStmt * postvisit( const WhileDoStmt * );
    115         void previsit( const ForStmt * );
    116         const ForStmt * postvisit( const ForStmt * );
    117         const CaseStmt * previsit( const CaseStmt * );
    118         void previsit( const IfStmt * );
    119         const IfStmt * postvisit( const IfStmt * );
    120         void previsit( const SwitchStmt * );
    121         const SwitchStmt * postvisit( const SwitchStmt * );
    122         void previsit( const ReturnStmt * );
    123         void previsit( const TryStmt * );
    124         void postvisit( const TryStmt * );
    125         void previsit( const FinallyStmt * );
    126 
    127         const Stmt * mutateLoop( const Stmt * body, Entry& );
     109        void previsit( const ast::FunctionDecl * );
     110
     111        const ast::CompoundStmt * previsit( const ast::CompoundStmt * );
     112        const ast::BranchStmt * postvisit( const ast::BranchStmt * );
     113        void previsit( const ast::WhileStmt * );
     114        const ast::WhileStmt * postvisit( const ast::WhileStmt * );
     115        void previsit( const ast::ForStmt * );
     116        const ast::ForStmt * postvisit( const ast::ForStmt * );
     117        const ast::CaseStmt * previsit( const ast::CaseStmt * );
     118        void previsit( const ast::IfStmt * );
     119        const ast::IfStmt * postvisit( const ast::IfStmt * );
     120        void previsit( const ast::SwitchStmt * );
     121        const ast::SwitchStmt * postvisit( const ast::SwitchStmt * );
     122        void previsit( const ast::ReturnStmt * );
     123        void previsit( const ast::TryStmt * );
     124        void postvisit( const ast::TryStmt * );
     125        void previsit( const ast::FinallyStmt * );
     126
     127        const ast::Stmt * mutateLoop( const ast::Stmt * body, Entry& );
    128128
    129129        const LabelToStmt & target_table;
    130         set<Label> fallthrough_labels;
    131         vector<Entry> enclosing_control_structures;
    132         Label break_label;
     130        std::set<ast::Label> fallthrough_labels;
     131        std::vector<Entry> enclosing_control_structures;
     132        ast::Label break_label;
    133133        bool inFinally;
    134134
     
    138138        const LoopNode * posthandleLoopStmt( const LoopNode * loopStmt );
    139139
    140         list<ptr<Stmt>> fixBlock(
    141                 const list<ptr<Stmt>> & kids, bool caseClause );
     140        std::list<ast::ptr<ast::Stmt>> fixBlock(
     141                const std::list<ast::ptr<ast::Stmt>> & kids, bool caseClause );
    142142
    143143        template<typename UnaryPredicate>
    144144        auto findEnclosingControlStructure( UnaryPredicate pred ) {
    145                 return find_if( enclosing_control_structures.rbegin(),
    146                                                 enclosing_control_structures.rend(), pred );
     145                return std::find_if( enclosing_control_structures.rbegin(),
     146                        enclosing_control_structures.rend(), pred );
    147147        }
    148148};
    149149
    150 NullStmt * labelledNullStmt(
    151         const CodeLocation & cl, const Label & label ) {
    152         return new NullStmt( cl, vector<Label>{ label } );
     150ast::NullStmt * labelledNullStmt(
     151                const CodeLocation & cl, const ast::Label & label ) {
     152        return new ast::NullStmt( cl, std::vector<ast::Label>{ label } );
    153153}
    154154
     
    158158{}
    159159
    160 void MultiLevelExitCore::previsit( const FunctionDecl * ) {
     160void MultiLevelExitCore::previsit( const ast::FunctionDecl * ) {
    161161        visit_children = false;
    162162}
    163163
    164 const CompoundStmt * MultiLevelExitCore::previsit(
    165         const CompoundStmt * stmt ) {
     164const ast::CompoundStmt * MultiLevelExitCore::previsit(
     165                const ast::CompoundStmt * stmt ) {
    166166        visit_children = false;
    167 
    168         // if the stmt is labelled then generate a label to check in postvisit if the label is used
    169         bool isLabeled = ! stmt->labels.empty();
     167        bool isLabeled = !stmt->labels.empty();
    170168        if ( isLabeled ) {
    171                 Label breakLabel = newLabel( "blockBreak", stmt );
     169                ast::Label breakLabel = LabelGenerator::newLabel( "blockBreak", stmt );
    172170                enclosing_control_structures.emplace_back( stmt, breakLabel );
    173171                GuardAction( [this]() { enclosing_control_structures.pop_back(); } );
    174172        }
    175173
    176         auto mutStmt = mutate( stmt );
     174        auto mutStmt = ast::mutate( stmt );
    177175        // A child statement may set the break label.
    178         mutStmt->kids = move( fixBlock( stmt->kids, false ) );
     176        mutStmt->kids = std::move( fixBlock( stmt->kids, false ) );
    179177
    180178        if ( isLabeled ) {
    181                 assert( ! enclosing_control_structures.empty() );
     179                assert( !enclosing_control_structures.empty() );
    182180                Entry & entry = enclosing_control_structures.back();
    183                 if ( ! entry.useBreakExit().empty() ) {
     181                if ( !entry.useBreakExit().empty() ) {
    184182                        break_label = entry.useBreakExit();
    185183                }
     
    189187
    190188size_t getUnusedIndex(
    191         const Stmt * stmt, const Label & originalTarget ) {
     189                const ast::Stmt * stmt, const ast::Label & originalTarget ) {
    192190        const size_t size = stmt->labels.size();
    193191
    194         // If the label is empty, do not add unused attribute.
    195   if ( originalTarget.empty() ) return size;
     192        // If the label is empty, we can skip adding the unused attribute:
     193        if ( originalTarget.empty() ) return size;
    196194
    197195        // Search for a label that matches the originalTarget.
    198196        for ( size_t i = 0 ; i < size ; ++i ) {
    199                 const Label & label = stmt->labels[i];
     197                const ast::Label & label = stmt->labels[i];
    200198                if ( label == originalTarget ) {
    201                         for ( const Attribute * attr : label.attributes ) {
     199                        for ( const ast::Attribute * attr : label.attributes ) {
    202200                                if ( attr->name == "unused" ) return size;
    203201                        }
     
    205203                }
    206204        }
    207         assertf( false, "CFA internal error: could not find label '%s' on statement %s",
    208                          originalTarget.name.c_str(), toString( stmt ).c_str() );
    209 }
    210 
    211 const Stmt * addUnused(
    212         const Stmt * stmt, const Label & originalTarget ) {
     205        assertf( false, "Could not find label '%s' on statement %s",
     206                originalTarget.name.c_str(), toString( stmt ).c_str() );
     207}
     208
     209const ast::Stmt * addUnused(
     210                const ast::Stmt * stmt, const ast::Label & originalTarget ) {
    213211        size_t i = getUnusedIndex( stmt, originalTarget );
    214212        if ( i == stmt->labels.size() ) {
    215213                return stmt;
    216214        }
    217         Stmt * mutStmt = mutate( stmt );
    218         mutStmt->labels[i].attributes.push_back( new Attribute( "unused" ) );
     215        ast::Stmt * mutStmt = ast::mutate( stmt );
     216        mutStmt->labels[i].attributes.push_back( new ast::Attribute( "unused" ) );
    219217        return mutStmt;
    220218}
    221219
    222 // This routine updates targets on enclosing control structures to indicate which
    223 //     label is used by the BranchStmt that is passed
    224 const BranchStmt * MultiLevelExitCore::postvisit( const BranchStmt * stmt ) {
    225         vector<Entry>::reverse_iterator targetEntry =
     220const ast::BranchStmt * MultiLevelExitCore::postvisit( const ast::BranchStmt * stmt ) {
     221        std::vector<Entry>::reverse_iterator targetEntry =
    226222                enclosing_control_structures.rend();
    227 
    228         // Labels on different stmts require different approaches to access
    229223        switch ( stmt->kind ) {
    230           case BranchStmt::Goto:
     224        case ast::BranchStmt::Goto:
    231225                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() ) {
    241                                           SemanticError( stmt->location,
    242                                                                          "'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){
    251                                           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'"),
    257                                                         " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "),
    258                                                         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: ",
    273                                                                                                                    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 subStmt : switchStmt->stmts ) {
    291                           const CaseStmt * caseStmt = subStmt.strict_as<CaseStmt>();
    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:
     226        case ast::BranchStmt::Continue:
     227        case ast::BranchStmt::Break: {
     228                bool isContinue = stmt->kind == ast::BranchStmt::Continue;
     229                // Handle unlabeled break and continue.
     230                if ( stmt->target.empty() ) {
     231                        if ( isContinue ) {
     232                                targetEntry = findEnclosingControlStructure( isContinueTarget );
     233                        } else {
     234                                if ( enclosing_control_structures.empty() ) {
     235                                        SemanticError( stmt->location,
     236                                                "'break' outside a loop, 'switch', or labelled block" );
     237                                }
     238                                targetEntry = findEnclosingControlStructure( isBreakTarget );
     239                        }
     240                // Handle labeled break and continue.
     241                } else {
     242                        // Lookup label in table to find attached control structure.
     243                        targetEntry = findEnclosingControlStructure(
     244                                [ targetStmt = target_table.at(stmt->target) ](auto entry){
     245                                        return entry.stmt == targetStmt;
     246                                } );
     247                }
     248                // Ensure that selected target is valid.
     249                if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && !isContinueTarget( *targetEntry ) ) ) {
     250                        SemanticError(
     251                                stmt->location,
     252                                toString( (isContinue ? "'continue'" : "'break'"),
     253                                        " target must be an enclosing ",
     254                                        (isContinue ? "loop: " : "control structure: "),
     255                                        stmt->originalTarget ) );
     256                }
     257                break;
     258        }
     259        case ast::BranchStmt::FallThrough: {
     260                targetEntry = findEnclosingControlStructure( isFallthroughTarget );
     261                // Check that target is valid.
     262                if ( targetEntry == enclosing_control_structures.rend() ) {
     263                        SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
     264                }
     265                if ( !stmt->target.empty() ) {
     266                        // Labelled fallthrough: target must be a valid fallthough label.
     267                        if ( !fallthrough_labels.count( stmt->target ) ) {
     268                                SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ", stmt->originalTarget ) );
     269                        }
     270                        return new ast::BranchStmt(
     271                                stmt->location, ast::BranchStmt::Goto, stmt->originalTarget );
     272                }
     273                break;
     274        }
     275        case ast::BranchStmt::FallThroughDefault: {
     276                targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget );
     277
     278                // Check that this is in a switch or choose statement.
     279                if ( targetEntry == enclosing_control_structures.rend() ) {
     280                        SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
     281                }
     282
     283                // Check that the switch or choose has a default clause.
     284                auto switchStmt = strict_dynamic_cast< const ast::SwitchStmt * >(
     285                        targetEntry->stmt );
     286                bool foundDefault = false;
     287                for ( auto subStmt : switchStmt->stmts ) {
     288                        const ast::CaseStmt * caseStmt = subStmt.strict_as<ast::CaseStmt>();
     289                        if ( caseStmt->isDefault() ) {
     290                                foundDefault = true;
     291                                break;
     292                        }
     293                }
     294                if ( !foundDefault ) {
     295                        SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose' control structure with a 'default' clause" );
     296                }
     297                break;
     298        }
     299        default:
    304300                assert( false );
    305301        }
    306302
    307         // Branch error checks: get the appropriate label name, which is always replaced.
    308         Label exitLabel( CodeLocation(), "" );
     303        // Branch error checks: get the appropriate label name:
     304        // (This label will always be replaced.)
     305        ast::Label exitLabel( CodeLocation(), "" );
    309306        switch ( stmt->kind ) {
    310           case BranchStmt::Break:
    311                 assert( ! targetEntry->useBreakExit().empty() );
     307        case ast::BranchStmt::Break:
     308                assert( !targetEntry->useBreakExit().empty() );
    312309                exitLabel = targetEntry->useBreakExit();
    313310                break;
    314           case BranchStmt::Continue:
    315                 assert( ! targetEntry->useContExit().empty() );
     311        case ast::BranchStmt::Continue:
     312                assert( !targetEntry->useContExit().empty() );
    316313                exitLabel = targetEntry->useContExit();
    317314                break;
    318           case BranchStmt::FallThrough:
    319                 assert( ! targetEntry->useFallExit().empty() );
     315        case ast::BranchStmt::FallThrough:
     316                assert( !targetEntry->useFallExit().empty() );
    320317                exitLabel = targetEntry->useFallExit();
    321318                break;
    322           case BranchStmt::FallThroughDefault:
    323                 assert( ! targetEntry->useFallDefaultExit().empty() );
     319        case ast::BranchStmt::FallThroughDefault:
     320                assert( !targetEntry->useFallDefaultExit().empty() );
    324321                exitLabel = targetEntry->useFallDefaultExit();
    325322                // Check that fallthrough default comes before the default clause.
    326                 if ( ! targetEntry->isFallDefaultValid() ) {
    327                         SemanticError( stmt->location, "'fallthrough default' must precede the 'default' clause" );
     323                if ( !targetEntry->isFallDefaultValid() ) {
     324                        SemanticError( stmt->location,
     325                                "'fallthrough default' must precede the 'default' clause" );
    328326                }
    329327                break;
    330           default:
     328        default:
    331329                assert(0);
    332330        }
     
    335333        targetEntry->stmt = addUnused( targetEntry->stmt, stmt->originalTarget );
    336334
    337         // Replace with goto to make later passes more uniform.
    338         return new BranchStmt( stmt->location, BranchStmt::Goto, exitLabel );
    339 }
    340 
    341 void MultiLevelExitCore::previsit( const WhileDoStmt * stmt ) {
     335        // Replace this with a goto to make later passes more uniform.
     336        return new ast::BranchStmt( stmt->location, ast::BranchStmt::Goto, exitLabel );
     337}
     338
     339void MultiLevelExitCore::previsit( const ast::WhileStmt * stmt ) {
    342340        return prehandleLoopStmt( stmt );
    343341}
    344342
    345 const WhileDoStmt * MultiLevelExitCore::postvisit( const WhileDoStmt * stmt ) {
     343const ast::WhileStmt * MultiLevelExitCore::postvisit( const ast::WhileStmt * stmt ) {
    346344        return posthandleLoopStmt( stmt );
    347345}
    348346
    349 void MultiLevelExitCore::previsit( const ForStmt * stmt ) {
     347void MultiLevelExitCore::previsit( const ast::ForStmt * stmt ) {
    350348        return prehandleLoopStmt( stmt );
    351349}
    352350
    353 const ForStmt * MultiLevelExitCore::postvisit( const ForStmt * stmt ) {
     351const ast::ForStmt * MultiLevelExitCore::postvisit( const ast::ForStmt * stmt ) {
    354352        return posthandleLoopStmt( stmt );
    355353}
     
    357355// Mimic what the built-in push_front would do anyways. It is O(n).
    358356void push_front(
    359         vector<ptr<Stmt>> & vec, const Stmt * element ) {
     357                std::vector<ast::ptr<ast::Stmt>> & vec, const ast::Stmt * element ) {
    360358        vec.emplace_back( nullptr );
    361359        for ( size_t i = vec.size() - 1 ; 0 < i ; --i ) {
    362                 vec[ i ] = move( vec[ i - 1 ] );
     360                vec[ i ] = std::move( vec[ i - 1 ] );
    363361        }
    364362        vec[ 0 ] = element;
    365363}
    366364
    367 const CaseStmt * MultiLevelExitCore::previsit( const CaseStmt * stmt ) {
     365const ast::CaseStmt * MultiLevelExitCore::previsit( const ast::CaseStmt * stmt ) {
    368366        visit_children = false;
    369367
    370         // If default, mark seen.
     368        // If it is the default, mark the default as seen.
    371369        if ( stmt->isDefault() ) {
    372                 assert( ! enclosing_control_structures.empty() );
     370                assert( !enclosing_control_structures.empty() );
    373371                enclosing_control_structures.back().seenDefault();
    374372        }
    375373
    376374        // The cond may not exist, but if it does update it now.
    377         visitor->maybe_accept( stmt, &CaseStmt::cond );
     375        visitor->maybe_accept( stmt, &ast::CaseStmt::cond );
    378376
    379377        // Just save the mutated node for simplicity.
    380         CaseStmt * mutStmt = mutate( stmt );
    381 
    382         Label fallLabel = newLabel( "fallThrough", stmt );
    383         if ( ! mutStmt->stmts.empty() ) {
     378        ast::CaseStmt * mutStmt = ast::mutate( stmt );
     379
     380        ast::Label fallLabel = LabelGenerator::newLabel( "fallThrough", stmt );
     381        if ( !mutStmt->stmts.empty() ) {
    384382                // Ensure that the stack isn't corrupted by exceptions in fixBlock.
    385383                auto guard = makeFuncGuard(
    386384                        [&](){ enclosing_control_structures.emplace_back( mutStmt, fallLabel ); },
    387385                        [this](){ enclosing_control_structures.pop_back(); }
    388                         );
     386                );
    389387
    390388                // These should already be in a block.
    391                 auto block = mutate( mutStmt->stmts.front().strict_as<CompoundStmt>() );
     389                auto block = ast::mutate( mutStmt->stmts.front().strict_as<ast::CompoundStmt>() );
    392390                block->kids = fixBlock( block->kids, true );
    393391
    394392                // Add fallthrough label if necessary.
    395                 assert( ! enclosing_control_structures.empty() );
     393                assert( !enclosing_control_structures.empty() );
    396394                Entry & entry = enclosing_control_structures.back();
    397395                if ( entry.isFallUsed() ) {
    398                         mutStmt->stmts.push_back( labelledNullStmt( mutStmt->location, entry.useFallExit() ) );
    399                 }
    400         }
    401         assert( ! enclosing_control_structures.empty() );
     396                        mutStmt->stmts.push_back(
     397                                labelledNullStmt( mutStmt->location, entry.useFallExit() ) );
     398                }
     399        }
     400        assert( !enclosing_control_structures.empty() );
    402401        Entry & entry = enclosing_control_structures.back();
    403         assertf( dynamic_cast< const SwitchStmt * >( entry.stmt ),
    404                          "CFA internal error: control structure enclosing a case clause must be a switch, but is: %s",
    405                          toString( entry.stmt ).c_str() );
     402        assertf( dynamic_cast< const ast::SwitchStmt * >( entry.stmt ),
     403                "Control structure enclosing a case clause must be a switch, but is: %s",
     404                toString( entry.stmt ).c_str() );
    406405        if ( mutStmt->isDefault() ) {
    407406                if ( entry.isFallDefaultUsed() ) {
    408407                        // Add fallthrough default label if necessary.
    409                         push_front( mutStmt->stmts, labelledNullStmt( stmt->location, entry.useFallDefaultExit() ) );
     408                        push_front( mutStmt->stmts, labelledNullStmt(
     409                                stmt->location, entry.useFallDefaultExit()
     410                        ) );
    410411                }
    411412        }
     
    413414}
    414415
    415 void MultiLevelExitCore::previsit( const IfStmt * stmt ) {
    416         bool labeledBlock = ! stmt->labels.empty();
     416void MultiLevelExitCore::previsit( const ast::IfStmt * stmt ) {
     417        bool labeledBlock = !stmt->labels.empty();
    417418        if ( labeledBlock ) {
    418                 Label breakLabel = newLabel( "blockBreak", stmt );
     419                ast::Label breakLabel = LabelGenerator::newLabel( "blockBreak", stmt );
    419420                enclosing_control_structures.emplace_back( stmt, breakLabel );
    420421                GuardAction( [this](){ enclosing_control_structures.pop_back(); } );
     
    422423}
    423424
    424 const IfStmt * MultiLevelExitCore::postvisit( const IfStmt * stmt ) {
    425         bool labeledBlock = ! stmt->labels.empty();
     425const ast::IfStmt * MultiLevelExitCore::postvisit( const ast::IfStmt * stmt ) {
     426        bool labeledBlock = !stmt->labels.empty();
    426427        if ( labeledBlock ) {
    427428                auto this_label = enclosing_control_structures.back().useBreakExit();
    428                 if ( ! this_label.empty() ) {
     429                if ( !this_label.empty() ) {
    429430                        break_label = this_label;
    430431                }
     
    433434}
    434435
    435 bool isDefaultCase( const ptr<Stmt> & stmt ) {
    436         const CaseStmt * caseStmt = stmt.strict_as<CaseStmt>();
     436bool isDefaultCase( const ast::ptr<ast::Stmt> & stmt ) {
     437        const ast::CaseStmt * caseStmt = stmt.strict_as<ast::CaseStmt>();
    437438        return caseStmt->isDefault();
    438439}
    439440
    440 void MultiLevelExitCore::previsit( const SwitchStmt * stmt ) {
    441         Label label = newLabel( "switchBreak", stmt );
    442         auto it = find_if( stmt->stmts.rbegin(), stmt->stmts.rend(), isDefaultCase );
    443 
    444         const CaseStmt * defaultCase = it != stmt->stmts.rend() ? (it)->strict_as<CaseStmt>() : nullptr;
    445         Label defaultLabel = defaultCase ? newLabel( "fallThroughDefault", defaultCase ) : Label( stmt->location, "" );
     441void MultiLevelExitCore::previsit( const ast::SwitchStmt * stmt ) {
     442        ast::Label label = LabelGenerator::newLabel( "switchBreak", stmt );
     443        auto it = std::find_if( stmt->stmts.rbegin(), stmt->stmts.rend(), isDefaultCase );
     444
     445        const ast::CaseStmt * defaultCase = it != stmt->stmts.rend()
     446                ? (it)->strict_as<ast::CaseStmt>() : nullptr;
     447        ast::Label defaultLabel = defaultCase
     448                ? LabelGenerator::newLabel( "fallThroughDefault", defaultCase )
     449                : ast::Label( stmt->location, "" );
    446450        enclosing_control_structures.emplace_back( stmt, label, defaultLabel );
    447451        GuardAction( [this]() { enclosing_control_structures.pop_back(); } );
    448452
    449         // Collect valid labels for fallthrough. It starts with all labels at this level, then remove as each is seen during
    450         // traversal.
    451         for ( const Stmt * stmt : stmt->stmts ) {
    452                 auto * caseStmt = strict_dynamic_cast< const CaseStmt * >( stmt );
     453        // Collect valid labels for fallthrough. It starts with all labels at
     454        // this level, then removed as we see them in traversal.
     455        for ( const ast::Stmt * stmt : stmt->stmts ) {
     456                auto * caseStmt = strict_dynamic_cast< const ast::CaseStmt * >( stmt );
    453457                if ( caseStmt->stmts.empty() ) continue;
    454                 auto block = caseStmt->stmts.front().strict_as<CompoundStmt>();
    455                 for ( const Stmt * stmt : block->kids ) {
    456                         for ( const Label & l : stmt->labels ) {
     458                auto block = caseStmt->stmts.front().strict_as<ast::CompoundStmt>();
     459                for ( const ast::Stmt * stmt : block->kids ) {
     460                        for ( const ast::Label & l : stmt->labels ) {
    457461                                fallthrough_labels.insert( l );
    458462                        }
     
    461465}
    462466
    463 const SwitchStmt * MultiLevelExitCore::postvisit( const SwitchStmt * stmt ) {
    464         assert( ! enclosing_control_structures.empty() );
     467const ast::SwitchStmt * MultiLevelExitCore::postvisit( const ast::SwitchStmt * stmt ) {
     468        assert( !enclosing_control_structures.empty() );
    465469        Entry & entry = enclosing_control_structures.back();
    466470        assert( entry.stmt == stmt );
    467471
    468         // Only run to generate the break label.
     472        // Only run if we need to generate the break label.
    469473        if ( entry.isBreakUsed() ) {
    470                 // To keep the switch statements uniform (all direct children of a SwitchStmt should be CastStmts), append the
    471                 // exit label and break to the last case, create a default case if no cases.
    472                 SwitchStmt * mutStmt = mutate( stmt );
     474                // To keep the switch statements uniform (all direct children of a
     475                // SwitchStmt should be CastStmts), append the exit label and break
     476                // to the last case, create a default case is there are no cases.
     477                ast::SwitchStmt * mutStmt = ast::mutate( stmt );
    473478                if ( mutStmt->stmts.empty() ) {
    474                         mutStmt->stmts.push_back( new CaseStmt( mutStmt->location, nullptr, {} ) );
    475                 }
    476 
    477                 auto caseStmt = mutStmt->stmts.back().strict_as<CaseStmt>();
    478                 auto mutCase = mutate( caseStmt );
     479                        mutStmt->stmts.push_back( new ast::CaseStmt(
     480                                mutStmt->location, nullptr, {} ));
     481                }
     482
     483                auto caseStmt = mutStmt->stmts.back().strict_as<ast::CaseStmt>();
     484                auto mutCase = ast::mutate( caseStmt );
    479485                mutStmt->stmts.back() = mutCase;
    480486
    481                 Label label( mutCase->location, "breakLabel" );
    482                 auto branch = new BranchStmt( mutCase->location, BranchStmt::Break, label );
     487                ast::Label label( mutCase->location, "breakLabel" );
     488                auto branch = new ast::BranchStmt( mutCase->location, ast::BranchStmt::Break, label );
    483489                branch->labels.push_back( entry.useBreakExit() );
    484490                mutCase->stmts.push_back( branch );
     
    489495}
    490496
    491 void MultiLevelExitCore::previsit( const ReturnStmt * stmt ) {
     497void MultiLevelExitCore::previsit( const ast::ReturnStmt * stmt ) {
    492498        if ( inFinally ) {
    493499                SemanticError( stmt->location, "'return' may not appear in a finally clause" );
     
    495501}
    496502
    497 void MultiLevelExitCore::previsit( const TryStmt * stmt ) {
    498         bool isLabeled = ! stmt->labels.empty();
     503void MultiLevelExitCore::previsit( const ast::TryStmt * stmt ) {
     504        bool isLabeled = !stmt->labels.empty();
    499505        if ( isLabeled ) {
    500                 Label breakLabel = newLabel( "blockBreak", stmt );
     506                ast::Label breakLabel = LabelGenerator::newLabel( "blockBreak", stmt );
    501507                enclosing_control_structures.emplace_back( stmt, breakLabel );
    502508                GuardAction([this](){ enclosing_control_structures.pop_back(); } );
     
    504510}
    505511
    506 void MultiLevelExitCore::postvisit( const TryStmt * stmt ) {
    507         bool isLabeled = ! stmt->labels.empty();
     512void MultiLevelExitCore::postvisit( const ast::TryStmt * stmt ) {
     513        bool isLabeled = !stmt->labels.empty();
    508514        if ( isLabeled ) {
    509515                auto this_label = enclosing_control_structures.back().useBreakExit();
    510                 if ( ! this_label.empty() ) {
     516                if ( !this_label.empty() ) {
    511517                        break_label = this_label;
    512518                }
     
    514520}
    515521
    516 void MultiLevelExitCore::previsit( const FinallyStmt * ) {
    517         GuardAction([this, old = move( enclosing_control_structures)](){ enclosing_control_structures = move(old); });
    518         enclosing_control_structures = vector<Entry>();
     522void MultiLevelExitCore::previsit( const ast::FinallyStmt * ) {
     523        GuardAction([this, old = std::move(enclosing_control_structures)](){
     524                enclosing_control_structures = std::move(old);
     525        });
     526        enclosing_control_structures = std::vector<Entry>();
    519527        GuardValue( inFinally ) = true;
    520528}
    521529
    522 const Stmt * MultiLevelExitCore::mutateLoop(
    523         const Stmt * body, Entry & entry ) {
     530const ast::Stmt * MultiLevelExitCore::mutateLoop(
     531                const ast::Stmt * body, Entry & entry ) {
    524532        if ( entry.isBreakUsed() ) {
    525533                break_label = entry.useBreakExit();
    526534        }
    527535
    528         // if continue is used insert a continue label into the back of the body of the loop
    529536        if ( entry.isContUsed() ) {
    530                 CompoundStmt * new_body = new CompoundStmt( body->location );
    531                 // {}
     537                ast::CompoundStmt * new_body = new ast::CompoundStmt( body->location );
    532538                new_body->kids.push_back( body );
    533                 // {
    534                 //  body
    535                 // }
    536539                new_body->kids.push_back(
    537540                        labelledNullStmt( body->location, entry.useContExit() ) );
    538                 // {
    539                 //  body
    540                 //  ContinueLabel: {}
    541                 // }
    542541                return new_body;
    543542        }
     
    550549        // Remember is loop before going onto mutate the body.
    551550        // The labels will be folded in if they are used.
    552         Label breakLabel = newLabel( "loopBreak", loopStmt );
    553         Label contLabel = newLabel( "loopContinue", loopStmt );
     551        ast::Label breakLabel = LabelGenerator::newLabel( "loopBreak", loopStmt );
     552        ast::Label contLabel = LabelGenerator::newLabel( "loopContinue", loopStmt );
    554553        enclosing_control_structures.emplace_back( loopStmt, breakLabel, contLabel );
    555         // labels are added temporarily to see if they are used and then added permanently in postvisit if ther are used
    556         // children will tag labels as being used during their traversal which occurs before postvisit
    557 
    558         // GuardAction calls the lambda after the node is done being visited
    559554        GuardAction( [this](){ enclosing_control_structures.pop_back(); } );
    560555}
     
    562557template<typename LoopNode>
    563558const LoopNode * MultiLevelExitCore::posthandleLoopStmt( const LoopNode * loopStmt ) {
    564         assert( ! enclosing_control_structures.empty() );
     559        assert( !enclosing_control_structures.empty() );
    565560        Entry & entry = enclosing_control_structures.back();
    566561        assert( entry.stmt == loopStmt );
    567562
    568         // Now check if the labels are used and add them if so.
    569         return mutate_field( loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) );
    570         // this call to mutate_field compares loopStmt->body and the result of mutateLoop
    571         //              if they are the same the node isn't mutated, if they differ then the new mutated node is returned
    572         //              the stmts will only differ if a label is used
    573 }
    574 
    575 list<ptr<Stmt>> MultiLevelExitCore::fixBlock(
    576         const list<ptr<Stmt>> & kids, bool is_case_clause ) {
    577         // Unfortunately cannot use automatic error collection.
     563        // Now we check if the labels are used and add them if so.
     564        return ast::mutate_field(
     565                loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) );
     566}
     567
     568std::list<ast::ptr<ast::Stmt>> MultiLevelExitCore::fixBlock(
     569                const std::list<ast::ptr<ast::Stmt>> & kids, bool is_case_clause ) {
     570        // Unfortunately we can't use the automatic error collection.
    578571        SemanticErrorException errors;
    579572
    580         list<ptr<Stmt>> ret;
     573        std::list<ast::ptr<ast::Stmt>> ret;
    581574
    582575        // Manually visit each child.
    583         for ( const ptr<Stmt> & kid : kids ) {
     576        for ( const ast::ptr<ast::Stmt> & kid : kids ) {
    584577                if ( is_case_clause ) {
    585578                        // Once a label is seen, it's no longer a valid for fallthrough.
    586                         for ( const Label & l : kid->labels ) {
     579                        for ( const ast::Label & l : kid->labels ) {
    587580                                fallthrough_labels.erase( l );
    588581                        }
     
    595588                }
    596589
    597                 if ( ! break_label.empty() ) {
    598                         ret.push_back( labelledNullStmt( ret.back()->location, break_label ) );
    599                         break_label = Label( CodeLocation(), "" );
    600                 }
    601         }
    602 
    603         if ( ! errors.isEmpty() ) {
     590                if ( !break_label.empty() ) {
     591                        ret.push_back(
     592                                labelledNullStmt( ret.back()->location, break_label ) );
     593                        break_label = ast::Label( CodeLocation(), "" );
     594                }
     595        }
     596
     597        if ( !errors.isEmpty() ) {
    604598                throw errors;
    605599        }
     
    607601}
    608602
    609 const CompoundStmt * multiLevelExitUpdate(
    610         const CompoundStmt * stmt,
    611         const LabelToStmt & labelTable ) {
     603} // namespace
     604
     605const ast::CompoundStmt * multiLevelExitUpdate(
     606        const ast::CompoundStmt * stmt,
     607                const LabelToStmt & labelTable ) {
    612608        // Must start in the body, so FunctionDecls can be a stopping point.
    613         Pass<MultiLevelExitCore> visitor( labelTable );
    614         const CompoundStmt * ret = stmt->accept( visitor );
     609        ast::Pass<MultiLevelExitCore> visitor( labelTable );
     610        const ast::CompoundStmt * ret = stmt->accept( visitor );
    615611        return ret;
    616612}
     613
    617614} // namespace ControlStruct
    618615
  • src/ControlStruct/MultiLevelExit.hpp

    rf5a51db r97c215f  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Nov  1 13:49:00 2021
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 31 22:34:06 2022
    13 // Update Count     : 6
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  8 10:53:00 2021
     13// Update Count     : 3
    1414//
    1515
     
    1919
    2020namespace ast {
    21 class CompoundStmt;
    22 class Label;
    23 class Stmt;
     21        class CompoundStmt;
     22        class Label;
     23        class Stmt;
    2424}
    2525
    2626namespace ControlStruct {
     27
    2728using LabelToStmt = std::map<ast::Label, const ast::Stmt *>;
    2829
    29 // Mutate a function body to handle multi-level exits.
    30 const ast::CompoundStmt * multiLevelExitUpdate( const ast::CompoundStmt *, const LabelToStmt & );
     30/// Mutate a function body to handle multi-level exits.
     31const ast::CompoundStmt * multiLevelExitUpdate(
     32        const ast::CompoundStmt *, const LabelToStmt & );
     33
    3134}
    3235
  • src/ControlStruct/module.mk

    rf5a51db r97c215f  
    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 : Henry Xue
     13## Last Modified On : Tue Jul 20 04:10:50 2021
     14## Update Count     : 5
    1515###############################################################################
    1616
     
    2222        ControlStruct/ForExprMutator.cc \
    2323        ControlStruct/ForExprMutator.h \
    24         ControlStruct/HoistControlDecls.cpp \
    25         ControlStruct/HoistControlDecls.hpp \
    2624        ControlStruct/LabelFixer.cc \
    2725        ControlStruct/LabelFixer.h \
    2826        ControlStruct/LabelGenerator.cc \
    2927        ControlStruct/LabelGenerator.h \
    30         ControlStruct/LabelGeneratorNew.cpp \
    31         ControlStruct/LabelGeneratorNew.hpp \
    3228        ControlStruct/MLEMutator.cc \
    3329        ControlStruct/MLEMutator.h \
  • src/InitTweak/InitTweak.cc

    rf5a51db r97c215f  
    1010// Created On       : Fri May 13 11:26:36 2016
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Dec  6 13:21:00 2021
    13 // Update Count     : 20
     12// Last Modified On : Fri Nov 19 19:22:00 2021
     13// Update Count     : 19
    1414//
    1515
     
    11911191        }
    11921192
    1193 bool isAssignment( const ast::FunctionDecl * decl ) {
    1194         return isAssignment( decl->name ) && isCopyFunction( decl );
    1195 }
    1196 
    1197 bool isDestructor( const ast::FunctionDecl * decl ) {
    1198         return isDestructor( decl->name );
    1199 }
    1200 
    1201 bool isDefaultConstructor( const ast::FunctionDecl * decl ) {
    1202         return isConstructor( decl->name ) && 1 == decl->params.size();
    1203 }
    1204 
    1205 bool isCopyConstructor( const ast::FunctionDecl * decl ) {
    1206         return isConstructor( decl->name ) && 2 == decl->params.size();
    1207 }
    1208 
    1209 bool isCopyFunction( const ast::FunctionDecl * decl ) {
    1210         const ast::FunctionType * ftype = decl->type;
    1211         if ( ftype->params.size() != 2 ) return false;
    1212 
    1213         const ast::Type * t1 = getPointerBase( ftype->params.front() );
    1214         if ( ! t1 ) return false;
    1215         const ast::Type * t2 = ftype->params.back();
    1216 
    1217         return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, ast::SymbolTable{} );
    1218 }
     1193        bool isCopyFunction( const ast::FunctionDecl * decl ) {
     1194                const ast::FunctionType * ftype = decl->type;
     1195                if ( ftype->params.size() != 2 ) return false;
     1196
     1197                const ast::Type * t1 = getPointerBase( ftype->params.front() );
     1198                if ( ! t1 ) return false;
     1199                const ast::Type * t2 = ftype->params.back();
     1200
     1201                return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, ast::SymbolTable{} );
     1202        }
    12191203
    12201204        const FunctionDecl * isAssignment( const Declaration * decl ) {
  • src/InitTweak/InitTweak.h

    rf5a51db r97c215f  
    1010// Created On       : Fri May 13 11:26:36 2016
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Dec  6 13:20:00 2021
    13 // Update Count     : 8
     12// Last Modified On : Fri Nov 19 14:18:00 2021
     13// Update Count     : 7
    1414//
    1515
     
    3131        const FunctionDecl * isCopyConstructor( const Declaration * decl );
    3232        const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname );
    33         bool isAssignment( const ast::FunctionDecl * decl );
    34         bool isDestructor( const ast::FunctionDecl * decl );
    35         bool isDefaultConstructor( const ast::FunctionDecl * decl );
    36         bool isCopyConstructor( const ast::FunctionDecl * decl );
    3733        bool isCopyFunction( const ast::FunctionDecl * decl );
    3834
  • src/Parser/ParseNode.h

    rf5a51db r97c215f  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  2 09:15:49 2022
    13 // Update Count     : 905
     12// Last Modified On : Wed Jul 14 17:28:53 2021
     13// Update Count     : 900
    1414//
    1515
     
    390390Statement * build_expr( ExpressionNode * ctl );
    391391
    392 struct CondCtl {
    393         CondCtl( DeclarationNode * decl, ExpressionNode * condition ) :
     392struct IfCtrl {
     393        IfCtrl( DeclarationNode * decl, ExpressionNode * condition ) :
    394394                init( decl ? new StatementNode( decl ) : nullptr ), condition( condition ) {}
    395395
     
    409409};
    410410
    411 Expression * build_if_control( CondCtl * ctl, std::list< Statement * > & init );
    412 Statement * build_if( CondCtl * ctl, StatementNode * then, StatementNode * else_ );
     411Expression * build_if_control( IfCtrl * ctl, std::list< Statement * > & init );
     412Statement * build_if( IfCtrl * ctl, StatementNode * then_stmt, StatementNode * else_stmt );
    413413Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt );
    414414Statement * build_case( ExpressionNode * ctl );
    415415Statement * build_default();
    416 Statement * build_while( CondCtl * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    417 Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    418 Statement * build_for( ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ = nullptr );
     416Statement * build_while( IfCtrl * ctl, StatementNode * stmt );
     417Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt );
     418Statement * build_for( ForCtrl * forctl, StatementNode * stmt );
    419419Statement * build_branch( BranchStmt::Type kind );
    420420Statement * build_branch( std::string * identifier, BranchStmt::Type kind );
     
    424424Statement * build_resume( ExpressionNode * ctl );
    425425Statement * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
    426 Statement * build_try( StatementNode * try_, StatementNode * catch_, StatementNode * finally_ );
    427 Statement * build_catch( CatchStmt::Kind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body );
     426Statement * build_try( StatementNode * try_stmt, StatementNode * catch_stmt, StatementNode * finally_stmt );
     427Statement * build_catch( CatchStmt::Kind kind, DeclarationNode *decl, ExpressionNode *cond, StatementNode *body );
    428428Statement * build_finally( StatementNode * stmt );
    429429Statement * build_compound( StatementNode * first );
  • src/Parser/StatementNode.cc

    rf5a51db r97c215f  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // StatementNode.cc -- Transform from parse data-structures to AST data-structures, usually deleting the parse
    8 //     data-structure after the transformation.
     7// StatementNode.cc --
    98//
    109// Author           : Rodolfo G. Esteves
    1110// Created On       : Sat May 16 14:59:41 2015
    1211// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Wed Feb  2 20:29:30 2022
    14 // Update Count     : 425
     12// Last Modified On : Sat Oct 24 04:20:55 2020
     13// Update Count     : 383
    1514//
    1615
     
    6463        // convert from StatementNode list to Statement list
    6564        StatementNode * node = dynamic_cast< StatementNode * >(prev);
    66         list< Statement * > stmts;
     65        std::list< Statement * > stmts;
    6766        buildMoveList( stmt, stmts );
    6867        // splice any new Statements to end of current Statements
     
    7978} // build_expr
    8079
    81 Expression * build_if_control( CondCtl * ctl, list< Statement * > & init ) {
     80Expression * build_if_control( IfCtrl * ctl, std::list< Statement * > & init ) {
    8281        if ( ctl->init != 0 ) {
    8382                buildMoveList( ctl->init, init );
     
    101100} // build_if_control
    102101
    103 Statement * build_if( CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
    104         list< Statement * > astinit;                                            // maybe empty
    105         Expression * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    106 
    107         Statement * astthen, * astelse = nullptr;
    108         list< Statement * > aststmt;
    109         buildMoveList< Statement, StatementNode >( then, aststmt );
    110         assert( aststmt.size() == 1 );
    111         astthen = aststmt.front();
    112 
    113         if ( else_ ) {
    114                 list< Statement * > aststmt;
    115                 buildMoveList< Statement, StatementNode >( else_, aststmt );
    116                 assert( aststmt.size() == 1 );
    117                 astelse = aststmt.front();
    118         } // if
    119 
    120         return new IfStmt( astcond, astthen, astelse, astinit );
     102Statement * build_if( IfCtrl * ctl, StatementNode * then_stmt, StatementNode * else_stmt ) {
     103        Statement * thenb, * elseb = nullptr;
     104        std::list< Statement * > branches;
     105        buildMoveList< Statement, StatementNode >( then_stmt, branches );
     106        assert( branches.size() == 1 );
     107        thenb = branches.front();
     108
     109        if ( else_stmt ) {
     110                std::list< Statement * > branches;
     111                buildMoveList< Statement, StatementNode >( else_stmt, branches );
     112                assert( branches.size() == 1 );
     113                elseb = branches.front();
     114        } // if
     115
     116        std::list< Statement * > init;
     117        Expression * cond = build_if_control( ctl, init );
     118        return new IfStmt( cond, thenb, elseb, init );
    121119} // build_if
    122120
    123121Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) {
    124         list< Statement * > aststmt;
    125         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    126         if ( ! isSwitch ) {                                                                     // choose statement
    127                 for ( Statement * stmt : aststmt ) {
     122        std::list< Statement * > branches;
     123        buildMoveList< Statement, StatementNode >( stmt, branches );
     124        if ( ! isSwitch ) {                                                                             // choose statement
     125                for ( Statement * stmt : branches ) {
    128126                        CaseStmt * caseStmt = strict_dynamic_cast< CaseStmt * >( stmt );
    129127                        if ( ! caseStmt->stmts.empty() ) {                      // code after "case" => end of case list
     
    133131                } // for
    134132        } // if
    135         // aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements
    136         return new SwitchStmt( maybeMoveBuild< Expression >(ctl), aststmt );
     133        // branches.size() == 0 for switch (...) {}, i.e., no declaration or statements
     134        return new SwitchStmt( maybeMoveBuild< Expression >(ctl), branches );
    137135} // build_switch
    138136
    139137Statement * build_case( ExpressionNode * ctl ) {
    140         return new CaseStmt( maybeMoveBuild< Expression >(ctl), {} ); // stmt starts empty and then added to
     138        std::list< Statement * > branches;
     139        return new CaseStmt( maybeMoveBuild< Expression >(ctl), branches );
    141140} // build_case
    142141
    143142Statement * build_default() {
    144         return new CaseStmt( nullptr, {}, true );                       // stmt starts empty and then added to
     143        std::list< Statement * > branches;
     144        return new CaseStmt( nullptr, branches, true );
    145145} // build_default
    146146
    147 Statement * build_while( CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
    148         list< Statement * > astinit;                                            // maybe empty
    149         Expression * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    150 
    151         list< Statement * > aststmt;                                            // loop body, compound created if empty
    152         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    153         assert( aststmt.size() == 1 );
    154 
    155         list< Statement * > astelse;                                            // else clause, maybe empty
    156         buildMoveList< Statement, StatementNode >( else_, astelse );
    157 
    158         return new WhileDoStmt( astcond, aststmt.front(), astelse.front(), astinit, false );
     147Statement * build_while( IfCtrl * ctl, StatementNode * stmt ) {
     148        std::list< Statement * > branches;
     149        buildMoveList< Statement, StatementNode >( stmt, branches );
     150        assert( branches.size() == 1 );
     151
     152        std::list< Statement * > init;
     153        Expression * cond = build_if_control( ctl, init );
     154        return new WhileStmt( cond, branches.front(), init, false );
    159155} // build_while
    160156
    161 Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
    162         list< Statement * > aststmt;                                            // loop body, compound created if empty
    163         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    164         assert( aststmt.size() == 1 );                                          // compound created if empty
    165 
    166         list< Statement * > astelse;                                            // else clause, maybe empty
    167         buildMoveList< Statement, StatementNode >( else_, astelse );
    168 
    169         // do-while cannot have declarations in the contitional, so init is always empty
    170         return new WhileDoStmt( notZeroExpr( maybeMoveBuild< Expression >(ctl) ), aststmt.front(), astelse.front(), {}, true );
     157Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt ) {
     158        std::list< Statement * > branches;
     159        buildMoveList< Statement, StatementNode >( stmt, branches );
     160        assert( branches.size() == 1 );
     161
     162        std::list< Statement * > init;
     163        return new WhileStmt( notZeroExpr( maybeMoveBuild< Expression >(ctl) ), branches.front(), init, true );
    171164} // build_do_while
    172165
    173 Statement * build_for( ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
    174         list< Statement * > astinit;                                            // maybe empty
    175         buildMoveList( forctl->init, astinit );
    176 
    177         Expression * astcond = nullptr;                                         // maybe empty
    178         astcond = notZeroExpr( maybeMoveBuild< Expression >(forctl->condition) );
    179 
    180         Expression * astincr = nullptr;                                         // maybe empty
    181         astincr = maybeMoveBuild< Expression >(forctl->change);
     166Statement * build_for( ForCtrl * forctl, StatementNode * stmt ) {
     167        std::list< Statement * > branches;
     168        buildMoveList< Statement, StatementNode >( stmt, branches );
     169        assert( branches.size() == 1 );
     170
     171        std::list< Statement * > init;
     172        if ( forctl->init != 0 ) {
     173                buildMoveList( forctl->init, init );
     174        } // if
     175
     176        Expression * cond = 0;
     177        if ( forctl->condition != 0 )
     178                cond = notZeroExpr( maybeMoveBuild< Expression >(forctl->condition) );
     179
     180        Expression * incr = 0;
     181        if ( forctl->change != 0 )
     182                incr = maybeMoveBuild< Expression >(forctl->change);
     183
    182184        delete forctl;
    183 
    184         list< Statement * > aststmt;                                            // loop body, compound created if empty
    185         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    186         assert( aststmt.size() == 1 );
    187 
    188         list< Statement * > astelse;                                            // else clause, maybe empty
    189         buildMoveList< Statement, StatementNode >( else_, astelse );
    190 
    191         return new ForStmt( astinit, astcond, astincr, aststmt.front(), astelse.front() );
     185        return new ForStmt( init, cond, incr, branches.front() );
    192186} // build_for
    193187
     
    197191} // build_branch
    198192
    199 Statement * build_branch( string * identifier, BranchStmt::Type kind ) {
     193Statement * build_branch( std::string * identifier, BranchStmt::Type kind ) {
    200194        Statement * ret = new BranchStmt( * identifier, kind );
    201195        delete identifier;                                                                      // allocated by lexer
     
    208202
    209203Statement * build_return( ExpressionNode * ctl ) {
    210         list< Expression * > exps;
     204        std::list< Expression * > exps;
    211205        buildMoveList( ctl, exps );
    212206        return new ReturnStmt( exps.size() > 0 ? exps.back() : nullptr );
     
    214208
    215209Statement * build_throw( ExpressionNode * ctl ) {
    216         list< Expression * > exps;
     210        std::list< Expression * > exps;
    217211        buildMoveList( ctl, exps );
    218         assertf( exps.size() < 2, "CFA internal error: leaking memory" );
     212        assertf( exps.size() < 2, "This means we are leaking memory");
    219213        return new ThrowStmt( ThrowStmt::Terminate, !exps.empty() ? exps.back() : nullptr );
    220214} // build_throw
    221215
    222216Statement * build_resume( ExpressionNode * ctl ) {
    223         list< Expression * > exps;
     217        std::list< Expression * > exps;
    224218        buildMoveList( ctl, exps );
    225         assertf( exps.size() < 2, "CFA internal error: leaking memory" );
     219        assertf( exps.size() < 2, "This means we are leaking memory");
    226220        return new ThrowStmt( ThrowStmt::Resume, !exps.empty() ? exps.back() : nullptr );
    227221} // build_resume
     
    233227} // build_resume_at
    234228
    235 Statement * build_try( StatementNode * try_, StatementNode * catch_, StatementNode * finally_ ) {
    236         list< CatchStmt * > aststmt;
    237         buildMoveList< CatchStmt, StatementNode >( catch_, aststmt );
    238         CompoundStmt * tryBlock = strict_dynamic_cast< CompoundStmt * >(maybeMoveBuild< Statement >(try_));
    239         FinallyStmt * finallyBlock = dynamic_cast< FinallyStmt * >(maybeMoveBuild< Statement >(finally_) );
    240         return new TryStmt( tryBlock, aststmt, finallyBlock );
     229Statement * build_try( StatementNode * try_stmt, StatementNode * catch_stmt, StatementNode * finally_stmt ) {
     230        std::list< CatchStmt * > branches;
     231        buildMoveList< CatchStmt, StatementNode >( catch_stmt, branches );
     232        CompoundStmt * tryBlock = strict_dynamic_cast< CompoundStmt * >(maybeMoveBuild< Statement >(try_stmt));
     233        FinallyStmt * finallyBlock = dynamic_cast< FinallyStmt * >(maybeMoveBuild< Statement >(finally_stmt) );
     234        return new TryStmt( tryBlock, branches, finallyBlock );
    241235} // build_try
    242236
    243237Statement * build_catch( CatchStmt::Kind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
    244         list< Statement * > aststmt;
    245         buildMoveList< Statement, StatementNode >( body, aststmt );
    246         assert( aststmt.size() == 1 );
    247         return new CatchStmt( kind, maybeMoveBuild< Declaration >(decl), maybeMoveBuild< Expression >(cond), aststmt.front() );
     238        std::list< Statement * > branches;
     239        buildMoveList< Statement, StatementNode >( body, branches );
     240        assert( branches.size() == 1 );
     241        return new CatchStmt( kind, maybeMoveBuild< Declaration >(decl), maybeMoveBuild< Expression >(cond), branches.front() );
    248242} // build_catch
    249243
    250244Statement * build_finally( StatementNode * stmt ) {
    251         list< Statement * > aststmt;
    252         buildMoveList< Statement, StatementNode >( stmt, aststmt );
    253         assert( aststmt.size() == 1 );
    254         return new FinallyStmt( dynamic_cast< CompoundStmt * >( aststmt.front() ) );
     245        std::list< Statement * > branches;
     246        buildMoveList< Statement, StatementNode >( stmt, branches );
     247        assert( branches.size() == 1 );
     248        return new FinallyStmt( dynamic_cast< CompoundStmt * >( branches.front() ) );
    255249} // build_finally
    256250
     
    260254        node->type = type;
    261255
    262         list< Statement * > stmts;
     256        std::list< Statement * > stmts;
    263257        buildMoveList< Statement, StatementNode >( then, stmts );
    264258        if(!stmts.empty()) {
     
    325319} // build_waitfor_timeout
    326320
    327 WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when,  StatementNode * else_, ExpressionNode * else_when ) {
     321WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when,  StatementNode * else_stmt, ExpressionNode * else_when ) {
    328322        auto node = new WaitForStmt();
    329323
     
    332326        node->timeout.condition = notZeroExpr( maybeMoveBuild<Expression>( when ) );
    333327
    334         node->orelse.statement  = maybeMoveBuild<Statement >( else_ );
     328        node->orelse.statement  = maybeMoveBuild<Statement >( else_stmt );
    335329        node->orelse.condition  = notZeroExpr( maybeMoveBuild<Expression>( else_when ) );
    336330
     
    339333
    340334Statement * build_with( ExpressionNode * exprs, StatementNode * stmt ) {
    341         list< Expression * > e;
     335        std::list< Expression * > e;
    342336        buildMoveList( exprs, e );
    343337        Statement * s = maybeMoveBuild<Statement>( stmt );
     
    367361
    368362Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    369         list< Expression * > out, in;
    370         list< ConstantExpr * > clob;
     363        std::list< Expression * > out, in;
     364        std::list< ConstantExpr * > clob;
    371365
    372366        buildMoveList( output, out );
     
    381375
    382376Statement * build_mutex( ExpressionNode * exprs, StatementNode * stmt ) {
    383         list< Expression * > expList;
     377        std::list< Expression * > expList;
    384378        buildMoveList( exprs, expList );
    385379        Statement * body = maybeMoveBuild<Statement>( stmt );
  • src/Parser/parser.yy

    rf5a51db r97c215f  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 11:06:13 2022
    13 // Update Count     : 5167
     12// Last Modified On : Fri Oct 15 09:20:17 2021
     13// Update Count     : 5163
    1414//
    1515
     
    238238        WaitForStmt * wfs;
    239239        Expression * constant;
    240         CondCtl * ifctl;
     240        IfCtrl * ifctl;
    241241        ForCtrl * fctl;
    242242        enum OperKinds compop;
     
    327327%type<en> comma_expression                              comma_expression_opt
    328328%type<en> argument_expression_list_opt  argument_expression_list        argument_expression                     default_initializer_opt
    329 %type<ifctl> conditional_declaration
     329%type<ifctl> if_control_expression
    330330%type<fctl> for_control_expression              for_control_expression_list
    331331%type<compop> inclexcl
     
    11231123
    11241124if_statement:
    1125         IF '(' conditional_declaration ')' statement            %prec THEN
     1125        IF '(' if_control_expression ')' statement                      %prec THEN
    11261126                // explicitly deal with the shift/reduce conflict on if/else
    11271127                { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); }
    1128         | IF '(' conditional_declaration ')' statement ELSE statement
     1128        | IF '(' if_control_expression ')' statement ELSE statement
    11291129                { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); }
    11301130        ;
    11311131
    1132 conditional_declaration:
     1132if_control_expression:
    11331133        comma_expression
    1134                 { $$ = new CondCtl( nullptr, $1 ); }
     1134                { $$ = new IfCtrl( nullptr, $1 ); }
    11351135        | c_declaration                                                                         // no semi-colon
    1136                 { $$ = new CondCtl( $1, nullptr ); }
     1136                { $$ = new IfCtrl( $1, nullptr ); }
    11371137        | cfa_declaration                                                                       // no semi-colon
    1138                 { $$ = new CondCtl( $1, nullptr ); }
     1138                { $$ = new IfCtrl( $1, nullptr ); }
    11391139        | declaration comma_expression                                          // semi-colon separated
    1140                 { $$ = new CondCtl( $1, $2 ); }
     1140                { $$ = new IfCtrl( $1, $2 ); }
    11411141        ;
    11421142
     
    11931193iteration_statement:
    11941194        WHILE '(' ')' statement                                                         // CFA => while ( 1 )
    1195                 { $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
    1196         | WHILE '(' conditional_declaration ')' statement       %prec THEN
     1195                { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
     1196        | WHILE '(' if_control_expression ')' statement         %prec THEN
    11971197                { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); }
    1198         | WHILE '(' conditional_declaration ')' statement ELSE statement // CFA
    1199                 // { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    1200                 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ), $7 ) ); }
     1198        | WHILE '(' if_control_expression ')' statement ELSE statement // CFA
     1199                { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    12011200        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    12021201                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
     
    12041203                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
    12051204        | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA
    1206                 // { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    1207                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ), $8 ) ); }
     1205                { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    12081206        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
    12091207                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
     
    12111209                { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }
    12121210        | FOR '(' for_control_expression_list ')' statement ELSE statement // CFA
    1213                 // { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    1214                 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ), $7 ) ); }
     1211                { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    12151212        ;
    12161213
  • src/ResolvExpr/Resolver.cc

    rf5a51db r97c215f  
    99// Author           : Aaron B. Moss
    1010// Created On       : Sun May 17 12:17:01 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 16:27:14 2022
    13 // Update Count     : 245
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Mar 27 11:58:00 2020
     13// Update Count     : 242
    1414//
    1515
     
    8080                void previsit( AsmStmt * asmStmt );
    8181                void previsit( IfStmt * ifStmt );
    82                 void previsit( WhileDoStmt * whileDoStmt );
     82                void previsit( WhileStmt * whileStmt );
    8383                void previsit( ForStmt * forStmt );
    8484                void previsit( SwitchStmt * switchStmt );
     
    502502        }
    503503
    504         void Resolver_old::previsit( WhileDoStmt * whileDoStmt ) {
    505                 findIntegralExpression( whileDoStmt->condition, indexer );
     504        void Resolver_old::previsit( WhileStmt * whileStmt ) {
     505                findIntegralExpression( whileStmt->condition, indexer );
    506506        }
    507507
     
    572572
    573573        void Resolver_old::previsit( CatchStmt * catchStmt ) {
    574                 // Until we are very sure this invarent (ifs that move between passes have then)
     574                // Until we are very sure this invarent (ifs that move between passes have thenPart)
    575575                // holds, check it. This allows a check for when to decode the mangling.
    576576                if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {
    577                         assert( ifStmt->then );
     577                        assert( ifStmt->thenPart );
    578578                }
    579579                // Encode the catchStmt so the condition can see the declaration.
     
    588588                // Decode the catchStmt so everything is stored properly.
    589589                IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );
    590                 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
     590                if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) {
    591591                        assert( ifStmt->condition );
    592                         assert( ifStmt->else_ );
     592                        assert( ifStmt->elsePart );
    593593                        catchStmt->cond = ifStmt->condition;
    594                         catchStmt->body = ifStmt->else_;
     594                        catchStmt->body = ifStmt->elsePart;
    595595                        ifStmt->condition = nullptr;
    596                         ifStmt->else_ = nullptr;
     596                        ifStmt->elsePart = nullptr;
    597597                        delete ifStmt;
    598598                }
     
    12721272                const ast::AsmStmt *         previsit( const ast::AsmStmt * );
    12731273                const ast::IfStmt *          previsit( const ast::IfStmt * );
    1274                 const ast::WhileDoStmt *       previsit( const ast::WhileDoStmt * );
     1274                const ast::WhileStmt *       previsit( const ast::WhileStmt * );
    12751275                const ast::ForStmt *         previsit( const ast::ForStmt * );
    12761276                const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
     
    15811581        }
    15821582
    1583         const ast::WhileDoStmt * Resolver_new::previsit( const ast::WhileDoStmt * whileDoStmt ) {
     1583        const ast::WhileStmt * Resolver_new::previsit( const ast::WhileStmt * whileStmt ) {
    15841584                return ast::mutate_field(
    1585                         whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, symtab ) );
     1585                        whileStmt, &ast::WhileStmt::cond, findIntegralExpression( whileStmt->cond, symtab ) );
    15861586        }
    15871587
     
    16691669
    16701670        const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) {
    1671                 // Until we are very sure this invarent (ifs that move between passes have then)
     1671                // Until we are very sure this invarent (ifs that move between passes have thenPart)
    16721672                // holds, check it. This allows a check for when to decode the mangling.
    16731673                if ( auto ifStmt = catchStmt->body.as<ast::IfStmt>() ) {
    1674                         assert( ifStmt->then );
     1674                        assert( ifStmt->thenPart );
    16751675                }
    16761676                // Encode the catchStmt so the condition can see the declaration.
     
    16871687                // Decode the catchStmt so everything is stored properly.
    16881688                const ast::IfStmt * ifStmt = catchStmt->body.as<ast::IfStmt>();
    1689                 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
     1689                if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) {
    16901690                        assert( ifStmt->cond );
    1691                         assert( ifStmt->else_ );
     1691                        assert( ifStmt->elsePart );
    16921692                        ast::CatchStmt * stmt = ast::mutate( catchStmt );
    16931693                        stmt->cond = ifStmt->cond;
    1694                         stmt->body = ifStmt->else_;
     1694                        stmt->body = ifStmt->elsePart;
    16951695                        // ifStmt should be implicately deleted here.
    16961696                        return stmt;
  • src/SymTab/Validate.cc

    rf5a51db r97c215f  
    453453        }
    454454
    455         void decayForallPointers( std::list< Declaration * > & translationUnit ) {
    456                 PassVisitor<ForallPointerDecay_old> fpd;
    457                 acceptAll( translationUnit, fpd );
    458         }
    459 
    460455        void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) {
    461456                validate_A( translationUnit );
     
    475470                type->accept( fpd );
    476471        }
     472
    477473
    478474        void HoistTypeDecls::handleType( Type * type ) {
  • src/SymTab/Validate.h

    rf5a51db r97c215f  
    4242        void validate_E( std::list< Declaration * > &translationUnit );
    4343        void validate_F( std::list< Declaration * > &translationUnit );
    44         void decayForallPointers( std::list< Declaration * > & translationUnit );
    4544
    4645        const ast::Type * validateType(
  • src/SynTree/Mutator.h

    rf5a51db r97c215f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:26:49 2022
    13 // Update Count     : 20
     12// Last Modified On : Fri Mar 12 18:35:36 2021
     13// Update Count     : 18
    1414//
    1515#pragma once
     
    4242        virtual Statement * mutate( DirectiveStmt * dirStmt ) = 0;
    4343        virtual Statement * mutate( IfStmt * ifStmt ) = 0;
    44         virtual Statement * mutate( WhileDoStmt * whileDoStmt ) = 0;
     44        virtual Statement * mutate( WhileStmt * whileStmt ) = 0;
    4545        virtual Statement * mutate( ForStmt * forStmt ) = 0;
    4646        virtual Statement * mutate( SwitchStmt * switchStmt ) = 0;
  • src/SynTree/Statement.cc

    rf5a51db r97c215f  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  2 20:19:33 2022
    13 // Update Count     : 90
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Jan 20 16:03:00 2020
     13// Update Count     : 71
    1414//
    1515
     
    2929#include "SynTree/Label.h"         // for Label, operator<<
    3030
    31 using namespace std;
    32 
    33 
    34 Statement::Statement( const list<Label> & labels ) : labels( labels ) {}
    35 
    36 void Statement::print( ostream & os, Indenter indent ) const {
     31using std::string;
     32using std::endl;
     33
     34Statement::Statement( const std::list<Label> & labels ) : labels( labels ) {}
     35
     36void Statement::print( std::ostream & os, Indenter indent ) const {
    3737        if ( ! labels.empty() ) {
    3838                os << indent << "... Labels: {";
     
    5454}
    5555
    56 void ExprStmt::print( ostream & os, Indenter indent ) const {
    57         os << "Expression Statement:" << endl << indent + 1;
    58         expr->print( os, indent + 1 );
    59 }
    60 
    61 
    62 AsmStmt::AsmStmt( bool voltile, Expression * instruction, const list<Expression *> output, const list<Expression *> input, const list<ConstantExpr *> clobber, const list<Label> gotolabels ) : Statement(), voltile( voltile ), instruction( instruction ), output( output ), input( input ), clobber( clobber ), gotolabels( gotolabels ) {}
     56void ExprStmt::print( std::ostream & os, Indenter indent ) const {
     57        os << "Expression Statement:" << endl << indent+1;
     58        expr->print( os, indent+1 );
     59}
     60
     61
     62AsmStmt::AsmStmt( bool voltile, Expression * instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels ) : Statement(), voltile( voltile ), instruction( instruction ), output( output ), input( input ), clobber( clobber ), gotolabels( gotolabels ) {}
    6363
    6464AsmStmt::AsmStmt( const AsmStmt & other ) : Statement( other ), voltile( other.voltile ), instruction( maybeClone( other.instruction ) ), gotolabels( other.gotolabels ) {
     
    7575}
    7676
    77 void AsmStmt::print( ostream & os, Indenter indent ) const {
     77void AsmStmt::print( std::ostream & os, Indenter indent ) const {
    7878        os << "Assembler Statement:" << endl;
    79         os << indent + 1 << "instruction: " << endl << indent;
    80         instruction->print( os, indent + 1 );
     79        os << indent+1 << "instruction: " << endl << indent;
     80        instruction->print( os, indent+1 );
    8181        if ( ! output.empty() ) {
    82                 os << endl << indent + 1 << "output: " << endl;
    83                 printAll( output, os, indent + 1 );
     82                os << endl << indent+1 << "output: " << endl;
     83                printAll( output, os, indent+1 );
    8484        } // if
    8585        if ( ! input.empty() ) {
    86                 os << indent + 1 << "input: " << endl;
    87                 printAll( input, os, indent + 1 );
     86                os << indent+1 << "input: " << endl;
     87                printAll( input, os, indent+1 );
    8888        } // if
    8989        if ( ! clobber.empty() ) {
    90                 os << indent + 1 << "clobber: " << endl;
    91                 printAll( clobber, os, indent + 1 );
     90                os << indent+1 << "clobber: " << endl;
     91                printAll( clobber, os, indent+1 );
    9292        } // if
    9393}
    9494
    9595
    96 DirectiveStmt::DirectiveStmt( const string & directive ) : Statement(), directive( directive ) {}
    97 
    98 void DirectiveStmt::print( ostream & os, Indenter ) const {
     96DirectiveStmt::DirectiveStmt( const std::string & directive ) : Statement(), directive( directive ) {}
     97
     98void DirectiveStmt::print( std::ostream & os, Indenter ) const {
    9999        os << "GCC Directive:" << directive << endl;
    100100}
     
    120120}
    121121
    122 void BranchStmt::print( ostream & os, Indenter indent ) const {
    123         assertf(type < BranchStmts, "CFA internal error: invalid branch statement" );
     122void BranchStmt::print( std::ostream & os, Indenter indent ) const {
     123        assert(type < 5);
    124124        os << "Branch (" << brType[type] << ")" << endl ;
    125         if ( target != "" ) os << indent + 1 << "with target: " << target << endl;
    126         if ( originalTarget != "" ) os << indent + 1 << "with original target: " << originalTarget << endl;
    127         if ( computedTarget != nullptr ) os << indent + 1 << "with computed target: " << computedTarget << endl;
     125        if ( target != "" ) os << indent+1 << "with target: " << target << endl;
     126        if ( originalTarget != "" ) os << indent+1 << "with original target: " << originalTarget << endl;
     127        if ( computedTarget != nullptr ) os << indent+1 << "with computed target: " << computedTarget << endl;
    128128}
    129129
     
    136136}
    137137
    138 void ReturnStmt::print( ostream & os, Indenter indent ) const {
     138void ReturnStmt::print( std::ostream & os, Indenter indent ) const {
    139139        os << "Return Statement, returning: ";
    140140        if ( expr != nullptr ) {
    141                 os << endl << indent + 1;
    142                 expr->print( os, indent + 1 );
    143         }
    144         os << endl;
    145 }
    146 
    147 IfStmt::IfStmt( Expression * condition, Statement * then, Statement * else_, const list<Statement *> initialization ):
    148         Statement(), condition( condition ), then( then ), else_( else_ ), initialization( initialization ) {}
     141                os << endl << indent+1;
     142                expr->print( os, indent+1 );
     143        }
     144        os << endl;
     145}
     146
     147IfStmt::IfStmt( Expression * condition, Statement * thenPart, Statement * elsePart, std::list<Statement *> initialization ):
     148        Statement(), condition( condition ), thenPart( thenPart ), elsePart( elsePart ), initialization( initialization ) {}
    149149
    150150IfStmt::IfStmt( const IfStmt & other ) :
    151         Statement( other ), condition( maybeClone( other.condition ) ), then( maybeClone( other.then ) ), else_( maybeClone( other.else_ ) ) {
     151        Statement( other ), condition( maybeClone( other.condition ) ), thenPart( maybeClone( other.thenPart ) ), elsePart( maybeClone( other.elsePart ) ) {
    152152        cloneAll( other.initialization, initialization );
    153153}
     
    156156        deleteAll( initialization );
    157157        delete condition;
    158         delete then;
    159         delete else_;
    160 }
    161 
    162 void IfStmt::print( ostream & os, Indenter indent ) const {
     158        delete thenPart;
     159        delete elsePart;
     160}
     161
     162void IfStmt::print( std::ostream & os, Indenter indent ) const {
    163163        os << "If on condition: " << endl;
    164         os << indent + 1;
    165         condition->print( os, indent + 1 );
     164        os << indent+1;
     165        condition->print( os, indent+1 );
    166166
    167167        if ( !initialization.empty() ) {
    168168                os << indent << "... with initialization: \n";
    169169                for ( const Statement * stmt : initialization ) {
    170                         os << indent + 1;
    171                         stmt->print( os, indent + 1 );
     170                        os << indent+1;
     171                        stmt->print( os, indent+1 );
    172172                }
    173173                os << endl;
     
    176176        os << indent << "... then: " << endl;
    177177
    178         os << indent + 1;
    179         then->print( os, indent + 1 );
    180 
    181         if ( else_ != nullptr ) {
     178        os << indent+1;
     179        thenPart->print( os, indent+1 );
     180
     181        if ( elsePart != nullptr ) {
    182182                os << indent << "... else: " << endl;
    183                 os << indent + 1;
    184                 else_->print( os, indent + 1 );
     183                os << indent+1;
     184                elsePart->print( os, indent+1 );
    185185        } // if
    186186}
    187187
    188 SwitchStmt::SwitchStmt( Expression * condition, const list<Statement *> & statements ):
     188SwitchStmt::SwitchStmt( Expression * condition, const std::list<Statement *> & statements ):
    189189        Statement(), condition( condition ), statements( statements ) {
    190190}
     
    201201}
    202202
    203 void SwitchStmt::print( ostream & os, Indenter indent ) const {
     203void SwitchStmt::print( std::ostream & os, Indenter indent ) const {
    204204        os << "Switch on condition: ";
    205205        condition->print( os );
     
    207207
    208208        for ( const Statement * stmt : statements ) {
    209                 stmt->print( os, indent + 1 );
    210         }
    211 }
    212 
    213 CaseStmt::CaseStmt( Expression * condition, const list<Statement *> & statements, bool deflt ) throw ( SemanticErrorException ) :
    214                 Statement(), condition( condition ), stmts( statements ), _isDefault( deflt ) {
     209                stmt->print( os, indent+1 );
     210        }
     211}
     212
     213CaseStmt::CaseStmt( Expression * condition, const std::list<Statement *> & statements, bool deflt ) throw ( SemanticErrorException ) :
     214        Statement(), condition( condition ), stmts( statements ), _isDefault( deflt ) {
    215215        if ( isDefault() && condition != nullptr ) SemanticError( condition, "default case with condition: " );
    216216}
    217217
    218218CaseStmt::CaseStmt( const CaseStmt & other ) :
    219                 Statement( other ), condition( maybeClone(other.condition ) ), _isDefault( other._isDefault ) {
     219        Statement( other ), condition( maybeClone(other.condition ) ), _isDefault( other._isDefault ) {
    220220        cloneAll( other.stmts, stmts );
    221221}
     
    226226}
    227227
    228 CaseStmt * CaseStmt::makeDefault( const list<Label> & labels, list<Statement *> stmts ) {
     228CaseStmt * CaseStmt::makeDefault( const std::list<Label> & labels, std::list<Statement *> stmts ) {
    229229        CaseStmt * stmt = new CaseStmt( nullptr, stmts, true );
    230230        stmt->labels = labels;
     
    232232}
    233233
    234 void CaseStmt::print( ostream & os, Indenter indent ) const {
     234void CaseStmt::print( std::ostream & os, Indenter indent ) const {
    235235        if ( isDefault() ) os << indent << "Default ";
    236236        else {
     
    241241
    242242        for ( Statement * stmt : stmts ) {
    243                 os << indent + 1;
    244                 stmt->print( os, indent + 1 );
    245         }
    246 }
    247 
    248 WhileDoStmt::WhileDoStmt( Expression * condition, Statement * body, const list< Statement * > & initialization, bool isDoWhile ):
    249         Statement(), condition( condition ), body( body ), else_( nullptr ), initialization( initialization ), isDoWhile( isDoWhile) {
    250 }
    251 
    252 WhileDoStmt::WhileDoStmt( Expression * condition, Statement * body, Statement * else_, const list< Statement * > & initialization, bool isDoWhile ):
    253         Statement(), condition( condition), body( body ), else_( else_ ), initialization( initialization ), isDoWhile( isDoWhile) {
    254 }
    255 
    256 WhileDoStmt::WhileDoStmt( const WhileDoStmt & other ):
     243                os << indent+1;
     244                stmt->print( os, indent+1 );
     245        }
     246}
     247
     248WhileStmt::WhileStmt( Expression * condition, Statement * body, std::list< Statement * > & initialization, bool isDoWhile ):
     249        Statement(), condition( condition), body( body), initialization( initialization ), isDoWhile( isDoWhile) {
     250}
     251
     252WhileStmt::WhileStmt( const WhileStmt & other ):
    257253        Statement( other ), condition( maybeClone( other.condition ) ), body( maybeClone( other.body ) ), isDoWhile( other.isDoWhile ) {
    258254}
    259255
    260 WhileDoStmt::~WhileDoStmt() {
     256WhileStmt::~WhileStmt() {
    261257        delete body;
    262258        delete condition;
    263259}
    264260
    265 void WhileDoStmt::print( ostream & os, Indenter indent ) const {
     261void WhileStmt::print( std::ostream & os, Indenter indent ) const {
    266262        os << "While on condition: " << endl ;
    267         condition->print( os, indent + 1 );
     263        condition->print( os, indent+1 );
    268264
    269265        os << indent << "... with body: " << endl;
    270266
    271         if ( body != nullptr ) body->print( os, indent + 1 );
    272 }
    273 
    274 ForStmt::ForStmt( const list<Statement *> initialization, Expression * condition, Expression * increment, Statement * body, Statement * else_ ):
    275         Statement(), initialization( initialization ), condition( condition ), increment( increment ), body( body ), else_( else_ ) {
     267        if ( body != nullptr ) body->print( os, indent+1 );
     268}
     269
     270ForStmt::ForStmt( std::list<Statement *> initialization, Expression * condition, Expression * increment, Statement * body ):
     271        Statement(), initialization( initialization ), condition( condition ), increment( increment ), body( body ) {
    276272}
    277273
    278274ForStmt::ForStmt( const ForStmt & other ):
    279         Statement( other ), condition( maybeClone( other.condition ) ), increment( maybeClone( other.increment ) ), body( maybeClone( other.body ) ), else_( maybeClone( other.else_ ) ) {
     275        Statement( other ), condition( maybeClone( other.condition ) ), increment( maybeClone( other.increment ) ), body( maybeClone( other.body ) ) {
    280276                cloneAll( other.initialization, initialization );
    281277
     
    287283        delete increment;
    288284        delete body;
    289         delete else_;
    290 }
    291 
    292 void ForStmt::print( ostream & os, Indenter indent ) const {
     285}
     286
     287void ForStmt::print( std::ostream & os, Indenter indent ) const {
    293288        Statement::print( os, indent ); // print labels
    294289
     
    298293                os << indent << "... initialization: \n";
    299294                for ( Statement * stmt : initialization ) {
    300                         os << indent + 1;
    301                         stmt->print( os, indent + 1 );
     295                        os << indent+1;
     296                        stmt->print( os, indent+1 );
    302297                }
    303298        }
    304299
    305300        if ( condition != nullptr ) {
    306                 os << indent << "... condition: \n" << indent + 1;
    307                 condition->print( os, indent + 1 );
     301                os << indent << "... condition: \n" << indent+1;
     302                condition->print( os, indent+1 );
    308303        }
    309304
    310305        if ( increment != nullptr ) {
    311                 os << "\n" << indent << "... increment: \n" << indent + 1;
    312                 increment->print( os, indent + 1 );
     306                os << "\n" << indent << "... increment: \n" << indent+1;
     307                increment->print( os, indent+1 );
    313308        }
    314309
    315310        if ( body != nullptr ) {
    316                 os << "\n" << indent << "... with body: \n" << indent + 1;
    317                 body->print( os, indent + 1 );
    318         }
    319 
    320         if ( else_ != nullptr ) {
    321                 os << "\n" << indent << "... with body: \n" << indent + 1;
    322                 else_->print( os, indent + 1 );
     311                os << "\n" << indent << "... with body: \n" << indent+1;
     312                body->print( os, indent+1 );
    323313        }
    324314        os << endl;
     
    339329}
    340330
    341 void ThrowStmt::print( ostream & os, Indenter indent) const {
     331void ThrowStmt::print( std::ostream & os, Indenter indent) const {
    342332        if ( target ) os << "Non-Local ";
    343333        os << "Throw Statement, raising: ";
    344         expr->print(os, indent + 1);
     334        expr->print(os, indent+1);
    345335        if ( target ) {
    346336                os << "... at: ";
    347                 target->print(os, indent + 1);
    348         }
    349 }
    350 
    351 TryStmt::TryStmt( CompoundStmt * tryBlock, const list<CatchStmt *> & handlers, FinallyStmt * finallyBlock ) :
     337                target->print(os, indent+1);
     338        }
     339}
     340
     341TryStmt::TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock ) :
    352342        Statement(), block( tryBlock ),  handlers( handlers ), finallyBlock( finallyBlock ) {
    353343}
     
    363353}
    364354
    365 void TryStmt::print( ostream & os, Indenter indent ) const {
     355void TryStmt::print( std::ostream & os, Indenter indent ) const {
    366356        os << "Try Statement" << endl;
    367         os << indent << "... with block:" << endl << indent + 1;
    368         block->print( os, indent + 1 );
     357        os << indent << "... with block:" << endl << indent+1;
     358        block->print( os, indent+1 );
    369359
    370360        // handlers
    371361        os << indent << "... and handlers:" << endl;
    372362        for ( const CatchStmt * stmt : handlers ) {
    373                 os << indent + 1;
    374                 stmt->print( os, indent + 1 );
     363                os << indent+1;
     364                stmt->print( os, indent+1 );
    375365        }
    376366
    377367        // finally block
    378368        if ( finallyBlock != nullptr ) {
    379                 os << indent << "... and finally:" << endl << indent + 1;
    380                 finallyBlock->print( os, indent + 1 );
     369                os << indent << "... and finally:" << endl << indent+1;
     370                finallyBlock->print( os, indent+1 );
    381371        } // if
    382372}
     
    396386}
    397387
    398 void CatchStmt::print( ostream & os, Indenter indent ) const {
     388void CatchStmt::print( std::ostream & os, Indenter indent ) const {
    399389        os << "Catch " << ((Terminate == kind) ? "Terminate" : "Resume") << " Statement" << endl;
    400390
    401391        os << indent << "... catching: ";
    402         decl->printShort( os, indent + 1 );
     392        decl->printShort( os, indent+1 );
    403393        os << endl;
    404394
    405395        if ( cond ) {
    406                 os << indent << "... with conditional:" << endl << indent + 1;
    407                 cond->print( os, indent + 1 );
     396                os << indent << "... with conditional:" << endl << indent+1;
     397                cond->print( os, indent+1 );
    408398        }
    409399
    410400        os << indent << "... with block:" << endl;
    411         os << indent + 1;
    412         body->print( os, indent + 1 );
     401        os << indent+1;
     402        body->print( os, indent+1 );
    413403}
    414404
     
    424414}
    425415
    426 void FinallyStmt::print( ostream & os, Indenter indent ) const {
     416void FinallyStmt::print( std::ostream & os, Indenter indent ) const {
    427417        os << "Finally Statement" << endl;
    428         os << indent << "... with block:" << endl << indent + 1;
    429         block->print( os, indent + 1 );
     418        os << indent << "... with block:" << endl << indent+1;
     419        block->print( os, indent+1 );
    430420}
    431421
     
    439429}
    440430
    441 void SuspendStmt::print( ostream & os, Indenter indent ) const {
     431void SuspendStmt::print( std::ostream & os, Indenter indent ) const {
    442432        os << "Suspend Statement";
    443433        switch (type) {
     
    496486}
    497487
    498 void WaitForStmt::print( ostream & os, Indenter indent ) const {
     488void WaitForStmt::print( std::ostream & os, Indenter indent ) const {
    499489        os << "Waitfor Statement" << endl;
    500490        indent += 1;
     
    531521
    532522
    533 WithStmt::WithStmt( const list< Expression * > & exprs, Statement * stmt ) : Declaration("", noStorageClasses, LinkageSpec::Cforall), exprs( exprs ), stmt( stmt ) {}
     523WithStmt::WithStmt( const std::list< Expression * > & exprs, Statement * stmt ) : Declaration("", noStorageClasses, LinkageSpec::Cforall), exprs( exprs ), stmt( stmt ) {}
    534524WithStmt::WithStmt( const WithStmt & other ) : Declaration( other ), stmt( maybeClone( other.stmt ) ) {
    535525        cloneAll( other.exprs, exprs );
     
    540530}
    541531
    542 void WithStmt::print( ostream & os, Indenter indent ) const {
     532void WithStmt::print( std::ostream & os, Indenter indent ) const {
    543533        os << "With statement" << endl;
    544534        os << indent << "... with expressions: " << endl;
    545         printAll( exprs, os, indent + 1 );
    546         os << indent << "... with statement:" << endl << indent + 1;
    547         stmt->print( os, indent + 1 );
    548 }
    549 
    550 
    551 NullStmt::NullStmt( const list<Label> & labels ) : Statement( labels ) {
    552 }
    553 
    554 void NullStmt::print( ostream & os, Indenter indent ) const {
     535        printAll( exprs, os, indent+1 );
     536        os << indent << "... with statement:" << endl << indent+1;
     537        stmt->print( os, indent+1 );
     538}
     539
     540
     541NullStmt::NullStmt( const std::list<Label> & labels ) : Statement( labels ) {
     542}
     543
     544void NullStmt::print( std::ostream & os, Indenter indent ) const {
    555545        os << "Null Statement" << endl;
    556546        Statement::print( os, indent );
     
    568558}
    569559
    570 void ImplicitCtorDtorStmt::print( ostream & os, Indenter indent ) const {
     560void ImplicitCtorDtorStmt::print( std::ostream & os, Indenter indent ) const {
    571561        os << "Implicit Ctor Dtor Statement" << endl;
    572562        os << indent << "... with Ctor/Dtor: ";
    573         callStmt->print( os, indent + 1);
    574         os << endl;
    575 }
    576 
    577 MutexStmt::MutexStmt( Statement * stmt, const list<Expression *> mutexObjs )
     563        callStmt->print( os, indent+1);
     564        os << endl;
     565}
     566
     567MutexStmt::MutexStmt( Statement * stmt, std::list<Expression *> mutexObjs )
    578568        : Statement(), stmt( stmt ), mutexObjs( mutexObjs ) { }
    579569
     
    587577}
    588578
    589 void MutexStmt::print( ostream & os, Indenter indent ) const {
     579void MutexStmt::print( std::ostream & os, Indenter indent ) const {
    590580        os << "Mutex Statement" << endl;
    591581        os << indent << "... with Expressions: " << endl;
    592582        for (auto * obj : mutexObjs) {
    593                 os << indent + 1;
    594                 obj->print( os, indent + 1);
     583                os << indent+1;
     584                obj->print( os, indent+1);
    595585                os << endl;
    596586        }
    597         os << indent << "... with Statement: " << endl << indent + 1;
    598         stmt->print( os, indent + 1 );
     587        os << indent << "... with Statement: " << endl << indent+1;
     588        stmt->print( os, indent+1 );
    599589}
    600590
  • src/SynTree/Statement.h

    rf5a51db r97c215f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  2 20:15:30 2022
    13 // Update Count     : 98
     12// Last Modified On : Fri Jan 10 14:13:24 2020
     13// Update Count     : 85
    1414//
    1515
     
    107107        std::list<Label> gotolabels;
    108108
    109         AsmStmt( bool voltile, Expression * instruction, const std::list<Expression *> output, const std::list<Expression *> input, const std::list<ConstantExpr *> clobber, const std::list<Label> gotolabels );
     109        AsmStmt( bool voltile, Expression * instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels );
    110110        AsmStmt( const AsmStmt & other );
    111111        virtual ~AsmStmt();
     
    148148  public:
    149149        Expression * condition;
    150         Statement * then;
    151         Statement * else_;
     150        Statement * thenPart;
     151        Statement * elsePart;
    152152        std::list<Statement *> initialization;
    153153
    154         IfStmt( Expression * condition, Statement * then, Statement * else_,
    155                         const std::list<Statement *> initialization = std::list<Statement *>() );
     154        IfStmt( Expression * condition, Statement * thenPart, Statement * elsePart,
     155                        std::list<Statement *> initialization = std::list<Statement *>() );
    156156        IfStmt( const IfStmt & other );
    157157        virtual ~IfStmt();
     
    160160        Expression * get_condition() { return condition; }
    161161        void set_condition( Expression * newValue ) { condition = newValue; }
    162         Statement * get_then() { return then; }
    163         void set_then( Statement * newValue ) { then = newValue; }
    164         Statement * get_else() { return else_; }
    165         void set_else( Statement * newValue ) { else_ = newValue; }
     162        Statement * get_thenPart() { return thenPart; }
     163        void set_thenPart( Statement * newValue ) { thenPart = newValue; }
     164        Statement * get_elsePart() { return elsePart; }
     165        void set_elsePart( Statement * newValue ) { elsePart = newValue; }
    166166
    167167        virtual IfStmt * clone() const override { return new IfStmt( *this ); }
     
    225225};
    226226
    227 class WhileDoStmt : public Statement {
     227class WhileStmt : public Statement {
    228228  public:
    229229        Expression * condition;
    230230        Statement * body;
    231         Statement * else_;
    232231        std::list<Statement *> initialization;
    233232        bool isDoWhile;
    234233
    235         WhileDoStmt( Expression * condition, Statement * body, const std::list<Statement *> & initialization, bool isDoWhile = false );
    236         WhileDoStmt( Expression * condition, Statement * body, Statement * else_, const std::list<Statement *> & initialization, bool isDoWhile = false );
    237         WhileDoStmt( const WhileDoStmt & other );
    238         virtual ~WhileDoStmt();
     234        WhileStmt( Expression * condition, Statement * body, std::list<Statement *> & initialization, bool isDoWhile = false );
     235        WhileStmt( const WhileStmt & other );
     236        virtual ~WhileStmt();
    239237
    240238        Expression * get_condition() { return condition; }
     
    245243        void set_isDoWhile( bool newValue ) { isDoWhile = newValue; }
    246244
    247         virtual WhileDoStmt * clone() const override { return new WhileDoStmt( *this ); }
     245        virtual WhileStmt * clone() const override { return new WhileStmt( *this ); }
    248246        virtual void accept( Visitor & v ) override { v.visit( this ); }
    249247        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     
    258256        Expression * increment;
    259257        Statement * body;
    260         Statement * else_;
    261 
    262         ForStmt( const std::list<Statement *> initialization, Expression * condition = nullptr, Expression * increment = nullptr, Statement * body = nullptr, Statement * else_ = nullptr );
     258
     259        ForStmt( std::list<Statement *> initialization, Expression * condition = nullptr, Expression * increment = nullptr, Statement * body = nullptr );
    263260        ForStmt( const ForStmt & other );
    264261        virtual ~ForStmt();
     
    281278class BranchStmt : public Statement {
    282279  public:
    283         enum Type { Goto, Break, Continue, FallThrough, FallThroughDefault, BranchStmts };
     280        enum Type { Goto = 0, Break, Continue, FallThrough, FallThroughDefault };
    284281
    285282        // originalTarget kept for error messages.
     
    360357        FinallyStmt * finallyBlock;
    361358
    362         TryStmt( CompoundStmt * tryBlock, const std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = nullptr );
     359        TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = nullptr );
    363360        TryStmt( const TryStmt & other );
    364361        virtual ~TryStmt();
     
    543540        std::list<Expression *> mutexObjs; // list of mutex objects to acquire
    544541
    545         MutexStmt( Statement * stmt, const std::list<Expression *> mutexObjs );
     542        MutexStmt( Statement * stmt, std::list<Expression *> mutexObjs );
    546543        MutexStmt( const MutexStmt & other );
    547544        virtual ~MutexStmt();
  • src/SynTree/SynTree.h

    rf5a51db r97c215f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:22:33 2022
    13 // Update Count     : 14
     12// Last Modified On : Fri Mar 12 18:56:44 2021
     13// Update Count     : 13
    1414//
    1515
     
    4545class DirectiveStmt;
    4646class IfStmt;
    47 class WhileDoStmt;
     47class WhileStmt;
    4848class ForStmt;
    4949class SwitchStmt;
  • src/SynTree/Visitor.h

    rf5a51db r97c215f  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:26:57 2022
    13 // Update Count     : 17
     12// Last Modified On : Fri Mar 12 18:35:35 2021
     13// Update Count     : 15
    1414//
    1515
     
    6060        virtual void visit( IfStmt * node ) { visit( const_cast<const IfStmt *>(node) ); }
    6161        virtual void visit( const IfStmt * ifStmt ) = 0;
    62         virtual void visit( WhileDoStmt * node ) { visit( const_cast<const WhileDoStmt *>(node) ); }
    63         virtual void visit( const WhileDoStmt * whileDoStmt ) = 0;
     62        virtual void visit( WhileStmt * node ) { visit( const_cast<const WhileStmt *>(node) ); }
     63        virtual void visit( const WhileStmt * whileStmt ) = 0;
    6464        virtual void visit( ForStmt * node ) { visit( const_cast<const ForStmt *>(node) ); }
    6565        virtual void visit( const ForStmt * forStmt ) = 0;
  • src/Validate/module.mk

    rf5a51db r97c215f  
    1616
    1717SRC_VALIDATE = \
    18         Validate/Autogen.cpp \
    19         Validate/Autogen.hpp \
    2018        Validate/CompoundLiteral.cpp \
    2119        Validate/CompoundLiteral.hpp \
  • src/main.cc

    rf5a51db r97c215f  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jan 26 14:09:00 2022
    13 // Update Count     : 670
     12// Last Modified On : Tue Nov 30 10:25:00 2021
     13// Update Count     : 659
    1414//
    1515
     
    5555#include "ControlStruct/ExceptTranslate.h"  // for translateEHM
    5656#include "ControlStruct/FixLabels.hpp"      // for fixLabels
    57 #include "ControlStruct/HoistControlDecls.hpp" //  hoistControlDecls
    5857#include "ControlStruct/Mutate.h"           // for mutate
    5958#include "GenPoly/Box.h"                    // for box
     
    7473#include "SynTree/Visitor.h"                // for acceptAll
    7574#include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
    76 #include "Validate/Autogen.hpp"             // for autogenerateRoutines
    7775#include "Validate/FindSpecialDecls.h"      // for findGlobalDecls
    7876#include "Validate/CompoundLiteral.hpp"     // for handleCompoundLiterals
     
    8078#include "Validate/LabelAddressFixer.hpp"   // for fixLabelAddresses
    8179#include "Virtual/ExpandCasts.h"            // for expandCasts
     80
    8281
    8382static void NewPass( const char * const name ) {
     
    327326                PASS( "Validate-B", SymTab::validate_B( translationUnit ) );
    328327                PASS( "Validate-C", SymTab::validate_C( translationUnit ) );
     328                PASS( "Validate-D", SymTab::validate_D( translationUnit ) );
    329329
    330330                CodeTools::fillLocations( translationUnit );
    331331
    332332                if( useNewAST ) {
    333                         PASS( "Apply Concurrent Keywords", Concurrency::applyKeywords( translationUnit ) );
    334                         PASS( "Forall Pointer Decay", SymTab::decayForallPointers( translationUnit ) );
    335                         CodeTools::fillLocations( translationUnit );
    336 
    337333                        if (Stats::Counters::enabled) {
    338334                                ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");
     
    342338
    343339                        forceFillCodeLocations( transUnit );
    344 
    345                         // Must happen before autogen routines are added.
    346                         PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls( transUnit ) );
    347 
    348                         // Must be after enum and pointer decay.
    349                         // Must be before compound literals.
    350                         PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) );
    351340
    352341                        PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
     
    415404                        // Currently not working due to unresolved issues with UniqueExpr
    416405                        PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( transUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    417 
    418                         PASS( "Translate Tries" , ControlStruct::translateTries( transUnit ) );
    419 
    420406                        translationUnit = convert( move( transUnit ) );
    421407                } else {
    422                         PASS( "Validate-D", SymTab::validate_D( translationUnit ) );
    423408                        PASS( "Validate-E", SymTab::validate_E( translationUnit ) );
    424409                        PASS( "Validate-F", SymTab::validate_F( translationUnit ) );
     
    484469
    485470                        PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    486 
    487                         PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) );
    488471                }
    489472
    490                
     473                PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) );
    491474
    492475                PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) );
  • tests/concurrent/.expect/ctor-check.txt

    rf5a51db r97c215f  
    22?{}: function
    33... with parameters
    4   this: lvalue reference to instance of struct Empty with body
     4  lvalue reference to instance of struct Empty with body
    55... returning nothing
    66 with body
  • tests/concurrent/mutexstmt/.expect/locks.txt

    rf5a51db r97c215f  
    33Start Test: multi lock deadlock/mutual exclusion
    44End Test: multi lock deadlock/mutual exclusion
    5 Start Test: single scoped lock mutual exclusion
    6 End Test: single scoped lock mutual exclusion
    7 Start Test: multi scoped lock deadlock/mutual exclusion
    8 End Test: multi scoped lock deadlock/mutual exclusion
  • tests/concurrent/mutexstmt/locks.cfa

    rf5a51db r97c215f  
    5959}
    6060
    61 thread T_Mutex_Scoped {};
    6261
    63 void main( T_Mutex_Scoped & this ) {
    64         for (unsigned int i = 0; i < num_times; i++) {
    65                 {
    66                         scoped_lock(single_acquisition_lock) s{m1};
    67                         count++;
    68                 }
    69                 {
    70                         scoped_lock(single_acquisition_lock) s{m1};
    71                         assert(!insideFlag);
    72                         insideFlag = true;
    73                         assert(insideFlag);
    74                         insideFlag = false;
    75                 }
    76         }
    77 }
    78 
    79 thread T_Multi_Scoped {};
    80 
    81 void main( T_Multi_Scoped & this ) {
    82         for (unsigned int i = 0; i < num_times; i++) {
    83                 {
    84                         scoped_lock(single_acquisition_lock) s{m1};
    85                         assert(!insideFlag);
    86                         insideFlag = true;
    87                         assert(insideFlag);
    88                         insideFlag = false;
    89                 }
    90                 {
    91                         scoped_lock(single_acquisition_lock) s1{m1};
    92                         scoped_lock(single_acquisition_lock) s2{m2};
    93                         scoped_lock(single_acquisition_lock) s3{m3};
    94                         scoped_lock(single_acquisition_lock) s4{m4};
    95                         scoped_lock(single_acquisition_lock) s5{m5};
    96                         assert(!insideFlag);
    97                         insideFlag = true;
    98                         assert(insideFlag);
    99                         insideFlag = false;
    100                 }
    101                 {
    102                         scoped_lock(single_acquisition_lock) s1{m1};
    103                         scoped_lock(single_acquisition_lock) s3{m3};
    104                         assert(!insideFlag);
    105                         insideFlag = true;
    106                         assert(insideFlag);
    107                         insideFlag = false;
    108                 }
    109                 {
    110                         scoped_lock(single_acquisition_lock) s1{m1};
    111                         scoped_lock(single_acquisition_lock) s2{m2};
    112                         scoped_lock(single_acquisition_lock) s4{m4};
    113                         assert(!insideFlag);
    114                         insideFlag = true;
    115                         assert(insideFlag);
    116                         insideFlag = false;
    117                 }
    118                 {
    119                         scoped_lock(single_acquisition_lock) s1{m1};
    120                         scoped_lock(single_acquisition_lock) s3{m3};
    121                         scoped_lock(single_acquisition_lock) s4{m4};
    122                         scoped_lock(single_acquisition_lock) s5{m5};
    123                         assert(!insideFlag);
    124                         insideFlag = true;
    125                         assert(insideFlag);
    126                         insideFlag = false;
    127                 }
    128         }
    129 }
    130 
    131 int num_tasks = 10;
    13262int main() {
    13363        processor p[10];
     
    13767                T_Mutex t[10];
    13868        }
    139         assert(count == num_tasks * num_times);
    14069        printf("End Test: single lock mutual exclusion\n");
    14170        printf("Start Test: multi lock deadlock/mutual exclusion\n");
     
    14473        }
    14574        printf("End Test: multi lock deadlock/mutual exclusion\n");
    146        
    147         count = 0;
    148         printf("Start Test: single scoped lock mutual exclusion\n");
    149         {
    150                 T_Mutex_Scoped t[10];
    151         }
    152         assert(count == num_tasks * num_times);
    153         printf("End Test: single scoped lock mutual exclusion\n");
    154         printf("Start Test: multi scoped lock deadlock/mutual exclusion\n");
    155         {
    156                 T_Multi_Scoped t[10];
    157         }
    158         printf("End Test: multi scoped lock deadlock/mutual exclusion\n");     
    15975}
  • tests/concurrent/preempt.cfa

    rf5a51db r97c215f  
    1 #include <clock.hfa>
    2 #include <fstream.hfa>
    31#include <kernel.hfa>
    42#include <thread.hfa>
     
    2321extern void __cfaabi_check_preemption();
    2422
    25 static struct {
    26         volatile int counter;
    27         volatile Time prev;
    28         Duration durations[6];
    29 } globals;
     23static volatile int counter = 0;
    3024
    3125thread worker_t {
    3226        int value;
    33         unsigned long long spin;
    3427};
    3528
    3629void ?{}( worker_t & this, int value ) {
    3730        this.value = value;
    38         this.spin = 0;
    3931}
    4032
    4133void main(worker_t & this) {
    42         while(TEST(globals.counter < N)) {
    43                 if(this.spin > 50_000_000_000) abort | "Worker" | this.value | "has been spinning too long! (" | this.spin | ")";
     34        while(TEST(counter < N)) {
    4435                __cfaabi_check_preemption();
    45                 if( (globals.counter % 7) == this.value ) {
     36                if( (counter % 7) == this.value ) {
    4637                        __cfaabi_check_preemption();
    47                         #if !defined(TEST_LONG)
    48                                 Time now = timeHiRes();
    49                                 Duration diff = now - globals.prev;
    50                                 globals.prev = now;
    51                         #endif
    52                         int next = __atomic_add_fetch( &globals.counter, 1, __ATOMIC_SEQ_CST );
     38                        int next = __atomic_add_fetch( &counter, 1, __ATOMIC_SEQ_CST );
    5339                        __cfaabi_check_preemption();
    54                         if( (next % 100) == 0 ) {
    55                                 #if !defined(TEST_LONG)
    56                                         unsigned idx = next / 100;
    57                                         if (idx >= 6) abort | "Idx from next is invalid: " | idx | "vs" | next;
    58                                         globals.durations[idx] = diff;
    59                                         if(diff > 12`s) serr | "Duration suspiciously large:" | diff;
    60                                 #endif
    61                                 printf("%d\n", (int)next);
    62 
    63                         }
     40                        if( (next % 100) == 0 ) printf("%d\n", (int)next);
    6441                        __cfaabi_check_preemption();
    65                         this.spin = 0;
    6642                }
    6743                __cfaabi_check_preemption();
    6844                KICK_WATCHDOG;
    69                 this.spin++;
    7045        }
    7146}
     
    7348int main(int argc, char* argv[]) {
    7449        processor p;
    75         globals.counter = 0;
    76         globals.durations[0] = 0;
    77         globals.durations[1] = 0;
    78         globals.durations[2] = 0;
    79         globals.durations[3] = 0;
    80         globals.durations[4] = 0;
    81         globals.durations[5] = 0;
    8250        {
    83                 globals.prev = timeHiRes();
    8451                worker_t w0 = 0;
    8552                worker_t w1 = 1;
  • tests/include/.expect/includes.nast.txt

    rf5a51db r97c215f  
    1 include/includes.cfa:153:25: warning: Compiled
     1include/includes.cfa:154:25: warning: Compiled
  • tests/include/includes.cfa

    rf5a51db r97c215f  
    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 : Sat Jun  5 10:06:46 2021
     13// Update Count     : 751
    1414//
    1515
     
    1818#endif // __CFA__
    1919
    20 #if 1
    2120//#define _GNU_SOURCE
    2221#include <aio.h>
     
    4140#include <errno.h>
    4241#include <error.h>
    43 //#include <eti.h>                                                                              // may not be installed, comes with ncurses
     42//#include <eti.h>                                                                              // may not be installed, comes with ncurses
    4443#include <execinfo.h>
    4544#include <expat.h>
     
    5049#include <fmtmsg.h>
    5150#include <fnmatch.h>
    52 //#include <form.h>                                                                             // may not be installed, comes with ncurses
     51//#include <form.h>                                                                             // may not be installed, comes with ncurses
    5352#include <fstab.h>
    5453#include <fts.h>
     
    7877#include <mcheck.h>
    7978#include <memory.h>
    80 //#include <menu.h>                                                                             // may not be installed, comes with ncurses
     79//#include <menu.h>                                                                             // may not be installed, comes with ncurses
    8180#include <mntent.h>
    8281#include <monetary.h>
    8382#include <mqueue.h>
    84 //#include <ncurses_dll.h>                                                              // may not be installed, comes with ncurses
     83//#include <ncurses_dll.h>                                                                      // may not be installed, comes with ncurses
    8584#include <netdb.h>
    8685#include <nl_types.h>
    8786#include <nss.h>
    8887#include <obstack.h>
    89 //#include <panel.h>                                                                            // may not be installed, comes with ncurses
     88//#include <panel.h>                                                                            // may not be installed, comes with ncurses
    9089#include <paths.h>
    9190#include <poll.h>
     
    118117#include <syslog.h>
    119118#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
     119//#include <term.h>                                                                             // may not be installed, comes with ncurses
     120//#include <termcap.h>                                                                          // may not be installed, comes with ncurses
    122121#include <termio.h>
    123122#include <termios.h>
     
    131130#include <ucontext.h>
    132131#include <ulimit.h>
    133 //#include <unctrl.h>                                                                           // may not be installed, comes with ncurses
     132//#include <unctrl.h>                                                                           // may not be installed, comes with ncurses
    134133#include <unistd.h>
    135134#include <utime.h>
     
    144143#include <wctype.h>
    145144#include <wordexp.h>
     145
     146#if 0
    146147#endif // 0
    147148
     
    150151#endif // __CFA__
    151152
    152 int main( int argc, char const * argv[] ) {
    153     #pragma GCC warning "Compiled"                                                      // force non-empty .expect file, NO TABS!!!
     153int main( int argc, char const *argv[] ) {
     154    #pragma GCC warning "Compiled"                      // force non-empty .expect file, NO TABS!!!
    154155}
    155156
  • tools/auto-complete.md

    rf5a51db r97c215f  
    3232
    3333### Zsh
    34 
    35 1 - Add the following somewhere:
    36     #compdef test.py
    37 
    38     _test_py() {
    39         local -a options
    40         options=$($words[1] --list-comp)
    41         _alternative "files:filenames:($options)"
    42     }
    43 
    44     _test_py "$@"
    45 
    46 2 - Add the path to that file to the "fpath" environment variable.
    47 
    48 3 - In ~/.zshrc add
    49     autoload -U compinit
    50     compinit
    51 
    52 *How it works:* I don't know ;P
    53 
    54 
Note: See TracChangeset for help on using the changeset viewer.