Changes in / [b56ad5e:5f3ba11]


Ignore:
Files:
8 deleted
69 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/thierry_delisle_PhD/thesis/fig/base.fig

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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         // __cfaasm_label(debug, before);
     360        __cfaasm_label(debug, before);
    374361
    375362                sigset_t oldset;
     
    390377                if(ret == 1) { abort("ERROR SIGTERM is disabled"); }
    391378
    392         // __cfaasm_label(debug, after);
     379        __cfaasm_label(debug, after);
    393380}
    394381
     
    561548        __cfaasm_label( check  );
    562549        __cfaasm_label( dsable );
    563         // __cfaasm_label( debug  );
     550        __cfaasm_label( debug  );
    564551
    565552        // Check if preemption is safe
     
    568555        if( __cfaasm_in( ip, check  ) ) { ready = false; goto EXIT; };
    569556        if( __cfaasm_in( ip, dsable ) ) { ready = false; goto EXIT; };
    570         // if( __cfaasm_in( ip, debug  ) ) { ready = false; goto EXIT; };
     557        if( __cfaasm_in( ip, debug  ) ) { ready = false; goto EXIT; };
    571558        if( !__cfaabi_tls.preemption_state.enabled) { ready = false; goto EXIT; };
    572559        if( __cfaabi_tls.preemption_state.in_progress ) { ready = false; goto EXIT; };
     
    674661
    675662        // Check if it is safe to preempt here
    676         if( !preemption_ready( ip ) ) {
    677                 #if !defined(__CFA_NO_STATISTICS__)
    678                         __cfaabi_tls.this_stats->ready.threads.preempt.rllfwd++;
    679                 #endif
    680                 return;
    681         }
     663        if( !preemption_ready( ip ) ) { return; }
    682664
    683665        __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) );
     
    698680
    699681        // Preemption can occur here
    700 
    701         #if !defined(__CFA_NO_STATISTICS__)
    702                 __cfaabi_tls.this_stats->ready.threads.preempt.yield++;
    703         #endif
    704682
    705683        force_yield( __ALARM_PREEMPTION ); // Do the actual __cfactx_switch
  • libcfa/src/concurrency/stats.cfa

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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;
  • src/AST/Pass.impl.hpp

    rb56ad5e r5f3ba11  
    3333        /* call the implementation of the previsit of this pass */ \
    3434        __pass::previsit( core, node, 0 );
     35
     36#define VISIT( code... ) \
     37        /* if this node should visit its children */ \
     38        if ( __visit_children() ) { \
     39                /* visit the children */ \
     40                code \
     41        }
    3542
    3643#define VISIT_END( type, node ) \
     
    445452        VISIT_START( node );
    446453
    447         if ( __visit_children() ) {
     454        VISIT(
    448455                {
    449456                        guard_symtab guard { *this };
     
    453460                maybe_accept( node, &ObjectDecl::bitfieldWidth );
    454461                maybe_accept( node, &ObjectDecl::attributes    );
    455         }
     462        )
    456463
    457464        __pass::symtab::addId( core, 0, node );
     
    468475        __pass::symtab::addId( core, 0, node );
    469476
    470         if ( __visit_children() ) {
    471                 maybe_accept( node, &FunctionDecl::withExprs );
    472         }
     477        VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
    473478        {
    474479                // with clause introduces a level of scope (for the with expression members).
     
    488493                        } };
    489494                        __pass::symtab::addId( core, 0, func );
    490                         if ( __visit_children() ) {
     495                        VISIT(
    491496                                // parameter declarations
    492497                                maybe_accept( node, &FunctionDecl::params );
     
    504509                                maybe_accept( node, &FunctionDecl::stmts );
    505510                                maybe_accept( node, &FunctionDecl::attributes );
    506                         }
     511                        )
    507512                }
    508513        }
     
    521526        __pass::symtab::addStructFwd( core, 0, node );
    522527
    523         if ( __visit_children() ) {
     528        VISIT({
    524529                guard_symtab guard { * this };
    525530                maybe_accept( node, &StructDecl::params     );
    526531                maybe_accept( node, &StructDecl::members    );
    527532                maybe_accept( node, &StructDecl::attributes );
    528         }
     533        })
    529534
    530535        // this addition replaces the forward declaration
     
    543548        __pass::symtab::addUnionFwd( core, 0, node );
    544549
    545         if ( __visit_children() ) {
     550        VISIT({
    546551                guard_symtab guard { * this };
    547552                maybe_accept( node, &UnionDecl::params     );
    548553                maybe_accept( node, &UnionDecl::members    );
    549554                maybe_accept( node, &UnionDecl::attributes );
    550         }
     555        })
    551556
    552557        __pass::symtab::addUnion( core, 0, node );
     
    563568        __pass::symtab::addEnum( core, 0, node );
    564569
    565         if ( __visit_children() ) {
     570        VISIT(
    566571                // unlike structs, traits, and unions, enums inject their members into the global scope
    567572                maybe_accept( node, &EnumDecl::params     );
    568573                maybe_accept( node, &EnumDecl::members    );
    569574                maybe_accept( node, &EnumDecl::attributes );
    570         }
     575        )
    571576
    572577        VISIT_END( Decl, node );
     
    579584        VISIT_START( node );
    580585
    581         if ( __visit_children() ) {
     586        VISIT({
    582587                guard_symtab guard { *this };
    583588                maybe_accept( node, &TraitDecl::params     );
    584589                maybe_accept( node, &TraitDecl::members    );
    585590                maybe_accept( node, &TraitDecl::attributes );
    586         }
     591        })
    587592
    588593        __pass::symtab::addTrait( core, 0, node );
     
    597602        VISIT_START( node );
    598603
    599         if ( __visit_children() ) {
     604        VISIT({
    600605                guard_symtab guard { *this };
    601606                maybe_accept( node, &TypeDecl::base   );
    602         }
     607        })
    603608
    604609        // see A NOTE ON THE ORDER OF TRAVERSAL, above
     
    607612        __pass::symtab::addType( core, 0, node );
    608613
    609         if ( __visit_children() ) {
     614        VISIT(
    610615                maybe_accept( node, &TypeDecl::assertions );
    611616
     
    614619                        maybe_accept( node, &TypeDecl::init );
    615620                }
    616         }
     621        )
    617622
    618623        VISIT_END( Decl, node );
     
    625630        VISIT_START( node );
    626631
    627         if ( __visit_children() ) {
     632        VISIT({
    628633                guard_symtab guard { *this };
    629634                maybe_accept( node, &TypedefDecl::base   );
    630         }
     635        })
    631636
    632637        __pass::symtab::addType( core, 0, node );
    633638
    634         if ( __visit_children() ) {
    635                 maybe_accept( node, &TypedefDecl::assertions );
    636         }
     639        VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
    637640
    638641        VISIT_END( Decl, node );
     
    645648        VISIT_START( node );
    646649
    647         if ( __visit_children() ) {
     650        VISIT(
    648651                maybe_accept( node, &AsmDecl::stmt );
    649         }
     652        )
    650653
    651654        VISIT_END( AsmDecl, node );
     
    658661        VISIT_START( node );
    659662
    660         if ( __visit_children() ) {
     663        VISIT(
    661664                maybe_accept( node, &DirectiveDecl::stmt );
    662         }
     665        )
    663666
    664667        VISIT_END( DirectiveDecl, node );
     
    671674        VISIT_START( node );
    672675
    673         if ( __visit_children() ) {
     676        VISIT(
    674677                maybe_accept( node, &StaticAssertDecl::cond );
    675678                maybe_accept( node, &StaticAssertDecl::msg  );
    676         }
     679        )
    677680
    678681        VISIT_END( StaticAssertDecl, node );
     
    684687const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
    685688        VISIT_START( node );
    686 
    687         if ( __visit_children() ) {
     689        VISIT(
    688690                // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result.
    689691                auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() {
     
    702704                guard_scope guard3 { *this };
    703705                maybe_accept( node, &CompoundStmt::kids );
    704         }
    705 
     706        )
    706707        VISIT_END( CompoundStmt, node );
    707708}
     
    713714        VISIT_START( node );
    714715
    715         if ( __visit_children() ) {
     716        VISIT(
    716717                maybe_accept( node, &ExprStmt::expr );
    717         }
     718        )
    718719
    719720        VISIT_END( Stmt, node );
     
    726727        VISIT_START( node )
    727728
    728         if ( __visit_children() ) {
     729        VISIT(
    729730                maybe_accept( node, &AsmStmt::instruction );
    730731                maybe_accept( node, &AsmStmt::output      );
    731732                maybe_accept( node, &AsmStmt::input       );
    732733                maybe_accept( node, &AsmStmt::clobber     );
    733         }
     734        )
    734735
    735736        VISIT_END( Stmt, node );
     
    751752        VISIT_START( node );
    752753
    753         if ( __visit_children() ) {
     754        VISIT({
    754755                // if statements introduce a level of scope (for the initialization)
    755756                guard_symtab guard { *this };
    756757                maybe_accept( node, &IfStmt::inits    );
    757758                maybe_accept( node, &IfStmt::cond     );
    758                 maybe_accept_as_compound( node, &IfStmt::then );
    759                 maybe_accept_as_compound( node, &IfStmt::else_ );
    760         }
     759                maybe_accept_as_compound( node, &IfStmt::thenPart );
     760                maybe_accept_as_compound( node, &IfStmt::elsePart );
     761        })
    761762
    762763        VISIT_END( Stmt, node );
     
    764765
    765766//--------------------------------------------------------------------------
    766 // WhileDoStmt
    767 template< typename core_t >
    768 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileDoStmt * node ) {
    769         VISIT_START( node );
    770 
    771         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({
    772773                // while statements introduce a level of scope (for the initialization)
    773774                guard_symtab guard { *this };
    774                 maybe_accept( node, &WhileDoStmt::inits );
    775                 maybe_accept( node, &WhileDoStmt::cond  );
    776                 maybe_accept_as_compound( node, &WhileDoStmt::body  );
    777         }
     775                maybe_accept( node, &WhileStmt::inits );
     776                maybe_accept( node, &WhileStmt::cond  );
     777                maybe_accept_as_compound( node, &WhileStmt::body  );
     778        })
    778779
    779780        VISIT_END( Stmt, node );
     
    786787        VISIT_START( node );
    787788
    788         if ( __visit_children() ) {
     789        VISIT({
    789790                // for statements introduce a level of scope (for the initialization)
    790791                guard_symtab guard { *this };
     
    794795                maybe_accept( node, &ForStmt::inc   );
    795796                maybe_accept_as_compound( node, &ForStmt::body  );
    796         }
     797        })
    797798
    798799        VISIT_END( Stmt, node );
     
    805806        VISIT_START( node );
    806807
    807         if ( __visit_children() ) {
     808        VISIT(
    808809                maybe_accept( node, &SwitchStmt::cond  );
    809810                maybe_accept( node, &SwitchStmt::stmts );
    810         }
     811        )
    811812
    812813        VISIT_END( Stmt, node );
     
    819820        VISIT_START( node );
    820821
    821         if ( __visit_children() ) {
     822        VISIT(
    822823                maybe_accept( node, &CaseStmt::cond  );
    823824                maybe_accept( node, &CaseStmt::stmts );
    824         }
     825        )
    825826
    826827        VISIT_END( Stmt, node );
     
    841842        VISIT_START( node );
    842843
    843         if ( __visit_children() ) {
     844        VISIT(
    844845                maybe_accept( node, &ReturnStmt::expr );
    845         }
     846        )
    846847
    847848        VISIT_END( Stmt, node );
     
    854855        VISIT_START( node );
    855856
    856         if ( __visit_children() ) {
     857        VISIT(
    857858                maybe_accept( node, &ThrowStmt::expr   );
    858859                maybe_accept( node, &ThrowStmt::target );
    859         }
     860        )
    860861
    861862        VISIT_END( Stmt, node );
     
    868869        VISIT_START( node );
    869870
    870         if ( __visit_children() ) {
     871        VISIT(
    871872                maybe_accept( node, &TryStmt::body     );
    872873                maybe_accept( node, &TryStmt::handlers );
    873874                maybe_accept( node, &TryStmt::finally  );
    874         }
     875        )
    875876
    876877        VISIT_END( Stmt, node );
     
    883884        VISIT_START( node );
    884885
    885         if ( __visit_children() ) {
     886        VISIT({
    886887                // catch statements introduce a level of scope (for the caught exception)
    887888                guard_symtab guard { *this };
     
    889890                maybe_accept( node, &CatchStmt::cond );
    890891                maybe_accept_as_compound( node, &CatchStmt::body );
    891         }
     892        })
    892893
    893894        VISIT_END( Stmt, node );
     
    900901        VISIT_START( node );
    901902
    902         if ( __visit_children() ) {
     903        VISIT(
    903904                maybe_accept( node, &FinallyStmt::body );
    904         }
     905        )
    905906
    906907        VISIT_END( Stmt, node );
     
    913914        VISIT_START( node );
    914915
    915         if ( __visit_children() ) {
     916        VISIT(
    916917                maybe_accept( node, &SuspendStmt::then   );
    917         }
     918        )
    918919
    919920        VISIT_END( Stmt, node );
     
    933934                // }
    934935
    935         if ( __visit_children() ) {
     936        VISIT({
    936937                std::vector<WaitForStmt::Clause> new_clauses;
    937938                new_clauses.reserve( node->clauses.size() );
     
    964965                        node = n;
    965966                }
    966         }
     967        })
    967968
    968969        #define maybe_accept(field) \
     
    976977                }
    977978
    978         if ( __visit_children() ) {
     979        VISIT(
    979980                maybe_accept( timeout.time );
    980981                maybe_accept( timeout.stmt );
     
    982983                maybe_accept( orElse.stmt  );
    983984                maybe_accept( orElse.cond  );
    984         }
     985        )
    985986
    986987        #undef maybe_accept
     
    995996        VISIT_START( node );
    996997
    997         if ( __visit_children() ) {
     998        VISIT(
    998999                maybe_accept( node, &WithStmt::exprs );
    9991000                {
     
    10031004                        maybe_accept( node, &WithStmt::stmt );
    10041005                }
    1005         }
    1006 
     1006        )
    10071007        VISIT_END( Stmt, node );
    10081008}
     
    10221022        VISIT_START( node );
    10231023
    1024         if ( __visit_children() ) {
     1024        VISIT(
    10251025                maybe_accept( node, &DeclStmt::decl );
    1026         }
     1026        )
    10271027
    10281028        VISIT_END( Stmt, node );
     
    10371037        // For now this isn't visited, it is unclear if this causes problem
    10381038        // if all tests are known to pass, remove this code
    1039         if ( __visit_children() ) {
     1039        VISIT(
    10401040                maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
    1041         }
     1041        )
    10421042
    10431043        VISIT_END( Stmt, node );
     
    10501050        VISIT_START( node );
    10511051
    1052         if ( __visit_children() ) {
     1052        VISIT({
    10531053                // mutex statements introduce a level of scope (for the initialization)
    10541054                guard_symtab guard { *this };
    10551055                maybe_accept( node, &MutexStmt::stmt );
    10561056                maybe_accept( node, &MutexStmt::mutexObjs );
    1057         }
     1057        })
    10581058
    10591059        VISIT_END( Stmt, node );
     
    10661066        VISIT_START( node );
    10671067
    1068         if ( __visit_children() ) {
     1068        VISIT(
    10691069                {
    10701070                        guard_symtab guard { *this };
     
    10731073                maybe_accept( node, &ApplicationExpr::func );
    10741074                maybe_accept( node, &ApplicationExpr::args );
    1075         }
     1075        )
    10761076
    10771077        VISIT_END( Expr, node );
     
    10841084        VISIT_START( node );
    10851085
    1086         if ( __visit_children() ) {
     1086        VISIT(
    10871087                {
    10881088                        guard_symtab guard { *this };
     
    10911091
    10921092                maybe_accept( node, &UntypedExpr::args );
    1093         }
     1093        )
    10941094
    10951095        VISIT_END( Expr, node );
     
    11021102        VISIT_START( node );
    11031103
    1104         if ( __visit_children() ) {
     1104        VISIT({
    11051105                guard_symtab guard { *this };
    11061106                maybe_accept( node, &NameExpr::result );
    1107         }
     1107        })
    11081108
    11091109        VISIT_END( Expr, node );
     
    11161116        VISIT_START( node );
    11171117
    1118         if ( __visit_children() ) {
    1119                 {
     1118        VISIT({
    11201119                        guard_symtab guard { *this };
    11211120                        maybe_accept( node, &CastExpr::result );
    11221121                }
    11231122                maybe_accept( node, &CastExpr::arg );
    1124         }
     1123        )
    11251124
    11261125        VISIT_END( Expr, node );
     
    11331132        VISIT_START( node );
    11341133
    1135         if ( __visit_children() ) {
    1136                 {
     1134        VISIT({
    11371135                        guard_symtab guard { *this };
    11381136                        maybe_accept( node, &KeywordCastExpr::result );
    11391137                }
    11401138                maybe_accept( node, &KeywordCastExpr::arg );
    1141         }
     1139        )
    11421140
    11431141        VISIT_END( Expr, node );
     
    11501148        VISIT_START( node );
    11511149
    1152         if ( __visit_children() ) {
    1153                 {
     1150        VISIT({
    11541151                        guard_symtab guard { *this };
    11551152                        maybe_accept( node, &VirtualCastExpr::result );
    11561153                }
    11571154                maybe_accept( node, &VirtualCastExpr::arg );
    1158         }
     1155        )
    11591156
    11601157        VISIT_END( Expr, node );
     
    11671164        VISIT_START( node );
    11681165
    1169         if ( __visit_children() ) {
    1170                 {
     1166        VISIT({
    11711167                        guard_symtab guard { *this };
    11721168                        maybe_accept( node, &AddressExpr::result );
    11731169                }
    11741170                maybe_accept( node, &AddressExpr::arg );
    1175         }
     1171        )
    11761172
    11771173        VISIT_END( Expr, node );
     
    11841180        VISIT_START( node );
    11851181
    1186         if ( __visit_children() ) {
     1182        VISIT({
    11871183                guard_symtab guard { *this };
    11881184                maybe_accept( node, &LabelAddressExpr::result );
    1189         }
     1185        })
    11901186
    11911187        VISIT_END( Expr, node );
     
    11981194        VISIT_START( node );
    11991195
    1200         if ( __visit_children() ) {
    1201                 {
     1196        VISIT({
    12021197                        guard_symtab guard { *this };
    12031198                        maybe_accept( node, &UntypedMemberExpr::result );
     
    12051200                maybe_accept( node, &UntypedMemberExpr::aggregate );
    12061201                maybe_accept( node, &UntypedMemberExpr::member    );
    1207         }
     1202        )
    12081203
    12091204        VISIT_END( Expr, node );
     
    12161211        VISIT_START( node );
    12171212
    1218         if ( __visit_children() ) {
    1219                 {
     1213        VISIT({
    12201214                        guard_symtab guard { *this };
    12211215                        maybe_accept( node, &MemberExpr::result );
    12221216                }
    12231217                maybe_accept( node, &MemberExpr::aggregate );
    1224         }
     1218        )
    12251219
    12261220        VISIT_END( Expr, node );
     
    12331227        VISIT_START( node );
    12341228
    1235         if ( __visit_children() ) {
     1229        VISIT({
    12361230                guard_symtab guard { *this };
    12371231                maybe_accept( node, &VariableExpr::result );
    1238         }
     1232        })
    12391233
    12401234        VISIT_END( Expr, node );
     
    12471241        VISIT_START( node );
    12481242
    1249         if ( __visit_children() ) {
     1243        VISIT({
    12501244                guard_symtab guard { *this };
    12511245                maybe_accept( node, &ConstantExpr::result );
    1252         }
     1246        })
    12531247
    12541248        VISIT_END( Expr, node );
     
    12611255        VISIT_START( node );
    12621256
    1263         if ( __visit_children() ) {
    1264                 {
     1257        VISIT({
    12651258                        guard_symtab guard { *this };
    12661259                        maybe_accept( node, &SizeofExpr::result );
     
    12711264                        maybe_accept( node, &SizeofExpr::expr );
    12721265                }
    1273         }
     1266        )
    12741267
    12751268        VISIT_END( Expr, node );
     
    12821275        VISIT_START( node );
    12831276
    1284         if ( __visit_children() ) {
    1285                 {
     1277        VISIT({
    12861278                        guard_symtab guard { *this };
    12871279                        maybe_accept( node, &AlignofExpr::result );
     
    12921284                        maybe_accept( node, &AlignofExpr::expr );
    12931285                }
    1294         }
     1286        )
    12951287
    12961288        VISIT_END( Expr, node );
     
    13031295        VISIT_START( node );
    13041296
    1305         if ( __visit_children() ) {
    1306                 {
     1297        VISIT({
    13071298                        guard_symtab guard { *this };
    13081299                        maybe_accept( node, &UntypedOffsetofExpr::result );
    13091300                }
    13101301                maybe_accept( node, &UntypedOffsetofExpr::type   );
    1311         }
     1302        )
    13121303
    13131304        VISIT_END( Expr, node );
     
    13201311        VISIT_START( node );
    13211312
    1322         if ( __visit_children() ) {
    1323                 {
     1313        VISIT({
    13241314                        guard_symtab guard { *this };
    13251315                        maybe_accept( node, &OffsetofExpr::result );
    13261316                }
    13271317                maybe_accept( node, &OffsetofExpr::type   );
    1328         }
     1318        )
    13291319
    13301320        VISIT_END( Expr, node );
     
    13371327        VISIT_START( node );
    13381328
    1339         if ( __visit_children() ) {
    1340                 {
     1329        VISIT({
    13411330                        guard_symtab guard { *this };
    13421331                        maybe_accept( node, &OffsetPackExpr::result );
    13431332                }
    13441333                maybe_accept( node, &OffsetPackExpr::type   );
    1345         }
     1334        )
    13461335
    13471336        VISIT_END( Expr, node );
     
    13541343        VISIT_START( node );
    13551344
    1356         if ( __visit_children() ) {
    1357                 {
     1345        VISIT({
    13581346                        guard_symtab guard { *this };
    13591347                        maybe_accept( node, &LogicalExpr::result );
     
    13611349                maybe_accept( node, &LogicalExpr::arg1 );
    13621350                maybe_accept( node, &LogicalExpr::arg2 );
    1363         }
     1351        )
    13641352
    13651353        VISIT_END( Expr, node );
     
    13721360        VISIT_START( node );
    13731361
    1374         if ( __visit_children() ) {
    1375                 {
     1362        VISIT({
    13761363                        guard_symtab guard { *this };
    13771364                        maybe_accept( node, &ConditionalExpr::result );
     
    13801367                maybe_accept( node, &ConditionalExpr::arg2 );
    13811368                maybe_accept( node, &ConditionalExpr::arg3 );
    1382         }
     1369        )
    13831370
    13841371        VISIT_END( Expr, node );
     
    13911378        VISIT_START( node );
    13921379
    1393         if ( __visit_children() ) {
    1394                 {
     1380        VISIT({
    13951381                        guard_symtab guard { *this };
    13961382                        maybe_accept( node, &CommaExpr::result );
     
    13981384                maybe_accept( node, &CommaExpr::arg1 );
    13991385                maybe_accept( node, &CommaExpr::arg2 );
    1400         }
     1386        )
    14011387
    14021388        VISIT_END( Expr, node );
     
    14091395        VISIT_START( node );
    14101396
    1411         if ( __visit_children() ) {
    1412                 {
     1397        VISIT({
    14131398                        guard_symtab guard { *this };
    14141399                        maybe_accept( node, &TypeExpr::result );
    14151400                }
    14161401                maybe_accept( node, &TypeExpr::type );
    1417         }
     1402        )
    14181403
    14191404        VISIT_END( Expr, node );
     
    14261411        VISIT_START( node );
    14271412
    1428         if ( __visit_children() ) {
    1429                 {
     1413        VISIT({
    14301414                        guard_symtab guard { *this };
    14311415                        maybe_accept( node, &AsmExpr::result );
     
    14331417                maybe_accept( node, &AsmExpr::constraint );
    14341418                maybe_accept( node, &AsmExpr::operand    );
    1435         }
     1419        )
    14361420
    14371421        VISIT_END( Expr, node );
     
    14441428        VISIT_START( node );
    14451429
    1446         if ( __visit_children() ) {
    1447                 {
     1430        VISIT({
    14481431                        guard_symtab guard { *this };
    14491432                        maybe_accept( node, &ImplicitCopyCtorExpr::result );
    14501433                }
    14511434                maybe_accept( node, &ImplicitCopyCtorExpr::callExpr    );
    1452         }
     1435        )
    14531436
    14541437        VISIT_END( Expr, node );
     
    14611444        VISIT_START( node );
    14621445
    1463         if ( __visit_children() ) {
    1464                 {
     1446        VISIT({
    14651447                        guard_symtab guard { *this };
    14661448                        maybe_accept( node, &ConstructorExpr::result );
    14671449                }
    14681450                maybe_accept( node, &ConstructorExpr::callExpr );
    1469         }
     1451        )
    14701452
    14711453        VISIT_END( Expr, node );
     
    14781460        VISIT_START( node );
    14791461
    1480         if ( __visit_children() ) {
    1481                 {
     1462        VISIT({
    14821463                        guard_symtab guard { *this };
    14831464                        maybe_accept( node, &CompoundLiteralExpr::result );
    14841465                }
    14851466                maybe_accept( node, &CompoundLiteralExpr::init );
    1486         }
     1467        )
    14871468
    14881469        VISIT_END( Expr, node );
     
    14951476        VISIT_START( node );
    14961477
    1497         if ( __visit_children() ) {
    1498                 {
     1478        VISIT({
    14991479                        guard_symtab guard { *this };
    15001480                        maybe_accept( node, &RangeExpr::result );
     
    15021482                maybe_accept( node, &RangeExpr::low    );
    15031483                maybe_accept( node, &RangeExpr::high   );
    1504         }
     1484        )
    15051485
    15061486        VISIT_END( Expr, node );
     
    15131493        VISIT_START( node );
    15141494
    1515         if ( __visit_children() ) {
    1516                 {
     1495        VISIT({
    15171496                        guard_symtab guard { *this };
    15181497                        maybe_accept( node, &UntypedTupleExpr::result );
    15191498                }
    15201499                maybe_accept( node, &UntypedTupleExpr::exprs  );
    1521         }
     1500        )
    15221501
    15231502        VISIT_END( Expr, node );
     
    15301509        VISIT_START( node );
    15311510
    1532         if ( __visit_children() ) {
    1533                 {
     1511        VISIT({
    15341512                        guard_symtab guard { *this };
    15351513                        maybe_accept( node, &TupleExpr::result );
    15361514                }
    15371515                maybe_accept( node, &TupleExpr::exprs  );
    1538         }
     1516        )
    15391517
    15401518        VISIT_END( Expr, node );
     
    15471525        VISIT_START( node );
    15481526
    1549         if ( __visit_children() ) {
    1550                 {
     1527        VISIT({
    15511528                        guard_symtab guard { *this };
    15521529                        maybe_accept( node, &TupleIndexExpr::result );
    15531530                }
    15541531                maybe_accept( node, &TupleIndexExpr::tuple  );
    1555         }
     1532        )
    15561533
    15571534        VISIT_END( Expr, node );
     
    15641541        VISIT_START( node );
    15651542
    1566         if ( __visit_children() ) {
    1567                 {
     1543        VISIT({
    15681544                        guard_symtab guard { *this };
    15691545                        maybe_accept( node, &TupleAssignExpr::result );
    15701546                }
    15711547                maybe_accept( node, &TupleAssignExpr::stmtExpr );
    1572         }
     1548        )
    15731549
    15741550        VISIT_END( Expr, node );
     
    15811557        VISIT_START( node );
    15821558
    1583         if ( __visit_children() ) {
    1584                 // 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
    15851560                // get the stmts that will need to be spliced in
    15861561                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     
    15991574                maybe_accept( node, &StmtExpr::returnDecls );
    16001575                maybe_accept( node, &StmtExpr::dtors       );
    1601         }
     1576        )
    16021577
    16031578        VISIT_END( Expr, node );
     
    16101585        VISIT_START( node );
    16111586
    1612         if ( __visit_children() ) {
    1613                 {
     1587        VISIT({
    16141588                        guard_symtab guard { *this };
    16151589                        maybe_accept( node, &UniqueExpr::result );
    16161590                }
    16171591                maybe_accept( node, &UniqueExpr::expr   );
    1618         }
     1592        )
    16191593
    16201594        VISIT_END( Expr, node );
     
    16271601        VISIT_START( node );
    16281602
    1629         if ( __visit_children() ) {
    1630                 {
     1603        VISIT({
    16311604                        guard_symtab guard { *this };
    16321605                        maybe_accept( node, &UntypedInitExpr::result );
     
    16341607                maybe_accept( node, &UntypedInitExpr::expr   );
    16351608                // not currently visiting initAlts, but this doesn't matter since this node is only used in the resolver.
    1636         }
     1609        )
    16371610
    16381611        VISIT_END( Expr, node );
     
    16451618        VISIT_START( node );
    16461619
    1647         if ( __visit_children() ) {
    1648                 {
     1620        VISIT({
    16491621                        guard_symtab guard { *this };
    16501622                        maybe_accept( node, &InitExpr::result );
     
    16521624                maybe_accept( node, &InitExpr::expr   );
    16531625                maybe_accept( node, &InitExpr::designation );
    1654         }
     1626        )
    16551627
    16561628        VISIT_END( Expr, node );
     
    16631635        VISIT_START( node );
    16641636
    1665         if ( __visit_children() ) {
    1666                 {
     1637        VISIT({
    16671638                        guard_symtab guard { *this };
    16681639                        maybe_accept( node, &DeletedExpr::result );
     
    16701641                maybe_accept( node, &DeletedExpr::expr );
    16711642                // don't visit deleteStmt, because it is a pointer to somewhere else in the tree.
    1672         }
     1643        )
    16731644
    16741645        VISIT_END( Expr, node );
     
    16811652        VISIT_START( node );
    16821653
    1683         if ( __visit_children() ) {
    1684                 {
     1654        VISIT({
    16851655                        guard_symtab guard { *this };
    16861656                        maybe_accept( node, &DefaultArgExpr::result );
    16871657                }
    16881658                maybe_accept( node, &DefaultArgExpr::expr );
    1689         }
     1659        )
    16901660
    16911661        VISIT_END( Expr, node );
     
    16981668        VISIT_START( node );
    16991669
    1700         if ( __visit_children() ) {
    1701                 {
     1670        VISIT({
    17021671                        guard_symtab guard { *this };
    17031672                        maybe_accept( node, &GenericExpr::result );
     
    17281697                        node = n;
    17291698                }
    1730         }
     1699        )
    17311700
    17321701        VISIT_END( Expr, node );
     
    17571726        VISIT_START( node );
    17581727
    1759         if ( __visit_children() ) {
     1728        VISIT(
    17601729                // xxx - should PointerType visit/mutate dimension?
    17611730                maybe_accept( node, &PointerType::base );
    1762         }
     1731        )
    17631732
    17641733        VISIT_END( Type, node );
     
    17711740        VISIT_START( node );
    17721741
    1773         if ( __visit_children() ) {
     1742        VISIT(
    17741743                maybe_accept( node, &ArrayType::dimension );
    17751744                maybe_accept( node, &ArrayType::base );
    1776         }
     1745        )
    17771746
    17781747        VISIT_END( Type, node );
     
    17851754        VISIT_START( node );
    17861755
    1787         if ( __visit_children() ) {
     1756        VISIT(
    17881757                maybe_accept( node, &ReferenceType::base );
    1789         }
     1758        )
    17901759
    17911760        VISIT_END( Type, node );
     
    17981767        VISIT_START( node );
    17991768
    1800         if ( __visit_children() ) {
     1769        VISIT(
    18011770                maybe_accept( node, &QualifiedType::parent );
    18021771                maybe_accept( node, &QualifiedType::child );
    1803         }
     1772        )
    18041773
    18051774        VISIT_END( Type, node );
     
    18121781        VISIT_START( node );
    18131782
    1814         if ( __visit_children() ) {
     1783        VISIT({
    18151784                // guard_forall_subs forall_guard { *this, node };
    18161785                // mutate_forall( node );
     
    18181787                maybe_accept( node, &FunctionType::returns );
    18191788                maybe_accept( node, &FunctionType::params  );
    1820         }
     1789        })
    18211790
    18221791        VISIT_END( Type, node );
     
    18311800        __pass::symtab::addStruct( core, 0, node->name );
    18321801
    1833         if ( __visit_children() ) {
     1802        VISIT({
    18341803                guard_symtab guard { *this };
    18351804                maybe_accept( node, &StructInstType::params );
    1836         }
     1805        })
    18371806
    18381807        VISIT_END( Type, node );
     
    18471816        __pass::symtab::addUnion( core, 0, node->name );
    18481817
    1849         if ( __visit_children() ) {
     1818        VISIT({
    18501819                guard_symtab guard { *this };
    18511820                maybe_accept( node, &UnionInstType::params );
    1852         }
     1821        })
    18531822
    18541823        VISIT_END( Type, node );
     
    18611830        VISIT_START( node );
    18621831
    1863         if ( __visit_children() ) {
     1832        VISIT({
    18641833                maybe_accept( node, &EnumInstType::params );
    1865         }
     1834        })
    18661835
    18671836        VISIT_END( Type, node );
     
    18741843        VISIT_START( node );
    18751844
    1876         if ( __visit_children() ) {
     1845        VISIT({
    18771846                maybe_accept( node, &TraitInstType::params );
    1878         }
     1847        })
    18791848
    18801849        VISIT_END( Type, node );
     
    18871856        VISIT_START( node );
    18881857
    1889         if ( __visit_children() ) {
     1858        VISIT(
    18901859                {
    18911860                        maybe_accept( node, &TypeInstType::params );
     
    18931862                // ensure that base re-bound if doing substitution
    18941863                __pass::forall::replace( core, 0, node );
    1895         }
     1864        )
    18961865
    18971866        VISIT_END( Type, node );
     
    19041873        VISIT_START( node );
    19051874
    1906         if ( __visit_children() ) {
     1875        VISIT(
    19071876                maybe_accept( node, &TupleType::types );
    19081877                maybe_accept( node, &TupleType::members );
    1909         }
     1878        )
    19101879
    19111880        VISIT_END( Type, node );
     
    19181887        VISIT_START( node );
    19191888
    1920         if ( __visit_children() ) {
     1889        VISIT(
    19211890                maybe_accept( node, &TypeofType::expr );
    1922         }
     1891        )
    19231892
    19241893        VISIT_END( Type, node );
     
    19311900        VISIT_START( node );
    19321901
    1933         if ( __visit_children() ) {
     1902        VISIT(
    19341903                maybe_accept( node, &VTableType::base );
    1935         }
     1904        )
    19361905
    19371906        VISIT_END( Type, node );
     
    19811950        VISIT_START( node );
    19821951
    1983         if ( __visit_children() ) {
    1984                 maybe_accept( node, &Designation::designators );
    1985         }
     1952        VISIT( maybe_accept( node, &Designation::designators ); )
    19861953
    19871954        VISIT_END( Designation, node );
     
    19941961        VISIT_START( node );
    19951962
    1996         if ( __visit_children() ) {
     1963        VISIT(
    19971964                maybe_accept( node, &SingleInit::value );
    1998         }
     1965        )
    19991966
    20001967        VISIT_END( Init, node );
     
    20071974        VISIT_START( node );
    20081975
    2009         if ( __visit_children() ) {
     1976        VISIT(
    20101977                maybe_accept( node, &ListInit::designations );
    20111978                maybe_accept( node, &ListInit::initializers );
    2012         }
     1979        )
    20131980
    20141981        VISIT_END( Init, node );
     
    20211988        VISIT_START( node );
    20221989
    2023         if ( __visit_children() ) {
     1990        VISIT(
    20241991                maybe_accept( node, &ConstructorInit::ctor );
    20251992                maybe_accept( node, &ConstructorInit::dtor );
    20261993                maybe_accept( node, &ConstructorInit::init );
    2027         }
     1994        )
    20281995
    20291996        VISIT_END( Init, node );
     
    20362003        VISIT_START( node );
    20372004
    2038         if ( __visit_children() ) {
     2005        VISIT(
    20392006                maybe_accept( node, &Attribute::params );
    2040         }
     2007        )
    20412008
    20422009        VISIT_END( Attribute, node );
     
    20492016        VISIT_START( node );
    20502017
    2051         if ( __visit_children() ) {
     2018        VISIT(
    20522019                {
    20532020                        bool mutated = false;
     
    20652032                        }
    20662033                }
    2067         }
     2034        )
    20682035
    20692036        VISIT_END( TypeSubstitution, node );
     
    20712038
    20722039#undef VISIT_START
     2040#undef VISIT
    20732041#undef VISIT_END
  • src/AST/Print.cpp

    rb56ad5e r5f3ba11  
    511511                ++indent;
    512512                os << indent;
    513                 safe_print( node->then );
    514                 --indent;
    515 
    516                 if ( node->else_ != 0 ) {
     513                safe_print( node->thenPart );
     514                --indent;
     515
     516                if ( node->elsePart != 0 ) {
    517517                        os << indent << "... else:" << endl;
    518518                        ++indent;
    519519                        os << indent;
    520                         node->else_->accept( *this );
     520                        node->elsePart->accept( *this );
    521521                        --indent;
    522522                } // if
     
    524524        }
    525525
    526         virtual const ast::Stmt * visit( const ast::WhileDoStmt * node ) override final {
     526        virtual const ast::Stmt * visit( const ast::WhileStmt * node ) override final {
    527527                if ( node->isDoWhile ) { os << "Do-"; }
    528528                os << "While on condition:" << endl;
  • src/AST/Stmt.cpp

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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/ControlStruct/ExceptTranslateNew.cpp

    rb56ad5e r5f3ba11  
    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
  • src/ControlStruct/FixLabels.cpp

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

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

    rb56ad5e r5f3ba11  
    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 ) );
     
    420409                        translationUnit = convert( move( transUnit ) );
    421410                } else {
    422                         PASS( "Validate-D", SymTab::validate_D( translationUnit ) );
    423411                        PASS( "Validate-E", SymTab::validate_E( translationUnit ) );
    424412                        PASS( "Validate-F", SymTab::validate_F( translationUnit ) );
  • tests/concurrent/.expect/ctor-check.txt

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    1 #include <clock.hfa>
    21#include <fstream.hfa>
    32#include <kernel.hfa>
     
    2322extern void __cfaabi_check_preemption();
    2423
    25 static struct {
    26         volatile int counter;
    27         volatile Time prev;
    28         Duration durations[6];
    29 } globals;
     24static volatile int counter = 0;
    3025
    3126thread worker_t {
    3227        int value;
    33         unsigned long long spin;
     28        unsigned spin;
    3429};
    3530
     
    4035
    4136void 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 | ")";
     37        while(TEST(counter < N)) {
     38                if(this.spin > 100_000_000) abort | "Worker" | this.value | "has been spinning too long! (" | this.spin | ")";
    4439                __cfaabi_check_preemption();
    45                 if( (globals.counter % 7) == this.value ) {
     40                if( (counter % 7) == this.value ) {
    4641                        __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 );
     42                        int next = __atomic_add_fetch( &counter, 1, __ATOMIC_SEQ_CST );
    5343                        __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                         }
     44                        if( (next % 100) == 0 ) printf("%d\n", (int)next);
    6445                        __cfaabi_check_preemption();
    6546                        this.spin = 0;
     
    7354int main(int argc, char* argv[]) {
    7455        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;
    8256        {
    83                 globals.prev = timeHiRes();
    8457                worker_t w0 = 0;
    8558                worker_t w1 = 1;
  • tests/include/.expect/includes.nast.txt

    rb56ad5e r5f3ba11  
    1 include/includes.cfa:153:25: warning: Compiled
     1include/includes.cfa:154:25: warning: Compiled
  • tests/include/includes.cfa

    rb56ad5e r5f3ba11  
    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

    rb56ad5e r5f3ba11  
    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.