Changeset 8dbedfc


Ignore:
Timestamp:
May 25, 2018, 1:37:38 PM (3 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, with_gc
Children:
58e822a
Parents:
13073be (diff), 34ca532 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
5 added
30 edited
2 moved

Legend:

Unmodified
Added
Removed
  • doc/bibliography/pl.bib

    r13073be r8dbedfc  
    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

    r13073be r8dbedfc  
    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

    r13073be r8dbedfc  
    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/Parser/parser.yy

    r13073be r8dbedfc  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue May 22 08:41:57 2018
    13 // Update Count     : 3353
     12// Last Modified On : Thu May 24 18:11:59 2018
     13// Update Count     : 3369
    1414//
    1515
     
    837837//      '[' push assignment_expression pop ']'
    838838//              { $$ = new ExpressionNode( build_tuple( $3 ) ); }
    839         '[' ',' tuple_expression_list ']'
    840                 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
    841         | '[' assignment_expression ',' tuple_expression_list ']'
    842                 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)$2->set_last( $4 ) ) ); }
     839        '[' push ',' tuple_expression_list pop ']'
     840                { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $4 ) ) ); }
     841        | '[' push assignment_expression ',' tuple_expression_list pop ']'
     842                { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)$3->set_last( $5 ) ) ); }
    843843        ;
    844844
     
    866866        labeled_statement
    867867        | compound_statement
    868         | expression_statement                                          { $$ = $1; }
     868        | expression_statement
    869869        | selection_statement
    870870        | iteration_statement
     
    11831183        type_specifier_nobody
    11841184        | type_specifier_nobody declarator
    1185                 {
    1186                         $$ = $2->addType( $1 );
    1187                 }
     1185                { $$ = $2->addType( $1 ); }
    11881186        | type_specifier_nobody variable_abstract_declarator
    11891187                { $$ = $2->addType( $1 ); }
    11901188        | cfa_abstract_declarator_tuple no_attr_identifier      // CFA
    1191                 {
    1192                         $$ = $1->addName( $2 );
    1193                 }
     1189                { $$ = $1->addName( $2 ); }
    11941190        | cfa_abstract_declarator_tuple                                         // CFA
    11951191        ;
     
    12691265
    12701266declaration_list_opt:                                                                   // used at beginning of switch statement
    1271         pop
     1267        pop     // empty
    12721268                { $$ = nullptr; }
    12731269        | declaration_list
     
    13041300
    13051301local_label_list:                                                                               // GCC, local label
    1306         no_attr_identifier_or_type_name                         {}
    1307         | 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
    13081304        ;
    13091305
     
    14001396                // type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be
    14011397                // flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name.
    1402         cfa_abstract_tuple identifier_or_type_name '(' cfa_parameter_type_list_opt ')'
     1398        cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_type_list_opt pop ')'
    14031399                // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
    1404                 { $$ = DeclarationNode::newFunction( $2, $1, $4, 0 ); }
    1405         | cfa_function_return identifier_or_type_name '(' cfa_parameter_type_list_opt ')'
    1406                 { $$ = DeclarationNode::newFunction( $2, $1, $4, 0 ); }
     1400                { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
     1401        | cfa_function_return identifier_or_type_name '(' push cfa_parameter_type_list_opt pop ')'
     1402                { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
    14071403        ;
    14081404
    14091405cfa_function_return:                                                                    // CFA
    1410         '[' cfa_parameter_list ']'
    1411                 { $$ = DeclarationNode::newTuple( $2 ); }
    1412         | '[' cfa_parameter_list ',' cfa_abstract_parameter_list ']'
    1413                 // To obtain LR(1 ), the last cfa_abstract_parameter_list is added into this flattened rule to lookahead to the
    1414                 // ']'.
    1415                 { $$ = DeclarationNode::newTuple( $2->appendList( $4 ) ); }
     1406        '[' push cfa_parameter_list pop ']'
     1407                { $$ = DeclarationNode::newTuple( $3 ); }
     1408        | '[' push cfa_parameter_list pop ',' push cfa_abstract_parameter_list pop ']'
     1409                // To obtain LR(1 ), the last cfa_abstract_parameter_list is added into this flattened rule to lookahead to the ']'.
     1410                { $$ = DeclarationNode::newTuple( $3->appendList( $7 ) ); }
    14161411        ;
    14171412
     
    15871582
    15881583forall:
    1589         FORALL '('
    1590                 {
    1591                         typedefTable.enterScope();
    1592                 }
    1593           type_parameter_list ')'                                                       // CFA
    1594                 {
    1595                         typedefTable.leaveScope();
    1596                         $$ = DeclarationNode::newForall( $4 );
    1597                 }
     1584        FORALL '(' push type_parameter_list pop ')'                                     // CFA
     1585                { $$ = DeclarationNode::newForall( $4 ); }
    15981586        ;
    15991587
     
    19701958        | cfa_abstract_parameter_list
    19711959        | cfa_parameter_list
    1972         | cfa_parameter_list ',' cfa_abstract_parameter_list
    1973                 { $$ = $1->appendList( $3 ); }
    1974         | cfa_abstract_parameter_list ',' ELLIPSIS
     1960        | cfa_parameter_list pop ',' push cfa_abstract_parameter_list
     1961                { $$ = $1->appendList( $5 ); }
     1962        | cfa_abstract_parameter_list pop ',' push ELLIPSIS
    19751963                { $$ = $1->addVarArgs(); }
    1976         | cfa_parameter_list ',' ELLIPSIS
     1964        | cfa_parameter_list pop ',' push ELLIPSIS
    19771965                { $$ = $1->addVarArgs(); }
    19781966        ;
     
    19821970                // factored out from cfa_parameter_list, flattening the rules to get lookahead to the ']'.
    19831971        cfa_parameter_declaration
    1984         | cfa_abstract_parameter_list ',' cfa_parameter_declaration
    1985                 { $$ = $1->appendList( $3 ); }
    1986         | cfa_parameter_list ',' cfa_parameter_declaration
    1987                 { $$ = $1->appendList( $3 ); }
    1988         | cfa_parameter_list ',' cfa_abstract_parameter_list ',' cfa_parameter_declaration
    1989                 { $$ = $1->appendList( $3 )->appendList( $5 ); }
     1972        | cfa_abstract_parameter_list pop ',' push cfa_parameter_declaration
     1973                { $$ = $1->appendList( $5 ); }
     1974        | cfa_parameter_list pop ',' push cfa_parameter_declaration
     1975                { $$ = $1->appendList( $5 ); }
     1976        | cfa_parameter_list pop ',' push cfa_abstract_parameter_list pop ',' push cfa_parameter_declaration
     1977                { $$ = $1->appendList( $5 )->appendList( $9 ); }
    19901978        ;
    19911979
    19921980cfa_abstract_parameter_list:                                                    // CFA, new & old style abstract
    19931981        cfa_abstract_parameter_declaration
    1994         | cfa_abstract_parameter_list ',' cfa_abstract_parameter_declaration
    1995                 { $$ = $1->appendList( $3 ); }
     1982        | cfa_abstract_parameter_list pop ',' push cfa_abstract_parameter_declaration
     1983                { $$ = $1->appendList( $5 ); }
    19961984        ;
    19971985
     
    21422130        '.' no_attr_identifier                                                          // C99, field name
    21432131                { $$ = new ExpressionNode( build_varref( $2 ) ); }
    2144         | '[' assignment_expression ']'                                         // C99, single array element
     2132        | '[' push assignment_expression pop ']'                        // C99, single array element
    21452133                // assignment_expression used instead of constant_expression because of shift/reduce conflicts with tuple.
    2146                 { $$ = $2; }
    2147         | '[' subrange ']'                                                                      // CFA, multiple array elements
    2148                 { $$ = $2; }
    2149         | '[' constant_expression ELLIPSIS constant_expression ']' // GCC, multiple array elements
    2150                 { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild< Expression >( $2 ), maybeMoveBuild< Expression >( $4 ) ) ); }
    2151         | '.' '[' field_list ']'                                                        // CFA, tuple field selector
    21522134                { $$ = $3; }
     2135        | '[' push subrange pop ']'                                                     // CFA, multiple array elements
     2136                { $$ = $3; }
     2137        | '[' push constant_expression ELLIPSIS constant_expression pop ']' // GCC, multiple array elements
     2138                { $$ = new ExpressionNode( new RangeExpr( maybeMoveBuild< Expression >( $3 ), maybeMoveBuild< Expression >( $5 ) ) ); }
     2139        | '.' '[' push field_list pop ']'                                       // CFA, tuple field selector
     2140                { $$ = $4; }
    21532141        ;
    21542142
     
    22692257        TRAIT no_attr_identifier_or_type_name '(' push type_parameter_list pop ')' '{' '}'
    22702258                { $$ = DeclarationNode::newTrait( $2, $5, 0 ); }
    2271         | TRAIT no_attr_identifier_or_type_name '(' push type_parameter_list pop ')' '{'
    2272                 { typedefTable.enterScope(); }
    2273           trait_declaration_list '}'
     2259        | TRAIT no_attr_identifier_or_type_name '(' push type_parameter_list pop ')' '{' push trait_declaration_list '}'
    22742260                { $$ = DeclarationNode::newTrait( $2, $5, $10 ); }
    22752261        ;
     
    22882274cfa_trait_declaring_list:                                                               // CFA
    22892275        cfa_variable_specifier
    2290                 { $$ = $1; }
    22912276        | cfa_function_specifier
    2292                 { $$ = $1; }
    22932277        | cfa_trait_declaring_list pop ',' push identifier_or_type_name
    22942278                { $$ = $1->appendList( $1->cloneType( $5 ) ); }
     
    23492333                }
    23502334        | type_qualifier_list
    2351                 {
    2352                         if ( $1->type->forall ) xxx = forall = true; // remember generic type
    2353                 }
     2335                { if ( $1->type->forall ) xxx = forall = true; } // remember generic type
    23542336          push '{' external_definition_list '}'                         // CFA, namespace
    23552337                {
     
    23642346                }
    23652347        | declaration_qualifier_list
    2366                 {
    2367                         if ( $1->type->forall ) xxx = forall = true; // remember generic type
    2368                 }
     2348                { if ( $1->type->forall ) xxx = forall = true; } // remember generic type
    23692349          push '{' external_definition_list '}'                         // CFA, namespace
    23702350                {
     
    24062386                // declaration must still have a type_specifier.  OBSOLESCENT (see 1)
    24072387        | function_declarator compound_statement
    2408                 {
    2409                         typedefTable.leaveScope();
    2410                         $$ = $1->addFunctionBody( $2 );
    2411                 }
     2388                { $$ = $1->addFunctionBody( $2 ); }
    24122389        | KR_function_declarator KR_declaration_list_opt compound_statement
    2413                 {
    2414                         typedefTable.leaveScope();
    2415                         $$ = $1->addOldDeclList( $2 )->addFunctionBody( $3 );
    2416                 }
     2390                { $$ = $1->addOldDeclList( $2 )->addFunctionBody( $3 ); }
    24172391        ;
    24182392
     
    24272401        cfa_function_declaration with_clause_opt compound_statement     // CFA
    24282402                {
    2429                         typedefTable.leaveScope();
    24302403                        // Add the function body to the last identifier in the function definition list, i.e., foo3:
    24312404                        //   [const double] foo1(), foo2( int ), foo3( double ) { return 3.0; }
     
    24362409                {
    24372410                        rebindForall( $1, $2 );
    2438                         typedefTable.leaveScope();
    24392411                        $$ = $2->addFunctionBody( $4, $3 )->addType( $1 );
    24402412                }
     
    24422414                {
    24432415                        rebindForall( $1, $2 );
    2444                         typedefTable.leaveScope();
    24452416                        $$ = $2->addFunctionBody( $4, $3 )->addType( $1 );
    24462417                }
    24472418                // handles default int return type, OBSOLESCENT (see 1)
    24482419        | type_qualifier_list function_declarator with_clause_opt compound_statement
    2449                 {
    2450                         typedefTable.leaveScope();
    2451                         $$ = $2->addFunctionBody( $4, $3 )->addQualifiers( $1 );
    2452                 }
     2420                { $$ = $2->addFunctionBody( $4, $3 )->addQualifiers( $1 ); }
    24532421                // handles default int return type, OBSOLESCENT (see 1)
    24542422        | declaration_qualifier_list function_declarator with_clause_opt compound_statement
    2455                 {
    2456                         typedefTable.leaveScope();
    2457                         $$ = $2->addFunctionBody( $4, $3 )->addQualifiers( $1 );
    2458                 }
     2423                { $$ = $2->addFunctionBody( $4, $3 )->addQualifiers( $1 ); }
    24592424                // handles default int return type, OBSOLESCENT (see 1)
    24602425        | declaration_qualifier_list type_qualifier_list function_declarator with_clause_opt compound_statement
    2461                 {
    2462                         typedefTable.leaveScope();
    2463                         $$ = $3->addFunctionBody( $5, $4 )->addQualifiers( $2 )->addQualifiers( $1 );
    2464                 }
     2426                { $$ = $3->addFunctionBody( $5, $4 )->addQualifiers( $2 )->addQualifiers( $1 ); }
    24652427
    24662428                // Old-style K&R function definition, OBSOLESCENT (see 4)
     
    24682430                {
    24692431                        rebindForall( $1, $2 );
    2470                         typedefTable.leaveScope();
    24712432                        $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addType( $1 );
    24722433                }
    24732434                // handles default int return type, OBSOLESCENT (see 1)
    24742435        | type_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement
    2475                 {
    2476                         typedefTable.leaveScope();
    2477                         $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 );
    2478                 }
     2436                { $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 ); }
    24792437                // handles default int return type, OBSOLESCENT (see 1)
    24802438        | declaration_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement
    2481                 {
    2482                         typedefTable.leaveScope();
    2483                         $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 );
    2484                 }
     2439                { $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 ); }
    24852440                // handles default int return type, OBSOLESCENT (see 1)
    24862441        | declaration_qualifier_list type_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement
    2487                 {
    2488                         typedefTable.leaveScope();
    2489                         $$ = $3->addOldDeclList( $4 )->addFunctionBody( $6, $5 )->addQualifiers( $2 )->addQualifiers( $1 );
    2490                 }
     2442                { $$ = $3->addOldDeclList( $4 )->addFunctionBody( $6, $5 )->addQualifiers( $2 )->addQualifiers( $1 ); }
    24912443        ;
    24922444
     
    26852637        paren_identifier '(' identifier_list ')'                        // function_declarator handles empty parameter
    26862638                { $$ = $1->addIdList( $3 ); }
    2687         | '(' KR_function_ptr ')' '(' parameter_type_list_opt ')'
    2688                 { $$ = $2->addParamList( $5 ); }
     2639        | '(' KR_function_ptr ')' '(' push parameter_type_list_opt pop ')'
     2640                { $$ = $2->addParamList( $6 ); }
    26892641        | '(' KR_function_no_ptr ')'                                            // redundant parenthesis
    26902642                { $$ = $2; }
     
    28042756
    28052757identifier_parameter_function:
    2806         paren_identifier '(' parameter_type_list_opt ')'        // empty parameter list OBSOLESCENT (see 3)
    2807                 { $$ = $1->addParamList( $3 ); }
    2808         | '(' identifier_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    2809                 { $$ = $2->addParamList( $5 ); }
     2758        paren_identifier '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     2759                { $$ = $1->addParamList( $4 ); }
     2760        | '(' identifier_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     2761                { $$ = $2->addParamList( $6 ); }
    28102762        | '(' identifier_parameter_function ')'                         // redundant parenthesis
    28112763                { $$ = $2; }
     
    28572809
    28582810type_parameter_function:
    2859         typedef '(' parameter_type_list_opt ')'                         // empty parameter list OBSOLESCENT (see 3)
    2860                 { $$ = $1->addParamList( $3 ); }
    2861         | '(' type_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    2862                 { $$ = $2->addParamList( $5 ); }
     2811        typedef '(' push parameter_type_list_opt pop ')'        // empty parameter list OBSOLESCENT (see 3)
     2812                { $$ = $1->addParamList( $4 ); }
     2813        | '(' type_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     2814                { $$ = $2->addParamList( $6 ); }
    28632815        ;
    28642816
     
    29072859
    29082860abstract_function:
    2909         '(' parameter_type_list_opt ')'                                         // empty parameter list OBSOLESCENT (see 3)
    2910                 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
    2911         | '(' abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    2912                 { $$ = $2->addParamList( $5 ); }
     2861        '(' push parameter_type_list_opt pop ')'                        // empty parameter list OBSOLESCENT (see 3)
     2862                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $3, nullptr ); }
     2863        | '(' abstract_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     2864                { $$ = $2->addParamList( $6 ); }
    29132865        | '(' abstract_function ')'                                                     // redundant parenthesis
    29142866                { $$ = $2; }
     
    29252877
    29262878multi_array_dimension:
    2927         '[' assignment_expression ']'
    2928                 { $$ = DeclarationNode::newArray( $2, 0, false ); }
    2929         | '[' '*' ']'                                                                           // C99
     2879        '[' push assignment_expression pop ']'
     2880                { $$ = DeclarationNode::newArray( $3, 0, false ); }
     2881        | '[' push '*' pop ']'                                                          // C99
    29302882                { $$ = DeclarationNode::newVarArray( 0 ); }
    2931         | multi_array_dimension '[' assignment_expression ']'
    2932                 { $$ = $1->addArray( DeclarationNode::newArray( $3, 0, false ) ); }
    2933         | multi_array_dimension '[' '*' ']'                                     // C99
     2883        | multi_array_dimension '[' push assignment_expression pop ']'
     2884                { $$ = $1->addArray( DeclarationNode::newArray( $4, 0, false ) ); }
     2885        | multi_array_dimension '[' push '*' pop ']'            // C99
    29342886                { $$ = $1->addArray( DeclarationNode::newVarArray( 0 ) ); }
    29352887        ;
     
    29982950
    29992951abstract_parameter_function:
    3000         '(' parameter_type_list_opt ')'                                         // empty parameter list OBSOLESCENT (see 3)
    3001                 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
    3002         | '(' abstract_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    3003                 { $$ = $2->addParamList( $5 ); }
     2952        '(' push parameter_type_list_opt pop ')'                        // empty parameter list OBSOLESCENT (see 3)
     2953                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $3, nullptr ); }
     2954        | '(' abstract_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     2955                { $$ = $2->addParamList( $6 ); }
    30042956        | '(' abstract_parameter_function ')'                           // redundant parenthesis
    30052957                { $$ = $2; }
     
    30232975                { $$ = DeclarationNode::newArray( 0, 0, false ); }
    30242976        // multi_array_dimension handles the '[' '*' ']' case
    3025         | '[' type_qualifier_list '*' ']'                                       // remaining C99
    3026                 { $$ = DeclarationNode::newVarArray( $2 ); }
    3027         | '[' type_qualifier_list ']'
    3028                 { $$ = DeclarationNode::newArray( 0, $2, false ); }
     2977        | '[' push type_qualifier_list '*' pop ']'                      // remaining C99
     2978                { $$ = DeclarationNode::newVarArray( $3 ); }
     2979        | '[' push type_qualifier_list pop ']'
     2980                { $$ = DeclarationNode::newArray( 0, $3, false ); }
    30292981        // multi_array_dimension handles the '[' assignment_expression ']' case
    3030         | '[' type_qualifier_list assignment_expression ']'
    3031                 { $$ = DeclarationNode::newArray( $3, $2, false ); }
    3032         | '[' STATIC type_qualifier_list_opt assignment_expression ']'
    3033                 { $$ = DeclarationNode::newArray( $4, $3, true ); }
    3034         | '[' type_qualifier_list STATIC assignment_expression ']'
    3035                 { $$ = DeclarationNode::newArray( $4, $2, true ); }
     2982        | '[' push type_qualifier_list assignment_expression pop ']'
     2983                { $$ = DeclarationNode::newArray( $4, $3, false ); }
     2984        | '[' push STATIC type_qualifier_list_opt assignment_expression pop ']'
     2985                { $$ = DeclarationNode::newArray( $5, $4, true ); }
     2986        | '[' push type_qualifier_list STATIC assignment_expression pop ']'
     2987                { $$ = DeclarationNode::newArray( $5, $3, true ); }
    30362988        ;
    30372989
     
    30773029
    30783030variable_abstract_function:
    3079         '(' variable_abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    3080                 { $$ = $2->addParamList( $5 ); }
     3031        '(' variable_abstract_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     3032                { $$ = $2->addParamList( $6 ); }
    30813033        | '(' variable_abstract_function ')'                            // redundant parenthesis
    30823034                { $$ = $2; }
     
    31413093
    31423094cfa_array_parameter_1st_dimension:
    3143         '[' type_qualifier_list '*' ']'                                         // remaining C99
    3144                 { $$ = DeclarationNode::newVarArray( $2 ); }
    3145         | '[' type_qualifier_list assignment_expression ']'
    3146                 { $$ = DeclarationNode::newArray( $3, $2, false ); }
    3147         | '[' declaration_qualifier_list assignment_expression ']'
     3095        '[' push type_qualifier_list '*' pop ']'                        // remaining C99
     3096                { $$ = DeclarationNode::newVarArray( $3 ); }
     3097        | '[' push type_qualifier_list assignment_expression pop ']'
     3098                { $$ = DeclarationNode::newArray( $4, $3, false ); }
     3099        | '[' push declaration_qualifier_list assignment_expression pop ']'
    31483100                // declaration_qualifier_list must be used because of shift/reduce conflict with
    31493101                // assignment_expression, so a semantic check is necessary to preclude them as a type_qualifier cannot
    31503102                // appear in this context.
    3151                 { $$ = DeclarationNode::newArray( $3, $2, true ); }
    3152         | '[' declaration_qualifier_list type_qualifier_list assignment_expression ']'
    3153                 { $$ = DeclarationNode::newArray( $4, $3->addQualifiers( $3 ), true ); }
     3103                { $$ = DeclarationNode::newArray( $4, $3, true ); }
     3104        | '[' push declaration_qualifier_list type_qualifier_list assignment_expression pop ']'
     3105                { $$ = DeclarationNode::newArray( $5, $4->addQualifiers( $3 ), true ); }
    31543106        ;
    31553107
     
    32203172
    32213173cfa_abstract_tuple:                                                                             // CFA
    3222         '[' cfa_abstract_parameter_list ']'
    3223                 { $$ = DeclarationNode::newTuple( $2 ); }
     3174        '[' push cfa_abstract_parameter_list pop ']'
     3175                { $$ = DeclarationNode::newTuple( $3 ); }
    32243176        ;
    32253177
     
    32273179//      '[' ']' '(' cfa_parameter_type_list_opt ')'
    32283180//              { $$ = DeclarationNode::newFunction( nullptr, DeclarationNode::newTuple( nullptr ), $4, nullptr ); }
    3229         cfa_abstract_tuple '(' cfa_parameter_type_list_opt ')'
    3230                 { $$ = DeclarationNode::newFunction( nullptr, $1, $3, nullptr ); }
    3231         | cfa_function_return '(' cfa_parameter_type_list_opt ')'
    3232                 { $$ = DeclarationNode::newFunction( nullptr, $1, $3, nullptr ); }
     3181        cfa_abstract_tuple '(' push cfa_parameter_type_list_opt pop ')'
     3182                { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); }
     3183        | cfa_function_return '(' push cfa_parameter_type_list_opt pop ')'
     3184                { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); }
    32333185        ;
    32343186
  • src/ResolvExpr/AlternativeFinder.cc

    r13073be r8dbedfc  
    698698                        const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
    699699                        const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
    700                 if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) {
     700                if ( TupleType * tupleType = dynamic_cast<TupleType*>( formalType ) ) {
    701701                        // formalType is a TupleType - group actuals into a TupleExpr
    702702                        ++nTuples;
    703703                        for ( Type* type : *tupleType ) {
    704704                                // xxx - dropping initializer changes behaviour from previous, but seems correct
     705                                // ^^^ need to handle the case where a tuple has a default argument
    705706                                if ( ! instantiateArgument(
    706707                                                type, nullptr, args, results, genStart, indexer, nTuples ) )
     
    713714                        }
    714715                        return true;
    715                 } else if ( TypeInstType* ttype = Tuples::isTtype( formalType ) ) {
     716                } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
    716717                        // formalType is a ttype, consumes all remaining arguments
    717718                        // xxx - mixing default arguments with variadic??
     
    916917                                // consider only first exploded actual
    917918                                Expression* expr = expl.exprs.front().get();
    918                                 Type* actualType = expr->get_result()->clone();
     919                                Type* actualType = expr->result->clone();
    919920
    920921                                PRINT(
     
    947948                ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
    948949                // sum cost and accumulate actuals
    949                 std::list<Expression*>& args = appExpr->get_args();
     950                std::list<Expression*>& args = appExpr->args;
    950951                Cost cost = func.cost;
    951952                const ArgPack* pack = &result;
     
    974975                // add all type variables as open variables now so that those not used in the parameter
    975976                // list are still considered open.
    976                 funcEnv.add( funcType->get_forall() );
    977 
    978                 if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) {
     977                funcEnv.add( funcType->forall );
     978
     979                if ( targetType && ! targetType->isVoid() && ! funcType->returnVals.empty() ) {
    979980                        // attempt to narrow based on expected target type
    980                         Type * returnType = funcType->get_returnVals().front()->get_type();
     981                        Type * returnType = funcType->returnVals.front()->get_type();
    981982                        if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
    982983                                        indexer ) ) {
     
    991992                std::size_t genStart = 0;
    992993
    993                 for ( DeclarationWithType* formal : funcType->get_parameters() ) {
     994                for ( DeclarationWithType* formal : funcType->parameters ) {
    994995                        ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
    995996                        if ( ! instantiateArgument(
    996                                         obj->get_type(), obj->get_init(), args, results, genStart, indexer ) )
     997                                        obj->type, obj->init, args, results, genStart, indexer ) )
    997998                                return;
    998999                }
     
    10751076        void AlternativeFinder::Finder::postvisit( UntypedExpr *untypedExpr ) {
    10761077                AlternativeFinder funcFinder( indexer, env );
    1077                 funcFinder.findWithAdjustment( untypedExpr->get_function() );
     1078                funcFinder.findWithAdjustment( untypedExpr->function );
    10781079                // if there are no function alternatives, then proceeding is a waste of time.
    10791080                if ( funcFinder.alternatives.empty() ) return;
     
    11201121                                )
    11211122                                // check if the type is pointer to function
    1122                                 if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
    1123                                         if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
     1123                                if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->result->stripReferences() ) ) {
     1124                                        if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->base ) ) {
    11241125                                                Alternative newFunc( *func );
    11251126                                                referenceToRvalueConversion( newFunc.expr, newFunc.cost );
     
    11271128                                                        std::back_inserter( candidates ) );
    11281129                                        }
    1129                                 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
     1130                                } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->result->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
    11301131                                        EqvClass eqvClass;
    1131                                         if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) {
     1132                                        if ( func->env.lookup( typeInst->name, eqvClass ) && eqvClass.type ) {
    11321133                                                if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) {
    11331134                                                        Alternative newFunc( *func );
     
    11581159                                        // check if type is a pointer to function
    11591160                                        if ( PointerType* pointer = dynamic_cast<PointerType*>(
    1160                                                         funcOp->expr->get_result()->stripReferences() ) ) {
     1161                                                        funcOp->expr->result->stripReferences() ) ) {
    11611162                                                if ( FunctionType* function =
    1162                                                                 dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
     1163                                                                dynamic_cast<FunctionType*>( pointer->base ) ) {
    11631164                                                        Alternative newFunc( *funcOp );
    11641165                                                        referenceToRvalueConversion( newFunc.expr, newFunc.cost );
     
    11821183                        PRINT(
    11831184                                ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc.expr );
    1184                                 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
    1185                                 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
    1186                                 std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
     1185                                PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->function->result );
     1186                                FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->base );
     1187                                std::cerr << "Case +++++++++++++ " << appExpr->function << std::endl;
    11871188                                std::cerr << "formals are:" << std::endl;
    1188                                 printAll( function->get_parameters(), std::cerr, 8 );
     1189                                printAll( function->parameters, std::cerr, 8 );
    11891190                                std::cerr << "actuals are:" << std::endl;
    1190                                 printAll( appExpr->get_args(), std::cerr, 8 );
     1191                                printAll( appExpr->args, std::cerr, 8 );
    11911192                                std::cerr << "bindings are:" << std::endl;
    11921193                                withFunc.env.print( std::cerr, 8 );
     
    12291230        bool isLvalue( Expression *expr ) {
    12301231                // xxx - recurse into tuples?
    1231                 return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
     1232                return expr->result && ( expr->result->get_lvalue() || dynamic_cast< ReferenceType * >( expr->result ) );
    12321233        }
    12331234
     
    12911292                        AssertionSet needAssertions, haveAssertions;
    12921293                        OpenVarSet openVars;
     1294
     1295                        alt.env.extractOpenVars( openVars );
    12931296
    12941297                        // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
     
    17091712                        AlternativeFinder finder( indexer, env );
    17101713                        finder.targetType = toType;
    1711                         finder.findWithAdjustment( initExpr->get_expr() );
     1714                        finder.findWithAdjustment( initExpr->expr );
    17121715                        for ( Alternative & alt : finder.get_alternatives() ) {
    17131716                                TypeEnvironment newEnv( alt.env );
     
    17161719                                PRINT(
    17171720                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
    1718                                  )
     1721                                )
    17191722                                // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
    17201723                                // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
    17211724                                // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
    17221725                                // to.
    1723                                 int discardedValues = alt.expr->get_result()->size() - toType->size();
     1726                                int discardedValues = alt.expr->result->size() - toType->size();
    17241727                                if ( discardedValues < 0 ) continue;
    17251728                                // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
     
    17281731                                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??
    17291732
    1730                                 Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv );
     1733                                Cost thisCost = castCost( alt.expr->result, toType, indexer, newEnv );
    17311734                                if ( thisCost != Cost::infinity ) {
    17321735                                        // count one safe conversion for each value that is thrown away
  • src/Tuples/TupleAssignment.cc

    r13073be r8dbedfc  
    231231
    232232                        ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),
    233                                 currentFinder.get_environ() };
     233                                matcher->compositeEnv };
     234
    234235                        try {
    235236                                finder.findWithAdjustment(*i);
     
    349350                                ltmp.push_back( lobj );
    350351                                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 );
    351358                        }
    352359                        tmpDecls.splice( tmpDecls.end(), ltmp );
  • src/libcfa/concurrency/alarm.c

    r13073be r8dbedfc  
    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 (%luns)", alarm.tv);
     39        verifyf(alarm >= 1`us || alarm == 0, "Setting timer to < 1us (%jins)", alarm.tv);
    4040        setitimer( ITIMER_REAL, &(itimerval){ alarm }, NULL );
    4141}
  • src/tests/.expect/io2.txt

    r13073be r8dbedfc  
    1 9 6 28 0 7 1 2
    2 1 2 3
    3 123
    4 123
    5 
    6 opening delimiters
    7 x (1 x [2 x {3 x =4 x $5 x £6 x ¥7 x ¡8 x ¿9 x «10
    8 
    9 closing delimiters
    10 1, x 2. x 3; x 4! x 5? x 6% x 7¢ x 8» x 9) x 10] x 11} x
    11 
    12 opening/closing delimiters
    13 x`1`x'2'x"3"x:4:x 5 x   6       x
    14 7
    15 x
    16 8
    17 x
    18 9
    19 x
    20 10
    21 x
    22 
    23 override opening/closing delimiters
    24 x ( 1 ) x 2 , x 3 :x: 4
    25 
    261input bacis types
    272
  • src/tests/.expect/math1.x64.txt

    r13073be r8dbedfc  
    1212\ 16 256
    1313\ 912673 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
    14 log:0 0 0 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
    15 log2:3 3 3
    16 log10:2 2 2
    17 log1p:0.693147 0.693147180559945 0.693147180559945309
    18 ilogb:0 0 0
    19 logb:3 3 3
    20 sqrt:1 1 1 1.09868+0.45509i 1.09868411346781+0.455089860562227i 1.09868411346780997+0.455089860562227341i
    21 cbrt:3 3 3
    22 hypot:1.41421 1.4142135623731 1.41421356237309505
  • src/tests/.expect/math1.x86.txt

    r13073be r8dbedfc  
    1212\ 16 256
    1313\ 912673 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
    14 log:0 0 0 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
    15 log2:3 3 3
    16 log10:2 2 2
    17 log1p:0.693147 0.693147180559945 0.693147180559945309
    18 ilogb:0 0 0
    19 logb:3 3 3
    20 sqrt:1 1 1 1.09868+0.45509i 1.09868411346781+0.455089860562227i 1.09868411346780997+0.455089860562227341i
    21 cbrt:3 3 3
    22 hypot:1.41421 1.4142135623731 1.41421356237309505
  • src/tests/.expect/math2.x64.txt

    r13073be r8dbedfc  
     1log:0 0 0 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
     2log2:3 3 3
     3log10:2 2 2
     4log1p:0.693147 0.693147180559945 0.693147180559945309
     5ilogb:0 0 0
     6logb:3 3 3
     7sqrt:1 1 1 1.09868+0.45509i 1.09868411346781+0.455089860562227i 1.09868411346780997+0.455089860562227341i
     8cbrt:3 3 3
     9hypot:1.41421 1.4142135623731 1.41421356237309505
    110sin:0.841471 0.841470984807897 0.841470984807896507 1.29846+0.634964i 1.29845758141598+0.634963914784736i 1.29845758141597729+0.634963914784736108i
    211cos:0.540302 0.54030230586814 0.540302305868139717 0.83373-0.988898i 0.833730025131149-0.988897705762865i 0.833730025131149049-0.988897705762865096i
     
    615atan:0.785398 0.785398163397448 0.78539816339744831 1.01722+0.402359i 1.01722196789785+0.402359478108525i 1.01722196789785137+0.402359478108525094i
    716atan2:0.785398 0.785398163397448 0.78539816339744831 atan:0.785398 0.785398163397448 0.78539816339744831
    8 sinh:1.1752 1.1752011936438 1.17520119364380146 0.634964+1.29846i 0.634963914784736+1.29845758141598i 0.634963914784736108+1.29845758141597729i
    9 cosh:1.54308 1.54308063481524 1.54308063481524378 0.83373+0.988898i 0.833730025131149+0.988897705762865i 0.833730025131149049+0.988897705762865096i
    10 tanh:0.761594 0.761594155955765 0.761594155955764888 1.08392+0.271753i 1.08392332733869+0.271752585319512i 1.08392332733869454+0.271752585319511717i
    11 acosh:0 0 0 1.06128+0.904557i 1.06127506190504+0.904556894302381i 1.06127506190503565+0.904556894302381364i
    12 asinh:0.881374 0.881373587019543 0.881373587019543025 1.06128+0.666239i 1.06127506190504+0.666239432492515i 1.06127506190503565+0.666239432492515255i
    13 atanh:inf inf inf 0.402359+1.01722i 0.402359478108525+1.01722196789785i 0.402359478108525094+1.01722196789785137i
    14 erf:0.842701 0.842700792949715 0.842700792949714869
    15 erfc:0.157299 0.157299207050285 0.157299207050285131
    16 lgamma:1.79176 1.79175946922805 1.791759469228055
    17 lgamma:1.79176 1 1.79175946922805 1 1.791759469228055 1
    18 tgamma:6 6 6
  • src/tests/.expect/math2.x86.txt

    r13073be r8dbedfc  
     1log:0 0 0 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
     2log2:3 3 3
     3log10:2 2 2
     4log1p:0.693147 0.693147180559945 0.693147180559945309
     5ilogb:0 0 0
     6logb:3 3 3
     7sqrt:1 1 1 1.09868+0.45509i 1.09868411346781+0.455089860562227i 1.09868411346780997+0.455089860562227341i
     8cbrt:3 3 3
     9hypot:1.41421 1.4142135623731 1.41421356237309505
    110sin:0.841471 0.841470984807897 0.841470984807896507 1.29846+0.634964i 1.29845758141598+0.634963914784736i 1.29845758141597729+0.634963914784736108i
    211cos:0.540302 0.54030230586814 0.540302305868139717 0.83373-0.988898i 0.833730025131149-0.988897705762865i 0.833730025131149049-0.988897705762865096i
     
    615atan:0.785398 0.785398163397448 0.78539816339744831 1.01722+0.402359i 1.01722196789785+0.402359478108525i 1.01722196789785137+0.402359478108525094i
    716atan2:0.785398 0.785398163397448 0.78539816339744831 atan:0.785398 0.785398163397448 0.78539816339744831
    8 sinh:1.1752 1.1752011936438 1.17520119364380146 0.634964+1.29846i 0.634963914784736+1.29845758141598i 0.634963914784736108+1.29845758141597729i
    9 cosh:1.54308 1.54308063481524 1.54308063481524378 0.83373+0.988898i 0.833730025131149+0.988897705762865i 0.833730025131149049+0.988897705762865096i
    10 tanh:0.761594 0.761594155955765 0.761594155955764888 1.08392+0.271753i 1.08392332733869+0.271752585319512i 1.08392332733869454+0.271752585319511717i
    11 acosh:0 0 0 1.06128+0.904557i 1.06127506190504+0.904556894302381i 1.06127506190503565+0.904556894302381364i
    12 asinh:0.881374 0.881373587019543 0.881373587019543025 1.06128+0.666239i 1.06127506190504+0.666239432492515i 1.06127506190503565+0.666239432492515255i
    13 atanh:inf inf inf 0.402359+1.01722i 0.402359478108525+1.01722196789785i 0.402359478108525094+1.01722196789785137i
    14 erf:0.842701 0.842700792949715 0.842700792949714869
    15 erfc:0.157299 0.157299207050285 0.157299207050285131
    16 lgamma:1.79176 1.79175946922805 1.791759469228055
    17 lgamma:1.79176 1 1.79175946922805 1 1.791759469228055 1
    18 tgamma:6 6 6
  • src/tests/.expect/math3.x64.txt

    r13073be r8dbedfc  
    1 floor:1 1 1
    2 ceil:2 2 2
    3 trunc:3 3 3
    4 rint:2 2 2
    5 rint:2 2 2
    6 rint:2 2 2
    7 lrint:2 2 2
    8 llrint:2 2 2
    9 nearbyint:4 4 4
    10 round:2 2 2
    11 round:2 2 2
    12 round:2 2 2
    13 lround:2 2 2
    14 llround:2 2 2
    15 copysign:-1 -1 -1
    16 frexp:0.5 3 0.5 3 0.5 3
    17 ldexp:8 8 8
    18 modf:2 0.3 2 0.3 2 0.3
    19 modf:2, 0.3 2, 0.3 2, 0.3
    20 nextafter:2 2 2
    21 nexttoward:2 2 2
    22 scalbn:16 16 16
    23 scalbln:16 16 16
     1sinh:1.1752 1.1752011936438 1.17520119364380146 0.634964+1.29846i 0.634963914784736+1.29845758141598i 0.634963914784736108+1.29845758141597729i
     2cosh:1.54308 1.54308063481524 1.54308063481524378 0.83373+0.988898i 0.833730025131149+0.988897705762865i 0.833730025131149049+0.988897705762865096i
     3tanh:0.761594 0.761594155955765 0.761594155955764888 1.08392+0.271753i 1.08392332733869+0.271752585319512i 1.08392332733869454+0.271752585319511717i
     4acosh:0 0 0 1.06128+0.904557i 1.06127506190504+0.904556894302381i 1.06127506190503565+0.904556894302381364i
     5asinh:0.881374 0.881373587019543 0.881373587019543025 1.06128+0.666239i 1.06127506190504+0.666239432492515i 1.06127506190503565+0.666239432492515255i
     6atanh:inf inf inf 0.402359+1.01722i 0.402359478108525+1.01722196789785i 0.402359478108525094+1.01722196789785137i
     7erf:0.842701 0.842700792949715 0.842700792949714869
     8erfc:0.157299 0.157299207050285 0.157299207050285131
     9lgamma:1.79176 1.79175946922805 1.791759469228055
     10lgamma:1.79176 1 1.79175946922805 1 1.791759469228055 1
     11tgamma:6 6 6
  • src/tests/.expect/math3.x86.txt

    r13073be r8dbedfc  
    1 floor:1 1 1
    2 ceil:2 2 2
    3 trunc:3 3 3
    4 rint:2 2 2
    5 rint:2 2 2
    6 rint:2 2 2
    7 lrint:2 2 2
    8 llrint:2 2 2
    9 nearbyint:4 4 4
    10 round:2 2 2
    11 round:2 2 2
    12 round:2 2 2
    13 lround:2 2 2
    14 llround:2 2 2
    15 copysign:-1 -1 -1
    16 frexp:0.5 3 0.5 3 0.5 3
    17 ldexp:8 8 8
    18 modf:2 0.3 2 0.3 2 0.3
    19 modf:2, 0.3 2, 0.3 2, 0.3
    20 nextafter:2 2 2
    21 nexttoward:2 2 2
    22 scalbn:16 16 16
    23 scalbln:16 16 16
     1sinh:1.1752 1.1752011936438 1.17520119364380146 0.634964+1.29846i 0.634963914784736+1.29845758141598i 0.634963914784736108+1.29845758141597729i
     2cosh:1.54308 1.54308063481524 1.54308063481524378 0.83373+0.988898i 0.833730025131149+0.988897705762865i 0.833730025131149049+0.988897705762865096i
     3tanh:0.761594 0.761594155955765 0.761594155955764888 1.08392+0.271753i 1.08392332733869+0.271752585319512i 1.08392332733869454+0.271752585319511717i
     4acosh:0 0 0 1.06128+0.904557i 1.06127506190504+0.904556894302381i 1.06127506190503565+0.904556894302381364i
     5asinh:0.881374 0.881373587019543 0.881373587019543025 1.06128+0.666239i 1.06127506190504+0.666239432492515i 1.06127506190503565+0.666239432492515255i
     6atanh:inf inf inf 0.402359+1.01722i 0.402359478108525+1.01722196789785i 0.402359478108525094+1.01722196789785137i
     7erf:0.842701 0.842700792949715 0.842700792949714869
     8erfc:0.157299 0.157299207050285 0.157299207050285131
     9lgamma:1.79176 1.79175946922805 1.791759469228055
     10lgamma:1.79176 1 1.79175946922805 1 1.791759469228055 1
     11tgamma:6 6 6
  • src/tests/concurrent/coroutineYield.c

    r13073be r8dbedfc  
    33#include <stdlib>
    44#include <thread>
     5#include <time>
     6
     7#ifndef PREEMPTION_RATE
     8#define PREEMPTION_RATE 10`ms
     9#endif
     10
     11Duration default_preemption() {
     12        return PREEMPTION_RATE;
     13}
    514
    615#ifdef LONG_TEST
  • src/tests/concurrent/examples/matrixSum.c

    r13073be r8dbedfc  
    1111// Created On       : Mon Oct  9 08:29:28 2017
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Tue Dec  5 22:56:46 2017
    14 // Update Count     : 4
     13// Last Modified On : Fri May 25 09:34:27 2018
     14// Update Count     : 10
    1515//
    1616
     
    2020
    2121thread Adder {
    22     int * row, cols, * subtotal;                                                // communication
     22        int * row, cols, & subtotal;                                            // communication
    2323};
    2424
    2525void ?{}( Adder & adder, int row[], int cols, int & subtotal ) {
    26     adder.row = row;
    27     adder.cols = cols;
    28     adder.subtotal = &subtotal;
     26        adder.[ row, cols ] = [ row, cols ];                            // expression disallowed in multi-member access
     27        &adder.subtotal = &subtotal;
    2928}
    3029
    31 void main( Adder & adder ) with( adder ) {
    32     *subtotal = 0;
    33     for ( int c = 0; c < cols; c += 1 ) {
    34                 *subtotal += row[c];
    35     } // for
     30void main( Adder & adder ) with( adder ) {                              // thread starts here
     31        subtotal = 0;
     32        for ( int c = 0; c < cols; c += 1 ) {
     33                subtotal += row[c];
     34        } // for
    3635}
    3736
    3837int main() {
    39     const int rows = 10, cols = 1000;
    40     int matrix[rows][cols], subtotals[rows], total = 0;
    41     processor p;                                                                                // extra kernel thread
     38        const int rows = 10, cols = 1000;
     39        int matrix[rows][cols], subtotals[rows], total = 0;
     40        processor p;                                                                            // add kernel thread
    4241
    43     for ( int r = 0; r < rows; r += 1 ) {
     42        for ( int r = 0; r < rows; r += 1 ) {
    4443                for ( int c = 0; c < cols; c += 1 ) {
    4544                        matrix[r][c] = 1;
    4645                } // for
    47     } // for
    48     Adder * adders[rows];
    49     for ( int r = 0; r < rows; r += 1 ) {                               // start threads to sum rows
     46        } // for
     47        Adder * adders[rows];
     48        for ( int r = 0; r < rows; r += 1 ) {                           // start threads to sum rows
    5049                adders[r] = &(*malloc()){ matrix[r], cols, subtotals[r] };
    5150//              adders[r] = new( matrix[r], cols, &subtotals[r] );
    52     } // for
    53     for ( int r = 0; r < rows; r += 1 ) {                               // wait for threads to finish
     51        } // for
     52        for ( int r = 0; r < rows; r += 1 ) {                           // wait for threads to finish
    5453                delete( adders[r] );
    5554                total += subtotals[r];                                                  // total subtotals
    56     } // for
    57     sout | total | endl;
     55        } // for
     56        sout | total | endl;
    5857}
    5958
  • src/tests/concurrent/signal/block.c

    r13073be r8dbedfc  
    1414#include <time>
    1515
    16 #ifdef LONG_TEST
    17 static const unsigned long N = 150_000ul;
    18 #else
    19 static const unsigned long N = 5_000ul;
    20 #endif
    21 
    2216#ifndef PREEMPTION_RATE
    2317#define PREEMPTION_RATE 10`ms
     
    2721        return PREEMPTION_RATE;
    2822}
     23
     24#ifdef LONG_TEST
     25static const unsigned long N = 150_000ul;
     26#else
     27static const unsigned long N = 5_000ul;
     28#endif
    2929
    3030enum state_t { WAITED, SIGNAL, BARGE };
  • src/tests/concurrent/signal/disjoint.c

    r13073be r8dbedfc  
    44#include <thread>
    55#include <time>
    6 
    7 #ifdef LONG_TEST
    8 static const unsigned long N = 300_000ul;
    9 #else
    10 static const unsigned long N = 10_000ul;
    11 #endif
    126
    137#ifndef PREEMPTION_RATE
     
    1812        return PREEMPTION_RATE;
    1913}
     14
     15#ifdef LONG_TEST
     16static const unsigned long N = 300_000ul;
     17#else
     18static const unsigned long N = 10_000ul;
     19#endif
    2020
    2121enum state_t { WAIT, SIGNAL, BARGE };
  • src/tests/concurrent/signal/wait.c

    r13073be r8dbedfc  
    1212#include <time>
    1313
    14 #ifdef LONG_TEST
    15 static const unsigned long N = 375_000ul;
    16 #else
    17 static const unsigned long N = 2_500ul;
    18 #endif
    19 
    2014#ifndef PREEMPTION_RATE
    2115#define PREEMPTION_RATE 10`ms
     
    2519        return PREEMPTION_RATE;
    2620}
     21
     22#ifdef LONG_TEST
     23static const unsigned long N = 375_000ul;
     24#else
     25static const unsigned long N = 2_500ul;
     26#endif
    2727
    2828monitor global_t {};
  • src/tests/io2.c

    r13073be r8dbedfc  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // io.c --
     7// io2.c --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Wed Mar  2 16:56:02 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jan 26 15:19:34 2018
    13 // Update Count     : 100
     12// Last Modified On : Thu May 24 21:17:41 2018
     13// Update Count     : 103
    1414//
    1515
     
    3737        enum { size = 10 };
    3838        char s1[size], s2[size];
    39 
    40         int x = 3, y = 5, z = 7;
    41         sout | x * 3 | y + 1 | z << 2 | x == y | (x | y) | (x || y) | (x > z ? 1 : 2) | endl;
    42         sout | 1 | 2 | 3 | endl;
    43         sout | '1' | '2' | '3' | endl;
    44         sout | 1 | "" | 2 | "" | 3 | endl;
    45         sout | endl;
    46 
    47         sout | "opening delimiters" | endl;
    48         sout
    49                  | "x (" | 1
    50                  | "x [" | 2
    51                  | "x {" | 3
    52                  | "x =" | 4
    53                  | "x $" | 5
    54                  | "x £" | 6
    55                  | "x ¥" | 7
    56                  | "x ¡" | 8
    57                  | "x ¿" | 9
    58                  | "x «" | 10
    59                  | endl | endl;
    60 
    61         sout | "closing delimiters" | endl;
    62         sout
    63                  | 1 | ", x"
    64                  | 2 | ". x"
    65                  | 3 | "; x"
    66                  | 4 | "! x"
    67                  | 5 | "? x"
    68                  | 6 | "% x"
    69                  | 7 | "¢ x"
    70                  | 8 | "» x"
    71                  | 9 | ") x"
    72                  | 10 | "] x"
    73                  | 11 | "} x"
    74                  | endl | endl;
    75 
    76         sout | "opening/closing delimiters" | endl;
    77         sout
    78                  | "x`" | 1 | "`x'" | 2
    79                  | "'x\"" | 3 | "\"x:" | 4
    80                  | ":x " | 5 | " x\t" | 6
    81                  | "\tx\f" | 7 | "\fx\v" | 8
    82                  | "\vx\n" | 9 | "\nx\r" | 10
    83                  | "\rx"
    84                  | endl | endl;
    85 
    86         sout | "override opening/closing delimiters" | endl;
    87         sout | "x ( " | 1 | " ) x" | 2 | " , x" | 3 | " :x: " | 4 | endl;
    88         sout | endl;
    8939
    9040        ifstream in = { "io.data" };                                            // create / open file
     
    181131// Local Variables: //
    182132// tab-width: 4 //
    183 // compile-command: "cfa io.c" //
     133// compile-command: "cfa io2.c" //
    184134// End: //
  • src/tests/math1.c

    r13073be r8dbedfc  
    1010// Created On       : Fri Apr 22 14:59:21 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Aug 11 15:16:41 2017
    13 // Update Count     : 84
     12// Last Modified On : Thu May 24 21:01:15 2018
     13// Update Count     : 85
    1414//
    1515
     
    4848    sout | "\\" | b | b \ e | endl;
    4949    sout | "\\" | 'a' \ 3u | 2 \ 8u | 4 \ 3u | -4 \ 3u | 4 \ -3 | -4 \ -3 | 4.0 \ 2.1 | (1.0f+2.0fi) \ (3.0f+2.0fi) | endl;
    50 
    51         //---------------------- Logarithm ----------------------
    52 
    53         sout | "log:" | log( 1.0F ) | log( 1.0D ) | log( 1.0L ) | log( 1.0F+1.0FI ) | log( 1.0D+1.0DI ) | log( 1.0DL+1.0LI ) | endl;
    54         sout | "log2:" | log2( 8.0F ) | log2( 8.0D ) | log2( 8.0L ) | endl;
    55         sout | "log10:" | log10( 100.0F ) | log10( 100.0D ) | log10( 100.0L ) | endl;
    56         sout | "log1p:" | log1p( 1.0F ) | log1p( 1.0D ) | log1p( 1.0L ) | endl;
    57         sout | "ilogb:" | ilogb( 1.0F ) | ilogb( 1.0D ) | ilogb( 1.0L ) | endl;
    58         sout | "logb:" | logb( 8.0F ) | logb( 8.0D ) | logb( 8.0L ) | endl;
    59 
    60         sout | "sqrt:" | sqrt( 1.0F ) | sqrt( 1.0D ) | sqrt( 1.0L ) | sqrt( 1.0F+1.0FI ) | sqrt( 1.0D+1.0DI ) | sqrt( 1.0DL+1.0LI ) | endl;
    61         sout | "cbrt:" | cbrt( 27.0F ) | cbrt( 27.0D ) | cbrt( 27.0L ) | endl;
    62         sout | "hypot:" | hypot( 1.0F, -1.0F ) | hypot( 1.0D, -1.0D ) | hypot( 1.0L, -1.0L ) | endl;
    6350} // main
    6451
  • src/tests/math2.c

    r13073be r8dbedfc  
    1010// Created On       : Fri Apr 22 14:59:21 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Aug 11 15:40:04 2017
    13 // Update Count     : 81
     12// Last Modified On : Thu May 24 21:06:10 2018
     13// Update Count     : 82
    1414//
    1515
     
    2121        double d;
    2222        long double l;
     23
     24        //---------------------- Logarithm ----------------------
     25
     26        sout | "log:" | log( 1.0F ) | log( 1.0D ) | log( 1.0L ) | log( 1.0F+1.0FI ) | log( 1.0D+1.0DI ) | log( 1.0DL+1.0LI ) | endl;
     27        sout | "log2:" | log2( 8.0F ) | log2( 8.0D ) | log2( 8.0L ) | endl;
     28        sout | "log10:" | log10( 100.0F ) | log10( 100.0D ) | log10( 100.0L ) | endl;
     29        sout | "log1p:" | log1p( 1.0F ) | log1p( 1.0D ) | log1p( 1.0L ) | endl;
     30        sout | "ilogb:" | ilogb( 1.0F ) | ilogb( 1.0D ) | ilogb( 1.0L ) | endl;
     31        sout | "logb:" | logb( 8.0F ) | logb( 8.0D ) | logb( 8.0L ) | endl;
     32
     33        sout | "sqrt:" | sqrt( 1.0F ) | sqrt( 1.0D ) | sqrt( 1.0L ) | sqrt( 1.0F+1.0FI ) | sqrt( 1.0D+1.0DI ) | sqrt( 1.0DL+1.0LI ) | endl;
     34        sout | "cbrt:" | cbrt( 27.0F ) | cbrt( 27.0D ) | cbrt( 27.0L ) | endl;
     35        sout | "hypot:" | hypot( 1.0F, -1.0F ) | hypot( 1.0D, -1.0D ) | hypot( 1.0L, -1.0L ) | endl;
    2336
    2437        //---------------------- Trigonometric ----------------------
     
    3245        sout | "atan2:" | atan2( 1.0F, 1.0F ) | atan2( 1.0D, 1.0D ) | atan2( 1.0L, 1.0L );
    3346        sout | "atan:" | atan( 1.0F, 1.0F ) | atan( 1.0D, 1.0D ) | atan( 1.0L, 1.0L ) | endl;
    34 
    35         //---------------------- Hyperbolic ----------------------
    36 
    37         sout | "sinh:" | sinh( 1.0F ) | sinh( 1.0D ) | sinh( 1.0L ) | sinh( 1.0F+1.0FI ) | sinh( 1.0D+1.0DI ) | sinh( 1.0DL+1.0LI ) | endl;
    38         sout | "cosh:" | cosh( 1.0F ) | cosh( 1.0D ) | cosh( 1.0L ) | cosh( 1.0F+1.0FI ) | cosh( 1.0D+1.0DI ) | cosh( 1.0DL+1.0LI ) | endl;
    39         sout | "tanh:" | tanh( 1.0F ) | tanh( 1.0D ) | tanh( 1.0L ) | tanh( 1.0F+1.0FI ) | tanh( 1.0D+1.0DI ) | tanh( 1.0DL+1.0LI ) | endl;
    40         sout | "acosh:" | acosh( 1.0F ) | acosh( 1.0D ) | acosh( 1.0L ) | acosh( 1.0F+1.0FI ) | acosh( 1.0D+1.0DI ) | acosh( 1.0DL+1.0LI ) | endl;
    41         sout | "asinh:" | asinh( 1.0F ) | asinh( 1.0D ) | asinh( 1.0L ) | asinh( 1.0F+1.0FI ) | asinh( 1.0D+1.0DI ) | asinh( 1.0DL+1.0LI ) | endl;
    42         sout | "atanh:" | atanh( 1.0F ) | atanh( 1.0D ) | atanh( 1.0L ) | atanh( 1.0F+1.0FI ) | atanh( 1.0D+1.0DI ) | atanh( 1.0DL+1.0LI ) | endl;
    43 
    44         //---------------------- Error / Gamma ----------------------
    45 
    46         sout | "erf:" | erf( 1.0F ) | erf( 1.0D ) | erf( 1.0L ) | endl;
    47         sout | "erfc:" | erfc( 1.0F ) | erfc( 1.0D ) | erfc( 1.0L ) | endl;
    48         sout | "lgamma:" | lgamma( 4.0F ) | lgamma( 4.0D ) | lgamma( 4.0L ) | endl;
    49         int sign;
    50         f = lgamma( 4.0F, &sign );
    51         sout | "lgamma:" | f | sign;
    52         d = lgamma( 4.0D, &sign );
    53         sout | d | sign;
    54         l = lgamma( 4.0L, &sign );
    55         sout | l | sign | endl;
    56         sout | "tgamma:" | tgamma( 4.0F ) | tgamma( 4.0D ) | tgamma( 4.0L ) | endl;
    5747} // main
    5848
  • src/tests/math3.c

    r13073be r8dbedfc  
    1010// Created On       : Fri Apr 22 14:59:21 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Aug 11 15:40:03 2017
    13 // Update Count     : 81
     12// Last Modified On : Thu May 24 21:06:12 2018
     13// Update Count     : 82
    1414//
    1515
     
    2222        long double l;
    2323
    24         //---------------------- Nearest Integer ----------------------
     24        //---------------------- Hyperbolic ----------------------
    2525
    26         sout | "floor:" | floor( 1.2F ) | floor( 1.2D ) | floor( 1.2L ) | endl;
    27         sout | "ceil:" | ceil( 1.6F ) | ceil( 1.6D ) | ceil( 1.6L ) | endl;
    28         sout | "trunc:" | trunc( 3.5F ) | trunc( 3.5D ) | trunc( 3.5L ) | endl;
    29         sout | "rint:" | (float)rint( 1.5F ) | (double)rint( 1.5D ) | (long double)rint( 1.5L ) | endl;
    30         sout | "rint:" | (long int)rint( 1.5F ) | (long int)rint( 1.5D ) | (long int)rint( 1.5L ) | endl;
    31         sout | "rint:" | (long long int)rint( 1.5F ) | (long long int)rint( 1.5D ) | (long long int)rint( 1.5L ) | endl;
    32         sout | "lrint:" | lrint( 1.5F ) | lrint( 1.5D ) | lrint( 1.5L ) | endl;
    33         sout | "llrint:" | llrint( 1.5F ) | llrint( 1.5D ) | llrint( 1.5L ) | endl;
    34         sout | "nearbyint:" | nearbyint( 3.5F ) | nearbyint( 3.5D ) | nearbyint( 3.5L ) | endl;
    35         sout | "round:" | (float)round( 1.5F ) | (double)round( 1.5D ) | (long double)round( 1.5L ) | endl;
    36         sout | "round:" | (long int)round( 1.5F ) | (long int)round( 1.5D ) | (long int)round( 1.5L ) | endl;
    37         sout | "round:" | (long long int)round( 1.5F ) | (long long int)round( 1.5D ) | (long long int)round( 1.5L ) | endl;
    38         sout | "lround:" | lround( 1.5F ) | lround( 1.5D ) | lround( 1.5L ) | endl;
    39         sout | "llround:" | llround( 1.5F ) | llround( 1.5D ) | llround( 1.5L ) | endl;
     26        sout | "sinh:" | sinh( 1.0F ) | sinh( 1.0D ) | sinh( 1.0L ) | sinh( 1.0F+1.0FI ) | sinh( 1.0D+1.0DI ) | sinh( 1.0DL+1.0LI ) | endl;
     27        sout | "cosh:" | cosh( 1.0F ) | cosh( 1.0D ) | cosh( 1.0L ) | cosh( 1.0F+1.0FI ) | cosh( 1.0D+1.0DI ) | cosh( 1.0DL+1.0LI ) | endl;
     28        sout | "tanh:" | tanh( 1.0F ) | tanh( 1.0D ) | tanh( 1.0L ) | tanh( 1.0F+1.0FI ) | tanh( 1.0D+1.0DI ) | tanh( 1.0DL+1.0LI ) | endl;
     29        sout | "acosh:" | acosh( 1.0F ) | acosh( 1.0D ) | acosh( 1.0L ) | acosh( 1.0F+1.0FI ) | acosh( 1.0D+1.0DI ) | acosh( 1.0DL+1.0LI ) | endl;
     30        sout | "asinh:" | asinh( 1.0F ) | asinh( 1.0D ) | asinh( 1.0L ) | asinh( 1.0F+1.0FI ) | asinh( 1.0D+1.0DI ) | asinh( 1.0DL+1.0LI ) | endl;
     31        sout | "atanh:" | atanh( 1.0F ) | atanh( 1.0D ) | atanh( 1.0L ) | atanh( 1.0F+1.0FI ) | atanh( 1.0D+1.0DI ) | atanh( 1.0DL+1.0LI ) | endl;
    4032
    41         //---------------------- Manipulation ----------------------
     33        //---------------------- Error / Gamma ----------------------
    4234
    43         sout | "copysign:" | copysign( 1.0F, -1.0F ) | copysign( 1.0D, -1.0D ) | copysign( 1.0L, -1.0L ) | endl;
    44         int exp;
    45         f = frexp( 4.0F, &exp );
    46         sout | "frexp:" | f | exp;
    47         d = frexp( 4.0D, &exp );
    48         sout | d | exp;
    49         l = frexp( 4.0L, &exp );
    50         sout | l | exp | endl;
    51         sout | "ldexp:" | ldexp( 2.0F, 2 ) | ldexp( 2.0D, 2 ) | ldexp( 2.0L, 2 ) | endl;
    52         float fi;
    53         double di;
    54         long double ldi;
    55         f = modf( 2.3F, &fi );
    56         sout | "modf:" | fi | f;
    57         d = modf( 2.3D, &di );
    58         sout | di | d;
    59         l = modf( 2.3L, &ldi );
    60         sout | ldi | l | endl;
    61         sout | "modf:" | modf( 2.3F ) | modf( 2.3D ) | modf( 2.3L ) | endl;
    62         sout | "nextafter:" | nextafter( 2.0F, 3.0F ) | nextafter( 2.0D, 3.0D ) | nextafter( 2.0L, 3.0L ) | endl;
    63         sout | "nexttoward:" | nexttoward( 2.0F, 3.0F ) | nexttoward( 2.0D, 3.0D ) | nexttoward( 2.0L, 3.0L ) | endl;
    64 
    65         sout | "scalbn:" | scalbn( 2.0F, 3 ) | scalbn( 2.0D, 3 ) | scalbn( 2.0L, 3 ) | endl;
    66         sout | "scalbln:" | scalbln( 2.0F, 3L ) | scalbln( 2.0D, 3L ) | scalbln( 2.0L, 3L ) | endl;
     35        sout | "erf:" | erf( 1.0F ) | erf( 1.0D ) | erf( 1.0L ) | endl;
     36        sout | "erfc:" | erfc( 1.0F ) | erfc( 1.0D ) | erfc( 1.0L ) | endl;
     37        sout | "lgamma:" | lgamma( 4.0F ) | lgamma( 4.0D ) | lgamma( 4.0L ) | endl;
     38        int sign;
     39        f = lgamma( 4.0F, &sign );
     40        sout | "lgamma:" | f | sign;
     41        d = lgamma( 4.0D, &sign );
     42        sout | d | sign;
     43        l = lgamma( 4.0L, &sign );
     44        sout | l | sign | endl;
     45        sout | "tgamma:" | tgamma( 4.0F ) | tgamma( 4.0D ) | tgamma( 4.0L ) | endl;
    6746} // main
    6847
  • src/tests/preempt_longrun/Makefile.am

    r13073be r8dbedfc  
    1717repeats=10
    1818max_time=600
    19 preempt=1_000ul
     19preempt=10ul\`ms
    2020debug=-debug
    2121
  • src/tests/preempt_longrun/Makefile.in

    r13073be r8dbedfc  
    450450repeats = 10
    451451max_time = 600
    452 preempt = 1_000ul
     452preempt = 10ul\`ms
    453453debug = -debug
    454454REPEAT = ${abs_top_srcdir}/tools/repeat
  • src/tests/preempt_longrun/create.c

    r13073be r8dbedfc  
    11#include <kernel>
    22#include <thread>
    3 
    4 static const unsigned long N = 60_000ul;
     3#include <time>
    54
    65#ifndef PREEMPTION_RATE
    7 #define PREEMPTION_RATE 10`ms
     6#error PREEMPTION_RATE not defined in makefile
    87#endif
    98
     
    1110        return PREEMPTION_RATE;
    1211}
     12
     13static const unsigned long N = 60_000ul;
    1314
    1415thread worker_t {};
  • src/tests/preempt_longrun/enter.c

    r13073be r8dbedfc  
    22#include <monitor>
    33#include <thread>
    4 
    5 static const unsigned long N  = 2_100_000ul;
     4#include <time>
    65
    76#ifndef PREEMPTION_RATE
    8 #define PREEMPTION_RATE 10`ms
     7#error PREEMPTION_RATE not defined in makefile
    98#endif
    109
     
    1211        return PREEMPTION_RATE;
    1312}
     13
     14static const unsigned long N  = 2_100_000ul;
    1415
    1516monitor mon_t {};
  • src/tests/preempt_longrun/enter3.c

    r13073be r8dbedfc  
    22#include <monitor>
    33#include <thread>
    4 
    5 static const unsigned long N  = 500_000ul;
     4#include <time>
    65
    76#ifndef PREEMPTION_RATE
    8 #define PREEMPTION_RATE 10`ms
     7#error PREEMPTION_RATE not defined in makefile
    98#endif
    109
     
    1211        return PREEMPTION_RATE;
    1312}
     13
     14static const unsigned long N  = 500_000ul;
    1415
    1516monitor mon_t {};
  • src/tests/preempt_longrun/processor.c

    r13073be r8dbedfc  
    11#include <kernel>
    22#include <thread>
    3 
    4 static const unsigned long N = 5_000ul;
     3#include <time>
    54
    65#ifndef PREEMPTION_RATE
    7 #define PREEMPTION_RATE 10`ms
     6#error PREEMPTION_RATE not defined in makefile
    87#endif
    98
     
    1110        return PREEMPTION_RATE;
    1211}
     12
     13static const unsigned long N = 5_000ul;
    1314
    1415int main(int argc, char* argv[]) {
  • src/tests/preempt_longrun/stack.c

    r13073be r8dbedfc  
    11#include <kernel>
     2#include <math>
    23#include <thread>
    3 
    4 #include <math>
     4#include <time>
    55
    66#ifndef PREEMPTION_RATE
    7 #define PREEMPTION_RATE 10`ms
     7#error PREEMPTION_RATE not defined in makefile
    88#endif
    99
  • src/tests/preempt_longrun/yield.c

    r13073be r8dbedfc  
    11#include <kernel>
    22#include <thread>
     3#include <time>
     4
     5#ifndef PREEMPTION_RATE
     6#error PREEMPTION_RATE not defined in makefile
     7#endif
     8
     9Duration default_preemption() {
     10        return PREEMPTION_RATE;
     11}
    312
    413#ifdef LONG_TEST
     
    716static const unsigned long N = 325_000ul;
    817#endif
    9 
    10 #ifndef PREEMPTION_RATE
    11 #define PREEMPTION_RATE 10`ms
    12 #endif
    13 
    14 Duration default_preemption() {
    15         return PREEMPTION_RATE;
    16 }
    1718
    1819thread worker_t {};
  • src/tests/test.py

    r13073be r8dbedfc  
    7878                        else :
    7979                                print('ERROR: No expected file for test %s, ignoring it' % testname, file=sys.stderr)
    80 
    81         # make sure we have at least some test to run
    82         if not tests :
    83                 print('ERROR: No valid test to run', file=sys.stderr)
    84                 sys.exit(1)
    8580
    8681        return tests
     
    266261                tests = validTests( options )
    267262
     263        # make sure we have at least some test to run
     264        if not tests :
     265                print('ERROR: No valid test to run', file=sys.stderr)
     266                sys.exit(1)
     267
     268
    268269        # sort the test alphabetically for convenience
    269270        tests.sort(key=lambda t: (t.arch if t.arch else '') + t.target())
Note: See TracChangeset for help on using the changeset viewer.