Changeset eba74ba


Ignore:
Timestamp:
May 25, 2018, 2:51:06 PM (3 years ago)
Author:
Aaron Moss <a3moss@…>
Branches:
new-env, with_gc
Children:
cdc4d43
Parents:
3ef35bd (diff), 58e822a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge remote-tracking branch 'origin/master' into with_gc

Files:
8 added
84 edited
2 moved

Legend:

Unmodified
Added
Removed
  • doc/bibliography/pl.bib

    r3ef35bd reba74ba  
    377377}
    378378
     379@article{Hoare61,
     380    keywords    = {quick sort},
     381    contributer = {pabuhr@plg},
     382    author      = {C. A. R. Hoare},
     383    title       = {Algorithms 63/64: Partition/Quicksort},
     384    journal     = cacm,
     385    volume      = 4,
     386    number      = 7,
     387    month       = jul,
     388    year        = 1961,
     389    pages       = {321},
     390}
     391
    379392@article{Cormack81,
    380393    keywords    = {},
     
    635648    year        = 2008,
    636649    pages       = {8-15},
     650}
     651
     652@article{Joung00,
     653    author      = {Joung, Yuh-Jzer},
     654    title       = {Asynchronous group mutual exclusion},
     655    journal     = {Distributed Computing},
     656    year        = {2000},
     657    month       = {Nov},
     658    volume      = {13},
     659    number      = {4},
     660    pages       = {189--206},
    637661}
    638662
     
    57915815@manual{Python,
    57925816    keywords    = {Python},
    5793     contributer = {pabuhr},
     5817    contributer = {pabuhr@plg},
    57945818    title       = {Python Reference Manual, Release 2.5},
    57955819    author      = {Guido van Rossum},
     
    58225846}
    58235847
    5824 @article{Hoare61,
    5825     keywords    = {quick sort},
    5826     contributer = {pabuhr@plg},
    5827     author      = {C. A. R. Hoare},
    5828     title       = {Algorithms 63/64: Partition/Quicksort},
    5829     journal     = cacm,
    5830     volume      = 4,
    5831     number      = 7,
    5832     month       = jul,
    5833     year        = 1961,
    5834     pages       = {321},
     5848@article{Nakaike15,
     5849    keywords    = {hardware transactional memory},
     5850    contributer = {pabuhr@plg},
     5851    author      = {Nakaike, Takuya and Odaira, Rei and Gaudet, Matthew and Michael, Maged M. and Tomari, Hisanobu},
     5852    title       = {Quantitative Comparison of Hardware Transactional Memory for Blue Gene/Q, zEnterprise {EC12}, {I}ntel Core, and {POWER8}},
     5853    journal     = {SIGARCH Comput. Archit. News},
     5854    volume      = {43},
     5855    number      = {3},
     5856    month       = jun,
     5857    year        = {2015},
     5858    pages       = {144--157},
     5859    publisher   = {ACM},
     5860    address     = {New York, NY, USA},
    58355861}
    58365862
  • doc/papers/concurrency/Paper.tex

    r3ef35bd reba74ba  
    7070%\DeclareTextCommandDefault{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.1ex}}}
    7171\renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}
    72 %\def\myCHarFont{\fontencoding{T1}\selectfont}%
    73 % \def\{{\ttfamily\upshape\myCHarFont \char`\}}}%
    7472
    7573\renewcommand*{\thefootnote}{\Alph{footnote}} % hack because fnsymbol does not work
     
    741739The coroutine main's stack holds the state for the next generation, @f1@ and @f2@, and the code has the three suspend points, representing the three states in the Fibonacci formula, to context switch back to the caller's resume.
    742740The interface function, @next@, takes a Fibonacci instance and context switches to it using @resume@;
    743 on return, the Fibonacci field, @fn@, contains the next value in the sequence, which is returned.
     741on restart, the Fibonacci field, @fn@, contains the next value in the sequence, which is returned.
    744742The first @resume@ is special because it cocalls the coroutine at its coroutine main and allocates the stack;
    745743when the coroutine main returns, its stack is deallocated.
    746744Hence, @Fib@ is an object at creation, transitions to a coroutine on its first resume, and transitions back to an object when the coroutine main finishes.
    747745Figure~\ref{f:Coroutine1State} shows the coroutine version of the C version in Figure~\ref{f:ExternalState}.
    748 Coroutine generators are called \newterm{output coroutines} because values are returned by the coroutine.
    749 
    750 Figure~\ref{f:CFAFmt} shows an \newterm{input coroutine}, @Format@, for restructuring text into groups of character blocks of fixed size.
     746Coroutine generators are called \newterm{output coroutines} because values are only returned.
     747
     748Figure~\ref{f:CFAFmt} shows an \newterm{input coroutine}, @Format@, for restructuring text into groups of characters of fixed-size blocks.
    751749For example, the input of the left is reformatted into the output on the right.
    752750\begin{quote}
     
    763761\end{tabular}
    764762\end{quote}
    765 The example takes advantage of resuming coroutines in the constructor to prime the coroutine loops so the first character sent for formatting appears inside the nested loops.
     763The example takes advantage of resuming a coroutine in the constructor to prime the loops so the first character sent for formatting appears inside the nested loops.
    766764The destruction provides a newline if formatted text ends with a full line.
    767765Figure~\ref{f:CFmt} shows the C equivalent formatter, where the loops of the coroutine are flatten (linearized) and rechecked on each call because execution location is not retained between calls.
     
    778776void main( Format & fmt ) with( fmt ) {
    779777        for ( ;; ) {   
    780                 for ( g = 0; g < 5; g += 1 ) {  // group
     778                for ( g = 0; g < 5; g += 1 ) {      // group
    781779                        for ( b = 0; b < 4; b += 1 ) { // block
    782780                                `suspend();`
     
    814812};
    815813void format( struct Format * fmt ) {
    816         if ( fmt->ch != -1 ) { // not EOF
     814        if ( fmt->ch != -1 ) {      // not EOF ?
    817815                printf( "%c", fmt->ch );
    818816                fmt->b += 1;
     
    823821                }
    824822                if ( fmt->g == 5 ) {  // group
    825                         printf( "\n" );      // separator
     823                        printf( "\n" );     // separator
    826824                        fmt->g = 0;
    827825                }
     
    850848
    851849The previous examples are \newterm{asymmetric (semi) coroutine}s because one coroutine always calls a resuming function for another coroutine, and the resumed coroutine always suspends back to its last resumer, similar to call/return for normal functions.
    852 However, there is no stack growth because @resume@/@suspend@ context switch to an existing stack frames rather than create a new one.
    853 \newterm{Symmetric (full) coroutine}s have a coroutine call a resuming function for another coroutine, which eventually forms a cycle.
     850However, there is no stack growth because @resume@/@suspend@ context switch to existing stack-frames rather than create new ones.
     851\newterm{Symmetric (full) coroutine}s have a coroutine call a resuming function for another coroutine, which eventually forms a resuming-call cycle.
    854852(The trivial cycle is a coroutine resuming itself.)
    855853This control flow is similar to recursion for normal routines, but again there is no stack growth from the context switch.
     
    935933The @start@ function communicates both the number of elements to be produced and the consumer into the producer's coroutine structure.
    936934Then the @resume@ to @prod@ creates @prod@'s stack with a frame for @prod@'s coroutine main at the top, and context switches to it.
    937 @prod@'s coroutine main starts, creates local variables that are retained between coroutine activations, and executes $N$ iterations, each generating two random vales, calling the consumer to deliver the values, and printing the status returned from the consumer.
     935@prod@'s coroutine main starts, creates local variables that are retained between coroutine activations, and executes $N$ iterations, each generating two random values, calling the consumer to deliver the values, and printing the status returned from the consumer.
    938936
    939937The producer call to @delivery@ transfers values into the consumer's communication variables, resumes the consumer, and returns the consumer status.
    940938For the first resume, @cons@'s stack is initialized, creating local variables retained between subsequent activations of the coroutine.
    941 The consumer iterates until the @done@ flag is set, prints, increments status, and calls back to the producer's @payment@ member, and on return prints the receipt from the producer and increments the money for the next payment.
    942 The call from the consumer to the producer's @payment@ member introduces the cycle between producer and consumer.
     939The consumer iterates until the @done@ flag is set, prints, increments status, and calls back to the producer via @payment@, and on return from @payment@, prints the receipt from the producer and increments @money@ (inflation).
     940The call from the consumer to the @payment@ introduces the cycle between producer and consumer.
    943941When @payment@ is called, the consumer copies values into the producer's communication variable and a resume is executed.
    944 The context switch restarts the producer at the point where it was last context switched and it continues in member @delivery@ after the resume.
    945 
    946 The @delivery@ member returns the status value in @prod@'s @main@ member, where the status is printed.
     942The context switch restarts the producer at the point where it was last context switched, so it continues in @delivery@ after the resume.
     943
     944@delivery@ returns the status value in @prod@'s coroutine main, where the status is printed.
    947945The loop then repeats calling @delivery@, where each call resumes the consumer coroutine.
    948946The context switch to the consumer continues in @payment@.
    949 The consumer increments and returns the receipt to the call in @cons@'s @main@ member.
     947The consumer increments and returns the receipt to the call in @cons@'s coroutine main.
    950948The loop then repeats calling @payment@, where each call resumes the producer coroutine.
    951949
     
    954952The context switch restarts @cons@ in @payment@ and it returns with the last receipt.
    955953The consumer terminates its loops because @done@ is true, its @main@ terminates, so @cons@ transitions from a coroutine back to an object, and @prod@ reactivates after the resume in @stop@.
    956 The @stop@ member returns and @prod@'s @main@ member terminates.
     954@stop@ returns and @prod@'s coroutine main terminates.
    957955The program main restarts after the resume in @start@.
    958 The @start@ member returns and the program main terminates.
    959 
    960 
    961 \subsubsection{Construction}
    962 
    963 One important design challenge for implementing coroutines and threads (shown in section \ref{threads}) is that the runtime system needs to run code after the user-constructor runs to connect the fully constructed object into the system.
    964 In the case of coroutines, this challenge is simpler since there is no non-determinism from preemption or scheduling.
    965 However, the underlying challenge remains the same for coroutines and threads.
    966 
    967 The runtime system needs to create the coroutine's stack and, more importantly, prepare it for the first resumption.
    968 The timing of the creation is non-trivial since users expect both to have fully constructed objects once execution enters the coroutine main and to be able to resume the coroutine from the constructor.
    969 There are several solutions to this problem but the chosen option effectively forces the design of the coroutine.
    970 
    971 Furthermore, \CFA faces an extra challenge as polymorphic routines create invisible thunks when cast to non-polymorphic routines and these thunks have function scope.
    972 For example, the following code, while looking benign, can run into undefined behaviour because of thunks:
    973 
    974 \begin{cfa}
    975 // async: Runs function asynchronously on another thread
    976 forall(otype T)
    977 extern void async(void (*func)(T*), T* obj);
    978 
    979 forall(otype T)
    980 void noop(T*) {}
    981 
    982 void bar() {
    983         int a;
    984         async(noop, &a); // start thread running noop with argument a
    985 }
    986 \end{cfa}
    987 
    988 The generated C code\footnote{Code trimmed down for brevity} creates a local thunk to hold type information:
    989 
    990 \begin{cfa}
    991 extern void async(/* omitted */, void (*func)(void*), void* obj);
    992 
    993 void noop(/* omitted */, void* obj){}
    994 
    995 void bar(){
    996         int a;
    997         void _thunk0(int* _p0){
    998                 /* omitted */
    999                 noop(/* omitted */, _p0);
    1000         }
    1001         /* omitted */
    1002         async(/* omitted */, ((void (*)(void*))(&_thunk0)), (&a));
    1003 }
    1004 \end{cfa}
    1005 The problem in this example is a storage management issue, the function pointer @_thunk0@ is only valid until the end of the block, which limits the viable solutions because storing the function pointer for too long causes undefined behaviour; \ie the stack-based thunk being destroyed before it can be used.
    1006 This challenge is an extension of challenges that come with second-class routines.
    1007 Indeed, GCC nested routines also have the limitation that nested routine cannot be passed outside of the declaration scope.
    1008 The case of coroutines and threads is simply an extension of this problem to multiple call stacks.
    1009 
    1010 
    1011 \subsubsection{Alternative: Composition}
    1012 
    1013 One solution to this challenge is to use composition/containment, where coroutine fields are added to manage the coroutine.
    1014 
    1015 \begin{cfa}
    1016 struct Fibonacci {
    1017         int fn; // used for communication
    1018         coroutine c; // composition
    1019 };
    1020 
    1021 void FibMain(void*) {
    1022         //...
    1023 }
    1024 
    1025 void ?{}(Fibonacci& this) {
    1026         this.fn = 0;
    1027         // Call constructor to initialize coroutine
    1028         (this.c){myMain};
    1029 }
    1030 \end{cfa}
    1031 The downside of this approach is that users need to correctly construct the coroutine handle before using it.
    1032 Like any other objects, the user must carefully choose construction order to prevent usage of objects not yet constructed.
    1033 However, in the case of coroutines, users must also pass to the coroutine information about the coroutine main, like in the previous example.
    1034 This opens the door for user errors and requires extra runtime storage to pass at runtime information that can be known statically.
    1035 
    1036 
    1037 \subsubsection{Alternative: Reserved keyword}
    1038 
    1039 The next alternative is to use language support to annotate coroutines as follows:
    1040 \begin{cfa}
    1041 coroutine Fibonacci {
    1042         int fn; // used for communication
    1043 };
    1044 \end{cfa}
    1045 The @coroutine@ keyword means the compiler can find and inject code where needed.
    1046 The downside of this approach is that it makes coroutine a special case in the language.
    1047 Users wanting to extend coroutines or build their own for various reasons can only do so in ways offered by the language.
    1048 Furthermore, implementing coroutines without language supports also displays the power of the programming language used.
    1049 While this is ultimately the option used for idiomatic \CFA code, coroutines and threads can still be constructed by users without using the language support.
    1050 The reserved keywords are only present to improve ease of use for the common cases.
    1051 
    1052 
    1053 \subsubsection{Alternative: Lambda Objects}
     956@start@ returns and the program main terminates.
     957
     958
     959\subsection{Coroutine Implementation}
     960
     961A significant implementation challenge for coroutines (and threads, see section \ref{threads}) is adding extra fields and executing code after/before the coroutine constructor/destructor and coroutine main to create/initialize/de-initialize/destroy extra fields and the stack.
     962There are several solutions to this problem and the chosen option forced the \CFA coroutine design.
     963
     964Object-oriented inheritance provides extra fields and code in a restricted context, but it requires programmers to explicitly perform the inheritance:
     965\begin{cfa}
     966struct mycoroutine $\textbf{\textsf{inherits}}$ baseCoroutine { ... }
     967\end{cfa}
     968and the programming language (and possibly its tool set, \eg debugger) may need to understand @baseCoroutine@ because of the stack.
     969Furthermore, the execution of constructs/destructors is in the wrong order for certain operations, \eg for threads;
     970\eg, if the thread is implicitly started, it must start \emph{after} all constructors, because the thread relies on a completely initialized object, but the inherited constructor runs \emph{before} the derived.
     971
     972An alternatively is composition:
     973\begin{cfa}
     974struct mycoroutine {
     975        ... // declarations
     976        baseCoroutine dummy; // composition, last declaration
     977}
     978\end{cfa}
     979which also requires an explicit declaration that must be the last one to ensure correct initialization order.
     980However, there is nothing preventing wrong placement or multiple declarations.
    1054981
    1055982For coroutines as for threads, many implementations are based on routine pointers or function objects~\cite{Butenhof97, C++14, MS:VisualC++, BoostCoroutines15}.
    1056 For example, Boost implements coroutines in terms of four functor object types:
     983For example, Boost implements coroutines in terms of four functor object-types:
    1057984\begin{cfa}
    1058985asymmetric_coroutine<>::pull_type
     
    1061988symmetric_coroutine<>::yield_type
    1062989\end{cfa}
    1063 Often, the canonical threading paradigm in languages is based on function pointers, @pthread@ being one of the most well-known examples.
    1064 The main problem of this approach is that the thread usage is limited to a generic handle that must otherwise be wrapped in a custom type.
    1065 Since the custom type is simple to write in \CFA and solves several issues, added support for routine/lambda based coroutines adds very little.
    1066 
    1067 A variation of this would be to use a simple function pointer in the same way @pthread@ does for threads:
    1068 \begin{cfa}
    1069 void foo( coroutine_t cid, void* arg ) {
    1070         int* value = (int*)arg;
     990Similarly, the canonical threading paradigm is often based on function pointers, \eg @pthread@~\cite{pthreads}, \Csharp~\cite{Csharp}, Go~\cite{Go}, and Scala~\cite{Scala}.
     991However, the generic thread-handle (identifier) is limited (few operations), unless it is wrapped in a custom type.
     992\begin{cfa}
     993void mycor( coroutine_t cid, void * arg ) {
     994        int * value = (int *)arg;                               $\C{// type unsafe, pointer-size only}$
    1071995        // Coroutine body
    1072996}
    1073 
    1074997int main() {
    1075         int value = 0;
    1076         coroutine_t cid = coroutine_create( &foo, (void*)&value );
    1077         coroutine_resume( &cid );
    1078 }
    1079 \end{cfa}
    1080 This semantics is more common for thread interfaces but coroutines work equally well.
    1081 As discussed in section \ref{threads}, this approach is superseded by static approaches in terms of expressivity.
    1082 
    1083 
    1084 \subsubsection{Alternative: Trait-Based Coroutines}
    1085 
    1086 Finally, the underlying approach, which is the one closest to \CFA idioms, is to use trait-based lazy coroutines.
    1087 This approach defines a coroutine as anything that satisfies the trait @is_coroutine@ (as defined below) and is used as a coroutine.
    1088 
    1089 \begin{cfa}
    1090 trait is_coroutine(dtype T) {
    1091       void main(T& this);
    1092       coroutine_desc* get_coroutine(T& this);
     998        int input = 0, output;
     999        coroutine_t cid = coroutine_create( &mycor, (void *)&input ); $\C{// type unsafe, pointer-size only}$
     1000        coroutine_resume( cid, (void *)input, (void **)&output ); $\C{// type unsafe, pointer-size only}$
     1001}
     1002\end{cfa}
     1003Since the custom type is simple to write in \CFA and solves several issues, added support for routine/lambda-based coroutines adds very little.
     1004
     1005The selected approach is to use language support by introducing a new kind of aggregate (structure):
     1006\begin{cfa}
     1007coroutine Fibonacci {
     1008        int fn; // communication variables
    10931009};
    1094 
    1095 forall( dtype T | is_coroutine(T) ) void suspend(T&);
    1096 forall( dtype T | is_coroutine(T) ) void resume (T&);
    1097 \end{cfa}
    1098 This ensures that an object is not a coroutine until @resume@ is called on the object.
    1099 Correspondingly, any object that is passed to @resume@ is a coroutine since it must satisfy the @is_coroutine@ trait to compile.
     1010\end{cfa}
     1011The @coroutine@ keyword means the compiler (and tool set) can find and inject code where needed.
     1012The downside of this approach is that it makes coroutine a special case in the language.
     1013Users wanting to extend coroutines or build their own for various reasons can only do so in ways offered by the language.
     1014Furthermore, implementing coroutines without language supports also displays the power of a programming language.
     1015While this is ultimately the option used for idiomatic \CFA code, coroutines and threads can still be constructed without using the language support.
     1016The reserved keyword eases use for the common cases.
     1017
     1018Part of the mechanism to generalize coroutines is using a \CFA trait, which defines a coroutine as anything satisfying the trait @is_coroutine@, and this trait is used to restrict coroutine-manipulation functions:
     1019\begin{cfa}
     1020trait is_coroutine( dtype T ) {
     1021      void main( T & this );
     1022      coroutine_desc * get_coroutine( T & this );
     1023};
     1024forall( dtype T | is_coroutine(T) ) void get_coroutine( T & );
     1025forall( dtype T | is_coroutine(T) ) void suspend( T & );
     1026forall( dtype T | is_coroutine(T) ) void resume( T & );
     1027\end{cfa}
     1028This definition ensures there is a statically-typed @main@ function that is the starting point (first stack frame) of a coroutine.
     1029No return value or additional parameters are necessary for this function, because the coroutine type allows an arbitrary number of interface functions with corresponding arbitrary typed input/output values.
     1030As well, any object passed to @suspend@ and @resume@ is a coroutine since it must satisfy the @is_coroutine@ trait to compile.
    11001031The advantage of this approach is that users can easily create different types of coroutines, for example, changing the memory layout of a coroutine is trivial when implementing the @get_coroutine@ routine.
    1101 The \CFA keyword @coroutine@ simply has the effect of implementing the getter and forward declarations required for users to implement the main routine.
    1102 
    1103 \begin{center}
    1104 \begin{tabular}{c c c}
    1105 \begin{cfa}[tabsize=3]
    1106 coroutine MyCoroutine {
    1107         int someValue;
     1032The \CFA keyword @coroutine@ implicitly implements the getter and forward declarations required for implementing the coroutine main:
     1033\begin{cquote}
     1034\begin{tabular}{@{}ccc@{}}
     1035\begin{cfa}
     1036coroutine MyCor {
     1037        int value;
     1038
    11081039};
    1109 \end{cfa} & == & \begin{cfa}[tabsize=3]
    1110 struct MyCoroutine {
    1111         int someValue;
    1112         coroutine_desc __cor;
     1040\end{cfa}
     1041& {\Large $\Rightarrow$} &
     1042\begin{tabular}{@{}ccc@{}}
     1043\begin{cfa}
     1044struct MyCor {
     1045        int value;
     1046        coroutine_desc cor;
    11131047};
    1114 
    1115 static inline
    1116 coroutine_desc* get_coroutine(
    1117         struct MyCoroutine& this
    1118 ) {
    1119         return &this.__cor;
    1120 }
    1121 
    1122 void main(struct MyCoroutine* this);
     1048\end{cfa}
     1049&
     1050\begin{cfa}
     1051static inline coroutine_desc *
     1052get_coroutine( MyCor & this ) {
     1053        return &this.cor;
     1054}
     1055\end{cfa}
     1056&
     1057\begin{cfa}
     1058void main( MyCor * this );
     1059
     1060
     1061
    11231062\end{cfa}
    11241063\end{tabular}
    1125 \end{center}
    1126 
    1127 The combination of these two approaches allows users new to coroutining and concurrency to have an easy and concise specification, while more advanced users have tighter control on memory layout and initialization.
    1128 
    1129 \subsection{Thread Interface}\label{threads}
    1130 The basic building blocks of multithreading in \CFA are \textbf{cfathread}.
    1131 Both user and kernel threads are supported, where user threads are the concurrency mechanism and kernel threads are the parallel mechanism.
    1132 User threads offer a flexible and lightweight interface.
    1133 A thread can be declared using a struct declaration @thread@ as follows:
    1134 
    1135 \begin{cfa}
    1136 thread foo {};
    1137 \end{cfa}
    1138 
    1139 As for coroutines, the keyword is a thin wrapper around a \CFA trait:
    1140 
    1141 \begin{cfa}
    1142 trait is_thread(dtype T) {
    1143       void ^?{}(T & mutex this);
    1144       void main(T & this);
    1145       thread_desc* get_thread(T & this);
     1064\end{tabular}
     1065\end{cquote}
     1066The combination of these two approaches allows an easy and concise specification to coroutining (and concurrency) for normal users, while more advanced users have tighter control on memory layout and initialization.
     1067
     1068
     1069\subsection{Thread Interface}
     1070\label{threads}
     1071
     1072Both user and kernel threads are supported, where user threads provide concurrency and kernel threads provide parallelism.
     1073Like coroutines and for the same design reasons, the selected approach for user threads is to use language support by introducing a new kind of aggregate (structure) and a \CFA trait:
     1074\begin{cquote}
     1075\begin{tabular}{@{}c@{\hspace{2\parindentlnth}}c@{}}
     1076\begin{cfa}
     1077thread myThread {
     1078        // communication variables
    11461079};
    1147 \end{cfa}
    1148 
    1149 Obviously, for this thread implementation to be useful it must run some user code.
    1150 Several other threading interfaces use a function-pointer representation as the interface of threads (for example \Csharp~\cite{Csharp} and Scala~\cite{Scala}).
    1151 However, this proposal considers that statically tying a @main@ routine to a thread supersedes this approach.
    1152 Since the @main@ routine is already a special routine in \CFA (where the program begins), it is a natural extension of the semantics to use overloading to declare mains for different threads (the normal main being the main of the initial thread).
     1080
     1081
     1082\end{cfa}
     1083&
     1084\begin{cfa}
     1085trait is_thread( dtype T ) {
     1086      void main( T & this );
     1087      thread_desc * get_thread( T & this );
     1088      void ^?{}( T & `mutex` this );
     1089};
     1090\end{cfa}
     1091\end{tabular}
     1092\end{cquote}
     1093(The qualifier @mutex@ for the destructor parameter is discussed in Section~\ref{s:Monitors}.)
     1094Like a coroutine, the statically-typed @main@ function is the starting point (first stack frame) of a user thread.
     1095The difference is that a coroutine borrows a thread from its caller, so the first thread resuming a coroutine creates an instance of @main@;
     1096whereas, a user thread receives its own thread from the runtime system, which starts in @main@ as some point after the thread constructor is run.\footnote{
     1097The \lstinline@main@ function is already a special routine in C (where the program begins), so it is a natural extension of the semantics to use overloading to declare mains for different coroutines/threads (the normal main being the main of the initial thread).}
     1098No return value or additional parameters are necessary for this function, because the task type allows an arbitrary number of interface functions with corresponding arbitrary typed input/output values.
     1099
     1100\begin{comment} % put in appendix with coroutine version ???
    11531101As such the @main@ routine of a thread can be defined as
    11541102\begin{cfa}
     
    11891137}
    11901138\end{cfa}
    1191 
    11921139A consequence of the strongly typed approach to main is that memory layout of parameters and return values to/from a thread are now explicitly specified in the \textbf{api}.
    1193 
    1194 Of course, for threads to be useful, it must be possible to start and stop threads and wait for them to complete execution.
    1195 While using an \textbf{api} such as @fork@ and @join@ is relatively common in the literature, such an interface is unnecessary.
    1196 Indeed, the simplest approach is to use \textbf{raii} principles and have threads @fork@ after the constructor has completed and @join@ before the destructor runs.
    1197 \begin{cfa}
    1198 thread World;
    1199 
    1200 void main(World & this) {
     1140\end{comment}
     1141
     1142For user threads to be useful, it must be possible to start and stop the underlying thread, and wait for it to complete execution.
     1143While using an API such as @fork@ and @join@ is relatively common, such an interface is awkward and unnecessary.
     1144A simple approach is to use allocation/deallocation principles, and have threads implicitly @fork@ after construction and @join@ before destruction.
     1145\begin{cfa}
     1146thread World {};
     1147void main( World & this ) {
    12011148        sout | "World!" | endl;
    12021149}
    1203 
    1204 void main() {
    1205         World w;
    1206         // Thread forks here
    1207 
    1208         // Printing "Hello " and "World!" are run concurrently
    1209         sout | "Hello " | endl;
    1210 
    1211         // Implicit join at end of scope
    1212 }
    1213 \end{cfa}
    1214 
    1215 This semantic has several advantages over explicit semantics: a thread is always started and stopped exactly once, users cannot make any programming errors, and it naturally scales to multiple threads meaning basic synchronization is very simple.
    1216 
    1217 \begin{cfa}
    1218 thread MyThread {
    1219         //...
     1150int main() {
     1151        World w`[10]`;                                                  $\C{// implicit forks after creation}$
     1152        sout | "Hello " | endl;                                 $\C{// "Hello " and 10 "World!" printed concurrently}$
     1153}                                                                                       $\C{// implicit joins before destruction}$
     1154\end{cfa}
     1155This semantics ensures a thread is started and stopped exactly once, eliminating some programming error, and scales to multiple threads for basic (termination) synchronization.
     1156This tree-structure (lattice) create/delete from C block-structure is generalized by using dynamic allocation, so threads can outlive the scope in which they are created, much like dynamically allocating memory lets objects outlive the scope in which they are created.
     1157\begin{cfa}
     1158int main() {
     1159        MyThread * heapLived;
     1160        {
     1161                MyThread blockLived;                            $\C{// fork block-based thread}$
     1162                heapLived = `new`( MyThread );          $\C{// fork heap-based thread}$
     1163                ...
     1164        }                                                                               $\C{// join block-based thread}$
     1165        ...
     1166        `delete`( heapLived );                                  $\C{// join heap-based thread}$
     1167}
     1168\end{cfa}
     1169The heap-based approach allows arbitrary thread-creation topologies, with respect to fork/join-style concurrency.
     1170
     1171Figure~\ref{s:ConcurrentMatrixSummation} shows concurrently adding the rows of a matrix and then totalling the subtotals sequential, after all the row threads have terminated.
     1172The program uses heap-based threads because each thread needs different constructor values.
     1173(Python provides a simple iteration mechanism to initialize array elements to different values allowing stack allocation.)
     1174The allocation/deallocation pattern appears unusual because allocated objects are immediately deleted without any intervening code.
     1175However, for threads, the deletion provides implicit synchronization, which is the intervening code.
     1176While the subtotals are added in linear order rather than completion order, which slight inhibits concurrency, the computation is restricted by the critical-path thread (\ie the thread that takes the longest), and so any inhibited concurrency is very small as totalling the subtotals is trivial.
     1177
     1178\begin{figure}
     1179\begin{cfa}
     1180thread Adder {
     1181    int * row, cols, & subtotal;                        $\C{// communication}$
    12201182};
    1221 
    1222 // main
    1223 void main(MyThread& this) {
    1224         //...
    1225 }
    1226 
    1227 void foo() {
    1228         MyThread thrds[10];
    1229         // Start 10 threads at the beginning of the scope
    1230 
    1231         DoStuff();
    1232 
    1233         // Wait for the 10 threads to finish
    1234 }
    1235 \end{cfa}
    1236 
    1237 However, one of the drawbacks of this approach is that threads always form a tree where nodes must always outlive their children, \ie they are always destroyed in the opposite order of construction because of C scoping rules.
    1238 This restriction is relaxed by using dynamic allocation, so threads can outlive the scope in which they are created, much like dynamically allocating memory lets objects outlive the scope in which they are created.
    1239 
    1240 \begin{cfa}
    1241 thread MyThread {
    1242         //...
    1243 };
    1244 
    1245 void main(MyThread& this) {
    1246         //...
    1247 }
    1248 
    1249 void foo() {
    1250         MyThread* long_lived;
    1251         {
    1252                 // Start a thread at the beginning of the scope
    1253                 MyThread short_lived;
    1254 
    1255                 // create another thread that will outlive the thread in this scope
    1256                 long_lived = new MyThread;
    1257 
    1258                 DoStuff();
    1259 
    1260                 // Wait for the thread short_lived to finish
    1261         }
    1262         DoMoreStuff();
    1263 
    1264         // Now wait for the long_lived to finish
    1265         delete long_lived;
    1266 }
    1267 \end{cfa}
    1268 
    1269 
    1270 % ======================================================================
    1271 % ======================================================================
    1272 \section{Concurrency}
    1273 % ======================================================================
    1274 % ======================================================================
    1275 Several tools can be used to solve concurrency challenges.
    1276 Since many of these challenges appear with the use of mutable shared state, some languages and libraries simply disallow mutable shared state (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka (Scala)~\cite{Akka}).
    1277 In these paradigms, interaction among concurrent objects relies on message passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms closely relate to networking concepts (channels~\cite{CSP,Go} for example).
    1278 However, in languages that use routine calls as their core abstraction mechanism, these approaches force a clear distinction between concurrent and non-concurrent paradigms (\ie message passing versus routine calls).
    1279 This distinction in turn means that, in order to be effective, programmers need to learn two sets of design patterns.
     1183void ?{}( Adder & adder, int row[], int cols, int & subtotal ) {
     1184    adder.[ row, cols, &subtotal ] = [ row, cols, &subtotal ];
     1185}
     1186void main( Adder & adder ) with( adder ) {
     1187    subtotal = 0;
     1188    for ( int c = 0; c < cols; c += 1 ) {
     1189                subtotal += row[c];
     1190    }
     1191}
     1192int main() {
     1193    const int rows = 10, cols = 1000;
     1194    int matrix[rows][cols], subtotals[rows], total = 0;
     1195    // read matrix
     1196    Adder * adders[rows];
     1197    for ( int r = 0; r < rows; r += 1 ) {       $\C{// start threads to sum rows}$
     1198                adders[r] = new( matrix[r], cols, &subtotals[r] );
     1199    }
     1200    for ( int r = 0; r < rows; r += 1 ) {       $\C{// wait for threads to finish}$
     1201                delete( adders[r] );                            $\C{// termination join}$
     1202                total += subtotals[r];                          $\C{// total subtotal}$
     1203    }
     1204    sout | total | endl;
     1205}
     1206\end{cfa}
     1207\caption{Concurrent Matrix Summation}
     1208\label{s:ConcurrentMatrixSummation}
     1209\end{figure}
     1210
     1211
     1212\section{Synchronization / Mutual Exclusion}
     1213
     1214Uncontrolled non-deterministic execution is meaningless.
     1215To reestablish meaningful execution requires mechanisms to reintroduce determinism (control non-determinism), called synchronization and mutual exclusion, where synchronization is a timing relationship among threads and mutual exclusion is an access-control mechanism on data shared by threads.
     1216Since many deterministic challenges appear with the use of mutable shared state, some languages/libraries disallow it (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka~\cite{Akka} (Scala)).
     1217In these paradigms, interaction among concurrent objects is performed by stateless message-passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms closely relate to networking concepts (\eg channels~\cite{CSP,Go}).
     1218However, in call/return-based languages, these approaches force a clear distinction (\ie introduce a new programming paradigm) between non-concurrent and concurrent computation (\ie function call versus message passing).
     1219This distinction means a programmers needs to learn two sets of design patterns.
    12801220While this distinction can be hidden away in library code, effective use of the library still has to take both paradigms into account.
    1281 
    1282 Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and shared objects.
    1283 At the lowest level, concurrent paradigms are implemented as atomic operations and locks.
    1284 Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}.
    1285 However, for productivity reasons it is desirable to have a higher-level construct be the core concurrency paradigm~\cite{Hochstein05}.
    1286 
    1287 An approach that is worth mentioning because it is gaining in popularity is transactional memory~\cite{Herlihy93}.
    1288 While this approach is even pursued by system languages like \CC~\cite{Cpp-Transactions}, the performance and feature set is currently too restrictive to be the main concurrency paradigm for system languages, which is why it was rejected as the core paradigm for concurrency in \CFA.
    1289 
    1290 One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared-memory systems, is the \emph{monitor}.
     1221In contrast, approaches based on statefull models more closely resemble the standard call/return programming-model, resulting in a single programming paradigm.
     1222
     1223At the lowest level, concurrent control is implemented as atomic operations, upon which different kinds of locks mechanism are constructed, \eg semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}.
     1224However, for productivity it is always desirable to use the highest-level construct that provides the necessary efficiency~\cite{Hochstein05}.
     1225A newer approach is transactional memory~\cite{Herlihy93}.
     1226While this approach is pursued in hardware~\cite{Nakaike15} and system languages, like \CC~\cite{Cpp-Transactions}, the performance and feature set is still too restrictive to be the main concurrency paradigm for system languages, which is why it was rejected as the core paradigm for concurrency in \CFA.
     1227
     1228One of the most natural, elegant, and efficient mechanisms for synchronization and mutual exclusion for shared-memory systems is the \emph{monitor}.
    12911229Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}.
    1292 Many programming languages---\eg Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs.
     1230Many programming languages -- \eg Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java} -- provide monitors as explicit language constructs.
    12931231In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors.
    1294 For these reasons, this project proposes monitors as the core concurrency construct.
    1295 
    1296 
    1297 \subsection{Basics}
    1298 
    1299 Non-determinism requires concurrent systems to offer support for mutual-exclusion and synchronization.
    1300 Mutual-exclusion is the concept that only a fixed number of threads can access a critical section at any given time, where a critical section is a group of instructions on an associated portion of data that requires the restricted access.
    1301 On the other hand, synchronization enforces relative ordering of execution and synchronization tools provide numerous mechanisms to establish timing relationships among threads.
    1302 
    1303 
    1304 \subsubsection{Mutual-Exclusion}
    1305 
    1306 As mentioned above, mutual-exclusion is the guarantee that only a fix number of threads can enter a critical section at once.
     1232For these reasons, this project proposes monitors as the core concurrency construct, upon which even higher-level approaches can be easily constructed..
     1233
     1234
     1235\subsection{Mutual Exclusion}
     1236
     1237A group of instructions manipulating a specific instance of shared data that must be performed atomically is called an (individual) \newterm{critical-section}~\cite{Dijkstra65}.
     1238A generalization is a \newterm{group critical-section}~\cite{Joung00}, where multiple tasks with the same session may use the resource simultaneously, but different sessions may not use the resource simultaneously.
     1239The readers/writer problem~\cite{Courtois71} is an instance of a group critical-section, where readers have the same session and all writers have a unique session.
     1240\newterm{Mutual exclusion} enforces the correction number of threads are using a critical section at the same time.
     1241
    13071242However, many solutions exist for mutual exclusion, which vary in terms of performance, flexibility and ease of use.
    1308 Methods range from low-level locks, which are fast and flexible but require significant attention to be correct, to  higher-level concurrency techniques, which sacrifice some performance in order to improve ease of use.
    1309 Ease of use comes by either guaranteeing some problems cannot occur (\eg being deadlock free) or by offering a more explicit coupling between data and corresponding critical section.
     1243Methods range from low-level locks, which are fast and flexible but require significant attention for correctness, to higher-level concurrency techniques, which sacrifice some performance to improve ease of use.
     1244Ease of use comes by either guaranteeing some problems cannot occur (\eg deadlock free), or by offering a more explicit coupling between shared data and critical section.
    13101245For example, the \CC @std::atomic<T>@ offers an easy way to express mutual-exclusion on a restricted set of operations (\eg reading/writing large types atomically).
    1311 Another challenge with low-level locks is composability.
    1312 Locks have restricted composability because it takes careful organizing for multiple locks to be used while preventing deadlocks.
    1313 Easing composability is another feature higher-level mutual-exclusion mechanisms often offer.
    1314 
    1315 
    1316 \subsubsection{Synchronization}
    1317 
    1318 As with mutual-exclusion, low-level synchronization primitives often offer good performance and good flexibility at the cost of ease of use.
    1319 Again, higher-level mechanisms often simplify usage by adding either better coupling between synchronization and data (\eg message passing) or offering a simpler solution to otherwise involved challenges.
     1246However, a significant challenge with (low-level) locks is composability because it takes careful organization for multiple locks to be used while preventing deadlock.
     1247Easing composability is another feature higher-level mutual-exclusion mechanisms offer.
     1248
     1249
     1250\subsection{Synchronization}
     1251
     1252Synchronization enforces relative ordering of execution, and synchronization tools provide numerous mechanisms to establish these timing relationships.
     1253Low-level synchronization primitives offer good performance and flexibility at the cost of ease of use.
     1254Higher-level mechanisms often simplify usage by adding better coupling between synchronization and data (\eg message passing), or offering a simpler solution to otherwise involved challenges, \eg barrier lock.
    13201255As mentioned above, synchronization can be expressed as guaranteeing that event \textit{X} always happens before \textit{Y}.
    1321 Most of the time, synchronization happens within a critical section, where threads must acquire mutual-exclusion in a certain order.
    1322 However, it may also be desirable to guarantee that event \textit{Z} does not occur between \textit{X} and \textit{Y}.
    1323 Not satisfying this property is called \textbf{barging}.
    1324 For example, where event \textit{X} tries to effect event \textit{Y} but another thread acquires the critical section and emits \textit{Z} before \textit{Y}.
    1325 The classic example is the thread that finishes using a resource and unblocks a thread waiting to use the resource, but the unblocked thread must compete to acquire the resource.
     1256Often synchronization is used to order access to a critical section, \eg ensuring the next kind of thread to enter a critical section is a reader thread
     1257If a writer thread is scheduled for next access, but another reader thread acquires the critical section first, the reader has \newterm{barged}.
     1258Barging can result in staleness/freshness problems, where a reader barges ahead of a write and reads temporally stale data, or a writer barges ahead of another writer overwriting data with a fresh value preventing the previous value from having an opportunity to be read.
    13261259Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs.
    1327 This challenge is often split into two different methods, barging avoidance and barging prevention.
    1328 Algorithms that use flag variables to detect barging threads are said to be using barging avoidance, while algorithms that baton-pass locks~\cite{Andrews89} between threads instead of releasing the locks are said to be using barging prevention.
    1329 
    1330 
    1331 % ======================================================================
    1332 % ======================================================================
     1260This challenge is often split into two different approaches, barging avoidance and barging prevention.
     1261Algorithms that allow a barger but divert it until later are avoiding the barger, while algorithms that preclude a barger from entering during synchronization in the critical section prevent the barger completely.
     1262baton-pass locks~\cite{Andrews89} between threads instead of releasing the locks are said to be using barging prevention.
     1263
     1264
    13331265\section{Monitors}
    1334 % ======================================================================
    1335 % ======================================================================
     1266\label{s:Monitors}
     1267
    13361268A \textbf{monitor} is a set of routines that ensure mutual-exclusion when accessing shared state.
    13371269More precisely, a monitor is a programming technique that associates mutual-exclusion to routine scopes, as opposed to mutex locks, where mutual-exclusion is defined by lock/release calls independently of any scoping of the calling routine.
     
    25012433Given these building blocks, it is possible to reproduce all three of the popular paradigms.
    25022434Indeed, \textbf{uthread} is the default paradigm in \CFA.
    2503 However, disabling \textbf{preemption} on the \textbf{cfacluster} means \textbf{cfathread} effectively become \textbf{fiber}.
     2435However, disabling \textbf{preemption} on a cluster means threads effectively become fibers.
    25042436Since several \textbf{cfacluster} with different scheduling policy can coexist in the same application, this allows \textbf{fiber} and \textbf{uthread} to coexist in the runtime of an application.
    25052437Finally, it is possible to build executors for thread pools from \textbf{uthread} or \textbf{fiber}, which includes specialized jobs like actors~\cite{Actors}.
  • doc/papers/general/Paper.tex

    r3ef35bd reba74ba  
    243243Nevertheless, C, first standardized almost forty years ago~\cite{ANSI89:C}, lacks many features that make programming in more modern languages safer and more productive.
    244244
    245 \CFA (pronounced ``C-for-all'', and written \CFA or Cforall) is an evolutionary extension of the C programming language that adds modern language-features to C, while maintaining both source and runtime compatibility with C and a familiar programming model for programmers.
     245\CFA (pronounced ``C-for-all'', and written \CFA or Cforall) is an evolutionary extension of the C programming language that adds modern language-features to C, while maintaining source and runtime compatibility in the familiar C programming model.
    246246The four key design goals for \CFA~\cite{Bilson03} are:
    247247(1) The behaviour of standard C code must remain the same when translated by a \CFA compiler as when translated by a C compiler;
     
    273273Starting with a translator versus a compiler makes it easier and faster to generate and debug C object-code rather than intermediate, assembler or machine code.
    274274The translator design is based on the \emph{visitor pattern}, allowing multiple passes over the abstract code-tree, which works well for incrementally adding new feature through additional visitor passes.
    275 At the heart of the translator is the type resolver, which handles the polymorphic routine/type overload-resolution.
     275At the heart of the translator is the type resolver, which handles the polymorphic function/type overload-resolution.
    276276% @plg2[8]% cd cfa-cc/src; cloc libcfa
    277277% -------------------------------------------------------------------------------
     
    310310
    311311Finally, it is impossible to describe a programming language without usages before definitions.
    312 Therefore, syntax and semantics appear before explanations;
    313 hence, patience is necessary until details are presented.
     312Therefore, syntax and semantics appear before explanations, and related work (Section~\ref{s:RelatedWork}) is deferred until \CFA is presented;
     313hence, patience is necessary until details are discussed.
    314314
    315315
     
    329329\end{quote}
    330330\vspace{-9pt}
    331 C already has a limited form of ad-hoc polymorphism in the form of its basic arithmetic operators, which apply to a variety of different types using identical syntax.
     331C already has a limited form of ad-hoc polymorphism in its basic arithmetic operators, which apply to a variety of different types using identical syntax.
    332332\CFA extends the built-in operator overloading by allowing users to define overloads for any function, not just operators, and even any variable;
    333333Section~\ref{sec:libraries} includes a number of examples of how this overloading simplifies \CFA programming relative to C.
     
    653653}
    654654\end{cfa}
    655 Since @pair( T *, T * )@ is a concrete type, there are no implicit parameters passed to @lexcmp@, so the generated code is identical to a function written in standard C using @void *@, yet the \CFA version is type-checked to ensure the fields of both pairs and the arguments to the comparison function match in type.
     655Since @pair( T *, T * )@ is a concrete type, there are no implicit parameters passed to @lexcmp@, so the generated code is identical to a function written in standard C using @void *@, yet the \CFA version is type-checked to ensure the members of both pairs and the arguments to the comparison function match in type.
    656656
    657657Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \newterm{tag-structures}.
     
    815815\subsection{Member Access}
    816816
    817 It is also possible to access multiple fields from a single expression using a \newterm{member-access}.
     817It is also possible to access multiple members from a single expression using a \newterm{member-access}.
    818818The result is a single tuple-valued expression whose type is the tuple of the types of the members, \eg:
    819819\begin{cfa}
     
    10201020\begin{cfa}
    10211021forall( dtype T0, dtype T1 | sized(T0) | sized(T1) ) struct _tuple2 {
    1022         T0 field_0;  T1 field_1;                                        $\C{// generated before the first 2-tuple}$
     1022        T0 member_0;  T1 member_1;                                      $\C{// generated before the first 2-tuple}$
    10231023};
    10241024_tuple2(int, int) f() {
    10251025        _tuple2(double, double) x;
    10261026        forall( dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2) ) struct _tuple3 {
    1027                 T0 field_0;  T1 field_1;  T2 field_2;   $\C{// generated before the first 3-tuple}$
     1027                T0 member_0;  T1 member_1;  T2 member_2;        $\C{// generated before the first 3-tuple}$
    10281028        };
    10291029        _tuple3(int, double, int) y;
     
    10331033
    10341034\begin{comment}
    1035 Since tuples are essentially structures, tuple indexing expressions are just field accesses:
     1035Since tuples are essentially structures, tuple indexing expressions are just member accesses:
    10361036\begin{cfa}
    10371037void f(int, [double, char]);
     
    10471047_tuple2(int, double) x;
    10481048
    1049 x.field_0+x.field_1;
    1050 printf("%d %g\n", x.field_0, x.field_1);
    1051 f(x.field_0, (_tuple2){ x.field_1, 'z' });
    1052 \end{cfa}
    1053 Note that due to flattening, @x@ used in the argument position is converted into the list of its fields.
     1049x.member_0+x.member_1;
     1050printf("%d %g\n", x.member_0, x.member_1);
     1051f(x.member_0, (_tuple2){ x.member_1, 'z' });
     1052\end{cfa}
     1053Note that due to flattening, @x@ used in the argument position is converted into the list of its members.
    10541054In the call to @f@, the second and third argument components are structured into a tuple argument.
    10551055Similarly, tuple member expressions are recursively expanded into a list of member access expressions.
     
    10831083
    10841084The various kinds of tuple assignment, constructors, and destructors generate GNU C statement expressions.
    1085 A variable is generated to store the value produced by a statement expression, since its fields may need to be constructed with a non-trivial constructor and it may need to be referred to multiple time, \eg in a unique expression.
     1085A variable is generated to store the value produced by a statement expression, since its members may need to be constructed with a non-trivial constructor and it may need to be referred to multiple time, \eg in a unique expression.
    10861086The use of statement expressions allows the translator to arbitrarily generate additional temporary variables as needed, but binds the implementation to a non-standard extension of the C language.
    10871087However, there are other places where the \CFA translator makes use of GNU C extensions, such as its use of nested functions, so this restriction is not new.
     
    14931493
    14941494Heterogeneous data is often aggregated into a structure/union.
    1495 To reduce syntactic noise, \CFA provides a @with@ statement (see Pascal~\cite[\S~4.F]{Pascal}) to elide aggregate field-qualification by opening a scope containing the field identifiers.
     1495To reduce syntactic noise, \CFA provides a @with@ statement (see Pascal~\cite[\S~4.F]{Pascal}) to elide aggregate member-qualification by opening a scope containing the member identifiers.
    14961496\begin{cquote}
    14971497\vspace*{-\baselineskip}%???
     
    15301530The type must be an aggregate type.
    15311531(Enumerations are already opened.)
    1532 The object is the implicit qualifier for the open structure-fields.
     1532The object is the implicit qualifier for the open structure-members.
    15331533
    15341534All expressions in the expression list are open in parallel within the compound statement, which is different from Pascal, which nests the openings from left to right.
    1535 The difference between parallel and nesting occurs for fields with the same name and type:
    1536 \begin{cfa}
    1537 struct S { int `i`; int j; double m; } s, w;
     1535The difference between parallel and nesting occurs for members with the same name and type:
     1536\begin{cfa}
     1537struct S { int `i`; int j; double m; } s, w;    $\C{// member i has same type in structure types S and T}$
    15381538struct T { int `i`; int k; int m; } t, w;
    1539 with ( s, t ) {
     1539with ( s, t ) {                                                         $\C{// open structure variables s and t in parallel}$
    15401540        j + k;                                                                  $\C{// unambiguous, s.j + t.k}$
    15411541        m = 5.0;                                                                $\C{// unambiguous, s.m = 5.0}$
     
    15491549For parallel semantics, both @s.i@ and @t.i@ are visible, so @i@ is ambiguous without qualification;
    15501550for nested semantics, @t.i@ hides @s.i@, so @i@ implies @t.i@.
    1551 \CFA's ability to overload variables means fields with the same name but different types are automatically disambiguated, eliminating most qualification when opening multiple aggregates.
     1551\CFA's ability to overload variables means members with the same name but different types are automatically disambiguated, eliminating most qualification when opening multiple aggregates.
    15521552Qualification or a cast is used to disambiguate.
    15531553
     
    15551555\begin{cfa}
    15561556void ?{}( S & s, int i ) with ( s ) {           $\C{// constructor}$
    1557         `s.i = i;`  j = 3;  m = 5.5;                    $\C{// initialize fields}$
     1557        `s.i = i;`  j = 3;  m = 5.5;                    $\C{// initialize members}$
    15581558}
    15591559\end{cfa}
     
    16591659\lstMakeShortInline@%
    16601660\end{cquote}
    1661 The only exception is bit field specification, which always appear to the right of the base type.
     1661The only exception is bit-field specification, which always appear to the right of the base type.
    16621662% Specifically, the character @*@ is used to indicate a pointer, square brackets @[@\,@]@ are used to represent an array or function return value, and parentheses @()@ are used to indicate a function parameter.
    16631663However, unlike C, \CFA type declaration tokens are distributed across all variables in the declaration list.
     
    17151715// pointer to array of 5 doubles
    17161716
    1717 // common bit field syntax
     1717// common bit-field syntax
    17181718
    17191719
     
    19111911\subsection{Type Nesting}
    19121912
    1913 Nested types provide a mechanism to organize associated types and refactor a subset of fields into a named aggregate (\eg sub-aggregates @name@, @address@, @department@, within aggregate @employe@).
     1913Nested types provide a mechanism to organize associated types and refactor a subset of members into a named aggregate (\eg sub-aggregates @name@, @address@, @department@, within aggregate @employe@).
    19141914Java nested types are dynamic (apply to objects), \CC are static (apply to the \lstinline[language=C++]@class@), and C hoists (refactors) nested types into the enclosing scope, meaning there is no need for type qualification.
    19151915Since \CFA in not object-oriented, adopting dynamic scoping does not make sense;
    1916 instead \CFA adopts \CC static nesting, using the field-selection operator ``@.@'' for type qualification, as does Java, rather than the \CC type-selection operator ``@::@'' (see Figure~\ref{f:TypeNestingQualification}).
     1916instead \CFA adopts \CC static nesting, using the member-selection operator ``@.@'' for type qualification, as does Java, rather than the \CC type-selection operator ``@::@'' (see Figure~\ref{f:TypeNestingQualification}).
    19171917\begin{figure}
    19181918\centering
     
    20052005Destruction parameters are useful for specifying storage-management actions, such as de-initialize but not deallocate.}.
    20062006\begin{cfa}
    2007 struct VLA { int len, * data; };                        $\C{// variable length array of integers}$
    2008 void ?{}( VLA & vla ) with ( vla ) { len = 10;  data = alloc( len ); }  $\C{// default constructor}$
     2007struct VLA { int size, * data; };                       $\C{// variable length array of integers}$
     2008void ?{}( VLA & vla ) with ( vla ) { size = 10;  data = alloc( size ); }  $\C{// default constructor}$
    20092009void ^?{}( VLA & vla ) with ( vla ) { free( data ); } $\C{// destructor}$
    20102010{
     
    20132013\end{cfa}
    20142014@VLA@ is a \newterm{managed type}\footnote{
    2015 A managed type affects the runtime environment versus a self-contained type.}: a type requiring a non-trivial constructor or destructor, or with a field of a managed type.
     2015A managed type affects the runtime environment versus a self-contained type.}: a type requiring a non-trivial constructor or destructor, or with a member of a managed type.
    20162016A managed type is implicitly constructed at allocation and destructed at deallocation to ensure proper interaction with runtime resources, in this case, the @data@ array in the heap.
    20172017For details of the code-generation placement of implicit constructor and destructor calls among complex executable statements see~\cite[\S~2.2]{Schluntz17}.
     
    20192019\CFA also provides syntax for \newterm{initialization} and \newterm{copy}:
    20202020\begin{cfa}
    2021 void ?{}( VLA & vla, int size, char fill ) with ( vla ) {  $\C{// initialization}$
    2022         len = size;  data = alloc( len, fill );
     2021void ?{}( VLA & vla, int size, char fill = '\0' ) {  $\C{// initialization}$
     2022        vla.[ size, data ] = [ size, alloc( size, fill ) ];
    20232023}
    20242024void ?{}( VLA & vla, VLA other ) {                      $\C{// copy, shallow}$
    2025         vla.len = other.len;  vla.data = other.data;
     2025        vla = other;
    20262026}
    20272027\end{cfa}
     
    20362036
    20372037\CFA constructors may be explicitly called, like Java, and destructors may be explicitly called, like \CC.
    2038 Explicit calls to constructors double as a \CC-style \emph{placement syntax}, useful for construction of member fields in user-defined constructors and reuse of existing storage allocations.
     2038Explicit calls to constructors double as a \CC-style \emph{placement syntax}, useful for construction of members in user-defined constructors and reuse of existing storage allocations.
    20392039Like the other operators in \CFA, there is a concise syntax for constructor/destructor function calls:
    20402040\begin{cfa}
     
    20482048        y{ x };                                                                 $\C{// reallocate y, points to x}$
    20492049        x{};                                                                    $\C{// reallocate x, not pointing to y}$
    2050         //  ^z{};  ^y{};  ^x{};
    2051 }
     2050}       //  ^z{};  ^y{};  ^x{};
    20522051\end{cfa}
    20532052
     
    20602059For compatibility with C, a copy constructor from the first union member type is also defined.
    20612060For @struct@ types, each of the four functions are implicitly defined to call their corresponding functions on each member of the struct.
    2062 To better simulate the behaviour of C initializers, a set of \newterm{field constructors} is also generated for structures.
     2061To better simulate the behaviour of C initializers, a set of \newterm{member constructors} is also generated for structures.
    20632062A constructor is generated for each non-empty prefix of a structure's member-list to copy-construct the members passed as parameters and default-construct the remaining members.
    2064 To allow users to limit the set of constructors available for a type, when a user declares any constructor or destructor, the corresponding generated function and all field constructors for that type are hidden from expression resolution;
     2063To allow users to limit the set of constructors available for a type, when a user declares any constructor or destructor, the corresponding generated function and all member constructors for that type are hidden from expression resolution;
    20652064similarly, the generated default constructor is hidden upon declaration of any constructor.
    20662065These semantics closely mirror the rule for implicit declaration of constructors in \CC\cite[p.~186]{ANSI98:C++}.
     
    27402739
    27412740\section{Related Work}
     2741\label{s:RelatedWork}
    27422742
    27432743
     
    27932793C provides variadic functions through @va_list@ objects, but the programmer is responsible for managing the number of arguments and their types, so the mechanism is type unsafe.
    27942794KW-C~\cite{Buhr94a}, a predecessor of \CFA, introduced tuples to C as an extension of the C syntax, taking much of its inspiration from SETL.
    2795 The main contributions of that work were adding MRVF, tuple mass and multiple assignment, and record-field access.
     2795The main contributions of that work were adding MRVF, tuple mass and multiple assignment, and record-member access.
    27962796\CCeleven introduced @std::tuple@ as a library variadic template structure.
    27972797Tuples are a generalization of @std::pair@, in that they allow for arbitrary length, fixed-size aggregation of heterogeneous values.
  • src/CodeGen/CodeGenerator.cc

    r3ef35bd reba74ba  
    119119
    120120        string CodeGenerator::mangleName( DeclarationWithType * decl ) {
    121                 if ( pretty ) return decl->get_name();
    122                 if ( decl->get_mangleName() != "" ) {
     121                // GCC builtins should always be printed unmangled
     122                if ( pretty || decl->linkage.is_gcc_builtin ) return decl->name;
     123                if ( decl->mangleName != "" ) {
    123124                        // need to incorporate scope level in order to differentiate names for destructors
    124125                        return decl->get_scopedMangleName();
    125126                } else {
    126                         return decl->get_name();
     127                        return decl->name;
    127128                } // if
    128129        }
  • src/Common/Heap.cc

    r3ef35bd reba74ba  
    2121#include <iostream>
    2222
    23 //#define WITH_HEAP_STATISTICS
     23#define WITH_HEAP_STATISTICS
    2424
    2525namespace HeapStats {
     
    3030#else
    3131        struct StatBlock {
    32                 const char * name = nullptr;
    33                 size_t mallocs    = 0;
    34                 size_t frees      = 0;
     32                const char * name  = nullptr;   ///< Name of this pass
     33                size_t mallocs     = 0;                 ///< Allocations in this pass
     34                size_t frees       = 0;                 ///< Frees in this pass
     35                size_t n_allocs    = 0;                 ///< Current number of live allocations
     36                size_t peak_allocs = 0;                 ///< Peak number of live allocations this pass
    3537        };
    3638
    37         StatBlock    passes[100] = {{ "Pre-Parse", 0, 0 }};
     39        StatBlock    passes[100] = {{ "Pre-Parse", 0, 0, 0, 0 }};
    3840        const size_t passes_size = sizeof(passes) / sizeof(passes[0]);
    3941        size_t       passes_cnt = 1;
     
    4345                passes[passes_cnt].mallocs = 0;
    4446                passes[passes_cnt].frees   = 0;
     47                passes[passes_cnt].n_allocs
     48                        = passes[passes_cnt].peak_allocs
     49                        = passes[passes_cnt-1].n_allocs;
    4550                passes_cnt++;
    4651
     
    5560        }
    5661
    57         void print(const StatBlock& stat, size_t nc, size_t total_mallocs, size_t total_frees) {
     62        void print(const StatBlock& stat, size_t nc, size_t total_mallocs, size_t total_frees, size_t overall_peak) {
    5863                std::cerr << std::setw(nc) << stat.name;
    5964                std::cerr << " | ";
    6065
    61                 print(stat.mallocs, total_mallocs);
    62                 print(stat.frees  , total_frees  );
     66                print(stat.mallocs,     total_mallocs);
     67                print(stat.frees,       total_frees  );
     68                print(stat.peak_allocs, overall_peak );
    6369                std::cerr << "\n";
    6470        }
     
    7581                size_t total_mallocs = 0;
    7682                size_t total_frees   = 0;
     83                size_t overall_peak  = 0;
    7784                for(size_t i = 0; i < passes_cnt; i++) {
    7885                        nc = std::max(nc, std::strlen(passes[i].name));
    7986                        total_mallocs += passes[i].mallocs;
    8087                        total_frees   += passes[i].frees;
    81                 }
    82                 size_t nct = nc + 44;
     88                        overall_peak = std::max(overall_peak, passes[i].peak_allocs);
     89                }
     90                size_t nct = nc + 65;
    8391
    8492                const char * const title = "Heap Usage Statistic";
     
    8896                print('-', nct);
    8997                std::cerr << std::setw(nc) << "Pass";
    90                 std::cerr << " |       Malloc Count |         Free Count |" << std::endl;
     98                std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
    9199
    92100                print('-', nct);
    93101                for(size_t i = 0; i < passes_cnt; i++) {
    94                         print(passes[i], nc, total_mallocs, total_frees);
     102                        print(passes[i], nc, total_mallocs, total_frees, overall_peak);
    95103                }
    96104                print('-', nct);
    97                 print({"Sum", total_mallocs, total_frees}, nc, total_mallocs, total_frees);
     105                print({"Sum", total_mallocs, total_frees, 0, overall_peak},
     106                        nc, total_mallocs, total_frees, overall_peak);
    98107
    99108        }
     
    158167                void * malloc( size_t size ) {
    159168                        static auto __malloc = reinterpret_cast<void * (*)(size_t)>(interpose_symbol( "malloc", nullptr ));
    160                         if( passes_cnt > 0 ) passes[passes_cnt - 1].mallocs++;
     169                        if( passes_cnt > 0 ) {
     170                                passes[passes_cnt - 1].mallocs++;
     171                                passes[passes_cnt - 1].n_allocs++;
     172                                passes[passes_cnt - 1].peak_allocs
     173                                        = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
     174                        }
    161175                        return __malloc( size );
    162176                }
     
    164178                void free( void * ptr ) {
    165179                        static auto __free = reinterpret_cast<void   (*)(void *)>(interpose_symbol( "free", nullptr ));
    166                         if( passes_cnt > 0 ) passes[passes_cnt - 1].frees++;
     180                        if( passes_cnt > 0 ) {
     181                                passes[passes_cnt - 1].frees++;
     182                                passes[passes_cnt - 1].n_allocs--;
     183                        }
    167184                        return __free( ptr );
    168185                }
     
    170187                void * calloc( size_t nelem, size_t size ) {
    171188                        static auto __calloc = reinterpret_cast<void * (*)(size_t, size_t)>(interpose_symbol( "calloc", nullptr ));
    172                         if( passes_cnt > 0 ) passes[passes_cnt - 1].mallocs++;
     189                        if( passes_cnt > 0 ) {
     190                                passes[passes_cnt - 1].mallocs++;
     191                                passes[passes_cnt - 1].n_allocs++;
     192                                passes[passes_cnt - 1].peak_allocs
     193                                        = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
     194                        }
    173195                        return __calloc( nelem, size );
    174196                }
  • src/Common/ScopedMap.h

    r3ef35bd reba74ba  
    1010// Created On       : Wed Dec 2 11:37:00 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 21 22:18:24 2017
    13 // Update Count     : 2
     12// Last Modified On : Mon May 21 15:22:40 2018
     13// Update Count     : 3
    1414//
    1515
     
    276276        }
    277277
     278        template< typename value_t >
     279        std::pair< iterator, bool > insertAt( size_type scope, const Key& key, value_t&& value ) {
     280                return insertAt( scope, std::make_pair( key, std::forward<value_t>( value ) ) );
     281        }
     282
    278283        Value& operator[] ( const Key &key ) {
    279284                iterator slot = find( key );
  • src/GenPoly/GenPoly.cc

    r3ef35bd reba74ba  
    371371                        return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )
    372372                                || typesPolyCompatible( ap->get_base(), bp->get_base() );
     373                } else if ( aid == type_index{typeid(ReferenceType)} ) {
     374                        ReferenceType *ap = as<ReferenceType>(a), *bp = as<ReferenceType>(b);
     375                        return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )
     376                                || typesPolyCompatible( ap->get_base(), bp->get_base() );
    373377                } else if ( aid == type_index{typeid(ArrayType)} ) {
    374378                        ArrayType *aa = as<ArrayType>(a), *ba = as<ArrayType>(b);
  • src/GenPoly/Lvalue.cc

    r3ef35bd reba74ba  
    165165                        if ( isIntrinsicReference( appExpr ) ) {
    166166                                // eliminate reference types from intrinsic applications - now they return lvalues
    167                                 Type * result = appExpr->result;
    168                                 appExpr->result = result->stripReferences()->clone();
     167                                ReferenceType * result = strict_dynamic_cast< ReferenceType * >( appExpr->result );
     168                                appExpr->result = result->base->clone();
    169169                                appExpr->result->set_lvalue( true );
    170170                                if ( ! inIntrinsic ) {
     
    181181                void FixIntrinsicResult::premutate( FunctionDecl * funcDecl ) {
    182182                        GuardValue( inIntrinsic );
    183                         inIntrinsic =  funcDecl->linkage == LinkageSpec::Intrinsic;
     183                        inIntrinsic = funcDecl->linkage == LinkageSpec::Intrinsic;
    184184                }
    185185
     
    399399                                        ret = new AddressExpr( ret );
    400400                                }
    401                                 if ( srcType->get_lvalue() && srcType->get_qualifiers() != strict_dynamic_cast<ReferenceType *>( destType )->base->get_qualifiers() ) {
     401                                if ( srcType->get_lvalue() && ! ResolvExpr::typesCompatible( srcType, strict_dynamic_cast<ReferenceType *>( destType )->base, SymTab::Indexer() ) ) {
    402402                                        // must keep cast if cast-to type is different from the actual type
    403403                                        castExpr->arg = ret;
  • src/Parser/DeclarationNode.cc

    r3ef35bd reba74ba  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May 16 09:37:17 2018
    13 // Update Count     : 1070
     12// Last Modified On : Tue May 22 08:39:29 2018
     13// Update Count     : 1074
    1414//
    1515
     
    3232#include "SynTree/Type.h"          // for Type, Type::StorageClasses, Type::...
    3333#include "TypeData.h"              // for TypeData, TypeData::Aggregate_t
    34 #include "TypedefTable.h"          // for TypedefTable, TypedefTable::kind_t...
     34#include "TypedefTable.h"          // for TypedefTable
    3535
    3636class Initializer;
     
    5454
    5555DeclarationNode::DeclarationNode() :
     56                builtin( NoBuiltinType ),
    5657                type( nullptr ),
    5758                bitfieldWidth( nullptr ),
     
    100101        newnode->name = name ? new string( *name ) : nullptr;
    101102
     103        newnode->builtin = NoBuiltinType;
    102104        newnode->type = maybeClone( type );
    103105        newnode->storageClasses = storageClasses;
     
    178180        newnode->type->function.body = body;
    179181
    180         // ignore unnamed routine declarations: void p( int (*)(int) );
    181         if ( newnode->name ) {
    182                 typedefTable.addToEnclosingScope( *newnode->name, TypedefTable::ID );
    183         } // if
    184 
    185182        if ( ret ) {
    186183                newnode->type->base = ret->type;
     
    284281        newnode->name = name;
    285282        newnode->enumeratorValue.reset( constant );
    286         typedefTable.addToEnclosingScope( *newnode->name, TypedefTable::ID );
    287283        return newnode;
    288284} // DeclarationNode::newEnumConstant
     
    550546                                        type->aggregate.params = q->type->forall; // make polymorphic type
    551547                                        // change implicit typedef from TYPEDEFname to TYPEGENname
    552                                         typedefTable.changeKind( *type->aggregate.name, TypedefTable::TG );
     548                                        typedefTable.changeKind( *type->aggregate.name, TYPEGENname );
    553549                                } // if
    554550                        } else {                                                                        // not polymorphic
  • src/Parser/LinkageSpec.h

    r3ef35bd reba74ba  
    2727                Overrideable = 1 << 2,
    2828                Builtin = 1 << 3,
     29                GccBuiltin = 1 << 4,
    2930
    30                 NoOfSpecs = 1 << 4,
     31                NoOfSpecs = 1 << 5,
    3132        };
    3233
     
    3839                        bool is_overridable : 1;
    3940                        bool is_builtin : 1;
     41                        bool is_gcc_builtin : 1;
    4042                };
    4143                constexpr Spec( unsigned int val ) : val( val ) {}
     
    6163        inline bool isOverridable( Spec spec ) { return spec.is_overridable; }
    6264        inline bool isBuiltin( Spec spec ) { return spec.is_builtin; }
     65        inline bool isGccBuiltin( Spec spec ) { return spec.is_gcc_builtin; }
    6366
    6467        // Pre-defined flag combinations:
     
    7275        constexpr Spec const AutoGen = { Mangle | Generate | Overrideable };
    7376        // gcc internal
    74         constexpr Spec const Compiler = { Builtin };
     77        constexpr Spec const Compiler = { Mangle | Builtin | GccBuiltin };
    7578        // mangled builtins
    7679        constexpr Spec const BuiltinCFA = { Mangle | Generate | Builtin };
  • src/Parser/TypedefTable.cc

    r3ef35bd reba74ba  
    77// TypedefTable.cc --
    88//
    9 // Author           : Rodolfo G. Esteves
     9// Author           : Peter A. Buhr
    1010// Created On       : Sat May 16 15:20:13 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug 15 18:24:42 2016
    13 // Update Count     : 25
     12// Last Modified On : Tue May 22 08:40:01 2018
     13// Update Count     : 121
    1414//
    1515
    16 #include <ext/alloc_traits.h>    // for __alloc_traits<>::value_type
    17 #include <cassert>               // for assert
    18 #include <list>                  // for list, _List_iterator, list<>::iterator
    19 #include <map>                   // for _Rb_tree_iterator, _Rb_tree_const_it...
    20 #include <memory>                // for allocator_traits<>::value_type
    21 #include <utility>               // for pair
    2216
    23 #include "Parser/ParserTypes.h"  // for typedefTable
    24 #include "Parser/parser.hh"      // for IDENTIFIER
    2517#include "TypedefTable.h"
    26 
    27 using namespace std;
     18#include <cassert>                                                                              // for assert
    2819
    2920#if 0
    3021#include <iostream>
    31 
    3222#define debugPrint( x ) cerr << x
    3323#else
     
    3525#endif
    3626
    37 TypedefTable::TypedefTable() : currentScope( 0 ) {}
     27using namespace std;                                                                    // string, iostream
    3828
    39 bool TypedefTable::exists( const string &identifier ) {
    40         return table.count( identifier ) > 0;
    41 }
     29TypedefTable::~TypedefTable() {
     30        if ( ! SemanticErrorThrow && kindTable.currentScope() != 0 ) {
     31                // std::cerr << "scope failure " << kindTable.currentScope() << endl;
     32        } // if
     33} // TypedefTable::~TypedefTable
    4234
    43 int TypedefTable::isKind( const string &identifier ) const {
    44         tableType::const_iterator id_pos = table.find( identifier );
     35bool TypedefTable::exists( const string & identifier ) {
     36        return kindTable.find( identifier ) != kindTable.end();
     37} // TypedefTable::exists
     38
     39int TypedefTable::isKind( const string & identifier ) const {
     40        KindTable::const_iterator posn = kindTable.find( identifier );
    4541        // Name lookup defaults to identifier, and then the identifier's kind is set by the parser.
    46         if ( id_pos == table.end() ) return IDENTIFIER;
    47         return id_pos->second.begin()->kind;
    48 }
     42        if ( posn == kindTable.end() ) return IDENTIFIER;
     43        return posn->second;
     44} // TypedefTable::isKind
    4945
    50 void TypedefTable::changeKind( const string &identifier, kind_t kind ) {
    51         tableType::iterator id_pos = table.find( identifier );
    52         if ( id_pos == table.end() ) return;
    53         id_pos->second.begin()->kind = kind;
    54 }
     46void TypedefTable::changeKind( const string & identifier, int kind ) {
     47        KindTable::iterator posn = kindTable.find( identifier );
     48        if ( posn != kindTable.end() ) posn->second = kind;     // exists => update
     49} // TypedefTable::changeKind
    5550
    5651// SKULLDUGGERY: Generate a typedef for the aggregate name so the aggregate does not have to be qualified by
    57 // "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed
    58 // if the name is explicitly used.
    59 void TypedefTable::makeTypedef( const string &name ) {
     52// "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the
     53// name is explicitly used.
     54void TypedefTable::makeTypedef( const string & name ) {
    6055        if ( ! typedefTable.exists( name ) ) {
    61                 typedefTable.addToEnclosingScope( name, TypedefTable::TD );
     56                typedefTable.addToEnclosingScope( name, TYPEDEFname );
    6257        } // if
    63 }
     58} // TypedefTable::makeTypedef
    6459
    65 void TypedefTable::addToScope( const std::string &identifier, kind_t kind, int scope ) {
    66         if ( currentTrait != "" && scope == contextScope ) {
    67                 DeferredEntry entry = { identifier, kind };
    68                 contexts[currentTrait].push_back( entry );
    69         } else {
    70                 debugPrint( "Adding " << identifier << " as kind " << kind << " scope " << scope << " from scope " << currentScope << endl );
    71                 Entry newEntry = { scope, kind };
    72                 tableType::iterator curPos = table.find( identifier );
    73                 if ( curPos == table.end()) {
    74                         list< Entry > newList;
    75                         newList.push_front( newEntry );
    76                         table[identifier] = newList;
    77                 } else {
    78                         list< Entry >::iterator listPos = (*curPos ).second.begin();
    79                         while ( listPos != (*curPos ).second.end() && listPos->scope > scope ) {
    80                                 listPos++;
    81                         } // while
    82                         (*curPos ).second.insert( listPos, newEntry );
    83                 } // if
    84         } // if
    85 }
    86 
    87 void TypedefTable::addToCurrentScope( const std::string &identifier, kind_t kind ) {
    88         addToScope( identifier, kind, currentScope );
    89 }
    90 
    91 void TypedefTable::addToCurrentScope( kind_t kind ) {
    92         addToCurrentScope( nextIdentifiers.top(), kind );
    93 }
    94 
    95 void TypedefTable::addToEnclosingScope( const std::string &identifier, kind_t kind ) {
    96         assert( currentScope >= 1 );
    97         addToScope( identifier, kind, currentScope - 1 );
    98 }
    99 
    100 void TypedefTable::addToEnclosingScope( kind_t kind ) {
    101         addToEnclosingScope( nextIdentifiers.top(), kind );
    102 }
    103 
    104 void TypedefTable::addToEnclosingScope2( const std::string &identifier, kind_t kind ) {
    105         assert( currentScope >= 2 );
    106         addToScope( identifier, kind, currentScope - 2 );
    107 }
    108 
    109 void TypedefTable::addToEnclosingScope2( kind_t kind ) {
    110         addToEnclosingScope2( nextIdentifiers.top(), kind );
    111 }
    112 
    113 void TypedefTable::setNextIdentifier( const std::string &identifier ) {
    114         nextIdentifiers.top() = identifier;
    115 }
    116 
    117 void TypedefTable::openTrait( const std::string &contextName ) {
    118         map< string, deferListType >::iterator i = contexts.find( contextName );
    119         if ( i != contexts.end() ) {
    120                 deferListType &entries = i->second;
    121                 for ( deferListType::iterator i = entries.begin(); i != entries.end(); i++) {
    122                         addToEnclosingScope( i->identifier, i->kind );
    123                 } // for
    124         } // if
    125 }
     60void TypedefTable::addToEnclosingScope( const std::string & identifier, int kind ) {
     61        assert( kindTable.currentScope() >= 1 );
     62        auto scope = kindTable.currentScope() - 1;
     63        debugPrint( "Adding " << identifier << " as kind " << kind << " scope " << scope << endl );
     64        auto ret = kindTable.insertAt( scope, identifier, kind );
     65        if ( ! ret.second ) ret.first->second = kind;           // exists => update
     66} // TypedefTable::addToEnclosingScope
    12667
    12768void TypedefTable::enterScope() {
    128         currentScope += 1;
    129         deferListStack.push( deferListType() );
    130         nextIdentifiers.push( "" );
    131         debugPrint( "Entering scope " << currentScope << ", nextIdentifiers size is " << nextIdentifiers.size() << endl );
    132 }
     69        kindTable.beginScope();
     70        debugPrint( "Entering scope " << kindTable.currentScope() << endl );
     71} // TypedefTable::enterScope
    13372
    13473void TypedefTable::leaveScope() {
    135         debugPrint( "Leaving scope " << currentScope << endl );
    136         for ( tableType::iterator i = table.begin(); i != table.end(); ) {
    137                 list< Entry > &declList = (*i).second;
    138                 while ( ! declList.empty() && declList.front().scope == currentScope ) {
    139                         declList.pop_front();
    140                 }
    141                 if ( declList.empty() ) {                                               // standard idom for erasing during traversal
    142                         table.erase( i++ );
    143                 } else
    144                         ++i;
    145         } // for
    146         currentScope -= 1;
    147         for ( deferListType::iterator i = deferListStack.top().begin(); i != deferListStack.top().end(); i++ ) {
    148                 addToCurrentScope( i->identifier, i->kind );
    149         } // for
    150         deferListStack.pop();
    151         debugPrint( "nextIdentifiers size is " << nextIdentifiers.size() << " top is " << nextIdentifiers.top() << endl );
    152         nextIdentifiers.pop();
    153 }
     74        debugPrint( "Leaving scope " << kindTable.currentScope() << endl );
     75        kindTable.endScope();
     76} // TypedefTable::leaveScope
    15477
    155 void TypedefTable::enterTrait( const std::string &contextName ) {
    156         currentTrait = contextName;
    157         contextScope = currentScope;
    158 }
    159 
    160 void TypedefTable::leaveTrait() {
    161         currentTrait = "";
    162 }
    163 
    164 void TypedefTable::print( void ) const {
    165         for ( tableType::const_iterator i = table.begin(); i != table.end(); i++) {
    166                 debugPrint( (*i ).first << ": " );
    167                 list< Entry > declList = (*i).second;
    168                 for ( list< Entry >::const_iterator j = declList.begin(); j != declList.end(); j++ ) {
    169                         debugPrint( "(" << (*j).scope << " " << (*j).kind << ") " );
    170                 }
    171                 debugPrint( endl );
    172         } // for
    173 }
     78// void TypedefTable::print( void ) const {
     79//      for ( KindTable::const_iterator i = table.begin(); i != table.end(); i++) {
     80//              debugPrint( (*i ).first << ": " );
     81//              list< Entry > declList = (*i).second;
     82//              for ( list< Entry >::const_iterator j = declList.begin(); j != declList.end(); j++ ) {
     83//                      debugPrint( "(" << (*j).scope << " " << (*j).kind << ") " );
     84//              }
     85//              debugPrint( endl );
     86//      } // for
     87// }
    17488
    17589// Local Variables: //
  • src/Parser/TypedefTable.h

    r3ef35bd reba74ba  
    77// TypedefTable.h --
    88//
    9 // Author           : Rodolfo G. Esteves
     9// Author           : Peter A. Buhr
    1010// Created On       : Sat May 16 15:24:36 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:33:14 2017
    13 // Update Count     : 34
     12// Last Modified On : Tue May 22 08:39:29 2018
     13// Update Count     : 77
    1414//
    1515
    1616#pragma once
    1717
    18 #include <list>       // for list
    19 #include <map>        // for map, map<>::value_compare
    20 #include <stack>      // for stack
    21 #include <string>     // for string
     18#include <string>                                                                               // for string
    2219
     20#include "Common/ScopedMap.h"                                                   // for ScopedMap
    2321#include "ParserTypes.h"
    24 #include "parser.hh"  // for IDENTIFIER, TYPEDEFname, TYPEGENname
     22#include "parser.hh"                                                                    // for IDENTIFIER, TYPEDEFname, TYPEGENname
    2523
    2624class TypedefTable {
     25        typedef ScopedMap< std::string, int > KindTable;
     26        KindTable kindTable;   
    2727  public:
    28         enum kind_t { ID = IDENTIFIER, TD = TYPEDEFname, TG = TYPEGENname };
    29   private:
    30         struct Entry {
    31                 int scope;
    32                 kind_t kind;
    33         };
     28        ~TypedefTable();
    3429
    35         struct DeferredEntry {
    36                 std::string identifier;
    37                 kind_t kind;
    38         };
    39 
    40         typedef std::map< std::string, std::list< Entry > > tableType;
    41         tableType table;
    42 
    43         int currentScope;
    44         std::string currentTrait;
    45         int contextScope;
    46 
    47         typedef std::list< DeferredEntry > deferListType;
    48         std::stack< deferListType > deferListStack;
    49         std::map< std::string, deferListType > contexts;
    50 
    51         std::stack< std::string > nextIdentifiers;
    52 
    53         void addToScope( const std::string &identifier, kind_t kind, int scope );
    54   public:
    55         TypedefTable();
    56 
    57         bool exists( const std::string &identifier );
    58         int isKind( const std::string &identifier ) const;
    59         void changeKind( const std::string &identifier, kind_t kind );
    60 
    61         void makeTypedef( const std::string &name );
    62 
    63         // "addToCurrentScope" adds the identifier/type pair to the current scope. This does less than you think it does,
    64         // since each declaration is within its own scope.  Mostly useful for type parameters.
    65         void addToCurrentScope( const std::string &identifier, kind_t kind );
    66         void addToCurrentScope( kind_t kind );                  // use nextIdentifiers.top()
    67 
    68         // "addToEnclosingScope" adds the identifier/type pair to the scope that encloses the current one.  This is the
    69         // right way to handle type and typedef names
    70         void addToEnclosingScope( const std::string &identifier, kind_t kind );
    71         void addToEnclosingScope( kind_t kind );                // use nextIdentifiers.top()
    72 
    73         // "addToEnclosingScope2" adds the identifier/type pair to the scope that encloses the scope enclosing the the
    74         // current one.  This is the right way to handle assertion names
    75         void addToEnclosingScope2( const std::string &identifier, kind_t kind );
    76         void addToEnclosingScope2( kind_t kind );               // use nextIdentifiers.top()
    77 
    78         // set the next identifier to be used by an "add" operation without an identifier parameter within the current scope
    79         void setNextIdentifier( const std::string &identifier );
    80 
    81         // dump the definitions from a pre-defined context into the current scope
    82         void openTrait( const std::string &contextName );
     30        bool exists( const std::string & identifier );
     31        int isKind( const std::string & identifier ) const;
     32        void changeKind( const std::string & identifier, int kind );
     33        void makeTypedef( const std::string & name );
     34        void addToEnclosingScope( const std::string & identifier, int kind );
    8335
    8436        void enterScope();
    8537        void leaveScope();
    86         void enterTrait( const std::string &contextName );
    87         void leaveTrait();
    88 
    89         void print() const;
    90 };
     38}; // TypedefTable
    9139
    9240// Local Variables: //
  • src/Parser/parser.yy

    r3ef35bd reba74ba  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri May 11 17:51:38 2018
    13 // Update Count     : 3261
     12// Last Modified On : Thu May 24 18:11:59 2018
     13// Update Count     : 3369
    1414//
    1515
     
    119119// Does the forall bind to the struct or the routine, and how would it be possible to explicitly specify the binding.
    120120//   forall( otype T ) struct S { int T; } forall( otype W ) bar( W ) {}
     121// Currently, the forall is associated with the routine, and the generic type has to be separately defined:
     122//   forall( otype T ) struct S { int T; };
     123//   forall( otype W ) bar( W ) {}
    121124
    122125void rebindForall( DeclarationNode * declSpec, DeclarationNode * funcDecl ) {
    123         if ( declSpec->type->kind == TypeData::Aggregate ) { // return is aggregate definition
     126        if ( declSpec->type->kind == TypeData::Aggregate ) { // ignore aggregate definition
    124127                funcDecl->type->forall = declSpec->type->aggregate.params; // move forall from aggregate to function type
    125128                declSpec->type->aggregate.params = nullptr;
     
    301304%type<decl> exception_declaration external_definition external_definition_list external_definition_list_opt
    302305
    303 %type<decl> field_declaration field_declaration_list field_declarator field_declaring_list
     306%type<decl> field_declaration field_declaration_list_opt field_declarator_opt field_declaring_list
    304307%type<en> field field_list field_name fraction_constants_opt
    305308
     
    361364
    362365// initializers
    363 %type<in>  initializer initializer_list initializer_opt
     366%type<in>  initializer initializer_list_opt initializer_opt
    364367
    365368// designators
     
    412415// actions during the parser update this data structure when the class of identifiers change.
    413416//
    414 // Because the Cforall language is block-scoped, there is the possibility that an identifier can change its class in a
    415 // local scope; it must revert to its original class at the end of the block.  Since type names can be local to a
    416 // particular declaration, each declaration is itself a scope.  This requires distinguishing between type names that are
    417 // local to the current declaration scope and those that persist past the end of the declaration (i.e., names defined in
    418 // "typedef" or "otype" declarations).
    419 //
    420 // The non-terminals "push" and "pop" derive the empty string; their only use is to denote the opening and closing of
    421 // scopes.  Every push must have a matching pop, although it is regrettable the matching pairs do not always occur
    422 // within the same rule.  These non-terminals may appear in more contexts than strictly necessary from a semantic point
    423 // of view.  Unfortunately, these extra rules are necessary to prevent parsing conflicts -- the parser may not have
    424 // enough context and look-ahead information to decide whether a new scope is necessary, so the effect of these extra
    425 // rules is to open a new scope unconditionally.  As the grammar evolves, it may be neccesary to add or move around
    426 // "push" and "pop" nonterminals to resolve conflicts of this sort.
     417// Because the Cforall language is block-scoped, an identifier can change its class in a local scope; it must revert to
     418// its original class at the end of the block.  Since type names can be local to a particular declaration, each
     419// declaration is itself a scope.  This requires distinguishing between type names that are local to the current
     420// declaration scope and those that persist past the end of the declaration (i.e., names defined in "typedef" or "otype"
     421// declarations).
     422//
     423// The non-terminals "push" and "pop" denote the opening and closing of scopes.  Every push must have a matching pop,
     424// although it is regrettable the matching pairs do not always occur within the same rule.  These non-terminals may
     425// appear in more contexts than strictly necessary from a semantic point of view.
    427426
    428427push:
     
    498497                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $5 ) ), $2 ) ); }
    499498        | type_name '.' no_attr_identifier                                      // CFA, nested type
    500                 { SemanticError( yylloc, "Qualified names are currently unimplemented." ); $$ = nullptr; }
    501 //              { $$ = nullptr; }
    502         | type_name '.' '[' push field_list pop ']'                     // CFA, nested type / tuple field selector
    503                 { SemanticError( yylloc, "Qualified names are currently unimplemented." ); $$ = nullptr; }
    504 //              { $$ = nullptr; }
     499                { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
     500        | type_name '.' '[' field_list ']'                                      // CFA, nested type / tuple field selector
     501                { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
    505502        | GENERIC '(' assignment_expression ',' generic_assoc_list ')' // C11
    506503                { SemanticError( yylloc, "_Generic is currently unimplemented." ); $$ = nullptr; }
     
    519516postfix_expression:
    520517        primary_expression
    521         | postfix_expression '[' push assignment_expression pop ']'
     518        | postfix_expression '[' assignment_expression ']'
    522519                // CFA, comma_expression disallowed in this context because it results in a common user error: subscripting a
    523520                // matrix with x[i,j] instead of x[i][j]. While this change is not backwards compatible, there seems to be
    524521                // little advantage to this feature and many disadvantages. It is possible to write x[(i,j)] in CFA, which is
    525522                // equivalent to the old x[i,j].
    526                 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $4 ) ); }
     523                { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
    527524        | postfix_expression '{' argument_expression_list '}' // CFA, constructor call
    528525                {
     
    539536        | postfix_expression FLOATING_FRACTIONconstant          // CFA, tuple index
    540537                { $$ = new ExpressionNode( build_fieldSel( $1, build_field_name_FLOATING_FRACTIONconstant( *$2 ) ) ); }
    541         | postfix_expression '.' '[' push field_list pop ']' // CFA, tuple field selector
    542                 { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $5 ) ) ); }
     538        | postfix_expression '.' '[' field_list ']'                     // CFA, tuple field selector
     539                { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
    543540        | postfix_expression ARROW no_attr_identifier
    544541                {
     
    547544        | postfix_expression ARROW INTEGERconstant                      // CFA, tuple index
    548545                { $$ = new ExpressionNode( build_pfieldSel( $1, build_constantInteger( *$3 ) ) ); }
    549         | postfix_expression ARROW '[' push field_list pop ']' // CFA, tuple field selector
    550                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $5 ) ) ); }
     546        | postfix_expression ARROW '[' field_list ']'           // CFA, tuple field selector
     547                { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $4 ) ) ); }
    551548        | postfix_expression ICR
    552549                { $$ = new ExpressionNode( build_unary_ptr( OperKinds::IncrPost, $1 ) ); }
    553550        | postfix_expression DECR
    554551                { $$ = new ExpressionNode( build_unary_ptr( OperKinds::DecrPost, $1 ) ); }
    555         | '(' type_no_function ')' '{' initializer_list comma_opt '}' // C99, compound-literal
     552        | '(' type_no_function ')' '{' initializer_list_opt comma_opt '}' // C99, compound-literal
    556553                { $$ = new ExpressionNode( build_compoundLiteral( $2, new InitializerNode( $5, true ) ) ); }
    557         | '(' type_no_function ')' '@' '{' initializer_list comma_opt '}' // CFA, explicit C compound-literal
     554        | '(' type_no_function ')' '@' '{' initializer_list_opt comma_opt '}' // CFA, explicit C compound-literal
    558555                { $$ = new ExpressionNode( build_compoundLiteral( $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
    559556        | '^' primary_expression '{' argument_expression_list '}' // CFA
     
    588585        | FLOATING_DECIMALconstant field
    589586                { $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( *$1 ) ), maybeMoveBuild<Expression>( $2 ) ) ); }
    590         | FLOATING_DECIMALconstant '[' push field_list pop ']'
    591                 { $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( *$1 ) ), build_tuple( $4 ) ) ); }
     587        | FLOATING_DECIMALconstant '[' field_list ']'
     588                { $$ = new ExpressionNode( build_fieldSel( new ExpressionNode( build_field_name_FLOATING_DECIMALconstant( *$1 ) ), build_tuple( $3 ) ) ); }
    592589        | field_name '.' field
    593590                { $$ = new ExpressionNode( build_fieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
    594         | field_name '.' '[' push field_list pop ']'
    595                 { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $5 ) ) ); }
     591        | field_name '.' '[' field_list ']'
     592                { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
    596593        | field_name ARROW field
    597594                { $$ = new ExpressionNode( build_pfieldSel( $1, maybeMoveBuild<Expression>( $3 ) ) ); }
    598         | field_name ARROW '[' push field_list pop ']'
    599                 { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $5 ) ) ); }
     595        | field_name ARROW '[' field_list ']'
     596                { $$ = new ExpressionNode( build_pfieldSel( $1, build_tuple( $4 ) ) ); }
    600597        ;
    601598
     
    807804        | unary_expression assignment_operator assignment_expression
    808805                { $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) ); }
    809         | unary_expression '=' '{' initializer_list comma_opt '}'
     806        | unary_expression '=' '{' initializer_list_opt comma_opt '}'
    810807                { SemanticError( yylloc, "Initializer assignment is currently unimplemented." ); $$ = nullptr; }
    811808        ;
     
    869866        labeled_statement
    870867        | compound_statement
    871         | expression_statement                                          { $$ = $1; }
     868        | expression_statement
    872869        | selection_statement
    873870        | iteration_statement
     
    10741071        | RETURN comma_expression_opt ';'
    10751072                { $$ = new StatementNode( build_return( $2 ) ); }
    1076         | RETURN '{' initializer_list comma_opt '}'
     1073        | RETURN '{' initializer_list_opt comma_opt '}'
    10771074                { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
    10781075        | THROW assignment_expression_opt ';'                           // handles rethrow
     
    11681165
    11691166handler_predicate_opt:
    1170         //empty
     1167        // empty
    11711168                { $$ = nullptr; }
    11721169        | ';' conditional_expression                            { $$ = $2; }
     
    11861183        type_specifier_nobody
    11871184        | type_specifier_nobody declarator
    1188                 {
    1189                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1190                         $$ = $2->addType( $1 );
    1191                 }
     1185                { $$ = $2->addType( $1 ); }
    11921186        | type_specifier_nobody variable_abstract_declarator
    11931187                { $$ = $2->addType( $1 ); }
    11941188        | cfa_abstract_declarator_tuple no_attr_identifier      // CFA
    1195                 {
    1196                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1197                         $$ = $1->addName( $2 );
    1198                 }
     1189                { $$ = $1->addName( $2 ); }
    11991190        | cfa_abstract_declarator_tuple                                         // CFA
    12001191        ;
     
    12741265
    12751266declaration_list_opt:                                                                   // used at beginning of switch statement
    1276         pop
     1267        pop     // empty
    12771268                { $$ = nullptr; }
    12781269        | declaration_list
     
    13091300
    13101301local_label_list:                                                                               // GCC, local label
    1311         no_attr_identifier_or_type_name                         {}
    1312         | local_label_list ',' no_attr_identifier_or_type_name {}
     1302        no_attr_identifier_or_type_name
     1303        | local_label_list ',' no_attr_identifier_or_type_name
    13131304        ;
    13141305
     
    13441335cfa_variable_declaration:                                                               // CFA
    13451336        cfa_variable_specifier initializer_opt
    1346                 {
    1347                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1348                         $$ = $1->addInitializer( $2 );
    1349                 }
     1337                { $$ = $1->addInitializer( $2 ); }
    13501338        | declaration_qualifier_list cfa_variable_specifier initializer_opt
    13511339                // declaration_qualifier_list also includes type_qualifier_list, so a semantic check is necessary to preclude
    13521340                // them as a type_qualifier cannot appear in that context.
    1353                 {
    1354                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1355                         $$ = $2->addQualifiers( $1 )->addInitializer( $3 );;
    1356                 }
     1341                { $$ = $2->addQualifiers( $1 )->addInitializer( $3 ); }
    13571342        | cfa_variable_declaration pop ',' push identifier_or_type_name initializer_opt
    1358                 {
    1359                         typedefTable.addToEnclosingScope( *$5, TypedefTable::ID );
    1360                         $$ = $1->appendList( $1->cloneType( $5 )->addInitializer( $6 ) );
    1361                 }
     1343                { $$ = $1->appendList( $1->cloneType( $5 )->addInitializer( $6 ) ); }
    13621344        ;
    13631345
     
    13661348                // storage-class
    13671349        cfa_abstract_declarator_no_tuple identifier_or_type_name asm_name_opt
    1368                 {
    1369                         typedefTable.setNextIdentifier( *$2 );
    1370                         $$ = $1->addName( $2 )->addAsmName( $3 );
    1371                 }
     1350                { $$ = $1->addName( $2 )->addAsmName( $3 ); }
    13721351        | cfa_abstract_tuple identifier_or_type_name asm_name_opt
    1373                 {
    1374                         typedefTable.setNextIdentifier( *$2 );
    1375                         $$ = $1->addName( $2 )->addAsmName( $3 );
    1376                 }
     1352                { $$ = $1->addName( $2 )->addAsmName( $3 ); }
    13771353        | type_qualifier_list cfa_abstract_tuple identifier_or_type_name asm_name_opt
    1378                 {
    1379                         typedefTable.setNextIdentifier( *$3 );
    1380                         $$ = $2->addQualifiers( $1 )->addName( $3 )->addAsmName( $4 );
    1381                 }
     1354                { $$ = $2->addQualifiers( $1 )->addName( $3 )->addAsmName( $4 ); }
    13821355        ;
    13831356
    13841357cfa_function_declaration:                                                               // CFA
    13851358        cfa_function_specifier
    1386                 {
    1387                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1388                         $$ = $1;
    1389                 }
     1359                { $$ = $1; }
    13901360        | type_qualifier_list cfa_function_specifier
    1391                 {
    1392                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1393                         $$ = $2->addQualifiers( $1 );
    1394                 }
     1361                { $$ = $2->addQualifiers( $1 ); }
    13951362        | declaration_qualifier_list cfa_function_specifier
    1396                 {
    1397                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1398                         $$ = $2->addQualifiers( $1 );
    1399                 }
     1363                { $$ = $2->addQualifiers( $1 ); }
    14001364        | declaration_qualifier_list type_qualifier_list cfa_function_specifier
    1401                 {
    1402                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1403                         $$ = $3->addQualifiers( $1 )->addQualifiers( $2 );
    1404                 }
    1405         | cfa_function_declaration pop ',' push identifier_or_type_name '(' push cfa_parameter_type_list_opt pop ')'
     1365                { $$ = $3->addQualifiers( $1 )->addQualifiers( $2 ); }
     1366        | cfa_function_declaration ',' identifier_or_type_name '(' cfa_parameter_type_list_opt ')'
    14061367                {
    14071368                        // Append the return type at the start (left-hand-side) to each identifier in the list.
    14081369                        DeclarationNode * ret = new DeclarationNode;
    14091370                        ret->type = maybeClone( $1->type->base );
    1410                         $$ = $1->appendList( DeclarationNode::newFunction( $5, ret, $8, nullptr ) );
     1371                        $$ = $1->appendList( DeclarationNode::newFunction( $3, ret, $5, nullptr ) );
    14111372                }
    14121373        ;
     
    14371398        cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_type_list_opt pop ')'
    14381399                // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
    1439                 {
    1440                         $$ = DeclarationNode::newFunction( $2, $1, $5, 0 );
    1441                 }
     1400                { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
    14421401        | cfa_function_return identifier_or_type_name '(' push cfa_parameter_type_list_opt pop ')'
    1443                 {
    1444                         $$ = DeclarationNode::newFunction( $2, $1, $5, 0 );
    1445                 }
     1402                { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
    14461403        ;
    14471404
     
    14501407                { $$ = DeclarationNode::newTuple( $3 ); }
    14511408        | '[' push cfa_parameter_list pop ',' push cfa_abstract_parameter_list pop ']'
    1452                 // To obtain LR(1 ), the last cfa_abstract_parameter_list is added into this flattened rule to lookahead to the
    1453                 // ']'.
     1409                // To obtain LR(1 ), the last cfa_abstract_parameter_list is added into this flattened rule to lookahead to the ']'.
    14541410                { $$ = DeclarationNode::newTuple( $3->appendList( $7 ) ); }
    14551411        ;
     
    14581414        TYPEDEF cfa_variable_specifier
    14591415                {
    1460                         typedefTable.addToEnclosingScope( TypedefTable::TD );
     1416                        typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname );
    14611417                        $$ = $2->addTypedef();
    14621418                }
    14631419        | TYPEDEF cfa_function_specifier
    14641420                {
    1465                         typedefTable.addToEnclosingScope( TypedefTable::TD );
     1421                        typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname );
    14661422                        $$ = $2->addTypedef();
    14671423                }
    14681424        | cfa_typedef_declaration pop ',' push no_attr_identifier
    14691425                {
    1470                         typedefTable.addToEnclosingScope( *$5, TypedefTable::TD );
     1426                        typedefTable.addToEnclosingScope( *$5, TYPEDEFname );
    14711427                        $$ = $1->appendList( $1->cloneType( $5 ) );
    14721428                }
     
    14791435        TYPEDEF type_specifier declarator
    14801436                {
    1481                         typedefTable.addToEnclosingScope( TypedefTable::TD );
     1437                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname );
    14821438                        $$ = $3->addType( $2 )->addTypedef();
    14831439                }
    14841440        | typedef_declaration pop ',' push declarator
    14851441                {
    1486                         typedefTable.addToEnclosingScope( TypedefTable::TD );
     1442                        typedefTable.addToEnclosingScope( *$5->name, TYPEDEFname );
    14871443                        $$ = $1->appendList( $1->cloneBaseType( $5 )->addTypedef() );
    14881444                }
    14891445        | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 )
    14901446                {
    1491                         typedefTable.addToEnclosingScope( TypedefTable::TD );
     1447                        typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname );
    14921448                        $$ = $4->addType( $3 )->addQualifiers( $1 )->addTypedef();
    14931449                }
    14941450        | type_specifier TYPEDEF declarator
    14951451                {
    1496                         typedefTable.addToEnclosingScope( TypedefTable::TD );
     1452                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname );
    14971453                        $$ = $3->addType( $1 )->addTypedef();
    14981454                }
    14991455        | type_specifier TYPEDEF type_qualifier_list declarator
    15001456                {
    1501                         typedefTable.addToEnclosingScope( TypedefTable::TD );
     1457                        typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname );
    15021458                        $$ = $4->addQualifiers( $1 )->addTypedef()->addType( $1 );
    15031459                }
     
    15081464        TYPEDEF no_attr_identifier '=' assignment_expression
    15091465                {
    1510                         typedefTable.addToEnclosingScope( *$2, TypedefTable::TD );
    1511                         $$ = DeclarationNode::newName( 0 );                     // unimplemented
     1466                        // $$ = DeclarationNode::newName( 0 );                  // unimplemented
     1467                        SemanticError( yylloc, "Typedef expression is currently unimplemented." ); $$ = nullptr;
    15121468                }
    15131469        | typedef_expression pop ',' push no_attr_identifier '=' assignment_expression
    15141470                {
    1515                         typedefTable.addToEnclosingScope( *$5, TypedefTable::TD );
    1516                         $$ = DeclarationNode::newName( 0 );                     // unimplemented
     1471                        // $$ = DeclarationNode::newName( 0 );                  // unimplemented
     1472                        SemanticError( yylloc, "Typedef expression is currently unimplemented." ); $$ = nullptr;
    15171473                }
    15181474        ;
     
    15301486//       declarator asm_name_opt initializer_opt
    15311487//              {
    1532 //                      typedefTable.addToEnclosingScope( TypedefTable::ID );
     1488//                      typedefTable.addToEnclosingScope( IDENTIFIER );
    15331489//                      $$ = ( $2->addType( $1 ))->addAsmName( $3 )->addInitializer( $4 );
    15341490//              }
    15351491//      | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
    15361492//              {
    1537 //                      typedefTable.addToEnclosingScope( TypedefTable::ID );
     1493//                      typedefTable.addToEnclosingScope( IDENTIFIER );
    15381494//                      $$ = $1->appendList( $1->cloneBaseType( $4->addAsmName( $5 )->addInitializer( $6 ) ) );
    15391495//              }
     
    15421498c_declaration:
    15431499        declaration_specifier declaring_list
    1544                 {
    1545                         $$ = distAttr( $1, $2 );
    1546                 }
     1500                { $$ = distAttr( $1, $2 ); }
    15471501        | typedef_declaration
    15481502        | typedef_expression                                                            // GCC, naming expression type
     
    15541508                // storage-class
    15551509        declarator asm_name_opt initializer_opt
    1556                 {
    1557                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1558                         $$ = $1->addAsmName( $2 )->addInitializer( $3 );
    1559                 }
     1510                { $$ = $1->addAsmName( $2 )->addInitializer( $3 ); }
    15601511        | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
    1561                 {
    1562                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    1563                         $$ = $1->appendList( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) );
    1564                 }
     1512                { $$ = $1->appendList( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
    15651513        ;
    15661514
     
    16341582
    16351583forall:
    1636         FORALL '('
    1637                 {
    1638                         typedefTable.enterScope();
    1639                 }
    1640           type_parameter_list ')'                                                       // CFA
    1641                 {
    1642                         typedefTable.leaveScope();
    1643                         $$ = DeclarationNode::newForall( $4 );
    1644                 }
     1584        FORALL '(' push type_parameter_list pop ')'                                     // CFA
     1585                { $$ = DeclarationNode::newForall( $4 ); }
    16451586        ;
    16461587
     
    18541795
    18551796aggregate_type:                                                                                 // struct, union
    1856         aggregate_key attribute_list_opt '{' field_declaration_list '}'
     1797        aggregate_key attribute_list_opt '{' field_declaration_list_opt '}'
    18571798                { $$ = DeclarationNode::newAggregate( $1, new string( DeclarationNode::anonymous.newName() ), nullptr, $4, true )->addQualifiers( $2 ); }
    18581799        | aggregate_key attribute_list_opt no_attr_identifier_or_type_name
    18591800                {
    18601801                        typedefTable.makeTypedef( *$3 );                        // create typedef
    1861                         if ( forall ) typedefTable.changeKind( *$3, TypedefTable::TG ); // possibly update
     1802                        if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update
    18621803                        forall = false;                                                         // reset
    18631804                }
    1864           '{' field_declaration_list '}'
     1805          '{' field_declaration_list_opt '}'
    18651806                { $$ = DeclarationNode::newAggregate( $1, $3, nullptr, $6, true )->addQualifiers( $2 ); }
    1866         | aggregate_key attribute_list_opt '(' type_list ')' '{' field_declaration_list '}' // CFA
     1807        | aggregate_key attribute_list_opt '(' type_list ')' '{' field_declaration_list_opt '}' // CFA
    18671808                { $$ = DeclarationNode::newAggregate( $1, new string( DeclarationNode::anonymous.newName() ), $4, $7, false )->addQualifiers( $2 ); }
    18681809        | aggregate_type_nobody
     
    18731814                {
    18741815                        typedefTable.makeTypedef( *$3 );
    1875                         if ( forall ) typedefTable.changeKind( *$3, TypedefTable::TG ); // possibly update
     1816                        if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update
    18761817                        forall = false;                                                         // reset
    18771818                        $$ = DeclarationNode::newAggregate( $1, $3, nullptr, nullptr, false )->addQualifiers( $2 );
     
    19091850        ;
    19101851
    1911 field_declaration_list:
     1852field_declaration_list_opt:
    19121853        // empty
    19131854                { $$ = nullptr; }
    1914         | field_declaration_list field_declaration
     1855        | field_declaration_list_opt field_declaration
    19151856                { $$ = $1 ? $1->appendList( $2 ) : $2; }
    19161857        ;
     
    19451886
    19461887field_declaring_list:
    1947         field_declarator
    1948         | field_declaring_list ',' attribute_list_opt field_declarator
     1888        field_declarator_opt
     1889        | field_declaring_list ',' attribute_list_opt field_declarator_opt
    19491890                { $$ = $1->appendList( $4->addQualifiers( $3 ) ); }
    19501891        ;
    19511892
    1952 field_declarator:
     1893field_declarator_opt:
    19531894        // empty
    19541895                { $$ = DeclarationNode::newName( 0 ); /* XXX */ } // CFA, no field name
     
    20902031                // No SUE declaration in parameter list.
    20912032        declaration_specifier_nobody identifier_parameter_declarator default_initialize_opt
    2092                 {
    2093                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2094                         $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr );
    2095                 }
     2033                { $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
    20962034        | declaration_specifier_nobody type_parameter_redeclarator default_initialize_opt
    2097                 {
    2098                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2099                         $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr );
    2100                 }
     2035                { $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
    21012036        ;
    21022037
     
    21562091initializer:
    21572092        assignment_expression                                           { $$ = new InitializerNode( $1 ); }
    2158         | '{' initializer_list comma_opt '}'            { $$ = new InitializerNode( $2, true ); }
    2159         ;
    2160 
    2161 initializer_list:
     2093        | '{' initializer_list_opt comma_opt '}'        { $$ = new InitializerNode( $2, true ); }
     2094        ;
     2095
     2096initializer_list_opt:
    21622097        // empty
    21632098                { $$ = nullptr; }
    21642099        | initializer
    21652100        | designation initializer                                       { $$ = $2->set_designators( $1 ); }
    2166         | initializer_list ',' initializer                      { $$ = (InitializerNode *)( $1->set_last( $3 ) ); }
    2167         | initializer_list ',' designation initializer
     2101        | initializer_list_opt ',' initializer          { $$ = (InitializerNode *)( $1->set_last( $3 ) ); }
     2102        | initializer_list_opt ',' designation initializer
    21682103                { $$ = (InitializerNode *)( $1->set_last( $4->set_designators( $3 ) ) ); }
    21692104        ;
     
    22402175type_parameter:                                                                                 // CFA
    22412176        type_class no_attr_identifier_or_type_name
    2242                 { typedefTable.addToEnclosingScope( *$2, TypedefTable::TD ); }
     2177                { typedefTable.addToEnclosingScope( *$2, TYPEDEFname ); }
    22432178          type_initializer_opt assertion_list_opt
    22442179                { $$ = DeclarationNode::newTypeParam( $1, $2 )->addTypeInitializer( $4 )->addAssertions( $5 ); }
     
    22732208assertion:                                                                                              // CFA
    22742209        '|' no_attr_identifier_or_type_name '(' type_list ')'
    2275                 {
    2276                         typedefTable.openTrait( *$2 );
    2277                         $$ = DeclarationNode::newTraitUse( $2, $4 );
    2278                 }
     2210                { $$ = DeclarationNode::newTraitUse( $2, $4 ); }
    22792211        | '|' '{' push trait_declaration_list '}'
    22802212                { $$ = $4; }
    22812213        | '|' '(' push type_parameter_list pop ')' '{' push trait_declaration_list '}' '(' type_list ')'
    2282                 { $$ = nullptr; }
     2214                { SemanticError( yylloc, "Generic data-type assertion is currently unimplemented." ); $$ = nullptr; }
    22832215        ;
    22842216
     
    23122244        no_attr_identifier_or_type_name
    23132245                {
    2314                         typedefTable.addToEnclosingScope( *$1, TypedefTable::TD );
     2246                        typedefTable.addToEnclosingScope( *$1, TYPEDEFname );
    23152247                        $$ = DeclarationNode::newTypeDecl( $1, 0 );
    23162248                }
    23172249        | no_attr_identifier_or_type_name '(' push type_parameter_list pop ')'
    23182250                {
    2319                         typedefTable.addToEnclosingScope( *$1, TypedefTable::TG );
     2251                        typedefTable.addToEnclosingScope( *$1, TYPEGENname );
    23202252                        $$ = DeclarationNode::newTypeDecl( $1, $4 );
    23212253                }
     
    23242256trait_specifier:                                                                                // CFA
    23252257        TRAIT no_attr_identifier_or_type_name '(' push type_parameter_list pop ')' '{' '}'
    2326                 {
    2327                         typedefTable.addToEnclosingScope( *$2, TypedefTable::ID );
    2328                         $$ = DeclarationNode::newTrait( $2, $5, 0 );
    2329                 }
    2330         | TRAIT no_attr_identifier_or_type_name '(' push type_parameter_list pop ')' '{'
    2331                 {
    2332                         typedefTable.enterTrait( *$2 );
    2333                         typedefTable.enterScope();
    2334                 }
    2335           trait_declaration_list '}'
    2336                 {
    2337                         typedefTable.leaveTrait();
    2338                         typedefTable.addToEnclosingScope( *$2, TypedefTable::ID );
    2339                         $$ = DeclarationNode::newTrait( $2, $5, $10 );
    2340                 }
     2258                { $$ = DeclarationNode::newTrait( $2, $5, 0 ); }
     2259        | TRAIT no_attr_identifier_or_type_name '(' push type_parameter_list pop ')' '{' push trait_declaration_list '}'
     2260                { $$ = DeclarationNode::newTrait( $2, $5, $10 ); }
    23412261        ;
    23422262
     
    23542274cfa_trait_declaring_list:                                                               // CFA
    23552275        cfa_variable_specifier
    2356                 {
    2357                         typedefTable.addToEnclosingScope2( TypedefTable::ID );
    2358                         $$ = $1;
    2359                 }
    23602276        | cfa_function_specifier
    2361                 {
    2362                         typedefTable.addToEnclosingScope2( TypedefTable::ID );
    2363                         $$ = $1;
    2364                 }
    23652277        | cfa_trait_declaring_list pop ',' push identifier_or_type_name
    2366                 {
    2367                         typedefTable.addToEnclosingScope2( *$5, TypedefTable::ID );
    2368                         $$ = $1->appendList( $1->cloneType( $5 ) );
    2369                 }
     2278                { $$ = $1->appendList( $1->cloneType( $5 ) ); }
    23702279        ;
    23712280
    23722281trait_declaring_list:                                                                   // CFA
    23732282        type_specifier declarator
    2374                 {
    2375                         typedefTable.addToEnclosingScope2( TypedefTable::ID );
    2376                         $$ = $2->addType( $1 );
    2377                 }
     2283                { $$ = $2->addType( $1 ); }
    23782284        | trait_declaring_list pop ',' push declarator
    2379                 {
    2380                         typedefTable.addToEnclosingScope2( TypedefTable::ID );
    2381                         $$ = $1->appendList( $1->cloneBaseType( $5 ) );
    2382                 }
     2285                { $$ = $1->appendList( $1->cloneBaseType( $5 ) ); }
    23832286        ;
    23842287
     
    24302333                }
    24312334        | type_qualifier_list
    2432                 {
    2433                         if ( $1->type->forall ) xxx = forall = true; // remember generic type
    2434                 }
     2335                { if ( $1->type->forall ) xxx = forall = true; } // remember generic type
    24352336          push '{' external_definition_list '}'                         // CFA, namespace
    24362337                {
     
    24452346                }
    24462347        | declaration_qualifier_list
    2447                 {
    2448                         if ( $1->type->forall ) xxx = forall = true; // remember generic type
    2449                 }
     2348                { if ( $1->type->forall ) xxx = forall = true; } // remember generic type
    24502349          push '{' external_definition_list '}'                         // CFA, namespace
    24512350                {
     
    24872386                // declaration must still have a type_specifier.  OBSOLESCENT (see 1)
    24882387        | function_declarator compound_statement
    2489                 {
    2490                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2491                         typedefTable.leaveScope();
    2492                         $$ = $1->addFunctionBody( $2 );
    2493                 }
     2388                { $$ = $1->addFunctionBody( $2 ); }
    24942389        | KR_function_declarator KR_declaration_list_opt compound_statement
    2495                 {
    2496                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2497                         typedefTable.leaveScope();
    2498                         $$ = $1->addOldDeclList( $2 )->addFunctionBody( $3 );
    2499                 }
     2390                { $$ = $1->addOldDeclList( $2 )->addFunctionBody( $3 ); }
    25002391        ;
    25012392
     
    25102401        cfa_function_declaration with_clause_opt compound_statement     // CFA
    25112402                {
    2512                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2513                         typedefTable.leaveScope();
    25142403                        // Add the function body to the last identifier in the function definition list, i.e., foo3:
    25152404                        //   [const double] foo1(), foo2( int ), foo3( double ) { return 3.0; }
     
    25202409                {
    25212410                        rebindForall( $1, $2 );
    2522                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2523                         typedefTable.leaveScope();
     2411                        $$ = $2->addFunctionBody( $4, $3 )->addType( $1 );
     2412                }
     2413        | declaration_specifier variable_type_redeclarator with_clause_opt compound_statement
     2414                {
     2415                        rebindForall( $1, $2 );
    25242416                        $$ = $2->addFunctionBody( $4, $3 )->addType( $1 );
    25252417                }
    25262418                // handles default int return type, OBSOLESCENT (see 1)
    25272419        | type_qualifier_list function_declarator with_clause_opt compound_statement
    2528                 {
    2529                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2530                         typedefTable.leaveScope();
    2531                         $$ = $2->addFunctionBody( $4, $3 )->addQualifiers( $1 );
    2532                 }
     2420                { $$ = $2->addFunctionBody( $4, $3 )->addQualifiers( $1 ); }
    25332421                // handles default int return type, OBSOLESCENT (see 1)
    25342422        | declaration_qualifier_list function_declarator with_clause_opt compound_statement
    2535                 {
    2536                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2537                         typedefTable.leaveScope();
    2538                         $$ = $2->addFunctionBody( $4, $3 )->addQualifiers( $1 );
    2539                 }
     2423                { $$ = $2->addFunctionBody( $4, $3 )->addQualifiers( $1 ); }
    25402424                // handles default int return type, OBSOLESCENT (see 1)
    25412425        | declaration_qualifier_list type_qualifier_list function_declarator with_clause_opt compound_statement
    2542                 {
    2543                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2544                         typedefTable.leaveScope();
    2545                         $$ = $3->addFunctionBody( $5, $4 )->addQualifiers( $2 )->addQualifiers( $1 );
    2546                 }
     2426                { $$ = $3->addFunctionBody( $5, $4 )->addQualifiers( $2 )->addQualifiers( $1 ); }
    25472427
    25482428                // Old-style K&R function definition, OBSOLESCENT (see 4)
     
    25502430                {
    25512431                        rebindForall( $1, $2 );
    2552                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2553                         typedefTable.leaveScope();
    25542432                        $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addType( $1 );
    25552433                }
    25562434                // handles default int return type, OBSOLESCENT (see 1)
    25572435        | type_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement
    2558                 {
    2559                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2560                         typedefTable.leaveScope();
    2561                         $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 );
    2562                 }
     2436                { $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 ); }
    25632437                // handles default int return type, OBSOLESCENT (see 1)
    25642438        | declaration_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement
    2565                 {
    2566                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2567                         typedefTable.leaveScope();
    2568                         $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 );
    2569                 }
     2439                { $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 ); }
    25702440                // handles default int return type, OBSOLESCENT (see 1)
    25712441        | declaration_qualifier_list type_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement
    2572                 {
    2573                         typedefTable.addToEnclosingScope( TypedefTable::ID );
    2574                         typedefTable.leaveScope();
    2575                         $$ = $3->addOldDeclList( $4 )->addFunctionBody( $6, $5 )->addQualifiers( $2 )->addQualifiers( $1 );
    2576                 }
     2442                { $$ = $3->addOldDeclList( $4 )->addFunctionBody( $6, $5 )->addQualifiers( $2 )->addQualifiers( $1 ); }
    25772443        ;
    25782444
     
    26842550paren_identifier:
    26852551        identifier
    2686                 {
    2687                         typedefTable.setNextIdentifier( *$1 );
    2688                         $$ = DeclarationNode::newName( $1 );
    2689                 }
     2552                { $$ = DeclarationNode::newName( $1 ); }
    26902553        | '(' paren_identifier ')'                                                      // redundant parenthesis
    26912554                { $$ = $2; }
     
    28202683paren_type:
    28212684        typedef
     2685                // hide type name in enclosing scope by variable name
     2686                { typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER ); }
    28222687        | '(' paren_type ')'
    28232688                { $$ = $2; }
     
    29222787typedef:
    29232788        TYPEDEFname
    2924                 {
    2925                         typedefTable.setNextIdentifier( *$1 );
    2926                         $$ = DeclarationNode::newName( $1 );
    2927                 }
     2789                { $$ = DeclarationNode::newName( $1 ); }
    29282790        | TYPEGENname
    2929                 {
    2930                         typedefTable.setNextIdentifier( *$1 );
    2931                         $$ = DeclarationNode::newName( $1 );
    2932                 }
     2791                { $$ = DeclarationNode::newName( $1 ); }
    29332792        ;
    29342793
  • src/ResolvExpr/AlternativeFinder.cc

    r3ef35bd reba74ba  
    689689                        const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
    690690                        const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
    691                 if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) {
     691                if ( TupleType * tupleType = dynamic_cast<TupleType*>( formalType ) ) {
    692692                        // formalType is a TupleType - group actuals into a TupleExpr
    693693                        ++nTuples;
    694694                        for ( Type* type : *tupleType ) {
    695695                                // xxx - dropping initializer changes behaviour from previous, but seems correct
     696                                // ^^^ need to handle the case where a tuple has a default argument
    696697                                if ( ! instantiateArgument(
    697698                                                type, nullptr, args, results, genStart, indexer, nTuples ) )
     
    704705                        }
    705706                        return true;
    706                 } else if ( TypeInstType* ttype = Tuples::isTtype( formalType ) ) {
     707                } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
    707708                        // formalType is a ttype, consumes all remaining arguments
    708709                        // xxx - mixing default arguments with variadic??
     
    907908                                // consider only first exploded actual
    908909                                Expression* expr = expl.exprs.front();
    909                                 Type* actualType = expr->get_result()->clone();
     910                                Type* actualType = expr->result->clone();
    910911
    911912                                PRINT(
     
    938939                ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
    939940                // sum cost and accumulate actuals
    940                 std::list<Expression*>& args = appExpr->get_args();
     941                std::list<Expression*>& args = appExpr->args;
    941942                Cost cost = func.cost;
    942943                const ArgPack* pack = &result;
     
    965966                // add all type variables as open variables now so that those not used in the parameter
    966967                // list are still considered open.
    967                 funcEnv.add( funcType->get_forall() );
    968 
    969                 if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) {
     968                funcEnv.add( funcType->forall );
     969
     970                if ( targetType && ! targetType->isVoid() && ! funcType->returnVals.empty() ) {
    970971                        // attempt to narrow based on expected target type
    971                         Type * returnType = funcType->get_returnVals().front()->get_type();
     972                        Type * returnType = funcType->returnVals.front()->get_type();
    972973                        if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
    973974                                        indexer ) ) {
     
    982983                std::size_t genStart = 0;
    983984
    984                 for ( DeclarationWithType* formal : funcType->get_parameters() ) {
     985                for ( DeclarationWithType* formal : funcType->parameters ) {
    985986                        ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
    986987                        if ( ! instantiateArgument(
    987                                         obj->get_type(), obj->get_init(), args, results, genStart, indexer ) )
     988                                        obj->type, obj->init, args, results, genStart, indexer ) )
    988989                                return;
    989990                }
     
    10661067        void AlternativeFinder::Finder::postvisit( UntypedExpr *untypedExpr ) {
    10671068                AlternativeFinder funcFinder( indexer, env );
    1068                 funcFinder.findWithAdjustment( untypedExpr->get_function() );
     1069                funcFinder.findWithAdjustment( untypedExpr->function );
    10691070                // if there are no function alternatives, then proceeding is a waste of time.
    10701071                if ( funcFinder.alternatives.empty() ) return;
     
    12751276                AlternativeFinder finder( indexer, env );
    12761277                finder.targetType = toType;
    1277                 finder.findWithAdjustment( castExpr->get_arg() );
     1278                finder.findWithAdjustment( castExpr->arg );
    12781279
    12791280                AltList candidates;
     
    12821283                        OpenVarSet openVars;
    12831284
     1285                        alt.env.extractOpenVars( openVars );
     1286
    12841287                        // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
    12851288                        // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
    12861289                        // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
    12871290                        // to.
    1288                         int discardedValues = alt.expr->get_result()->size() - castExpr->get_result()->size();
     1291                        int discardedValues = alt.expr->result->size() - castExpr->result->size();
    12891292                        if ( discardedValues < 0 ) continue;
    12901293                        // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
    12911294                        // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
    12921295                        // unification run for side-effects
    1293                         unify( castExpr->get_result(), alt.expr->get_result(), alt.env, needAssertions,
     1296                        unify( castExpr->result, alt.expr->result, alt.env, needAssertions,
    12941297                                haveAssertions, openVars, indexer );
    1295                         Cost thisCost = castCost( alt.expr->get_result(), castExpr->get_result(), indexer,
     1298                        Cost thisCost = castCost( alt.expr->result, castExpr->result, indexer,
    12961299                                alt.env );
    12971300                        PRINT(
     
    17061709                        AlternativeFinder finder( indexer, env );
    17071710                        finder.targetType = toType;
    1708                         finder.findWithAdjustment( initExpr->get_expr() );
     1711                        finder.findWithAdjustment( initExpr->expr );
    17091712                        for ( Alternative & alt : finder.get_alternatives() ) {
    17101713                                TypeEnvironment newEnv( alt.env );
     
    17131716                                PRINT(
    17141717                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
    1715                                  )
     1718                                )
    17161719                                // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
    17171720                                // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
    17181721                                // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
    17191722                                // to.
    1720                                 int discardedValues = alt.expr->get_result()->size() - toType->size();
     1723                                int discardedValues = alt.expr->result->size() - toType->size();
    17211724                                if ( discardedValues < 0 ) continue;
    17221725                                // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
    17231726                                // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
    17241727                                // unification run for side-effects
    1725                                 unify( toType, alt.expr->get_result(), newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
    1726 
    1727                                 Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv );
     1728                                unify( toType, alt.expr->result, newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
     1729
     1730                                Cost thisCost = castCost( alt.expr->result, toType, indexer, newEnv );
    17281731                                if ( thisCost != Cost::infinity ) {
    17291732                                        // count one safe conversion for each value that is thrown away
  • src/ResolvExpr/Resolver.cc

    r3ef35bd reba74ba  
    128128
    129129        namespace {
    130                 void finishExpr( Expression *expr, const TypeEnvironment &env, TypeSubstitution * oldenv = nullptr ) {
     130                struct StripCasts {
     131                        Expression * postmutate( CastExpr * castExpr ) {
     132                                if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {
     133                                        // generated cast is to the same type as its argument, so it's unnecessary -- remove it
     134                                        Expression * expr = castExpr->arg;
     135                                        castExpr->arg = nullptr;
     136                                        std::swap( expr->env, castExpr->env );
     137                                        return expr;
     138                                }
     139                                return castExpr;
     140                        }
     141
     142                        static void strip( Expression *& expr ) {
     143                                PassVisitor<StripCasts> stripper;
     144                                expr = expr->acceptMutator( stripper );
     145                        }
     146                };
     147
     148                void finishExpr( Expression *&expr, const TypeEnvironment &env, TypeSubstitution * oldenv = nullptr ) {
    131149                        expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;
    132                         env.makeSubstitution( *expr->get_env() );
     150                        env.makeSubstitution( *expr->env );
     151                        StripCasts::strip( expr ); // remove unnecessary casts that may be buried in an expression
    133152                }
    134153
     
    178197                        findMinCost( candidates.begin(), candidates.end(), back_inserter( winners ) );
    179198                        if ( winners.size() == 0 ) {
    180                                 SemanticError( untyped, toString(
    181                                         "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""),
    182                                         "expression: ") );
     199                                SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );
    183200                        } else if ( winners.size() != 1 ) {
    184201                                std::ostringstream stream;
    185                                 stream << "Cannot choose between " << winners.size() << " alternatives for "
    186                                         << kindStr << (kindStr != "" ? " " : "") << "expression\n";
     202                                stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";
    187203                                untyped->print( stream );
    188204                                stream << " Alternatives are:\n";
    189205                                printAlts( winners, stream, 1 );
    190                                
    191206                                SemanticError( untyped->location, stream.str() );
    192207                        }
     
    196211                        if ( findDeletedExpr( choice.expr ) ) {
    197212                                trace( choice.expr );
    198                                 SemanticError( choice.expr,
    199                                         "Unique best alternative includes deleted identifier in " );
     213                                SemanticError( choice.expr, "Unique best alternative includes deleted identifier in " );
    200214                        }
    201215                        alt = std::move( choice );
     
    416430
    417431        void Resolver::previsit( CaseStmt *caseStmt ) {
    418                 if ( caseStmt->get_condition() ) {
     432                if ( caseStmt->condition ) {
    419433                        std::list< InitAlternative > initAlts = currentObject.getOptions();
    420434                        assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." );
     
    422436                        Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() );
    423437                        findSingleExpression( newExpr, indexer );
    424                         CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( newExpr );
    425                         caseStmt->condition = castExpr->arg;
    426                         castExpr->arg = nullptr;
     438                        // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion.
     439                        // Ideally we would perform the conversion internally here.
     440                        if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) {
     441                                newExpr = castExpr->arg;
     442                                castExpr->arg = nullptr;
     443                                std::swap( newExpr->env, castExpr->env );
     444                        }
     445                        caseStmt->condition = newExpr;
    427446                }
    428447        }
     
    719738                initExpr->expr = nullptr;
    720739                std::swap( initExpr->env, newExpr->env );
    721                 std::swap( initExpr->inferParams, newExpr->inferParams ) ;
     740                // InitExpr may have inferParams in the case where the expression specializes a function pointer,
     741                // and newExpr may already have inferParams of its own, so a simple swap is not sufficient.
     742                newExpr->spliceInferParams( initExpr );
    722743
    723744                // get the actual object's type (may not exactly match what comes back from the resolver due to conversions)
  • src/ResolvExpr/TypeEnvironment.h

    r3ef35bd reba74ba  
    4141        //
    4242        // I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this comparator.
     43        //
     44        // Note: since this compares pointers for position, minor changes in the source file that affect
     45        // memory layout can alter compilation time in unpredictable ways. For example, the placement
     46        // of a line directive can reorder type pointers with respect to each other so that assertions
     47        // are seen in different orders, causing a potentially different number of unification calls when
     48        // resolving assertions. I've seen a TU go from 36 seconds to 27 seconds by reordering line directives
     49        // alone, so it would be nice to fix this comparison so that assertions compare more consistently.
     50        // I've tried to modify this to compare on mangle name instead of type as the second comparator, but
     51        // this causes some assertions to never be recorded. More investigation is needed.
    4352        struct AssertCompare {
    4453                bool operator()( DeclarationWithType * d1, DeclarationWithType * d2 ) const {
  • src/ResolvExpr/Unify.cc

    r3ef35bd reba74ba  
    306306                } else if ( isopen1 ) {
    307307                        result = bindVar( var1, type2, entry1->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
    308                 } else if ( isopen2 ) {
     308                } else if ( isopen2 ) { // TODO: swap widenMode values in call, since type positions are flipped?
    309309                        result = bindVar( var2, type1, entry2->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
    310310                } else {
  • src/SymTab/Indexer.cc

    r3ef35bd reba74ba  
    2626#include "Common/SemanticError.h"  // for SemanticError
    2727#include "Common/utility.h"        // for cloneAll
     28#include "GenPoly/GenPoly.h"
    2829#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    2930#include "Mangler.h"               // for Mangler
     
    377378        }
    378379
     380        bool isFunction( DeclarationWithType * decl ) {
     381                return GenPoly::getFunctionType( decl->get_type() );
     382        }
     383
     384        bool isObject( DeclarationWithType * decl ) {
     385                return ! isFunction( decl );
     386        }
     387
     388        bool isDefinition( DeclarationWithType * decl ) {
     389                if ( FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl ) ) {
     390                        // a function is a definition if it has a body
     391                        return func->statements;
     392                } else {
     393                        // an object is a definition if it is not marked extern.
     394                        // both objects must be marked extern
     395                        return ! decl->get_storageClasses().is_extern;
     396                }
     397        }
     398
    379399        bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) {
    380400                // if we're giving the same name mangling to things of different types then there is something wrong
    381                 assert( (dynamic_cast<ObjectDecl*>( added ) && dynamic_cast<ObjectDecl*>( existing.id ) )
    382                         || (dynamic_cast<FunctionDecl*>( added ) && dynamic_cast<FunctionDecl*>( existing.id ) ) );
     401                assert( (isObject( added ) && isObject( existing.id ) )
     402                        || ( isFunction( added ) && isFunction( existing.id ) ) );
    383403
    384404                if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
     
    394414                        }
    395415
    396                         // typesCompatible doesn't really do the right thing here. When checking compatibility of function types,
    397                         // we should ignore outermost pointer qualifiers, except _Atomic?
    398                         FunctionDecl * newentry = dynamic_cast< FunctionDecl * >( added );
    399                         FunctionDecl * oldentry = dynamic_cast< FunctionDecl * >( existing.id );
    400                         if ( newentry && oldentry ) {
    401                                 if ( newentry->get_statements() && oldentry->get_statements() ) {
     416                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
     417                                if ( isFunction( added ) ) {
    402418                                        return handleConflicts( existing, "duplicate function definition for " );
    403                                 } // if
    404                         } else {
    405                                 // two objects with the same mangled name defined in the same scope.
    406                                 // both objects must be marked extern or both must be intrinsic for this to be okay
    407                                 // xxx - perhaps it's actually if either is intrinsic then this is okay?
    408                                 //       might also need to be same storage class?
    409                                 ObjectDecl * newobj = dynamic_cast< ObjectDecl * >( added );
    410                                 ObjectDecl * oldobj = dynamic_cast< ObjectDecl * >( existing.id );
    411                                 if ( ! newobj->get_storageClasses().is_extern && ! oldobj->get_storageClasses().is_extern ) {
     419                                } else {
    412420                                        return handleConflicts( existing, "duplicate object definition for " );
    413421                                } // if
  • src/SymTab/Mangler.cc

    r3ef35bd reba74ba  
    3535                namespace {
    3636                        /// Mangles names to a unique C identifier
    37                         struct Mangler : public WithShortCircuiting, public WithVisitorRef<Mangler> {
     37                        struct Mangler : public WithShortCircuiting, public WithVisitorRef<Mangler>, public WithGuards {
    3838                                Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
    3939                                Mangler( const Mangler & ) = delete;
     
    5555                                void postvisit( EnumInstType * aggregateUseType );
    5656                                void postvisit( TypeInstType * aggregateUseType );
     57                                void postvisit( TraitInstType * inst );
    5758                                void postvisit( TupleType * tupleType );
    5859                                void postvisit( VarArgsType * varArgsType );
     
    7071                                bool typeMode;                  ///< Produce a unique mangled name for a type
    7172                                bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
     73                                bool inFunctionType = false;    ///< Include type qualifiers if false.
    7274
    7375                                void mangleDecl( DeclarationWithType *declaration );
     
    177179                        void Mangler::postvisit( PointerType * pointerType ) {
    178180                                printQualifiers( pointerType );
    179                                 mangleName << "P";
     181                                // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
     182                                if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName << "P";
    180183                                maybeAccept( pointerType->base, *visitor );
    181184                        }
     
    189192
    190193                        void Mangler::postvisit( ReferenceType * refType ) {
     194                                // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
     195                                // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
     196                                // by pretending every reference type is a function parameter.
     197                                GuardValue( inFunctionType );
     198                                inFunctionType = true;
    191199                                printQualifiers( refType );
    192                                 mangleName << "R";
    193200                                maybeAccept( refType->base, *visitor );
    194201                        }
     
    206213                                printQualifiers( functionType );
    207214                                mangleName << "F";
     215                                // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
     216                                // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
     217                                // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different
     218                                GuardValue( inFunctionType );
     219                                inFunctionType = true;
    208220                                std::list< Type* > returnTypes = getTypes( functionType->get_returnVals() );
    209221                                acceptAll( returnTypes, *visitor );
     
    270282                        }
    271283
     284                        void Mangler::postvisit( TraitInstType * inst ) {
     285                                printQualifiers( inst );
     286                                mangleName << "_Y" << inst->name << "_";
     287                        }
     288
    272289                        void Mangler::postvisit( TupleType * tupleType ) {
    273290                                printQualifiers( tupleType );
     
    304321                                // skip if not including qualifiers
    305322                                if ( typeMode ) return;
    306 
    307323                                if ( ! type->get_forall().empty() ) {
    308324                                        std::list< std::string > assertionNames;
     
    337353                                        mangleName << "_";
    338354                                } // if
    339                                 if ( type->get_const() ) {
    340                                         mangleName << "C";
    341                                 } // if
    342                                 if ( type->get_volatile() ) {
    343                                         mangleName << "V";
    344                                 } // if
     355                                if ( ! inFunctionType ) {
     356                                        // these qualifiers do not distinguish the outermost type of a function parameter
     357                                        if ( type->get_const() ) {
     358                                                mangleName << "C";
     359                                        } // if
     360                                        if ( type->get_volatile() ) {
     361                                                mangleName << "V";
     362                                        } // if
     363                                        // Removed due to restrict not affecting function compatibility in GCC
     364                                        // if ( type->get_isRestrict() ) {
     365                                        //      mangleName << "E";
     366                                        // } // if
     367                                        if ( type->get_atomic() ) {
     368                                                mangleName << "A";
     369                                        } // if
     370                                }
    345371                                if ( type->get_mutex() ) {
    346372                                        mangleName << "M";
    347373                                } // if
    348                                 // Removed due to restrict not affecting function compatibility in GCC
    349                 //              if ( type->get_isRestrict() ) {
    350                 //                      mangleName << "E";
    351                 //              } // if
    352374                                if ( type->get_lvalue() ) {
    353375                                        // mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues
    354376                                        mangleName << "L";
    355377                                }
    356                                 if ( type->get_atomic() ) {
    357                                         mangleName << "A";
    358                                 } // if
     378
     379                                if ( inFunctionType ) {
     380                                        // turn off inFunctionType so that types can be differentiated for nested qualifiers
     381                                        GuardValue( inFunctionType );
     382                                        inFunctionType = false;
     383                                }
    359384                        }
    360385                }       // namespace
  • src/SynTree/ApplicationExpr.cc

    r3ef35bd reba74ba  
    4242}
    4343
     44ParamEntry::ParamEntry( ParamEntry && other ) :
     45                decl( other.decl ), actualType( other.actualType ), formalType( other.formalType ), expr( other.expr ), inferParams( std::move( other.inferParams ) ) {
     46        other.actualType = nullptr;
     47        other.formalType = nullptr;
     48        other.expr = nullptr;
     49}
     50
     51ParamEntry & ParamEntry::operator=( ParamEntry && other ) {
     52        if ( &other == this ) return *this;
     53        decl = other.decl;
     54        actualType = other.actualType;
     55        formalType = other.formalType;
     56        expr = other.expr;
     57        other.actualType = nullptr;
     58        other.formalType = nullptr;
     59        other.expr = nullptr;
     60        inferParams = std::move( other.inferParams );
     61        return *this;
     62}
     63
    4464ApplicationExpr::ApplicationExpr( Expression *funcExpr, const std::list<Expression *> & args ) : function( funcExpr ), args( args ) {
    4565        PointerType *pointer = strict_dynamic_cast< PointerType* >( funcExpr->get_result() );
  • src/SynTree/Expression.cc

    r3ef35bd reba74ba  
    5050}
    5151
     52void Expression::spliceInferParams( Expression * other ) {
     53        if ( ! other ) return;
     54        for ( auto p : other->inferParams ) {
     55                inferParams[p.first] = std::move( p.second );
     56        }
     57}
     58
    5259Expression::~Expression() {
    5360        delete env;
  • src/SynTree/Expression.h

    r3ef35bd reba74ba  
    4141        ParamEntry( UniqueId decl, Type * actualType, Type * formalType, Expression* expr ): decl( decl ), actualType( actualType ), formalType( formalType ), expr( expr ), inferParams( new InferredParams ) {}
    4242        ParamEntry( const ParamEntry & other );
     43        ParamEntry( ParamEntry&& other );
    4344        ParamEntry & operator=( const ParamEntry & other );
     45        ParamEntry & operator=( ParamEntry && other );
    4446
    4547        UniqueId decl;
     
    7476
    7577        InferredParams & get_inferParams() { return inferParams; }
     78
     79        // move other's inferParams to this
     80        void spliceInferParams( Expression * other );
    7681
    7782        virtual Expression * clone() const override = 0;
  • src/Tuples/TupleAssignment.cc

    r3ef35bd reba74ba  
    154154                                                lhsAlt.expr = new CastExpr( lhsAlt.expr,
    155155                                                                new ReferenceType( Type::Qualifiers(),
    156                                                                         lhsAlt.expr->get_result()->clone() ) );
     156                                                                        lhsAlt.expr->result->clone() ) );
    157157                                        }
    158158
     
    231231
    232232                        ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),
    233                                 currentFinder.get_environ() };
     233                                matcher->compositeEnv };
     234
    234235                        try {
    235236                                finder.findWithAdjustment(*i);
     
    298299        ObjectDecl * TupleAssignSpotter::Matcher::newObject( UniqueName & namer, Expression * expr ) {
    299300                assert( expr->result && ! expr->get_result()->isVoid() );
    300                 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->get_result()->clone(), new SingleInit( expr->clone() ) );
     301                ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
    301302                // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.
    302                 if ( ! dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
     303                if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) {
    303304                        ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
    304305                        ret->init = ctorInit;
     
    318319                assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );
    319320
     321                // xxx - may need to split this up into multiple declarations, because potential conversion to references
     322                //  probably should not reference local variable - see MultipleAssignMatcher::match
    320323                ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
    321324                for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
     
    336339                        std::list< ObjectDecl * > ltmp;
    337340                        std::list< ObjectDecl * > rtmp;
    338                         std::transform( lhs.begin(), lhs.end(), back_inserter( ltmp ), [&]( ResolvExpr::Alternative & alt ){
    339                                 return newObject( lhsNamer, alt.expr );
    340                         });
    341                         std::transform( rhs.begin(), rhs.end(), back_inserter( rtmp ), [&]( ResolvExpr::Alternative & alt ){
    342                                 return newObject( rhsNamer, alt.expr );
    343                         });
    344                         zipWith( ltmp.begin(), ltmp.end(), rtmp.begin(), rtmp.end(), back_inserter(out), [&](ObjectDecl * obj1, ObjectDecl * obj2 ) { return createFunc(spotter.fname, obj1, obj2); } );
     341                        for ( auto p : group_iterate( lhs, rhs ) ) {
     342                                ResolvExpr::Alternative & lhsAlt = std::get<0>(p);
     343                                ResolvExpr::Alternative & rhsAlt = std::get<1>(p);
     344                                // convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc.
     345                                ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result );
     346                                rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() );
     347                                ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr );
     348                                ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr );
     349                                out.push_back( createFunc(spotter.fname, lobj, robj) );
     350                                ltmp.push_back( lobj );
     351                                rtmp.push_back( robj );
     352
     353                                // resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment
     354                                ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv };
     355                                finder.findWithAdjustment( rhsAlt.expr );
     356                                assert( finder.get_alternatives().size() == 1 );
     357                                compositeEnv = std::move( finder.get_alternatives().front().env );
     358                        }
    345359                        tmpDecls.splice( tmpDecls.end(), ltmp );
    346360                        tmpDecls.splice( tmpDecls.end(), rtmp );
  • src/Tuples/TupleExpansion.cc

    r3ef35bd reba74ba  
    3030#include "SynTree/Type.h"         // for Type, Type::Qualifiers, TupleType
    3131#include "SynTree/Visitor.h"      // for Visitor
     32#include "Tuples.h"
    3233
    3334class CompoundStmt;
     
    119120                        Expression * aggr = memberExpr->aggregate->clone()->acceptMutator( *visitor );
    120121                        // aggregate expressions which might be impure must be wrapped in unique expressions
    121                         // xxx - if there's a member-tuple expression nested in the aggregate, this currently generates the wrong code if a UniqueExpr is not used, and it's purely an optimization to remove the UniqueExpr
    122                         // if ( Tuples::maybeImpureIgnoreUnique( memberExpr->get_aggregate() ) ) aggr = new UniqueExpr( aggr );
    123                         aggr = new UniqueExpr( aggr );
     122                        if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new UniqueExpr( aggr );
    124123                        for ( Expression *& expr : tupleExpr->exprs ) {
    125124                                expr = reconstructMemberExpr( expr, aggr, memberExpr->location );
     
    214213
    215214        Expression * TupleIndexExpander::postmutate( TupleIndexExpr * tupleExpr ) {
    216                 Expression * tuple = tupleExpr->get_tuple();
     215                Expression * tuple = tupleExpr->tuple;
    217216                assert( tuple );
    218                 tupleExpr->set_tuple( nullptr );
    219                 unsigned int idx = tupleExpr->get_index();
    220                 TypeSubstitution * env = tupleExpr->get_env();
    221                 tupleExpr->set_env( nullptr );
    222 
    223                 StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->get_result() );
    224                 StructDecl * structDecl = type->get_baseStruct();
    225                 assert( structDecl->get_members().size() > idx );
    226                 Declaration * member = *std::next(structDecl->get_members().begin(), idx);
     217                tupleExpr->tuple = nullptr;
     218                unsigned int idx = tupleExpr->index;
     219                TypeSubstitution * env = tupleExpr->env;
     220                tupleExpr->env = nullptr;
     221                delete tupleExpr;
     222
     223                if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( tuple ) ) {
     224                        if ( ! maybeImpureIgnoreUnique( tupleExpr ) ) {
     225                                // optimization: definitely pure tuple expr => can reduce to the only relevant component.
     226                                assert( tupleExpr->exprs.size() > idx );
     227                                Expression *& expr = *std::next(tupleExpr->exprs.begin(), idx);
     228                                Expression * ret = expr;
     229                                ret->env = env;
     230                                expr = nullptr; // remove from list so it can safely be deleted
     231                                return ret;
     232                        }
     233                }
     234
     235                StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->result );
     236                StructDecl * structDecl = type->baseStruct;
     237                assert( structDecl->members.size() > idx );
     238                Declaration * member = *std::next(structDecl->members.begin(), idx);
    227239                MemberExpr * memExpr = new MemberExpr( strict_dynamic_cast< DeclarationWithType * >( member ), tuple );
    228                 memExpr->set_env( env );
     240                memExpr->env = env;
    229241                return memExpr;
    230242        }
     
    262274
    263275                // remove data from shell
     276                tupleExpr->set_result( nullptr );
     277                tupleExpr->get_exprs().clear();
    264278                tupleExpr->set_env( nullptr );
    265279
  • src/benchmark/Makefile.am

    r3ef35bd reba74ba  
    265265
    266266compile-array$(EXEEXT):
    267         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/array.c                                @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     267        @${CC} -quiet -fsyntax-only -w ../tests/array.c                         @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    268268
    269269compile-attributes$(EXEEXT):
    270         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/attributes.c                   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     270        @${CC} -quiet -fsyntax-only -w ../tests/attributes.c                    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    271271
    272272compile-empty$(EXEEXT):
    273         @${CC} -nodebug -quiet -fsyntax-only -w compile/empty.c                         @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     273        @${CC} -quiet -fsyntax-only -w compile/empty.c                          @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    274274
    275275compile-expression$(EXEEXT):
    276         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/expression.c                   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     276        @${CC} -quiet -fsyntax-only -w ../tests/expression.c                    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    277277
    278278compile-io$(EXEEXT):
    279         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/io.c                                   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     279        @${CC} -quiet -fsyntax-only -w ../tests/io.c                                    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    280280
    281281compile-monitor$(EXEEXT):
    282         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/concurrent/monitor.c           @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     282        @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c            @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    283283
    284284compile-operators$(EXEEXT):
    285         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/operators.c                    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     285        @${CC} -quiet -fsyntax-only -w ../tests/operators.c                     @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    286286
    287287compile-thread$(EXEEXT):
    288         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/concurrent/thread.c            @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     288        @${CC} -quiet -fsyntax-only -w ../tests/concurrent/thread.c             @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    289289
    290290compile-typeof$(EXEEXT):
    291         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/typeof.c                               @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    292 
     291        @${CC} -quiet -fsyntax-only -w ../tests/typeof.c                                @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     292
  • src/benchmark/Makefile.in

    r3ef35bd reba74ba  
    670670
    671671compile-array$(EXEEXT):
    672         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/array.c                                @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     672        @${CC} -quiet -fsyntax-only -w ../tests/array.c                         @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    673673
    674674compile-attributes$(EXEEXT):
    675         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/attributes.c                   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     675        @${CC} -quiet -fsyntax-only -w ../tests/attributes.c                    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    676676
    677677compile-empty$(EXEEXT):
    678         @${CC} -nodebug -quiet -fsyntax-only -w compile/empty.c                         @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     678        @${CC} -quiet -fsyntax-only -w compile/empty.c                          @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    679679
    680680compile-expression$(EXEEXT):
    681         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/expression.c                   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     681        @${CC} -quiet -fsyntax-only -w ../tests/expression.c                    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    682682
    683683compile-io$(EXEEXT):
    684         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/io.c                                   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     684        @${CC} -quiet -fsyntax-only -w ../tests/io.c                                    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    685685
    686686compile-monitor$(EXEEXT):
    687         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/concurrent/monitor.c           @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     687        @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c            @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    688688
    689689compile-operators$(EXEEXT):
    690         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/operators.c                    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     690        @${CC} -quiet -fsyntax-only -w ../tests/operators.c                     @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    691691
    692692compile-thread$(EXEEXT):
    693         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/concurrent/thread.c            @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     693        @${CC} -quiet -fsyntax-only -w ../tests/concurrent/thread.c             @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    694694
    695695compile-typeof$(EXEEXT):
    696         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/typeof.c                               @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     696        @${CC} -quiet -fsyntax-only -w ../tests/typeof.c                                @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    697697
    698698# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • src/libcfa/bits/containers.h

    r3ef35bd reba74ba  
    220220        }
    221221
    222         #define _next .0
    223         #define _prev .1
     222        #define next 0
     223        #define prev 1
    224224        forall(dtype T | sized(T))
    225225        static inline void push_front( __dllist(T) & this, T & node ) with( this ) {
     226                verify(__get);
    226227                if ( head ) {
    227                         __get( node )_next = head;
    228                         __get( node )_prev = __get( *head )_prev;
     228                        __get( node ).next = head;
     229                        __get( node ).prev = __get( *head ).prev;
    229230                        // inserted node must be consistent before it is seen
    230231                        // prevent code movement across barrier
    231232                        asm( "" : : : "memory" );
    232                         __get( *head )_prev = &node;
    233                         T & prev = *__get( node )_prev;
    234                         __get( prev )_next = &node;
     233                        __get( *head ).prev = &node;
     234                        T & _prev = *__get( node ).prev;
     235                        __get( _prev ).next = &node;
    235236                }
    236237                else {
    237                         __get( node )_next = &node;
    238                         __get( node )_prev = &node;
     238                        __get( node ).next = &node;
     239                        __get( node ).prev = &node;
    239240                }
    240241
     
    246247        forall(dtype T | sized(T))
    247248        static inline void remove( __dllist(T) & this, T & node ) with( this ) {
     249                verify(__get);
    248250                if ( &node == head ) {
    249                         if ( __get( *head )_next == head ) {
     251                        if ( __get( *head ).next == head ) {
    250252                                head = NULL;
    251253                        }
    252254                        else {
    253                                 head = __get( *head )_next;
     255                                head = __get( *head ).next;
    254256                        }
    255257                }
    256                 __get( *__get( node )_next )_prev = __get( node )_prev;
    257                 __get( *__get( node )_prev )_next = __get( node )_next;
    258                 __get( node )_next = NULL;
    259                 __get( node )_prev = NULL;
    260         }
    261         #undef _next
    262         #undef _prev
     258                __get( *__get( node ).next ).prev = __get( node ).prev;
     259                __get( *__get( node ).prev ).next = __get( node ).next;
     260                __get( node ).next = NULL;
     261                __get( node ).prev = NULL;
     262        }
     263        #undef next
     264        #undef prev
    263265#endif
    264266
  • src/libcfa/bits/locks.h

    r3ef35bd reba74ba  
    3939#endif
    4040
    41 #if __SIZEOF_SIZE_T__ == 8
    42         #define __lock_test_and_test_and_set( lock ) (lock) == 0 && __sync_lock_test_and_set_8( &(lock), 1 ) == 0
    43         #define __lock_release( lock ) __sync_lock_release_8( &(lock) );
    44 #elif __SIZEOF_SIZE_T__ == 4
    45         #define __lock_test_and_test_and_set( lock ) (lock) == 0 && __sync_lock_test_and_set_4( &(lock), 1 ) == 0
    46         #define __lock_release( lock ) __sync_lock_release_4( &(lock) );
    47 #else
    48         #error unsupported architecture
    49 #endif
    50 
    5141struct __spinlock_t {
    52         __ALIGN__ volatile size_t lock;
     42        // Wrap in struct to prevent false sharing with debug info
     43        struct {
     44                // Align lock on 128-bit boundary
     45                __ALIGN__ volatile _Bool lock;
     46        };
    5347        #ifdef __CFA_DEBUG__
     48                // previous function to acquire the lock
    5449                const char * prev_name;
     50                // previous thread to acquire the lock
    5551                void* prev_thrd;
    5652        #endif
     
    7874        // Lock the spinlock, return false if already acquired
    7975        static inline _Bool try_lock  ( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
    80                 _Bool result = __lock_test_and_test_and_set( this.lock );
     76                _Bool result = (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0);
    8177                if( result ) {
    8278                        disable_interrupts();
     
    9490
    9591                for ( unsigned int i = 1;; i += 1 ) {
    96                         if ( __lock_test_and_test_and_set( this.lock ) ) break;
     92                        if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break;
    9793                        #ifndef NOEXPBACK
    9894                                // exponential spin
     
    112108        }
    113109
    114         // // Lock the spinlock, yield if already acquired
    115         // static inline void lock_yield( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
    116         //      for ( unsigned int i = 1;; i += 1 ) {
    117         //              if ( __lock_test_and_test_and_set( this.lock ) ) break;
    118         //              yield( i );
    119         //      }
    120         //      disable_interrupts();
    121         //      __cfaabi_dbg_debug_do(
    122         //              this.prev_name = caller;
    123         //              this.prev_thrd = this_thread;
    124         //      )
    125         // }
    126 
    127110        static inline void unlock( __spinlock_t & this ) {
    128111                enable_interrupts_noPoll();
    129                 __lock_release( this.lock );
     112                __atomic_clear( &this.lock, __ATOMIC_RELEASE );
    130113        }
    131114#endif
  • src/libcfa/concurrency/alarm.c

    r3ef35bd reba74ba  
    1010// Created On       : Fri Jun 2 11:31:25 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr  9 13:36:18 2018
    13 // Update Count     : 61
     12// Last Modified On : Fri May 25 06:25:47 2018
     13// Update Count     : 67
    1414//
    1515
     
    3737
    3838void __kernel_set_timer( Duration alarm ) {
     39        verifyf(alarm >= 1`us || alarm == 0, "Setting timer to < 1us (%jins)", alarm.tv);
    3940        setitimer( ITIMER_REAL, &(itimerval){ alarm }, NULL );
    4041}
     
    6869}
    6970
    70 __cfaabi_dbg_debug_do( bool validate( alarm_list_t * this ) {
     71#if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__))
     72bool validate( alarm_list_t * this ) {
    7173        alarm_node_t ** it = &this->head;
    7274        while( (*it) ) {
     
    7577
    7678        return it == this->tail;
    77 })
     79}
     80#endif
    7881
    7982static inline void insert_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t p ) {
  • src/libcfa/concurrency/kernel

    r3ef35bd reba74ba  
    145145        __dllist_t(struct processor) idles;
    146146
     147        // List of processors
     148        __spinlock_t thread_list_lock;
     149        __dllist_t(struct thread_desc) threads;
     150
    147151        // Link lists fields
    148152        struct {
  • src/libcfa/concurrency/kernel.c

    r3ef35bd reba74ba  
    4949thread_desc * mainThread;
    5050
    51 struct { __dllist_t(thread_desc) list; __spinlock_t lock; } global_threads ;
    5251struct { __dllist_t(cluster    ) list; __spinlock_t lock; } global_clusters;
    5352
    5453//-----------------------------------------------------------------------------
    5554// Global state
    56 
    57 // volatile thread_local bool preemption_in_progress = 0;
    58 // volatile thread_local bool preemption_enabled = false;
    59 // volatile thread_local unsigned short disable_preempt_count = 1;
    60 
    6155thread_local struct KernelThreadData kernelTLS = {
    6256        NULL,
     
    123117        node.next = NULL;
    124118        node.prev = NULL;
    125         doregister(this);
     119        doregister(curr_cluster, this);
    126120
    127121        monitors{ &self_mon_p, 1, (fptr_t)0 };
     
    172166        procs{ __get };
    173167        idles{ __get };
     168        threads{ __get };
    174169
    175170        doregister(this);
     
    523518        __cfaabi_dbg_print_safe("Kernel : Starting\n");
    524519
    525         global_threads. list{ __get };
    526         global_threads. lock{};
    527520        global_clusters.list{ __get };
    528521        global_clusters.lock{};
     
    624617        ^(mainThread){};
    625618
     619        ^(global_clusters.list){};
     620        ^(global_clusters.lock){};
     621
    626622        __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n");
    627623}
     
    697693        else {
    698694                int len = snprintf( abort_text, abort_text_size, "Error occurred outside of any thread.\n" );
     695                __cfaabi_dbg_bits_write( abort_text, len );
    699696        }
    700697}
     
    760757//-----------------------------------------------------------------------------
    761758// Global Queues
    762 void doregister( thread_desc & thrd ) {
    763         // lock      ( global_thread.lock );
    764         // push_front( global_thread.list, thrd );
    765         // unlock    ( global_thread.lock );
    766 }
    767 
    768 void unregister( thread_desc & thrd ) {
    769         // lock  ( global_thread.lock );
    770         // remove( global_thread.list, thrd );
    771         // unlock( global_thread.lock );
    772 }
    773 
    774759void doregister( cluster     & cltr ) {
    775         // lock      ( global_cluster.lock );
    776         // push_front( global_cluster.list, cltr );
    777         // unlock    ( global_cluster.lock );
     760        lock      ( global_clusters.lock __cfaabi_dbg_ctx2);
     761        push_front( global_clusters.list, cltr );
     762        unlock    ( global_clusters.lock );
    778763}
    779764
    780765void unregister( cluster     & cltr ) {
    781         // lock  ( global_cluster.lock );
    782         // remove( global_cluster.list, cltr );
    783         // unlock( global_cluster.lock );
    784 }
    785 
     766        lock  ( global_clusters.lock __cfaabi_dbg_ctx2);
     767        remove( global_clusters.list, cltr );
     768        unlock( global_clusters.lock );
     769}
     770
     771void doregister( cluster * cltr, thread_desc & thrd ) {
     772        lock      (cltr->thread_list_lock __cfaabi_dbg_ctx2);
     773        push_front(cltr->threads, thrd);
     774        unlock    (cltr->thread_list_lock);
     775}
     776
     777void unregister( cluster * cltr, thread_desc & thrd ) {
     778        lock  (cltr->thread_list_lock __cfaabi_dbg_ctx2);
     779        remove(cltr->threads, thrd );
     780        unlock(cltr->thread_list_lock);
     781}
    786782
    787783void doregister( cluster * cltr, processor * proc ) {
    788         // lock      (cltr->proc_list_lock __cfaabi_dbg_ctx2);
    789         // push_front(cltr->procs, *proc);
    790         // unlock    (cltr->proc_list_lock);
     784        lock      (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     785        push_front(cltr->procs, *proc);
     786        unlock    (cltr->proc_list_lock);
    791787}
    792788
    793789void unregister( cluster * cltr, processor * proc ) {
    794         // lock  (cltr->proc_list_lock __cfaabi_dbg_ctx2);
    795         // remove(cltr->procs, *proc );
    796         // unlock(cltr->proc_list_lock);
     790        lock  (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     791        remove(cltr->procs, *proc );
     792        unlock(cltr->proc_list_lock);
    797793}
    798794
  • src/libcfa/concurrency/kernel_private.h

    r3ef35bd reba74ba  
    101101
    102102
    103 void doregister( struct thread_desc & thrd );
    104 void unregister( struct thread_desc & thrd );
     103void doregister( struct cluster & cltr );
     104void unregister( struct cluster & cltr );
    105105
    106 void doregister( struct cluster     & cltr );
    107 void unregister( struct cluster     & cltr );
     106void doregister( struct cluster * cltr, struct thread_desc & thrd );
     107void unregister( struct cluster * cltr, struct thread_desc & thrd );
    108108
    109109void doregister( struct cluster * cltr, struct processor * proc );
  • src/libcfa/concurrency/preemption.c

    r3ef35bd reba74ba  
    1515
    1616#include "preemption.h"
     17#include <assert.h>
    1718
    1819extern "C" {
     
    9192        //Loop throught every thing expired
    9293        while( node = get_expired( alarms, currtime ) ) {
     94                // __cfaabi_dbg_print_buffer_decl( " KERNEL: preemption tick.\n" );
    9395
    9496                // Check if this is a kernel
     
    103105                Duration period = node->period;
    104106                if( period > 0 ) {
     107                        // __cfaabi_dbg_print_buffer_local( " KERNEL: alarm period is %lu.\n", period.tv );
    105108                        node->alarm = currtime + period;    // Alarm is periodic, add currtime to it (used cached current time)
    106109                        insert( alarms, node );             // Reinsert the node for the next time it triggers
     
    112115
    113116        // If there are still alarms pending, reset the timer
    114         if( alarms->head ) { __kernel_set_timer( alarms->head->alarm - currtime ); }
     117        if( alarms->head ) {
     118                __cfaabi_dbg_print_buffer_decl( " KERNEL: @%lu(%lu) resetting alarm to %lu.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);
     119                Duration delta = alarms->head->alarm - currtime;
     120                Duration caped = max(delta, 50`us);
     121                // itimerval tim  = { caped };
     122                // __cfaabi_dbg_print_buffer_local( "    Values are %lu, %lu, %lu %lu.\n", delta.tv, caped.tv, tim.it_value.tv_sec, tim.it_value.tv_usec);
     123
     124                __kernel_set_timer( caped );
     125        }
    115126}
    116127
     
    150161        void disable_interrupts() {
    151162                with( kernelTLS.preemption_state ) {
    152                         enabled = false;
     163                        static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
     164
     165                        // Set enabled flag to false
     166                        // should be atomic to avoid preemption in the middle of the operation.
     167                        // use memory order RELAXED since there is no inter-thread on this variable requirements
     168                        __atomic_store_n(&enabled, false, __ATOMIC_RELAXED);
     169
     170                        // Signal the compiler that a fence is needed but only for signal handlers
     171                        __atomic_signal_fence(__ATOMIC_ACQUIRE);
     172
    153173                        __attribute__((unused)) unsigned short new_val = disable_count + 1;
    154174                        disable_count = new_val;
     
    160180        // If counter reaches 0, execute any pending CtxSwitch
    161181        void enable_interrupts( __cfaabi_dbg_ctx_param ) {
    162                 processor   * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic add
    163                 thread_desc * thrd = kernelTLS.this_thread;       // Cache the thread now since interrupts can start happening after the atomic add
     182                processor   * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic store
     183                thread_desc * thrd = kernelTLS.this_thread;       // Cache the thread now since interrupts can start happening after the atomic store
    164184
    165185                with( kernelTLS.preemption_state ){
     
    170190                        // Check if we need to prempt the thread because an interrupt was missed
    171191                        if( prev == 1 ) {
    172                                 enabled = true;
     192                                static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
     193
     194                                // Set enabled flag to true
     195                                // should be atomic to avoid preemption in the middle of the operation.
     196                                // use memory order RELAXED since there is no inter-thread on this variable requirements
     197                                __atomic_store_n(&enabled, true, __ATOMIC_RELAXED);
     198
     199                                // Signal the compiler that a fence is needed but only for signal handlers
     200                                __atomic_signal_fence(__ATOMIC_RELEASE);
    173201                                if( proc->pending_preemption ) {
    174202                                        proc->pending_preemption = false;
     
    189217                verifyf( prev != 0u, "Incremented from %u\n", prev );                     // If this triggers someone is enabled already enabled interrupts
    190218                if( prev == 1 ) {
    191                         kernelTLS.preemption_state.enabled = true;
     219                        static_assert(__atomic_always_lock_free(sizeof(kernelTLS.preemption_state.enabled), &kernelTLS.preemption_state.enabled), "Must be lock-free");
     220                        // Set enabled flag to true
     221                        // should be atomic to avoid preemption in the middle of the operation.
     222                        // use memory order RELAXED since there is no inter-thread on this variable requirements
     223                        __atomic_store_n(&kernelTLS.preemption_state.enabled, true, __ATOMIC_RELAXED);
     224
     225                        // Signal the compiler that a fence is needed but only for signal handlers
     226                        __atomic_signal_fence(__ATOMIC_RELEASE);
    192227                }
    193228        }
     
    335370        if( !preemption_ready() ) { return; }
    336371
    337         __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p).\n", kernelTLS.this_processor, kernelTLS.this_thread );
     372        __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", kernelTLS.this_processor, kernelTLS.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) );
    338373
    339374        // Sync flag : prevent recursive calls to the signal handler
    340375        kernelTLS.preemption_state.in_progress = true;
    341376
    342         // We are about to CtxSwitch out of the signal handler, let other handlers in
    343         signal_unblock( SIGUSR1 );
     377        // Clear sighandler mask before context switching.
     378        static_assert( sizeof( sigset_t ) == sizeof( cxt->uc_sigmask ), "Expected cxt->uc_sigmask to be of sigset_t" );
     379        if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), NULL ) == -1 ) {
     380                abort( "internal error, sigprocmask" );
     381        }
    344382
    345383        // TODO: this should go in finish action
     
    377415                                case EAGAIN :
    378416                                case EINTR :
     417                                        {__cfaabi_dbg_print_buffer_decl( " KERNEL: Spurious wakeup %d.\n", err );}
    379418                                        continue;
    380419                        case EINVAL :
     
    424463        sigset_t oldset;
    425464        int ret;
    426         ret = sigprocmask(0, NULL, &oldset);
     465        ret = pthread_sigmask(0, NULL, &oldset);
    427466        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    428467
    429468        ret = sigismember(&oldset, SIGUSR1);
    430469        if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
    431 
    432470        if(ret == 1) { abort("ERROR SIGUSR1 is disabled"); }
     471
     472        ret = sigismember(&oldset, SIGALRM);
     473        if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
     474        if(ret == 0) { abort("ERROR SIGALRM is enabled"); }
     475
     476        ret = sigismember(&oldset, SIGTERM);
     477        if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
     478        if(ret == 1) { abort("ERROR SIGTERM is disabled"); }
    433479}
    434480
  • src/libcfa/concurrency/thread.c

    r3ef35bd reba74ba  
    4242        node.next = NULL;
    4343        node.prev = NULL;
    44         doregister(this);
     44        doregister(curr_cluster, this);
    4545
    4646        monitors{ &self_mon_p, 1, (fptr_t)0 };
     
    4848
    4949void ^?{}(thread_desc& this) with( this ) {
    50         unregister(this);
     50        unregister(curr_cluster, this);
    5151        ^self_cor{};
    5252}
  • src/libcfa/time

    r3ef35bd reba74ba  
    1 // 
     1//
    22// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
    33//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 // 
    7 // time -- 
    8 // 
     6//
     7// time --
     8//
    99// Author           : Peter A. Buhr
    1010// Created On       : Wed Mar 14 23:18:57 2018
     
    1212// Last Modified On : Sat Apr 14 17:48:23 2018
    1313// Update Count     : 636
    14 // 
     14//
    1515
    1616#pragma once
     
    9191static inline int64_t ?`w( Duration dur ) { return dur.tv / (7LL * 24LL * 60LL * 60LL * TIMEGRAN); }
    9292
     93static inline Duration max( Duration lhs, Duration rhs ) { return  (lhs.tv < rhs.tv) ? rhs : lhs;}
     94static inline Duration min( Duration lhs, Duration rhs ) { return !(rhs.tv < lhs.tv) ? lhs : rhs;}
     95
    9396
    9497//######################### C timeval #########################
  • src/main.cc

    r3ef35bd reba74ba  
    299299
    300300                PASS( "expandUniqueExpr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    301                 Tuples::expandUniqueExpr( translationUnit );
    302301
    303302                PASS( "translateEHM" , ControlStruct::translateEHM( translationUnit ) );
  • src/prelude/Makefile.am

    r3ef35bd reba74ba  
    3737# create forward declarations for gcc builtins
    3838gcc-builtins.cf : gcc-builtins.c prototypes.sed
    39         ${AM_V_GEN}@BACKEND_CC@ -E -P $< | sed -f prototypes.sed > $@
     39        ${AM_V_GEN}@BACKEND_CC@ -E -P $< | sed -r -f prototypes.sed > $@
    4040
    41 gcc-builtins.c : builtins.def prototypes.awk
     41gcc-builtins.c : builtins.def prototypes.awk sync-builtins.cf
    4242        ${AM_V_GEN}@BACKEND_CC@ -E prototypes.c | awk -f prototypes.awk > $@
    4343
  • src/prelude/Makefile.in

    r3ef35bd reba74ba  
    506506# create forward declarations for gcc builtins
    507507gcc-builtins.cf : gcc-builtins.c prototypes.sed
    508         ${AM_V_GEN}@BACKEND_CC@ -E -P $< | sed -f prototypes.sed > $@
    509 
    510 gcc-builtins.c : builtins.def prototypes.awk
     508        ${AM_V_GEN}@BACKEND_CC@ -E -P $< | sed -r -f prototypes.sed > $@
     509
     510gcc-builtins.c : builtins.def prototypes.awk sync-builtins.cf
    511511        ${AM_V_GEN}@BACKEND_CC@ -E prototypes.c | awk -f prototypes.awk > $@
    512512
  • src/prelude/builtins.def

    r3ef35bd reba74ba  
    190190
    191191/* Builtin used by implementation of Cilk Plus.  Most of these are decomposed
    192    by the compiler but a few are implemented in libcilkrts.  */ 
     192   by the compiler but a few are implemented in libcilkrts.  */
    193193#undef DEF_CILK_BUILTIN_STUB
    194194#define DEF_CILK_BUILTIN_STUB(ENUM, NAME) \
     
    204204
    205205/* Builtin used by the implementation of libsanitizer. These
    206    functions are mapped to the actual implementation of the 
     206   functions are mapped to the actual implementation of the
    207207   libtsan library. */
    208208#undef DEF_SANITIZER_BUILTIN
     
    217217#define DEF_CILKPLUS_BUILTIN(ENUM, NAME, TYPE, ATTRS)  \
    218218  DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, BT_FN_INT_VAR, BT_LAST, \
    219                false, false, false, ATTRS, false, flag_cilkplus) 
     219               false, false, false, ATTRS, false, flag_cilkplus)
    220220
    221221/* Builtin used by the implementation of Pointer Bounds Checker.  */
     
    927927DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
    928928
     929#if 0 //Ifdefed out because we hard-coded the proper overloadings of the atomic built-ins
    929930/* Synchronization Primitives.  */
    930931#include "sync-builtins.def"
    931932
    932 #if 0
    933933/* Offloading and Multi Processing builtins.  */
    934934#include "omp-builtins.def"
  • src/prelude/prelude.cf

    r3ef35bd reba74ba  
    458458signed long long int    ?=?( signed long long int &, signed long long int ),    ?=?( volatile signed long long int &, signed long long int );
    459459unsigned long long int  ?=?( unsigned long long int &, unsigned long long int ), ?=?( volatile unsigned long long int &, unsigned long long int );
     460__int128        ?=?( __int128 &, __int128 ),    ?=?( volatile __int128 &, __int128 );
    460461zero_t                  ?=?( zero_t &, zero_t );
    461462one_t                   ?=?( one_t &, one_t );
  • src/prelude/prototypes.awk

    r3ef35bd reba74ba  
    55# file "LICENCE" distributed with Cforall.
    66#
    7 # prototypes.awk -- 
     7# prototypes.awk --
    88#
    99# Author           : Peter A. Buhr
     
    1212# Last Modified On : Tue Jul  5 14:32:52 2016
    1313# Update Count     : 32
    14 # 
     14#
    1515
    1616# http://llvm.org/svn/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def
     
    8383} # BEGIN
    8484
    85 /BT_FN/ { 
     85/BT_FN/ {
    8686    for (i = 1; i <= NF; i++) {
    8787      if( match($i, "BT_FN") != 0 ) {
     
    116116
    117117      # generate function return type as macro
    118       for ( t = 0; t < N; t += 1 ) {                                    # find longest match 
     118      for ( t = 0; t < N; t += 1 ) {                                    # find longest match
    119119        type = types[t];
    120120        if ( index( prototype, type ) == 1 ) {          # found match
     
    150150        # extras
    151151        printf( "\n#include \"builtins.def\"\n\n" );
     152        printf( "\n#include \"sync-builtins.cf\"\n\n" );
    152153        printf( "extern const char *__PRETTY_FUNCTION__;\n" );
    153154} # END
  • src/prelude/prototypes.sed

    r3ef35bd reba74ba  
    22/targetm/s/.*//                         #Remove targetm declarations
    33/__Unsupported/s/.*//                   #Remove Unsupported types declarations
    4 s/void (const char \*)0();//            #Remove void (const char \*)0();
     4s/void \(const char \*\)0\(\);//        #Remove void (const char \*)0();
    55s/\"//g                                         #Remove extraenous quotes in declarations
    6 /__builtin_/s/_ /_/g                    #Remove extraenous spaces in declarations
     6/__builtin_/s/_ /_/g                    #Remove extraenous spaces in declarations
     7
     8#Fix gcc overloading
     9# various sed rules for the gcc sync builtins which are overloaded
     10# kept here because they generate an acceptable approximate of the correct prototypes
     11
     12#/__sync_/s/_[0-9][0-9]*\(.*\)/\(\);/g  #hack since it will accept any parameters
     13#/__atomic_/s/_[0-9][0-9]*\(.*\)/\(\);/g        #hack since it will accept any parameters
     14
     15#/_16/s/void \*/__int128 \*/g
     16#/_8/s/void \*/long long int \*/g
     17#/_4/s/void \*/int \*/g
     18#/_2/s/void \*/short \*/g
     19#/_1/s/void \*/char \*/g
     20
     21#s/([a-zA-Z0-9_ ]+)\s+__sync([a-z_]+)_([0-9]+)\((.*)\);/\1 __sync\2\(\4\,...); \1 __sync\2_\3\(\4\,...);/
     22#s/([a-zA-Z0-9_ ]+)\s+__atomic([a-z_]+)_([0-9]+)\((.*)\);/\1 __atomic\2\(\4\); \1 __atomic\2_\3\(\4\);/
  • src/tests/.expect/KRfunctions.x64.txt

    r3ef35bd reba74ba  
    1111    signed int __i__i_1;
    1212};
    13 static inline void ___constructor__F_R2sS_autogen___1(struct S *___dst__R2sS_1);
    14 static inline void ___constructor__F_R2sS2sS_autogen___1(struct S *___dst__R2sS_1, struct S ___src__2sS_1);
    15 static inline void ___destructor__F_R2sS_autogen___1(struct S *___dst__R2sS_1);
    16 static inline struct S ___operator_assign__F2sS_R2sS2sS_autogen___1(struct S *___dst__R2sS_1, struct S ___src__2sS_1);
    17 static inline void ___constructor__F_R2sSi_autogen___1(struct S *___dst__R2sS_1, signed int __i__i_1);
    18 static inline void ___constructor__F_R2sS_autogen___1(struct S *___dst__R2sS_1){
    19     ((void)((*___dst__R2sS_1).__i__i_1) /* ?{} */);
     13static inline void ___constructor__F_2sS_autogen___1(struct S *___dst__2sS_1);
     14static inline void ___constructor__F_2sS2sS_autogen___1(struct S *___dst__2sS_1, struct S ___src__2sS_1);
     15static inline void ___destructor__F_2sS_autogen___1(struct S *___dst__2sS_1);
     16static inline struct S ___operator_assign__F2sS_2sS2sS_autogen___1(struct S *___dst__2sS_1, struct S ___src__2sS_1);
     17static inline void ___constructor__F_2sSi_autogen___1(struct S *___dst__2sS_1, signed int __i__i_1);
     18static inline void ___constructor__F_2sS_autogen___1(struct S *___dst__2sS_1){
     19    ((void)((*___dst__2sS_1).__i__i_1) /* ?{} */);
    2020}
    21 static inline void ___constructor__F_R2sS2sS_autogen___1(struct S *___dst__R2sS_1, struct S ___src__2sS_1){
    22     ((void)((*___dst__R2sS_1).__i__i_1=___src__2sS_1.__i__i_1) /* ?{} */);
     21static inline void ___constructor__F_2sS2sS_autogen___1(struct S *___dst__2sS_1, struct S ___src__2sS_1){
     22    ((void)((*___dst__2sS_1).__i__i_1=___src__2sS_1.__i__i_1) /* ?{} */);
    2323}
    24 static inline void ___destructor__F_R2sS_autogen___1(struct S *___dst__R2sS_1){
    25     ((void)((*___dst__R2sS_1).__i__i_1) /* ^?{} */);
     24static inline void ___destructor__F_2sS_autogen___1(struct S *___dst__2sS_1){
     25    ((void)((*___dst__2sS_1).__i__i_1) /* ^?{} */);
    2626}
    27 static inline struct S ___operator_assign__F2sS_R2sS2sS_autogen___1(struct S *___dst__R2sS_1, struct S ___src__2sS_1){
     27static inline struct S ___operator_assign__F2sS_2sS2sS_autogen___1(struct S *___dst__2sS_1, struct S ___src__2sS_1){
    2828    struct S ___ret__2sS_1;
    29     ((void)((*___dst__R2sS_1).__i__i_1=___src__2sS_1.__i__i_1));
    30     ((void)___constructor__F_R2sS2sS_autogen___1((&___ret__2sS_1), (*___dst__R2sS_1)));
     29    ((void)((*___dst__2sS_1).__i__i_1=___src__2sS_1.__i__i_1));
     30    ((void)___constructor__F_2sS2sS_autogen___1((&___ret__2sS_1), (*___dst__2sS_1)));
    3131    return ___ret__2sS_1;
    3232}
    33 static inline void ___constructor__F_R2sSi_autogen___1(struct S *___dst__R2sS_1, signed int __i__i_1){
    34     ((void)((*___dst__R2sS_1).__i__i_1=__i__i_1) /* ?{} */);
     33static inline void ___constructor__F_2sSi_autogen___1(struct S *___dst__2sS_1, signed int __i__i_1){
     34    ((void)((*___dst__2sS_1).__i__i_1=__i__i_1) /* ?{} */);
    3535}
    3636signed int __f3__Fi_2sS2sSPi__1(struct S __a__2sS_1, struct S __b__2sS_1, signed int *__c__Pi_1){
     
    4444    __attribute__ ((unused)) signed int ___retval_f5__i_1;
    4545}
    46 signed int (*__f6__FPFi_i__iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))(signed int __anonymous_object0){
    47     __attribute__ ((unused)) signed int (*___retval_f6__PFi_i__1)(signed int __anonymous_object1);
     46signed int (*__f6__FFi_i__iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))(signed int __anonymous_object0){
     47    __attribute__ ((unused)) signed int (*___retval_f6__Fi_i__1)(signed int __anonymous_object1);
    4848}
    49 signed int (*__f7__FPFi_ii__iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))(signed int __a__i_1, signed int __b__i_1){
    50     __attribute__ ((unused)) signed int (*___retval_f7__PFi_ii__1)(signed int __a__i_1, signed int __b__i_1);
     49signed int (*__f7__FFi_ii__iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))(signed int __a__i_1, signed int __b__i_1){
     50    __attribute__ ((unused)) signed int (*___retval_f7__Fi_ii__1)(signed int __a__i_1, signed int __b__i_1);
    5151}
    5252signed int *__f8__FPi_iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1){
    5353    __attribute__ ((unused)) signed int *___retval_f8__Pi_1;
    5454}
    55 signed int *const __f9__FCPi_PiiPi__1(signed int *__a__Pi_1, signed int __b__i_1, signed int *__c__Pi_1){
     55signed int *const __f9__FPi_PiiPi__1(signed int *__a__Pi_1, signed int __b__i_1, signed int *__c__Pi_1){
    5656    __attribute__ ((unused)) signed int *const ___retval_f9__CPi_1;
    5757}
    58 signed int *(*__f10__FPFPi_ii__iPiPid__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1, double __y__d_1))(signed int __x__i_1, signed int __y__i_1){
    59     __attribute__ ((unused)) signed int *(*___retval_f10__PFPi_ii__1)(signed int __x__i_1, signed int __y__i_1);
     58signed int *(*__f10__FFPi_ii__iPiPid__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1, double __y__d_1))(signed int __x__i_1, signed int __y__i_1){
     59    __attribute__ ((unused)) signed int *(*___retval_f10__FPi_ii__1)(signed int __x__i_1, signed int __y__i_1);
    6060    signed int *__x__FPi_ii__2(signed int __anonymous_object2, signed int __anonymous_object3);
    61     ((void)(___retval_f10__PFPi_ii__1=__x__FPi_ii__2) /* ?{} */);
    62     return ___retval_f10__PFPi_ii__1;
     61    ((void)(___retval_f10__FPi_ii__1=__x__FPi_ii__2) /* ?{} */);
     62    return ___retval_f10__FPi_ii__1;
    6363}
    6464signed int (*__f11__FPA0i_iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))[]{
     
    7777    __attribute__ ((unused)) signed int ___retval_f15__i_1;
    7878}
    79 const signed int __fred__FCi___1(){
     79const signed int __fred__Fi___1(){
    8080    __attribute__ ((unused)) const signed int ___retval_fred__Ci_1;
    81     signed int *(*__x__PFPi_ii__2)(signed int __anonymous_object4, signed int __anonymous_object5);
     81    signed int *(*__x__FPi_ii__2)(signed int __anonymous_object4, signed int __anonymous_object5);
    8282    signed int __a__i_2;
    8383    signed int __b__i_2;
    8484    signed int *(*_tmp_cp_ret2)(signed int __x__i_1, signed int __y__i_1);
    85     ((void)(__x__PFPi_ii__2=(((void)(_tmp_cp_ret2=__f10__FPFPi_ii__iPiPid__1(3, (&__a__i_2), (&__b__i_2), 3.5))) , _tmp_cp_ret2)));
     85    ((void)(__x__FPi_ii__2=(((void)(_tmp_cp_ret2=__f10__FFPi_ii__iPiPid__1(3, (&__a__i_2), (&__b__i_2), 3.5))) , _tmp_cp_ret2)));
    8686    ((void)(_tmp_cp_ret2) /* ^?{} */);
    87     const signed int __f1__FCi_iPiPi__2(signed int __a__i_2, signed int *__b__Pi_2, signed int *__c__Pi_2){
     87    const signed int __f1__Fi_iPiPi__2(signed int __a__i_2, signed int *__b__Pi_2, signed int *__c__Pi_2){
    8888        __attribute__ ((unused)) const signed int ___retval_f1__Ci_2;
    8989    }
    90     const signed int __f2__FCi_iii__2(signed int __a__i_2, signed int __b__i_2, signed int __c__i_2){
     90    const signed int __f2__Fi_iii__2(signed int __a__i_2, signed int __b__i_2, signed int __c__i_2){
    9191        __attribute__ ((unused)) const signed int ___retval_f2__Ci_2;
    9292    }
  • src/tests/.expect/KRfunctions.x86.txt

    r3ef35bd reba74ba  
    1111    signed int __i__i_1;
    1212};
    13 static inline void ___constructor__F_R2sS_autogen___1(struct S *___dst__R2sS_1);
    14 static inline void ___constructor__F_R2sS2sS_autogen___1(struct S *___dst__R2sS_1, struct S ___src__2sS_1);
    15 static inline void ___destructor__F_R2sS_autogen___1(struct S *___dst__R2sS_1);
    16 static inline struct S ___operator_assign__F2sS_R2sS2sS_autogen___1(struct S *___dst__R2sS_1, struct S ___src__2sS_1);
    17 static inline void ___constructor__F_R2sSi_autogen___1(struct S *___dst__R2sS_1, signed int __i__i_1);
    18 static inline void ___constructor__F_R2sS_autogen___1(struct S *___dst__R2sS_1){
    19     ((void)((*___dst__R2sS_1).__i__i_1) /* ?{} */);
     13static inline void ___constructor__F_2sS_autogen___1(struct S *___dst__2sS_1);
     14static inline void ___constructor__F_2sS2sS_autogen___1(struct S *___dst__2sS_1, struct S ___src__2sS_1);
     15static inline void ___destructor__F_2sS_autogen___1(struct S *___dst__2sS_1);
     16static inline struct S ___operator_assign__F2sS_2sS2sS_autogen___1(struct S *___dst__2sS_1, struct S ___src__2sS_1);
     17static inline void ___constructor__F_2sSi_autogen___1(struct S *___dst__2sS_1, signed int __i__i_1);
     18static inline void ___constructor__F_2sS_autogen___1(struct S *___dst__2sS_1){
     19    ((void)((*___dst__2sS_1).__i__i_1) /* ?{} */);
    2020}
    21 static inline void ___constructor__F_R2sS2sS_autogen___1(struct S *___dst__R2sS_1, struct S ___src__2sS_1){
    22     ((void)((*___dst__R2sS_1).__i__i_1=___src__2sS_1.__i__i_1) /* ?{} */);
     21static inline void ___constructor__F_2sS2sS_autogen___1(struct S *___dst__2sS_1, struct S ___src__2sS_1){
     22    ((void)((*___dst__2sS_1).__i__i_1=___src__2sS_1.__i__i_1) /* ?{} */);
    2323}
    24 static inline void ___destructor__F_R2sS_autogen___1(struct S *___dst__R2sS_1){
    25     ((void)((*___dst__R2sS_1).__i__i_1) /* ^?{} */);
     24static inline void ___destructor__F_2sS_autogen___1(struct S *___dst__2sS_1){
     25    ((void)((*___dst__2sS_1).__i__i_1) /* ^?{} */);
    2626}
    27 static inline struct S ___operator_assign__F2sS_R2sS2sS_autogen___1(struct S *___dst__R2sS_1, struct S ___src__2sS_1){
     27static inline struct S ___operator_assign__F2sS_2sS2sS_autogen___1(struct S *___dst__2sS_1, struct S ___src__2sS_1){
    2828    struct S ___ret__2sS_1;
    29     ((void)((*___dst__R2sS_1).__i__i_1=___src__2sS_1.__i__i_1));
    30     ((void)___constructor__F_R2sS2sS_autogen___1((&___ret__2sS_1), (*___dst__R2sS_1)));
     29    ((void)((*___dst__2sS_1).__i__i_1=___src__2sS_1.__i__i_1));
     30    ((void)___constructor__F_2sS2sS_autogen___1((&___ret__2sS_1), (*___dst__2sS_1)));
    3131    return ___ret__2sS_1;
    3232}
    33 static inline void ___constructor__F_R2sSi_autogen___1(struct S *___dst__R2sS_1, signed int __i__i_1){
    34     ((void)((*___dst__R2sS_1).__i__i_1=__i__i_1) /* ?{} */);
     33static inline void ___constructor__F_2sSi_autogen___1(struct S *___dst__2sS_1, signed int __i__i_1){
     34    ((void)((*___dst__2sS_1).__i__i_1=__i__i_1) /* ?{} */);
    3535}
    3636signed int __f3__Fi_2sS2sSPi__1(struct S __a__2sS_1, struct S __b__2sS_1, signed int *__c__Pi_1){
     
    4444    __attribute__ ((unused)) signed int ___retval_f5__i_1;
    4545}
    46 signed int (*__f6__FPFi_i__iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))(signed int __anonymous_object0){
    47     __attribute__ ((unused)) signed int (*___retval_f6__PFi_i__1)(signed int __anonymous_object1);
     46signed int (*__f6__FFi_i__iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))(signed int __anonymous_object0){
     47    __attribute__ ((unused)) signed int (*___retval_f6__Fi_i__1)(signed int __anonymous_object1);
    4848}
    49 signed int (*__f7__FPFi_ii__iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))(signed int __a__i_1, signed int __b__i_1){
    50     __attribute__ ((unused)) signed int (*___retval_f7__PFi_ii__1)(signed int __a__i_1, signed int __b__i_1);
     49signed int (*__f7__FFi_ii__iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))(signed int __a__i_1, signed int __b__i_1){
     50    __attribute__ ((unused)) signed int (*___retval_f7__Fi_ii__1)(signed int __a__i_1, signed int __b__i_1);
    5151}
    5252signed int *__f8__FPi_iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1){
    5353    __attribute__ ((unused)) signed int *___retval_f8__Pi_1;
    5454}
    55 signed int *const __f9__FCPi_PiiPi__1(signed int *__a__Pi_1, signed int __b__i_1, signed int *__c__Pi_1){
     55signed int *const __f9__FPi_PiiPi__1(signed int *__a__Pi_1, signed int __b__i_1, signed int *__c__Pi_1){
    5656    __attribute__ ((unused)) signed int *const ___retval_f9__CPi_1;
    5757}
    58 signed int *(*__f10__FPFPi_ii__iPiPid__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1, double __y__d_1))(signed int __x__i_1, signed int __y__i_1){
    59     __attribute__ ((unused)) signed int *(*___retval_f10__PFPi_ii__1)(signed int __x__i_1, signed int __y__i_1);
     58signed int *(*__f10__FFPi_ii__iPiPid__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1, double __y__d_1))(signed int __x__i_1, signed int __y__i_1){
     59    __attribute__ ((unused)) signed int *(*___retval_f10__FPi_ii__1)(signed int __x__i_1, signed int __y__i_1);
    6060    signed int *__x__FPi_ii__2(signed int __anonymous_object2, signed int __anonymous_object3);
    61     ((void)(___retval_f10__PFPi_ii__1=__x__FPi_ii__2) /* ?{} */);
    62     return ___retval_f10__PFPi_ii__1;
     61    ((void)(___retval_f10__FPi_ii__1=__x__FPi_ii__2) /* ?{} */);
     62    return ___retval_f10__FPi_ii__1;
    6363}
    6464signed int (*__f11__FPA0i_iPiPi__1(signed int __a__i_1, signed int *__b__Pi_1, signed int *__c__Pi_1))[]{
     
    7777    __attribute__ ((unused)) signed int ___retval_f15__i_1;
    7878}
    79 const signed int __fred__FCi___1(){
     79const signed int __fred__Fi___1(){
    8080    __attribute__ ((unused)) const signed int ___retval_fred__Ci_1;
    81     signed int *(*__x__PFPi_ii__2)(signed int __anonymous_object4, signed int __anonymous_object5);
     81    signed int *(*__x__FPi_ii__2)(signed int __anonymous_object4, signed int __anonymous_object5);
    8282    signed int __a__i_2;
    8383    signed int __b__i_2;
    8484    signed int *(*_tmp_cp_ret2)(signed int __x__i_1, signed int __y__i_1);
    85     ((void)(__x__PFPi_ii__2=(((void)(_tmp_cp_ret2=__f10__FPFPi_ii__iPiPid__1(3, (&__a__i_2), (&__b__i_2), 3.5))) , _tmp_cp_ret2)));
     85    ((void)(__x__FPi_ii__2=(((void)(_tmp_cp_ret2=__f10__FFPi_ii__iPiPid__1(3, (&__a__i_2), (&__b__i_2), 3.5))) , _tmp_cp_ret2)));
    8686    ((void)(_tmp_cp_ret2) /* ^?{} */);
    87     const signed int __f1__FCi_iPiPi__2(signed int __a__i_2, signed int *__b__Pi_2, signed int *__c__Pi_2){
     87    const signed int __f1__Fi_iPiPi__2(signed int __a__i_2, signed int *__b__Pi_2, signed int *__c__Pi_2){
    8888        __attribute__ ((unused)) const signed int ___retval_f1__Ci_2;
    8989    }
    90     const signed int __f2__FCi_iii__2(signed int __a__i_2, signed int __b__i_2, signed int __c__i_2){
     90    const signed int __f2__Fi_iii__2(signed int __a__i_2, signed int __b__i_2, signed int __c__i_2){
    9191        __attribute__ ((unused)) const signed int ___retval_f2__Ci_2;
    9292    }
  • src/tests/.expect/attributes.x64.txt

    r3ef35bd reba74ba  
    55struct __attribute__ ((unused)) __anonymous0 {
    66};
    7 static inline void ___constructor__F_R13s__anonymous0_autogen___1(struct __anonymous0 *___dst__R13s__anonymous0_1);
    8 static inline void ___constructor__F_R13s__anonymous013s__anonymous0_autogen___1(struct __anonymous0 *___dst__R13s__anonymous0_1, struct __anonymous0 ___src__13s__anonymous0_1);
    9 static inline void ___destructor__F_R13s__anonymous0_autogen___1(struct __anonymous0 *___dst__R13s__anonymous0_1);
    10 static inline struct __anonymous0 ___operator_assign__F13s__anonymous0_R13s__anonymous013s__anonymous0_autogen___1(struct __anonymous0 *___dst__R13s__anonymous0_1, struct __anonymous0 ___src__13s__anonymous0_1);
    11 static inline void ___constructor__F_R13s__anonymous0_autogen___1(struct __anonymous0 *___dst__R13s__anonymous0_1){
    12 }
    13 static inline void ___constructor__F_R13s__anonymous013s__anonymous0_autogen___1(struct __anonymous0 *___dst__R13s__anonymous0_1, struct __anonymous0 ___src__13s__anonymous0_1){
    14 }
    15 static inline void ___destructor__F_R13s__anonymous0_autogen___1(struct __anonymous0 *___dst__R13s__anonymous0_1){
    16 }
    17 static inline struct __anonymous0 ___operator_assign__F13s__anonymous0_R13s__anonymous013s__anonymous0_autogen___1(struct __anonymous0 *___dst__R13s__anonymous0_1, struct __anonymous0 ___src__13s__anonymous0_1){
     7static inline void ___constructor__F_13s__anonymous0_autogen___1(struct __anonymous0 *___dst__13s__anonymous0_1);
     8static inline void ___constructor__F_13s__anonymous013s__anonymous0_autogen___1(struct __anonymous0 *___dst__13s__anonymous0_1, struct __anonymous0 ___src__13s__anonymous0_1);
     9static inline void ___destructor__F_13s__anonymous0_autogen___1(struct __anonymous0 *___dst__13s__anonymous0_1);
     10static inline struct __anonymous0 ___operator_assign__F13s__anonymous0_13s__anonymous013s__anonymous0_autogen___1(struct __anonymous0 *___dst__13s__anonymous0_1, struct __anonymous0 ___src__13s__anonymous0_1);
     11static inline void ___constructor__F_13s__anonymous0_autogen___1(struct __anonymous0 *___dst__13s__anonymous0_1){
     12}
     13static inline void ___constructor__F_13s__anonymous013s__anonymous0_autogen___1(struct __anonymous0 *___dst__13s__anonymous0_1, struct __anonymous0 ___src__13s__anonymous0_1){
     14}
     15static inline void ___destructor__F_13s__anonymous0_autogen___1(struct __anonymous0 *___dst__13s__anonymous0_1){
     16}
     17static inline struct __anonymous0 ___operator_assign__F13s__anonymous0_13s__anonymous013s__anonymous0_autogen___1(struct __anonymous0 *___dst__13s__anonymous0_1, struct __anonymous0 ___src__13s__anonymous0_1){
    1818    struct __anonymous0 ___ret__13s__anonymous0_1;
    19     ((void)___constructor__F_R13s__anonymous013s__anonymous0_autogen___1((&___ret__13s__anonymous0_1), (*___dst__R13s__anonymous0_1)));
     19    ((void)___constructor__F_13s__anonymous013s__anonymous0_autogen___1((&___ret__13s__anonymous0_1), (*___dst__13s__anonymous0_1)));
    2020    return ___ret__13s__anonymous0_1;
    2121}
     
    2323struct __attribute__ ((unused)) Agn2 {
    2424};
    25 static inline void ___constructor__F_R5sAgn2_autogen___1(struct Agn2 *___dst__R5sAgn2_1);
    26 static inline void ___constructor__F_R5sAgn25sAgn2_autogen___1(struct Agn2 *___dst__R5sAgn2_1, struct Agn2 ___src__5sAgn2_1);
    27 static inline void ___destructor__F_R5sAgn2_autogen___1(struct Agn2 *___dst__R5sAgn2_1);
    28 static inline struct Agn2 ___operator_assign__F5sAgn2_R5sAgn25sAgn2_autogen___1(struct Agn2 *___dst__R5sAgn2_1, struct Agn2 ___src__5sAgn2_1);
    29 static inline void ___constructor__F_R5sAgn2_autogen___1(struct Agn2 *___dst__R5sAgn2_1){
    30 }
    31 static inline void ___constructor__F_R5sAgn25sAgn2_autogen___1(struct Agn2 *___dst__R5sAgn2_1, struct Agn2 ___src__5sAgn2_1){
    32 }
    33 static inline void ___destructor__F_R5sAgn2_autogen___1(struct Agn2 *___dst__R5sAgn2_1){
    34 }
    35 static inline struct Agn2 ___operator_assign__F5sAgn2_R5sAgn25sAgn2_autogen___1(struct Agn2 *___dst__R5sAgn2_1, struct Agn2 ___src__5sAgn2_1){
     25static inline void ___constructor__F_5sAgn2_autogen___1(struct Agn2 *___dst__5sAgn2_1);
     26static inline void ___constructor__F_5sAgn25sAgn2_autogen___1(struct Agn2 *___dst__5sAgn2_1, struct Agn2 ___src__5sAgn2_1);
     27static inline void ___destructor__F_5sAgn2_autogen___1(struct Agn2 *___dst__5sAgn2_1);
     28static inline struct Agn2 ___operator_assign__F5sAgn2_5sAgn25sAgn2_autogen___1(struct Agn2 *___dst__5sAgn2_1, struct Agn2 ___src__5sAgn2_1);
     29static inline void ___constructor__F_5sAgn2_autogen___1(struct Agn2 *___dst__5sAgn2_1){
     30}
     31static inline void ___constructor__F_5sAgn25sAgn2_autogen___1(struct Agn2 *___dst__5sAgn2_1, struct Agn2 ___src__5sAgn2_1){
     32}
     33static inline void ___destructor__F_5sAgn2_autogen___1(struct Agn2 *___dst__5sAgn2_1){
     34}
     35static inline struct Agn2 ___operator_assign__F5sAgn2_5sAgn25sAgn2_autogen___1(struct Agn2 *___dst__5sAgn2_1, struct Agn2 ___src__5sAgn2_1){
    3636    struct Agn2 ___ret__5sAgn2_1;
    37     ((void)___constructor__F_R5sAgn25sAgn2_autogen___1((&___ret__5sAgn2_1), (*___dst__R5sAgn2_1)));
     37    ((void)___constructor__F_5sAgn25sAgn2_autogen___1((&___ret__5sAgn2_1), (*___dst__5sAgn2_1)));
    3838    return ___ret__5sAgn2_1;
    3939}
     
    5959    __attribute__ ((unused,unused)) signed int *__f9__Pi_1;
    6060};
    61 static inline void ___constructor__F_R4sFdl_autogen___1(struct Fdl *___dst__R4sFdl_1);
    62 static inline void ___constructor__F_R4sFdl4sFdl_autogen___1(struct Fdl *___dst__R4sFdl_1, struct Fdl ___src__4sFdl_1);
    63 static inline void ___destructor__F_R4sFdl_autogen___1(struct Fdl *___dst__R4sFdl_1);
    64 static inline struct Fdl ___operator_assign__F4sFdl_R4sFdl4sFdl_autogen___1(struct Fdl *___dst__R4sFdl_1, struct Fdl ___src__4sFdl_1);
    65 static inline void ___constructor__F_R4sFdli_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1);
    66 static inline void ___constructor__F_R4sFdlii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1);
    67 static inline void ___constructor__F_R4sFdliii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1);
    68 static inline void ___constructor__F_R4sFdliiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1);
    69 static inline void ___constructor__F_R4sFdliiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1);
    70 static inline void ___constructor__F_R4sFdliiiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1);
    71 static inline void ___constructor__F_R4sFdliiiiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1);
    72 static inline void ___constructor__F_R4sFdliiiiiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1);
    73 static inline void ___constructor__F_R4sFdliiiiiiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1, __attribute__ ((unused)) signed int __anonymous_object1);
    74 static inline void ___constructor__F_R4sFdliiiiiiiiiPi_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1, __attribute__ ((unused)) signed int __anonymous_object2, __attribute__ ((unused,unused)) signed int *__f9__Pi_1);
    75 static inline void ___constructor__F_R4sFdl_autogen___1(struct Fdl *___dst__R4sFdl_1){
    76     ((void)((*___dst__R4sFdl_1).__f1__i_1) /* ?{} */);
    77     ((void)((*___dst__R4sFdl_1).__f2__i_1) /* ?{} */);
    78     ((void)((*___dst__R4sFdl_1).__f3__i_1) /* ?{} */);
    79     ((void)((*___dst__R4sFdl_1).__f4__i_1) /* ?{} */);
    80     ((void)((*___dst__R4sFdl_1).__f5__i_1) /* ?{} */);
    81     ((void)((*___dst__R4sFdl_1).__f6__i_1) /* ?{} */);
    82     ((void)((*___dst__R4sFdl_1).__f7__i_1) /* ?{} */);
    83     ((void)((*___dst__R4sFdl_1).__f8__i_1) /* ?{} */);
    84     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ?{} */);
    85     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    86 }
    87 static inline void ___constructor__F_R4sFdl4sFdl_autogen___1(struct Fdl *___dst__R4sFdl_1, struct Fdl ___src__4sFdl_1){
    88     ((void)((*___dst__R4sFdl_1).__f1__i_1=___src__4sFdl_1.__f1__i_1) /* ?{} */);
    89     ((void)((*___dst__R4sFdl_1).__f2__i_1=___src__4sFdl_1.__f2__i_1) /* ?{} */);
    90     ((void)((*___dst__R4sFdl_1).__f3__i_1=___src__4sFdl_1.__f3__i_1) /* ?{} */);
    91     ((void)((*___dst__R4sFdl_1).__f4__i_1=___src__4sFdl_1.__f4__i_1) /* ?{} */);
    92     ((void)((*___dst__R4sFdl_1).__f5__i_1=___src__4sFdl_1.__f5__i_1) /* ?{} */);
    93     ((void)((*___dst__R4sFdl_1).__f6__i_1=___src__4sFdl_1.__f6__i_1) /* ?{} */);
    94     ((void)((*___dst__R4sFdl_1).__f7__i_1=___src__4sFdl_1.__f7__i_1) /* ?{} */);
    95     ((void)((*___dst__R4sFdl_1).__f8__i_1=___src__4sFdl_1.__f8__i_1) /* ?{} */);
    96     ((void)((*___dst__R4sFdl_1).__anonymous_object0=___src__4sFdl_1.__anonymous_object0) /* ?{} */);
    97     ((void)((*___dst__R4sFdl_1).__f9__Pi_1=___src__4sFdl_1.__f9__Pi_1) /* ?{} */);
    98 }
    99 static inline void ___destructor__F_R4sFdl_autogen___1(struct Fdl *___dst__R4sFdl_1){
    100     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ^?{} */);
    101     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ^?{} */);
    102     ((void)((*___dst__R4sFdl_1).__f8__i_1) /* ^?{} */);
    103     ((void)((*___dst__R4sFdl_1).__f7__i_1) /* ^?{} */);
    104     ((void)((*___dst__R4sFdl_1).__f6__i_1) /* ^?{} */);
    105     ((void)((*___dst__R4sFdl_1).__f5__i_1) /* ^?{} */);
    106     ((void)((*___dst__R4sFdl_1).__f4__i_1) /* ^?{} */);
    107     ((void)((*___dst__R4sFdl_1).__f3__i_1) /* ^?{} */);
    108     ((void)((*___dst__R4sFdl_1).__f2__i_1) /* ^?{} */);
    109     ((void)((*___dst__R4sFdl_1).__f1__i_1) /* ^?{} */);
    110 }
    111 static inline struct Fdl ___operator_assign__F4sFdl_R4sFdl4sFdl_autogen___1(struct Fdl *___dst__R4sFdl_1, struct Fdl ___src__4sFdl_1){
     61static inline void ___constructor__F_4sFdl_autogen___1(struct Fdl *___dst__4sFdl_1);
     62static inline void ___constructor__F_4sFdl4sFdl_autogen___1(struct Fdl *___dst__4sFdl_1, struct Fdl ___src__4sFdl_1);
     63static inline void ___destructor__F_4sFdl_autogen___1(struct Fdl *___dst__4sFdl_1);
     64static inline struct Fdl ___operator_assign__F4sFdl_4sFdl4sFdl_autogen___1(struct Fdl *___dst__4sFdl_1, struct Fdl ___src__4sFdl_1);
     65static inline void ___constructor__F_4sFdli_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1);
     66static inline void ___constructor__F_4sFdlii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1);
     67static inline void ___constructor__F_4sFdliii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1);
     68static inline void ___constructor__F_4sFdliiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1);
     69static inline void ___constructor__F_4sFdliiiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1);
     70static inline void ___constructor__F_4sFdliiiiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1);
     71static inline void ___constructor__F_4sFdliiiiiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1);
     72static inline void ___constructor__F_4sFdliiiiiiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1);
     73static inline void ___constructor__F_4sFdliiiiiiiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1, __attribute__ ((unused)) signed int __anonymous_object1);
     74static inline void ___constructor__F_4sFdliiiiiiiiiPi_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1, __attribute__ ((unused)) signed int __anonymous_object2, __attribute__ ((unused,unused)) signed int *__f9__Pi_1);
     75static inline void ___constructor__F_4sFdl_autogen___1(struct Fdl *___dst__4sFdl_1){
     76    ((void)((*___dst__4sFdl_1).__f1__i_1) /* ?{} */);
     77    ((void)((*___dst__4sFdl_1).__f2__i_1) /* ?{} */);
     78    ((void)((*___dst__4sFdl_1).__f3__i_1) /* ?{} */);
     79    ((void)((*___dst__4sFdl_1).__f4__i_1) /* ?{} */);
     80    ((void)((*___dst__4sFdl_1).__f5__i_1) /* ?{} */);
     81    ((void)((*___dst__4sFdl_1).__f6__i_1) /* ?{} */);
     82    ((void)((*___dst__4sFdl_1).__f7__i_1) /* ?{} */);
     83    ((void)((*___dst__4sFdl_1).__f8__i_1) /* ?{} */);
     84    ((void)((*___dst__4sFdl_1).__anonymous_object0) /* ?{} */);
     85    ((void)((*___dst__4sFdl_1).__f9__Pi_1) /* ?{} */);
     86}
     87static inline void ___constructor__F_4sFdl4sFdl_autogen___1(struct Fdl *___dst__4sFdl_1, struct Fdl ___src__4sFdl_1){
     88    ((void)((*___dst__4sFdl_1).__f1__i_1=___src__4sFdl_1.__f1__i_1) /* ?{} */);
     89    ((void)((*___dst__4sFdl_1).__f2__i_1=___src__4sFdl_1.__f2__i_1) /* ?{} */);
     90    ((void)((*___dst__4sFdl_1).__f3__i_1=___src__4sFdl_1.__f3__i_1) /* ?{} */);
     91    ((void)((*___dst__4sFdl_1).__f4__i_1=___src__4sFdl_1.__f4__i_1) /* ?{} */);
     92    ((void)((*___dst__4sFdl_1).__f5__i_1=___src__4sFdl_1.__f5__i_1) /* ?{} */);
     93    ((void)((*___dst__4sFdl_1).__f6__i_1=___src__4sFdl_1.__f6__i_1) /* ?{} */);
     94    ((void)((*___dst__4sFdl_1).__f7__i_1=___src__4sFdl_1.__f7__i_1) /* ?{} */);
     95    ((void)((*___dst__4sFdl_1).__f8__i_1=___src__4sFdl_1.__f8__i_1) /* ?{} */);
     96    ((void)((*___dst__4sFdl_1).__anonymous_object0=___src__4sFdl_1.__anonymous_object0) /* ?{} */);
     97    ((void)((*___dst__4sFdl_1).__f9__Pi_1=___src__4sFdl_1.__f9__Pi_1) /* ?{} */);
     98}
     99static inline void ___destructor__F_4sFdl_autogen___1(struct Fdl *___dst__4sFdl_1){
     100    ((void)((*___dst__4sFdl_1).__f9__Pi_1) /* ^?{} */);
     101    ((void)((*___dst__4sFdl_1).__anonymous_object0) /* ^?{} */);
     102    ((void)((*___dst__4sFdl_1).__f8__i_1) /* ^?{} */);
     103    ((void)((*___dst__4sFdl_1).__f7__i_1) /* ^?{} */);
     104    ((void)((*___dst__4sFdl_1).__f6__i_1) /* ^?{} */);
     105    ((void)((*___dst__4sFdl_1).__f5__i_1) /* ^?{} */);
     106    ((void)((*___dst__4sFdl_1).__f4__i_1) /* ^?{} */);
     107    ((void)((*___dst__4sFdl_1).__f3__i_1) /* ^?{} */);
     108    ((void)((*___dst__4sFdl_1).__f2__i_1) /* ^?{} */);
     109    ((void)((*___dst__4sFdl_1).__f1__i_1) /* ^?{} */);
     110}
     111static inline struct Fdl ___operator_assign__F4sFdl_4sFdl4sFdl_autogen___1(struct Fdl *___dst__4sFdl_1, struct Fdl ___src__4sFdl_1){
    112112    struct Fdl ___ret__4sFdl_1;
    113     ((void)((*___dst__R4sFdl_1).__f1__i_1=___src__4sFdl_1.__f1__i_1));
    114     ((void)((*___dst__R4sFdl_1).__f2__i_1=___src__4sFdl_1.__f2__i_1));
    115     ((void)((*___dst__R4sFdl_1).__f3__i_1=___src__4sFdl_1.__f3__i_1));
    116     ((void)((*___dst__R4sFdl_1).__f4__i_1=___src__4sFdl_1.__f4__i_1));
    117     ((void)((*___dst__R4sFdl_1).__f5__i_1=___src__4sFdl_1.__f5__i_1));
    118     ((void)((*___dst__R4sFdl_1).__f6__i_1=___src__4sFdl_1.__f6__i_1));
    119     ((void)((*___dst__R4sFdl_1).__f7__i_1=___src__4sFdl_1.__f7__i_1));
    120     ((void)((*___dst__R4sFdl_1).__f8__i_1=___src__4sFdl_1.__f8__i_1));
    121     ((void)((*___dst__R4sFdl_1).__anonymous_object0=___src__4sFdl_1.__anonymous_object0));
    122     ((void)((*___dst__R4sFdl_1).__f9__Pi_1=___src__4sFdl_1.__f9__Pi_1));
    123     ((void)___constructor__F_R4sFdl4sFdl_autogen___1((&___ret__4sFdl_1), (*___dst__R4sFdl_1)));
     113    ((void)((*___dst__4sFdl_1).__f1__i_1=___src__4sFdl_1.__f1__i_1));
     114    ((void)((*___dst__4sFdl_1).__f2__i_1=___src__4sFdl_1.__f2__i_1));
     115    ((void)((*___dst__4sFdl_1).__f3__i_1=___src__4sFdl_1.__f3__i_1));
     116    ((void)((*___dst__4sFdl_1).__f4__i_1=___src__4sFdl_1.__f4__i_1));
     117    ((void)((*___dst__4sFdl_1).__f5__i_1=___src__4sFdl_1.__f5__i_1));
     118    ((void)((*___dst__4sFdl_1).__f6__i_1=___src__4sFdl_1.__f6__i_1));
     119    ((void)((*___dst__4sFdl_1).__f7__i_1=___src__4sFdl_1.__f7__i_1));
     120    ((void)((*___dst__4sFdl_1).__f8__i_1=___src__4sFdl_1.__f8__i_1));
     121    ((void)((*___dst__4sFdl_1).__anonymous_object0=___src__4sFdl_1.__anonymous_object0));
     122    ((void)((*___dst__4sFdl_1).__f9__Pi_1=___src__4sFdl_1.__f9__Pi_1));
     123    ((void)___constructor__F_4sFdl4sFdl_autogen___1((&___ret__4sFdl_1), (*___dst__4sFdl_1)));
    124124    return ___ret__4sFdl_1;
    125125}
    126 static inline void ___constructor__F_R4sFdli_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1){
    127     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    128     ((void)((*___dst__R4sFdl_1).__f2__i_1) /* ?{} */);
    129     ((void)((*___dst__R4sFdl_1).__f3__i_1) /* ?{} */);
    130     ((void)((*___dst__R4sFdl_1).__f4__i_1) /* ?{} */);
    131     ((void)((*___dst__R4sFdl_1).__f5__i_1) /* ?{} */);
    132     ((void)((*___dst__R4sFdl_1).__f6__i_1) /* ?{} */);
    133     ((void)((*___dst__R4sFdl_1).__f7__i_1) /* ?{} */);
    134     ((void)((*___dst__R4sFdl_1).__f8__i_1) /* ?{} */);
    135     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ?{} */);
    136     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    137 }
    138 static inline void ___constructor__F_R4sFdlii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1){
    139     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    140     ((void)((*___dst__R4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
    141     ((void)((*___dst__R4sFdl_1).__f3__i_1) /* ?{} */);
    142     ((void)((*___dst__R4sFdl_1).__f4__i_1) /* ?{} */);
    143     ((void)((*___dst__R4sFdl_1).__f5__i_1) /* ?{} */);
    144     ((void)((*___dst__R4sFdl_1).__f6__i_1) /* ?{} */);
    145     ((void)((*___dst__R4sFdl_1).__f7__i_1) /* ?{} */);
    146     ((void)((*___dst__R4sFdl_1).__f8__i_1) /* ?{} */);
    147     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ?{} */);
    148     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    149 }
    150 static inline void ___constructor__F_R4sFdliii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1){
    151     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    152     ((void)((*___dst__R4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
    153     ((void)((*___dst__R4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
    154     ((void)((*___dst__R4sFdl_1).__f4__i_1) /* ?{} */);
    155     ((void)((*___dst__R4sFdl_1).__f5__i_1) /* ?{} */);
    156     ((void)((*___dst__R4sFdl_1).__f6__i_1) /* ?{} */);
    157     ((void)((*___dst__R4sFdl_1).__f7__i_1) /* ?{} */);
    158     ((void)((*___dst__R4sFdl_1).__f8__i_1) /* ?{} */);
    159     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ?{} */);
    160     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    161 }
    162 static inline void ___constructor__F_R4sFdliiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1){
    163     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    164     ((void)((*___dst__R4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
    165     ((void)((*___dst__R4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
    166     ((void)((*___dst__R4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
    167     ((void)((*___dst__R4sFdl_1).__f5__i_1) /* ?{} */);
    168     ((void)((*___dst__R4sFdl_1).__f6__i_1) /* ?{} */);
    169     ((void)((*___dst__R4sFdl_1).__f7__i_1) /* ?{} */);
    170     ((void)((*___dst__R4sFdl_1).__f8__i_1) /* ?{} */);
    171     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ?{} */);
    172     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    173 }
    174 static inline void ___constructor__F_R4sFdliiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1){
    175     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    176     ((void)((*___dst__R4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
    177     ((void)((*___dst__R4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
    178     ((void)((*___dst__R4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
    179     ((void)((*___dst__R4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
    180     ((void)((*___dst__R4sFdl_1).__f6__i_1) /* ?{} */);
    181     ((void)((*___dst__R4sFdl_1).__f7__i_1) /* ?{} */);
    182     ((void)((*___dst__R4sFdl_1).__f8__i_1) /* ?{} */);
    183     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ?{} */);
    184     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    185 }
    186 static inline void ___constructor__F_R4sFdliiiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1){
    187     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    188     ((void)((*___dst__R4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
    189     ((void)((*___dst__R4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
    190     ((void)((*___dst__R4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
    191     ((void)((*___dst__R4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
    192     ((void)((*___dst__R4sFdl_1).__f6__i_1=__f6__i_1) /* ?{} */);
    193     ((void)((*___dst__R4sFdl_1).__f7__i_1) /* ?{} */);
    194     ((void)((*___dst__R4sFdl_1).__f8__i_1) /* ?{} */);
    195     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ?{} */);
    196     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    197 }
    198 static inline void ___constructor__F_R4sFdliiiiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1){
    199     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    200     ((void)((*___dst__R4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
    201     ((void)((*___dst__R4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
    202     ((void)((*___dst__R4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
    203     ((void)((*___dst__R4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
    204     ((void)((*___dst__R4sFdl_1).__f6__i_1=__f6__i_1) /* ?{} */);
    205     ((void)((*___dst__R4sFdl_1).__f7__i_1=__f7__i_1) /* ?{} */);
    206     ((void)((*___dst__R4sFdl_1).__f8__i_1) /* ?{} */);
    207     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ?{} */);
    208     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    209 }
    210 static inline void ___constructor__F_R4sFdliiiiiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1){
    211     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    212     ((void)((*___dst__R4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
    213     ((void)((*___dst__R4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
    214     ((void)((*___dst__R4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
    215     ((void)((*___dst__R4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
    216     ((void)((*___dst__R4sFdl_1).__f6__i_1=__f6__i_1) /* ?{} */);
    217     ((void)((*___dst__R4sFdl_1).__f7__i_1=__f7__i_1) /* ?{} */);
    218     ((void)((*___dst__R4sFdl_1).__f8__i_1=__f8__i_1) /* ?{} */);
    219     ((void)((*___dst__R4sFdl_1).__anonymous_object0) /* ?{} */);
    220     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    221 }
    222 static inline void ___constructor__F_R4sFdliiiiiiiii_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1, __attribute__ ((unused)) signed int __anonymous_object3){
    223     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    224     ((void)((*___dst__R4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
    225     ((void)((*___dst__R4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
    226     ((void)((*___dst__R4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
    227     ((void)((*___dst__R4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
    228     ((void)((*___dst__R4sFdl_1).__f6__i_1=__f6__i_1) /* ?{} */);
    229     ((void)((*___dst__R4sFdl_1).__f7__i_1=__f7__i_1) /* ?{} */);
    230     ((void)((*___dst__R4sFdl_1).__f8__i_1=__f8__i_1) /* ?{} */);
    231     ((void)((*___dst__R4sFdl_1).__anonymous_object0=__anonymous_object3) /* ?{} */);
    232     ((void)((*___dst__R4sFdl_1).__f9__Pi_1) /* ?{} */);
    233 }
    234 static inline void ___constructor__F_R4sFdliiiiiiiiiPi_autogen___1(struct Fdl *___dst__R4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1, __attribute__ ((unused)) signed int __anonymous_object4, __attribute__ ((unused,unused)) signed int *__f9__Pi_1){
    235     ((void)((*___dst__R4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
    236     ((void)((*___dst__R4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
    237     ((void)((*___dst__R4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
    238     ((void)((*___dst__R4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
    239     ((void)((*___dst__R4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
    240     ((void)((*___dst__R4sFdl_1).__f6__i_1=__f6__i_1) /* ?{} */);
    241     ((void)((*___dst__R4sFdl_1).__f7__i_1=__f7__i_1) /* ?{} */);
    242     ((void)((*___dst__R4sFdl_1).__f8__i_1=__f8__i_1) /* ?{} */);
    243     ((void)((*___dst__R4sFdl_1).__anonymous_object0=__anonymous_object4) /* ?{} */);
    244     ((void)((*___dst__R4sFdl_1).__f9__Pi_1=__f9__Pi_1) /* ?{} */);
     126static inline void ___constructor__F_4sFdli_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1){
     127    ((void)((*___dst__4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
     128    ((void)((*___dst__4sFdl_1).__f2__i_1) /* ?{} */);
     129    ((void)((*___dst__4sFdl_1).__f3__i_1) /* ?{} */);
     130    ((void)((*___dst__4sFdl_1).__f4__i_1) /* ?{} */);
     131    ((void)((*___dst__4sFdl_1).__f5__i_1) /* ?{} */);
     132    ((void)((*___dst__4sFdl_1).__f6__i_1) /* ?{} */);
     133    ((void)((*___dst__4sFdl_1).__f7__i_1) /* ?{} */);
     134    ((void)((*___dst__4sFdl_1).__f8__i_1) /* ?{} */);
     135    ((void)((*___dst__4sFdl_1).__anonymous_object0) /* ?{} */);
     136    ((void)((*___dst__4sFdl_1).__f9__Pi_1) /* ?{} */);
     137}
     138static inline void ___constructor__F_4sFdlii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1){
     139    ((void)((*___dst__4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
     140    ((void)((*___dst__4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
     141    ((void)((*___dst__4sFdl_1).__f3__i_1) /* ?{} */);
     142    ((void)((*___dst__4sFdl_1).__f4__i_1) /* ?{} */);
     143    ((void)((*___dst__4sFdl_1).__f5__i_1) /* ?{} */);
     144    ((void)((*___dst__4sFdl_1).__f6__i_1) /* ?{} */);
     145    ((void)((*___dst__4sFdl_1).__f7__i_1) /* ?{} */);
     146    ((void)((*___dst__4sFdl_1).__f8__i_1) /* ?{} */);
     147    ((void)((*___dst__4sFdl_1).__anonymous_object0) /* ?{} */);
     148    ((void)((*___dst__4sFdl_1).__f9__Pi_1) /* ?{} */);
     149}
     150static inline void ___constructor__F_4sFdliii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1){
     151    ((void)((*___dst__4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
     152    ((void)((*___dst__4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
     153    ((void)((*___dst__4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
     154    ((void)((*___dst__4sFdl_1).__f4__i_1) /* ?{} */);
     155    ((void)((*___dst__4sFdl_1).__f5__i_1) /* ?{} */);
     156    ((void)((*___dst__4sFdl_1).__f6__i_1) /* ?{} */);
     157    ((void)((*___dst__4sFdl_1).__f7__i_1) /* ?{} */);
     158    ((void)((*___dst__4sFdl_1).__f8__i_1) /* ?{} */);
     159    ((void)((*___dst__4sFdl_1).__anonymous_object0) /* ?{} */);
     160    ((void)((*___dst__4sFdl_1).__f9__Pi_1) /* ?{} */);
     161}
     162static inline void ___constructor__F_4sFdliiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1){
     163    ((void)((*___dst__4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
     164    ((void)((*___dst__4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
     165    ((void)((*___dst__4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
     166    ((void)((*___dst__4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
     167    ((void)((*___dst__4sFdl_1).__f5__i_1) /* ?{} */);
     168    ((void)((*___dst__4sFdl_1).__f6__i_1) /* ?{} */);
     169    ((void)((*___dst__4sFdl_1).__f7__i_1) /* ?{} */);
     170    ((void)((*___dst__4sFdl_1).__f8__i_1) /* ?{} */);
     171    ((void)((*___dst__4sFdl_1).__anonymous_object0) /* ?{} */);
     172    ((void)((*___dst__4sFdl_1).__f9__Pi_1) /* ?{} */);
     173}
     174static inline void ___constructor__F_4sFdliiiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1){
     175    ((void)((*___dst__4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
     176    ((void)((*___dst__4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
     177    ((void)((*___dst__4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
     178    ((void)((*___dst__4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
     179    ((void)((*___dst__4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
     180    ((void)((*___dst__4sFdl_1).__f6__i_1) /* ?{} */);
     181    ((void)((*___dst__4sFdl_1).__f7__i_1) /* ?{} */);
     182    ((void)((*___dst__4sFdl_1).__f8__i_1) /* ?{} */);
     183    ((void)((*___dst__4sFdl_1).__anonymous_object0) /* ?{} */);
     184    ((void)((*___dst__4sFdl_1).__f9__Pi_1) /* ?{} */);
     185}
     186static inline void ___constructor__F_4sFdliiiiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1){
     187    ((void)((*___dst__4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
     188    ((void)((*___dst__4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
     189    ((void)((*___dst__4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
     190    ((void)((*___dst__4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
     191    ((void)((*___dst__4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
     192    ((void)((*___dst__4sFdl_1).__f6__i_1=__f6__i_1) /* ?{} */);
     193    ((void)((*___dst__4sFdl_1).__f7__i_1) /* ?{} */);
     194    ((void)((*___dst__4sFdl_1).__f8__i_1) /* ?{} */);
     195    ((void)((*___dst__4sFdl_1).__anonymous_object0) /* ?{} */);
     196    ((void)((*___dst__4sFdl_1).__f9__Pi_1) /* ?{} */);
     197}
     198static inline void ___constructor__F_4sFdliiiiiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1){
     199    ((void)((*___dst__4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
     200    ((void)((*___dst__4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
     201    ((void)((*___dst__4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
     202    ((void)((*___dst__4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
     203    ((void)((*___dst__4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
     204    ((void)((*___dst__4sFdl_1).__f6__i_1=__f6__i_1) /* ?{} */);
     205    ((void)((*___dst__4sFdl_1).__f7__i_1=__f7__i_1) /* ?{} */);
     206    ((void)((*___dst__4sFdl_1).__f8__i_1) /* ?{} */);
     207    ((void)((*___dst__4sFdl_1).__anonymous_object0) /* ?{} */);
     208    ((void)((*___dst__4sFdl_1).__f9__Pi_1) /* ?{} */);
     209}
     210static inline void ___constructor__F_4sFdliiiiiiii_autogen___1(struct Fdl *___dst__4sFdl_1, __attribute__ ((unused)) signed int __f1__i_1, __attribute__ ((unused)) signed int __f2__i_1, __attribute__ ((unused,unused)) signed int __f3__i_1, __attribute__ ((unused)) signed int __f4__i_1, __attribute__ ((unused,unused)) signed int __f5__i_1, signed int __f6__i_1, __attribute__ ((unused,unused)) signed int __f7__i_1, __attribute__ ((unused)) signed int __f8__i_1){
     211    ((void)((*___dst__4sFdl_1).__f1__i_1=__f1__i_1) /* ?{} */);
     212    ((void)((*___dst__4sFdl_1).__f2__i_1=__f2__i_1) /* ?{} */);
     213    ((void)((*___dst__4sFdl_1).__f3__i_1=__f3__i_1) /* ?{} */);
     214    ((void)((*___dst__4sFdl_1).__f4__i_1=__f4__i_1) /* ?{} */);
     215    ((void)((*___dst__4sFdl_1).__f5__i_1=__f5__i_1) /* ?{} */);
     216    ((void)((*___dst__4sFdl_1).__f6__i_1=__f6__i_1) /* ?{} */);
     217    ((void)((*___dst__4sFdl_1).__f7__i_1=__f7__i_1) /* ?{} */);
     218