Changeset 6c2ba38
- Timestamp:
- Nov 28, 2017, 3:52:06 PM (7 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- 383e159, 8d5b9cf
- Parents:
- cf966b5 (diff), 8a0a64d9 (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. - Files:
-
- 9 added
- 32 edited
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
rcf966b5 r6c2ba38 25 25 include 26 26 share 27 *.class 27 28 28 29 # src executables, for lib and bin -
doc/refrat/refrat.tex
rcf966b5 r6c2ba38 11 11 %% Created On : Wed Apr 6 14:52:25 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Sun Aug 6 10:25:31 201714 %% Update Count : 10 513 %% Last Modified On : Tue Aug 15 18:46:31 2017 14 %% Update Count : 106 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 492 492 493 493 \begin{rationale} 494 The use of ``©?©'' in identifiers means that some C programs are not \CFA programs. For instance, the sequence of characters ``©(i < 0)?--i:i©'' is legal in a C program, but a495 \CFA compiler detects a syntax error because it treats ``©?--©'' as an identifier, not as the two tokens ``©?©'' and ``©--©''.494 The use of ``©?©'' in identifiers means that some C programs are not \CFA programs. 495 For instance, the sequence of characters ``©(i < 0)?--i:i©'' is legal in a C program, but a \CFA compiler detects a syntax error because it treats ``©?--©'' as an identifier, not as the two tokens ``©?©'' and ``©--©''. 496 496 \end{rationale} 497 497 -
doc/user/user.tex
rcf966b5 r6c2ba38 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Sun Aug 6 10:24:21201714 %% Update Count : 3 03613 %% Last Modified On : Mon Nov 27 18:09:59 2017 14 %% Update Count : 3143 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 59 59 \CFAStyle % use default CFA format-style 60 60 \lstnewenvironment{C++}[1][] % use C++ style 61 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®} #1}}61 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®},#1}} 62 62 {} 63 63 … … 777 777 case 7: 778 778 ... 779 ®break® §\C{// redundant explicit end of switch}§779 ®break® §\C{// explicit end of switch (redundant)}§ 780 780 default: 781 781 j = 3; … … 806 806 ®int k = 0;® §\C{// allowed at different nesting levels}§ 807 807 ... 808 ®case 2:® §\C{// disallow case in nested statements}§ 808 809 } 809 810 ... … … 962 963 \end{cfa} 963 964 965 The components in the "with" clause 966 967 with a, b, c { ... } 968 969 serve 2 purposes: each component provides a type and object. The type must be a 970 structure type. Enumerations are already opened, and I think a union is opened 971 to some extent, too. (Or is that just unnamed unions?) The object is the target 972 that the naked structure-fields apply to. The components are open in "parallel" 973 at the scope of the "with" clause/statement, so opening "a" does not affect 974 opening "b", etc. This semantic is different from Pascal, which nests the 975 openings. 976 977 Having said the above, it seems reasonable to allow a "with" component to be an 978 expression. The type is the static expression-type and the object is the result 979 of the expression. Again, the type must be an aggregate. Expressions require 980 parenthesis around the components. 981 982 with( a, b, c ) { ... } 983 984 Does this now make sense? 985 986 Having written more CFA code, it is becoming clear to me that I *really* want 987 the "with" to be implemented because I hate having to type all those object 988 names for fields. It's a great way to drive people away from the language. 989 964 990 965 991 \section{Exception Handling} … … 977 1003 try { 978 1004 f(...); 979 } catch( E e :§boolean-predicate§ ) { §\C[8cm]{// termination handler}§1005 } catch( E e ; §boolean-predicate§ ) { §\C[8cm]{// termination handler}§ 980 1006 // recover and continue 981 } catchResume( E e :§boolean-predicate§ ) { §\C{// resumption handler}\CRT§1007 } catchResume( E e ; §boolean-predicate§ ) { §\C{// resumption handler}\CRT§ 982 1008 // repair and return 983 1009 } finally { … … 1872 1898 \end{cfa} 1873 1899 This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa). 1874 It is possible to declare multiple routine-prototypes in a single declaration, but the entire type specification is distributed across \emph{all} routine names in the declaration list (see~\VRef{s:Declarations}), \eg: 1875 \begin{quote2} 1876 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 1877 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1878 \begin{cfa} 1879 [ int ] f( int ), g; 1880 \end{cfa} 1881 & 1882 \begin{cfa} 1883 int f( int ), g( int ); 1884 \end{cfa} 1885 \end{tabular} 1886 \end{quote2} 1900 Like C, it is possible to declare multiple routine-prototypes in a single declaration, where the return type is distributed across \emph{all} routine names in the declaration list (see~\VRef{s:Declarations}), \eg: 1901 \begin{cfa} 1902 C : const double bar1(), bar2( int ), bar3( double ); 1903 §\CFA§: [const double] foo(), foo( int ), foo( double ) { return 3.0; } 1904 \end{cfa} 1905 \CFA allows the last routine in the list to define its body. 1906 1887 1907 Declaration qualifiers can only appear at the start of a \CFA routine declaration,\footref{StorageClassSpecifier} \eg: 1888 1908 \begin{cfa} … … 2235 2255 \label{s:MRV_Functions} 2236 2256 2237 In standard C, functions can return at most one value. 2257 In C and most programming languages, functions return at most one value; 2258 however, many operations have multiple outcomes, some exceptional (see~\VRef{s:ExceptionHandling}). 2238 2259 To emulate functions with multiple return values, \emph{\Index{aggregation}} and/or \emph{\Index{aliasing}} is used. 2239 In the former situation, the function designer creates a record type that combines all of the return values into a single type. 2240 For example, consider a function returning the most frequently occurring letter in a string, and its frequency. 2241 This example is complex enough to illustrate that an array is insufficient, since arrays are homogeneous, and demonstrates a potential pitfall that exists with aliasing. 2242 \begin{cfa} 2243 struct mf_ret { 2244 int freq; 2245 char ch; 2246 }; 2247 2248 struct mf_ret most_frequent(const char * str) { 2249 char freqs [26] = { 0 }; 2250 struct mf_ret ret = { 0, 'a' }; 2251 for (int i = 0; str[i] != '\0'; ++i) { 2252 if (isalpha(str[i])) { // only count letters 2253 int ch = tolower(str[i]); // convert to lower case 2254 int idx = ch-'a'; 2255 if (++freqs[idx] > ret.freq) { // update on new max 2256 ret.freq = freqs[idx]; 2257 ret.ch = ch; 2258 } 2259 } 2260 } 2261 return ret; 2262 } 2263 2264 const char * str = "hello world"; 2265 struct mf_ret ret = most_frequent(str); 2266 printf("%s -- %d %c\n", str, ret.freq, ret.ch); 2267 \end{cfa} 2268 Of note, the designer must come up with a name for the return type and for each of its fields. 2269 Unnecessary naming is a common programming language issue, introducing verbosity and a complication of the user's mental model. 2270 That is, adding another named type creates another association in the programmer's mind that needs to be kept track of when reading and writing code. 2271 As such, this technique is effective when used sparingly, but can quickly get out of hand if many functions need to return different combinations of types. 2272 2273 In the latter approach, the designer simulates multiple return values by passing the additional return values as pointer parameters. 2274 The pointer parameters are assigned inside of the routine body to emulate a return. 2275 Using the same example, 2276 \begin{cfa} 2277 int most_frequent(const char * str, char * ret_ch) { 2278 char freqs [26] = { 0 }; 2279 int ret_freq = 0; 2280 for (int i = 0; str[i] != '\0'; ++i) { 2281 if (isalpha(str[i])) { // only count letters 2282 int ch = tolower(str[i]); // convert to lower case 2283 int idx = ch-'a'; 2284 if (++freqs[idx] > ret_freq) { // update on new max 2285 ret_freq = freqs[idx]; 2286 *ret_ch = ch; // assign to out parameter 2287 } 2288 } 2289 } 2290 return ret_freq; // only one value returned directly 2291 } 2292 2293 const char * str = "hello world"; 2294 char ch; // pre-allocate return value 2295 int freq = most_frequent(str, &ch); // pass return value as out parameter 2296 printf("%s -- %d %c\n", str, freq, ch); 2297 \end{cfa} 2298 Notably, using this approach, the caller is directly responsible for allocating storage for the additional temporary return values, which complicates the call site with a sequence of variable declarations leading up to the call. 2299 Also, while a disciplined use of ©const© can give clues about whether a pointer parameter is going to be used as an out parameter, it is not immediately obvious from only the routine signature whether the callee expects such a parameter to be initialized before the call. 2300 Furthermore, while many C routines that accept pointers are designed so that it is safe to pass ©NULL© as a parameter, there are many C routines that are not null-safe. 2301 On a related note, C does not provide a standard mechanism to state that a parameter is going to be used as an additional return value, which makes the job of ensuring that a value is returned more difficult for the compiler. 2302 Interestingly, there is a subtle bug in the previous example, in that ©ret_ch© is never assigned for a string that does not contain any letters, which can lead to undefined behaviour. 2303 In this particular case, it turns out that the frequency return value also doubles as an error code, where a frequency of 0 means the character return value should be ignored. 2260 2261 In the former approach, a record type is created combining all of the return values. 2262 For example, consider C's \Indexc{div} function, which returns the quotient and remainder for a division of an integer value. 2263 \begin{cfa} 2264 typedef struct { int quot, rem; } div_t; §\C[7cm]{// from include stdlib.h}§ 2265 div_t div( int num, int den ); 2266 div_t qr = div( 13, 5 ); §\C{// return quotient/remainder aggregate}§ 2267 printf( "%d %d\n", qr.quot, qr.rem ); §\C{// print quotient/remainder}§ 2268 \end{cfa} 2269 This approach requires a name for the return type and fields, where \Index{naming} is a common programming-language issue. 2270 That is, naming creates an association that must be managed when reading and writing code. 2271 While effective when used sparingly, this approach does not scale when functions need to return multiple combinations of types. 2272 2273 In the latter approach, additional return values are passed as pointer parameters. 2274 A pointer parameter is assigned inside the routine to emulate a return. 2275 For example, consider C's \Indexc{modf} function, which returns the integral and fractional part of a floating-point value. 2276 \begin{cfa} 2277 double modf( double x, double * i ); §\C{// from include math.h}§ 2278 double intp, frac = modf( 13.5, &intp ); §\C{// return integral and fractional components}§ 2279 printf( "%g %g\n", intp, frac ); §\C{// print integral/fractional components}§ 2280 \end{cfa} 2281 This approach requires allocating storage for the return values, which complicates the call site with a sequence of variable declarations leading to the call. 2282 Also, while a disciplined use of ©const© can give clues about whether a pointer parameter is used as an \Index{out parameter}, it is not obvious from the routine signature whether the callee expects such a parameter to be initialized before the call. 2283 Furthermore, while many C routines that accept pointers are safe for a ©NULL© argument, there are many C routines that are not null-safe. 2284 Finally, C does not provide a mechanism to state that a parameter is going to be used as an additional return value, which makes the job of ensuring that a value is returned more difficult for the compiler. 2304 2285 Still, not every routine with multiple return values should be required to return an error code, and error codes are easily ignored, so this is not a satisfying solution. 2305 2286 As with the previous approach, this technique can simulate multiple return values, but in practice it is verbose and error prone. 2306 2287 2307 In \CFA, functions can be declared to return multiple values with an extension tothe function declaration syntax.2288 \CFA allows functions to return multiple values by extending the function declaration syntax. 2308 2289 Multiple return values are declared as a comma-separated list of types in square brackets in the same location that the return type appears in standard C function declarations. 2290 \begin{cfa} 2291 [ char, int, double ] f( ... ); 2292 \end{cfa} 2309 2293 The ability to return multiple values from a function requires a new syntax for the return statement. 2310 2294 For consistency, the return statement in \CFA accepts a comma-separated list of expressions in square brackets. 2311 The expression resolution phase of the \CFA translator ensures that the correct form is used depending on the values being returned and the return type of the current function. 2295 \begin{cfa} 2296 return [ c, i, d ]; 2297 \end{cfa} 2298 The expression resolution ensures the correct form is used depending on the values being returned and the return type of the current function. 2312 2299 A multiple-returning function with return type ©T© can return any expression that is implicitly convertible to ©T©. 2313 Using the running example, the ©most_frequent© function can be written using multiple return values as such, 2314 \begin{cfa} 2315 [int, char] most_frequent(const char * str) { 2316 char freqs [26] = { 0 }; 2317 int ret_freq = 0; 2318 char ret_ch = 'a'; // arbitrary default value for consistent results 2319 for (int i = 0; str[i] != '\0'; ++i) { 2320 if (isalpha(str[i])) { // only count letters 2321 int ch = tolower(str[i]); // convert to lower case 2322 int idx = ch-'a'; 2323 if (++freqs[idx] > ret_freq) { // update on new max 2324 ret_freq = freqs[idx]; 2325 ret_ch = ch; 2326 } 2327 } 2328 } 2329 return [ret_freq, ret_ch]; 2330 } 2331 \end{cfa} 2332 This approach provides the benefits of compile-time checking for appropriate return statements as in aggregation, but without the required verbosity of declaring a new named type, which precludes the bug seen with out-parameters. 2333 2334 The addition of multiple-return-value functions necessitates a syntax for accepting multiple values at the call-site. 2300 2301 A common use of a function's output is input to another function. 2302 \CFA allows this case, without any new syntax; 2303 a multiple-returning function can be used in any of the contexts where an expression is allowed. 2304 When a function call is passed as an argument to another call, the best match of actual arguments to formal parameters is evaluated given all possible expression interpretations in the current scope. 2305 \begin{cfa} 2306 void g( int, int ); §\C{// 1}§ 2307 void g( double, double ); §\C{// 2}§ 2308 g( div( 13, 5 ) ); §\C{// select 1}§ 2309 g( modf( 13.5 ) ); §\C{// select 2}§ 2310 \end{cfa} 2311 In this case, there are two overloaded ©g© routines. 2312 Both calls to ©g© expect two arguments that are matched by the two return values from ©div© and ©modf©. respectively, which are fed directly to the first and second parameters of ©g©. 2313 As well, both calls to ©g© have exact type matches for the two different versions of ©g©, so these exact matches are chosen. 2314 When type matches are not exact, conversions are used to find a best match. 2315 2316 The previous examples can be rewritten passing the multiple returned-values directly to the ©printf© function call. 2317 \begin{cfa} 2318 [ int, int ] div( int x, int y ); §\C{// from include stdlib}§ 2319 printf( "%d %d\n", div( 13, 5 ) ); §\C{// print quotient/remainder}§ 2320 2321 [ double, double ] modf( double x ); §\C{// from include math}§ 2322 printf( "%g %g\n", modf( 13.5 ) ); §\C{// print integral/fractional components}§ 2323 \end{cfa} 2324 This approach provides the benefits of compile-time checking for appropriate return statements as in aggregation, but without the required verbosity of declaring a new named type. 2325 2326 Finally, the addition of multiple-return-value functions necessitates a syntax for retaining the multiple values at the call-site versus their temporary existence during a call. 2335 2327 The simplest mechanism for retaining a return value in C is variable assignment. 2336 By assigning the return value into a variable, its value can be retrieved later at any point in the program.2328 By assigning the multiple return-values into multiple variables, the values can be retrieved later. 2337 2329 As such, \CFA allows assigning multiple values from a function into multiple variables, using a square-bracketed list of lvalue expressions on the left side. 2338 2330 \begin{cfa} 2339 const char * str = "hello world"; 2340 int freq; 2341 char ch; 2342 [freq, ch] = most_frequent(str); // assign into multiple variables 2343 printf("%s -- %d %c\n", str, freq, ch); 2344 \end{cfa} 2345 It is also common to use a function's output as the input to another function. 2346 \CFA also allows this case, without any new syntax. 2347 When a function call is passed as an argument to another call, the expression resolver attempts to find the best match of actual arguments to formal parameters given all of the possible expression interpretations in the current scope \cite{Bilson03}. 2348 For example, 2349 \begin{cfa} 2350 void process(int); // (1) 2351 void process(char); // (2) 2352 void process(int, char); // (3) 2353 void process(char, int); // (4) 2354 2355 process(most_frequent("hello world")); // selects (3) 2356 \end{cfa} 2357 In this case, there is only one option for a function named ©most_frequent© that takes a string as input. 2358 This function returns two values, one ©int© and one ©char©. 2359 There are four options for a function named ©process©, but only two that accept two arguments, and of those the best match is (3), which is also an exact match. 2360 This expression first calls ©most_frequent("hello world")©, which produces the values ©3© and ©'l'©, which are fed directly to the first and second parameters of (3), respectively. 2361 2362 \section{Tuple Expressions} 2331 int quot, rem; 2332 [ quot, rem ] = div( 13, 5 ); §\C{// assign multiple variables}§ 2333 printf( "%d %d\n", quot, rem ); §\C{// print quotient/remainder}\CRT§ 2334 \end{cfa} 2335 Here, the multiple return-values are matched in much the same way as passing multiple return-values to multiple parameters in a call. 2336 2337 2338 \subsection{Expressions} 2339 2363 2340 Multiple-return-value functions provide \CFA with a new syntax for expressing a combination of expressions in the return statement and a combination of types in a function signature. 2364 These notions can be generalized to provide \CFA with \emph{tuple expressions} and \emph{tuple types}.2341 These notions are generalized to provide \CFA with \newterm{tuple expression}s and \newterm{tuple type}s. 2365 2342 A tuple expression is an expression producing a fixed-size, ordered list of values of heterogeneous types. 2366 The type of a tuple expression is the tuple of the subexpression types, or a \emph{tuple type}. 2343 The type of a tuple expression is the tuple of the subexpression types, or a tuple type. 2344 2367 2345 In \CFA, a tuple expression is denoted by a comma-separated list of expressions enclosed in square brackets. 2368 2346 For example, the expression ©[5, 'x', 10.5]© has type ©[int, char, double]©. … … 2371 2349 The order of evaluation of the components in a tuple expression is unspecified, to allow a compiler the greatest flexibility for program optimization. 2372 2350 It is, however, guaranteed that each component of a tuple expression is evaluated for side-effects, even if the result is not used. 2373 Multiple-return-value functions can equivalently be called \emph{tuple-returning functions}. 2374 2375 \subsection{Tuple Variables} 2376 The call-site of the ©most_frequent© routine has a notable blemish, in that it required the preallocation of return variables in a manner similar to the aliasing example, since it is impossible to declare multiple variables of different types in the same declaration in standard C. 2377 In \CFA, it is possible to overcome this restriction by declaring a \emph{tuple variable}. 2378 \begin{cfa}[emph=ret, emphstyle=\color{red}] 2379 const char * str = "hello world"; 2380 [int, char] ret = most_frequent(str); // initialize tuple variable 2381 printf("%s -- %d %c\n", str, ret); 2382 \end{cfa} 2383 It is now possible to accept multiple values into a single piece of storage, in much the same way that it was previously possible to pass multiple values from one function call to another. 2384 These variables can be used in any of the contexts where a tuple expression is allowed, such as in the ©printf© function call. 2385 As in the ©process© example, the components of the tuple value are passed as separate parameters to ©printf©, allowing very simple printing of tuple expressions. 2386 One way to access the individual components is with a simple assignment, as in previous examples. 2387 \begin{cfa} 2388 int freq; 2389 char ch; 2390 [freq, ch] = ret; 2391 \end{cfa} 2392 2393 \begin{sloppypar} 2351 Multiple-return-value functions can equivalently be called \newterm{tuple-returning functions}. 2352 2353 2354 \subsection{Variables} 2355 2356 The previous call of ©div© still requires the preallocation of multiple return-variables in a manner similar to the aliasing example. 2357 In \CFA, it is possible to overcome this restriction by declaring a \newterm{tuple variable}. 2358 \begin{cfa} 2359 [int, int] ®qr® = div( 13, 5 ); §\C{// initialize tuple variable}§ 2360 printf( "%d %d\n", ®qr® ); §\C{// print quotient/remainder}§ 2361 \end{cfa} 2362 It is now possible to match the multiple return-values to a single variable, in much the same way as \Index{aggregation}. 2363 As well, the components of the tuple value are passed as separate parameters to ©printf©, allowing direct printing of tuple variables. 2364 One way to access the individual components of a tuple variable is with assignment. 2365 \begin{cfa} 2366 [ quot, rem ] = qr; §\C{// assign multiple variables}§ 2367 \end{cfa} 2368 2394 2369 In addition to variables of tuple type, it is also possible to have pointers to tuples, and arrays of tuples. 2395 2370 Tuple types can be composed of any types, except for array types, since array assignment is disallowed, which makes tuple assignment difficult when a tuple contains an array. 2396 2371 \begin{cfa} 2397 [ double, int] di;2398 [ double, int] * pdi2399 [ double, int] adi[10];2372 [ double, int ] di; 2373 [ double, int ] * pdi 2374 [ double, int ] adi[10]; 2400 2375 \end{cfa} 2401 2376 This examples declares a variable of type ©[double, int]©, a variable of type pointer to ©[double, int]©, and an array of ten ©[double, int]©. 2402 \end{sloppypar} 2403 2404 \subsection{Tuple Indexing} 2405 2406 At times, it is desirable to access a single component of a tuple-valued expression without creating unnecessary temporary variables to assign to. 2407 Given a tuple-valued expression ©e© and a compile-time constant integer $i$ where $0 \leq i < n$, where $n$ is the number of components in ©e©, ©e.i© accesses the $i$\textsuperscript{th} component of ©e©. 2408 For example, 2377 2378 2379 \subsection{Indexing} 2380 2381 It is also possible to access a single component of a tuple-valued expression without creating temporary variables. 2382 Given a tuple-valued expression $e$np and a compile-time constant integer $i$ where $0 \leq i < n$, where $n$ is the number of components in $e$, $e.i$ accesses the $i^{\:th}$ component of $e$, \eg: 2409 2383 \begin{cfa} 2410 2384 [int, double] x; … … 2417 2391 p->0 = 5; §\C{// access int component of tuple pointed-to by p}§ 2418 2392 g( x.1, x.0 ); §\C{// rearrange x to pass to g}§ 2419 double z = [ x, f()].0.1; §\C{// access second component of first component of tuple expression}§2420 \end{cfa} 2421 As seen above, tuple-index expressions can occur on any tuple-typed expression, including tuple-returning functions, square-bracketed tuple expressions, and other tuple-index expressions, provided the retrieved component is also a tuple.2393 double z = [ x, f() ].0.1; §\C{// access second component of first component of tuple expression}§ 2394 \end{cfa} 2395 Tuple-index expressions can occur on any tuple-typed expression, including tuple-returning functions, square-bracketed tuple expressions, and other tuple-index expressions, provided the retrieved component is also a tuple. 2422 2396 This feature was proposed for \KWC but never implemented \cite[p.~45]{Till89}. 2423 2397 2398 2424 2399 \subsection{Flattening and Structuring} 2400 2425 2401 As evident in previous examples, tuples in \CFA do not have a rigid structure. 2426 2402 In function call contexts, tuples support implicit flattening and restructuring conversions. … … 2465 2441 There is only a single definition of ©f©, and 3 arguments with only single interpretations. 2466 2442 First, the argument alternative list ©[5, 10.2], 4© is flattened to produce the argument list ©5, 10.2, 4©. 2467 Next, the parameter matching algorithm begins, with $P = $©int© and $A = $©int©, which unifies exactly.2468 Moving to the next parameter and argument, $P = $©[double, int]© and $A = $©double©.2469 This time, the parameter is a tuple type, so the algorithm applies recursively with $P' = $©double© and $A = $©double©, which unifies exactly.2470 Then $P' = $©int© and $A = $©double©, which again unifies exactly.2443 Next, the parameter matching algorithm begins, with $P =$© int© and $A =$© int©, which unifies exactly. 2444 Moving to the next parameter and argument, $P =$© [double, int]© and $A =$© double©. 2445 This time, the parameter is a tuple type, so the algorithm applies recursively with $P' =$© double© and $A =$© double©, which unifies exactly. 2446 Then $P' =$© int© and $A =$© double©, which again unifies exactly. 2471 2447 At this point, the end of $P'$ has been reached, so the arguments ©10.2, 4© are structured into the tuple expression ©[10.2, 4]©. 2472 2448 Finally, the end of the parameter list $P$ has also been reached, so the final expression is ©f(5, [10.2, 4])©. 2473 2449 2474 \section{Tuple Assignment} 2450 2451 \subsection{Assignment} 2475 2452 \label{s:TupleAssignment} 2476 An assignment where the left side of the assignment operator has a tuple type is called tuple assignment. 2477 There are two kinds of tuple assignment depending on whether the right side of the assignment operator has a tuple type or a non-tuple type, called \emph{Multiple} and \emph{Mass} Assignment, respectively. 2453 2454 An assignment where the left side of the assignment operator has a tuple type is called \newterm{tuple assignment}. 2455 There are two kinds of tuple assignment depending on whether the right side of the assignment operator has a non-tuple or tuple type, called \newterm[mass assignment]{mass} and \newterm[multiple assignment]{multiple} assignment, respectively. 2478 2456 \begin{cfa} 2479 2457 int x; 2480 2458 double y; 2481 2459 [int, double] z; 2482 [y, x] = 3.14; // mass assignment2483 [x, y] = z; // multiple assignment2484 z = 10; // mass assignment2485 z = [x, y]; // multiple assignment2460 [y, x] = 3.14; §\C{// mass assignment}§ 2461 [x, y] = z; §\C{// multiple assignment}§ 2462 z = 10; §\C{// mass assignment}§ 2463 z = [x, y]; §\C{// multiple assignment}§ 2486 2464 \end{cfa} 2487 2465 Let $L_i$ for $i$ in $[0, n)$ represent each component of the flattened left side, $R_i$ represent each component of the flattened right side of a multiple assignment, and $R$ represent the right side of a mass assignment. … … 2490 2468 For example, the following is invalid because the number of components on the left does not match the number of components on the right. 2491 2469 \begin{cfa} 2492 [ int, int] x, y, z;2493 [ x, y] = z; // multiple assignment, invalid 4 != 22470 [ int, int ] x, y, z; 2471 [ x, y ] = z; §\C{// multiple assignment, invalid 4 != 2}§ 2494 2472 \end{cfa} 2495 2473 Multiple assignment assigns $R_i$ to $L_i$ for each $i$. … … 2507 2485 \begin{cfa} 2508 2486 int x = 10, y = 20; 2509 [ x, y] = [y, x];2487 [ x, y ] = [ y, x ]; 2510 2488 \end{cfa} 2511 2489 After executing this code, ©x© has the value ©20© and ©y© has the value ©10©. … … 2526 2504 int a, b; 2527 2505 double c, d; 2528 [ void] f([int, int]);2529 f( [c, a] = [b, d] = 1.5); // assignments in parameter list2506 [ void ] f( [ int, int ] ); 2507 f( [ c, a ] = [ b, d ] = 1.5 ); // assignments in parameter list 2530 2508 \end{cfa} 2531 2509 The tuple expression begins with a mass assignment of ©1.5© into ©[b, d]©, which assigns ©1.5© into ©b©, which is truncated to ©1©, and ©1.5© into ©d©, producing the tuple ©[1, 1.5]© as a result. … … 2533 2511 Finally, the tuple ©[1, 1]© is used as an expression in the call to ©f©. 2534 2512 2535 \subsection{Tuple Construction} 2513 2514 \subsection{Construction} 2515 2536 2516 Tuple construction and destruction follow the same rules and semantics as tuple assignment, except that in the case where there is no right side, the default constructor or destructor is called on each component of the tuple. 2537 2517 As constructors and destructors did not exist in previous versions of \CFA or in \KWC, this is a primary contribution of this thesis to the design of tuples. … … 2569 2549 The initialization of ©s© with ©t© works by default because ©t© is flattened into its components, which satisfies the generated field constructor ©?{}(S *, int, double)© to initialize the first two values. 2570 2550 2571 \section{Member-Access Tuple Expression} 2551 2552 \subsection{Member-Access Expression} 2572 2553 \label{s:MemberAccessTuple} 2573 It is possible to access multiple fields from a single expression using a \emph{Member-Access Tuple Expression}. 2554 2555 Tuples may be used to select multiple fields of a record by field name. 2574 2556 The result is a single tuple-valued expression whose type is the tuple of the types of the members. 2575 2557 For example, 2576 2558 \begin{cfa} 2577 struct S { int x; double y; char *z; } s;2559 struct S { char x; int y; double z; } s; 2578 2560 s.[x, y, z]; 2579 2561 \end{cfa} 2580 Here, the type of ©s.[x, y, z]© is ©[int, double, char *]©. 2581 A member tuple expression has the form ©a.[x, y, z];© where ©a© is an expression with type ©T©, where ©T© supports member access expressions, and ©x, y, z© are all members of ©T© with types ©T$_x$©, ©T$_y$©, and ©T$_z$© respectively. 2582 Then the type of ©a.[x, y, z]© is ©[T_x, T_y, T_z]©. 2583 2584 Since tuple index expressions are a form of member-access expression, it is possible to use tuple-index expressions in conjunction with member tuple expressions to manually restructure a tuple (\eg, rearrange components, drop components, duplicate components, etc.). 2585 \begin{cfa} 2586 [int, int, long, double] x; 2587 void f(double, long); 2588 2589 f(x.[0, 3]); // f(x.0, x.3) 2590 x.[0, 1] = x.[1, 0]; // [x.0, x.1] = [x.1, x.0] 2591 [long, int, long] y = x.[2, 0, 2]; 2592 \end{cfa} 2593 2594 It is possible for a member tuple expression to contain other member access expressions. 2595 For example, 2562 Here, the type of ©s.[ x, y, z ]© is ©[ char, int, double ]©. 2563 A member tuple expression has the form \emph{e}©.[x, y, z];© where \emph{e} is an expression with type ©T©, where ©T© supports member access expressions, and ©x, y, z© are all members of ©T© with types ©T$_x$©, ©T$_y$©, and ©T$_z$© respectively. 2564 Then the type of \emph{e}©.[x, y, z]© is ©[T$_x$, T$_y$, T$_z$]©. 2565 2566 A member-access tuple may be used anywhere a tuple can be used, \eg: 2567 \begin{cfa} 2568 s.[ y, z, x ] = [ 3, 3.2, 'x' ]; §\C{// equivalent to s.x = 'x', s.y = 3, s.z = 3.2}§ 2569 f( s.[ y, z ] ); §\C{// equivalent to f( s.y, s.z )}§ 2570 \end{cfa} 2571 Note, the fields appearing in a record-field tuple may be specified in any order; 2572 also, it is unnecessary to specify all the fields of a struct in a multiple record-field tuple. 2573 2574 Since tuple-index expressions are a form of member-access expression, it is possible to use tuple-index expressions in conjunction with member-access expressions to restructure a tuple (\eg, rearrange components, drop components, duplicate components, etc.). 2575 \begin{cfa} 2576 [ int, int, long, double ] x; 2577 void f( double, long ); 2578 2579 f( x.[ 0, 3 ] ); §\C{// f( x.0, x.3 )}§ 2580 x.[ 0, 1 ] = x.[ 1, 0 ]; §\C{// [ x.0, x.1 ] = [ x.1, x.0 ]}§ 2581 [ long, int, long ] y = x.[ 2, 0, 2 ]; 2582 \end{cfa} 2583 2584 It is possible for a member tuple expression to contain other member access expressions, \eg: 2596 2585 \begin{cfa} 2597 2586 struct A { double i; int j; }; 2598 2587 struct B { int * k; short l; }; 2599 2588 struct C { int x; A y; B z; } v; 2600 v.[ x, y.[i, j], z.k];2601 \end{cfa} 2602 This expression is equivalent to ©[ v.x, [v.y.i, v.y.j], v.z.k]©.2603 That is, the aggregate expression is effectively distributed across the tuple , which allows simple and easy access to multiple components in an aggregate,without repetition.2589 v.[ x, y.[ i, j ], z.k ]; 2590 \end{cfa} 2591 This expression is equivalent to ©[ v.x, [ v.y.i, v.y.j ], v.z.k ]©. 2592 That is, the aggregate expression is effectively distributed across the tuple allowing simple and easy access to multiple components in an aggregate without repetition. 2604 2593 It is guaranteed that the aggregate expression to the left of the ©.© in a member tuple expression is evaluated exactly once. 2605 As such, it is safe to use member tuple expressions on the result of a side-effecting function.2606 \begin{cfa} 2607 [ int, float, double] f();2608 [ double, float] x = f().[2, 1];2594 As such, it is safe to use member tuple expressions on the result of a function with side-effects. 2595 \begin{cfa} 2596 [ int, float, double ] f(); 2597 [ double, float ] x = f().[ 2, 1 ]; §\C{// f() called once}§ 2609 2598 \end{cfa} 2610 2599 … … 2612 2601 Since \CFA permits these tuple-access expressions using structures, unions, and tuples, \emph{member tuple expression} or \emph{field tuple expression} is more appropriate. 2613 2602 2614 It is possible to extend member-access expressions further. 2615 Currently, a member-access expression whose member is a name requires that the aggregate is a structure or union, while a constant integer member requires the aggregate to be a tuple. 2616 In the interest of orthogonal design, \CFA could apply some meaning to the remaining combinations as well. 2617 For example, 2618 \begin{cfa} 2619 struct S { int x, y; } s; 2620 [S, S] z; 2621 2622 s.x; // access member 2623 z.0; // access component 2624 2625 s.1; // ??? 2626 z.y; // ??? 2627 \end{cfa} 2628 One possibility is for ©s.1© to select the second member of ©s©. 2629 Under this interpretation, it becomes possible to not only access members of a struct by name, but also by position. 2630 Likewise, it seems natural to open this mechanism to enumerations as well, wherein the left side would be a type, rather than an expression. 2631 One benefit of this interpretation is familiarity, since it is extremely reminiscent of tuple-index expressions. 2632 On the other hand, it could be argued that this interpretation is brittle in that changing the order of members or adding new members to a structure becomes a brittle operation. 2633 This problem is less of a concern with tuples, since modifying a tuple affects only the code that directly uses the tuple, whereas modifying a structure has far reaching consequences for every instance of the structure. 2634 2635 As for ©z.y©, one interpretation is to extend the meaning of member tuple expressions. 2636 That is, currently the tuple must occur as the member, \ie to the right of the dot. 2637 Allowing tuples to the left of the dot could distribute the member across the elements of the tuple, in much the same way that member tuple expressions distribute the aggregate across the member tuple. 2638 In this example, ©z.y© expands to ©[z.0.y, z.1.y]©, allowing what is effectively a very limited compile-time field-sections map operation, where the argument must be a tuple containing only aggregates having a member named ©y©. 2639 It is questionable how useful this would actually be in practice, since structures often do not have names in common with other structures, and further this could cause maintainability issues in that it encourages programmers to adopt very simple naming conventions to maximize the amount of overlap between different types. 2640 Perhaps more useful would be to allow arrays on the left side of the dot, which would likewise allow mapping a field access across the entire array, producing an array of the contained fields. 2641 The immediate problem with this idea is that C arrays do not carry around their size, which would make it impossible to use this extension for anything other than a simple stack allocated array. 2642 2643 Supposing this feature works as described, it would be necessary to specify an ordering for the expansion of member-access expressions versus member-tuple expressions. 2644 \begin{cfa} 2645 struct { int x, y; }; 2646 [S, S] z; 2647 z.[x, y]; // ??? 2648 // => [z.0, z.1].[x, y] 2649 // => [z.0.x, z.0.y, z.1.x, z.1.y] 2650 // or 2651 // => [z.x, z.y] 2652 // => [[z.0, z.1].x, [z.0, z.1].y] 2653 // => [z.0.x, z.1.x, z.0.y, z.1.y] 2654 \end{cfa} 2655 Depending on exactly how the two tuples are combined, different results can be achieved. 2656 As such, a specific ordering would need to be imposed to make this feature useful. 2657 Furthermore, this addition moves a member-tuple expression's meaning from being clear statically to needing resolver support, since the member name needs to be distributed appropriately over each member of the tuple, which could itself be a tuple. 2658 2659 A second possibility is for \CFA to have named tuples, as they exist in Swift and D. 2660 \begin{cfa} 2661 typedef [int x, int y] Point2D; 2662 Point2D p1, p2; 2663 p1.x + p1.y + p2.x + p2.y; 2664 p1.0 + p1.1 + p2.0 + p2.1; // equivalent 2665 \end{cfa} 2666 In this simpler interpretation, a tuple type carries with it a list of possibly empty identifiers. 2667 This approach fits naturally with the named return-value feature, and would likely go a long way towards implementing it. 2668 2669 Ultimately, the first two extensions introduce complexity into the model, with relatively little perceived benefit, and so were dropped from consideration. 2670 Named tuples are a potentially useful addition to the language, provided they can be parsed with a reasonable syntax. 2671 2672 2673 \section{Casting} 2603 2604 \subsection{Casting} 2605 2674 2606 In C, the cast operator is used to explicitly convert between types. 2675 2607 In \CFA, the cast operator has a secondary use, which is type ascription, since it forces the expression resolution algorithm to choose the lowest cost conversion to the target type. … … 2725 2657 That is, it is invalid to cast ©[int, int]© to ©[int, int, int]©. 2726 2658 2727 \section{Polymorphism} 2659 2660 \subsection{Polymorphism} 2661 2728 2662 Due to the implicit flattening and structuring conversions involved in argument passing, ©otype© and ©dtype© parameters are restricted to matching only with non-tuple types. 2729 2663 The integration of polymorphism, type assertions, and monomorphic specialization of tuple-assertions are a primary contribution of this thesis to the design of tuples. … … 2778 2712 Until this point, it has been assumed that assertion arguments must match the parameter type exactly, modulo polymorphic specialization (\ie, no implicit conversions are applied to assertion arguments). 2779 2713 This decision presents a conflict with the flexibility of tuples. 2780 \subsection{Assertion Inference} 2714 2715 2716 \subsubsection{Assertion Inference} 2717 2781 2718 \begin{cfa} 2782 2719 int f([int, double], double); … … 2902 2839 Unfortunately, C's syntax for subscripts precluded treating them as tuples. 2903 2840 The C subscript list has the form ©[i][j]...© and not ©[i, j, ...]©. 2904 Therefore, there is no syntactic way for a routine returning multiple values to specify the different subscript values, \eg ©f[ g()]© always means a single subscript value because there is only one set of brackets.2841 Therefore, there is no syntactic way for a routine returning multiple values to specify the different subscript values, \eg ©f[ g() ]© always means a single subscript value because there is only one set of brackets. 2905 2842 Fixing this requires a major change to C because the syntactic form ©M[i, j, k]© already has a particular meaning: ©i, j, k© is a comma expression. 2906 2843 \end{rationale} … … 2951 2888 2952 2889 2953 \s ection{Mass Assignment}2890 \subsection{Mass Assignment} 2954 2891 2955 2892 \CFA permits assignment to several variables at once using mass assignment~\cite{CLU}. … … 2991 2928 2992 2929 2993 \s ection{Multiple Assignment}2930 \subsection{Multiple Assignment} 2994 2931 2995 2932 \CFA also supports the assignment of several values at once, known as multiple assignment~\cite{CLU,Galletly96}. … … 3032 2969 3033 2970 3034 \s ection{Cascade Assignment}2971 \subsection{Cascade Assignment} 3035 2972 3036 2973 As in C, \CFA mass and multiple assignments can be cascaded, producing cascade assignment. … … 3048 2985 \end{cfa} 3049 2986 As in C, the rightmost assignment is performed first, \ie assignment parses right to left. 3050 3051 3052 \section{Field Tuples}3053 3054 Tuples may be used to select multiple fields of a record by field name.3055 Its general form is:3056 \begin{cfa}3057 §\emph{expr}§ . [ §\emph{fieldlist}§ ]3058 §\emph{expr}§ -> [ §\emph{fieldlist}§ ]3059 \end{cfa}3060 \emph{expr} is any expression yielding a value of type record, \eg ©struct©, ©union©.3061 Each element of \emph{ fieldlist} is an element of the record specified by \emph{expr}.3062 A record-field tuple may be used anywhere a tuple can be used. An example of the use of a record-field tuple is3063 the following:3064 \begin{cfa}3065 struct s {3066 int f1, f2;3067 char f3;3068 double f4;3069 } v;3070 v.[ f3, f1, f2 ] = ['x', 11, 17 ]; §\C{// equivalent to v.f3 = 'x', v.f1 = 11, v.f2 = 17}§3071 f( v.[ f3, f1, f2 ] ); §\C{// equivalent to f( v.f3, v.f1, v.f2 )}§3072 \end{cfa}3073 Note, the fields appearing in a record-field tuple may be specified in any order;3074 also, it is unnecessary to specify all the fields of a struct in a multiple record-field tuple.3075 3076 If a field of a ©struct© is itself another ©struct©, multiple fields of this subrecord can be specified using a nested record-field tuple, as in the following example:3077 \begin{cfa}3078 struct inner {3079 int f2, f3;3080 };3081 struct outer {3082 int f1;3083 struct inner i;3084 double f4;3085 } o;3086 3087 o.[ f1, i.[ f2, f3 ], f4 ] = [ 11, 12, 13, 3.14159 ];3088 \end{cfa}3089 2987 3090 2988 -
src/Concurrency/Waitfor.cc
rcf966b5 r6c2ba38 416 416 makeAccStatement( acceptables, index, "is_dtor", detectIsDtor( clause.target.function ) , indexer ), 417 417 makeAccStatement( acceptables, index, "func" , new CastExpr( clause.target.function, fptr_t ) , indexer ), 418 makeAccStatement( acceptables, index, " list" , new VariableExpr( monitors ) , indexer ),418 makeAccStatement( acceptables, index, "data" , new VariableExpr( monitors ) , indexer ), 419 419 makeAccStatement( acceptables, index, "size" , new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ), indexer ), 420 420 setter->clone() -
src/GenPoly/Box.cc
rcf966b5 r6c2ba38 855 855 DeclarationWithType *adapteeDecl = adapterType->get_parameters().front(); 856 856 adapteeDecl->set_name( "_adaptee" ); 857 // do not carry over attributes to real type parameters/return values 858 for ( DeclarationWithType * dwt : realType->parameters ) { 859 deleteAll( dwt->get_type()->attributes ); 860 dwt->get_type()->attributes.clear(); 861 } 862 for ( DeclarationWithType * dwt : realType->returnVals ) { 863 deleteAll( dwt->get_type()->attributes ); 864 dwt->get_type()->attributes.clear(); 865 } 857 866 ApplicationExpr *adapteeApp = new ApplicationExpr( new CastExpr( new VariableExpr( adapteeDecl ), new PointerType( Type::Qualifiers(), realType ) ) ); 858 867 Statement *bodyStmt; -
src/GenPoly/InstantiateGeneric.cc
rcf966b5 r6c2ba38 210 210 PassVisitor<GenericInstantiator> instantiator; 211 211 212 mutateAll( translationUnit, fixer );212 // mutateAll( translationUnit, fixer ); 213 213 mutateAll( translationUnit, instantiator ); 214 214 } -
src/Parser/ParseNode.h
rcf966b5 r6c2ba38 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Sep 23 18:11:22201713 // Update Count : 82 112 // Last Modified On : Mon Nov 27 17:33:35 2017 13 // Update Count : 824 14 14 // 15 15 … … 292 292 DeclarationNode * set_extension( bool exten ) { extension = exten; return this; } 293 293 public: 294 DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); } 295 294 296 struct Variable_t { 295 297 // const std::string * name; -
src/Parser/TypeData.cc
rcf966b5 r6c2ba38 792 792 793 793 794 NamedTypeDecl * buildSymbolic( const TypeData * td, const string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage ) {794 NamedTypeDecl * buildSymbolic( const TypeData * td, std::list< Attribute * > attributes, const string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage ) { 795 795 assert( td->kind == TypeData::Symbolic ); 796 796 NamedTypeDecl * ret; … … 803 803 buildList( td->symbolic.params, ret->get_parameters() ); 804 804 buildList( td->symbolic.assertions, ret->get_assertions() ); 805 ret->base->attributes.splice( ret->base->attributes.end(), attributes ); 805 806 return ret; 806 807 } // buildSymbolic … … 866 867 return buildEnum( td, attributes, linkage ); 867 868 } else if ( td->kind == TypeData::Symbolic ) { 868 return buildSymbolic( td, name, scs, linkage );869 return buildSymbolic( td, attributes, name, scs, linkage ); 869 870 } else { 870 871 return (new ObjectDecl( name, scs, linkage, bitfieldWidth, typebuild( td ), init, attributes ))->set_asmName( asmName ); -
src/Parser/parser.yy
rcf966b5 r6c2ba38 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Nov 2 0 09:45:36201713 // Update Count : 29 4512 // Last Modified On : Mon Nov 27 17:23:35 2017 13 // Update Count : 2992 14 14 // 15 15 … … 345 345 %type<en> type_list 346 346 347 %type<decl> type_qualifier type_qualifier_name type_qualifier_list_opt type_qualifier_list347 %type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list 348 348 %type<decl> type_specifier type_specifier_nobody 349 349 … … 379 379 // `---' matches start of TYPEGENname '(' 380 380 // Must be: 381 // Foo( int ) ( *fp )( int );381 // Foo( int ) ( *fp )( int ); 382 382 383 383 // Order of these lines matters (low-to-high precedence). … … 1058 1058 with_statement: 1059 1059 WITH '(' tuple_expression_list ')' statement 1060 { $$ = nullptr; }// FIX ME1060 { throw SemanticError("With clause is currently unimplemented."); $$ = nullptr; } // FIX ME 1061 1061 ; 1062 1062 … … 1064 1064 mutex_statement: 1065 1065 MUTEX '(' argument_expression_list ')' statement 1066 { $$ = nullptr; }// FIX ME1066 { throw SemanticError("Mutex statement is currently unimplemented."); $$ = nullptr; } // FIX ME 1067 1067 ; 1068 1068 … … 1280 1280 c_declaration pop ';' 1281 1281 | cfa_declaration pop ';' // CFA 1282 | STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11 1283 { throw SemanticError("Static assert is currently unimplemented."); $$ = nullptr; } // FIX ME 1282 1284 ; 1283 1285 … … 1362 1364 $$ = $3->addQualifiers( $1 )->addQualifiers( $2 ); 1363 1365 } 1364 | cfa_function_declaration pop ',' push identifier_or_type_name 1365 { 1366 typedefTable.addToEnclosingScope( *$5, TypedefTable::ID ); 1367 $$ = $1->appendList( $1->cloneType( $5 ) ); 1366 | cfa_function_declaration pop ',' push identifier_or_type_name '(' push cfa_parameter_type_list_opt pop ')' 1367 { 1368 // Append the return type at the start (left-hand-side) to each identifier in the list. 1369 DeclarationNode * ret = new DeclarationNode; 1370 ret->type = maybeClone( $1->type->base ); 1371 $$ = $1->appendList( DeclarationNode::newFunction( $5, ret, $8, nullptr, true ) ); 1368 1372 } 1369 1373 ; … … 1587 1591 | ATOMIC 1588 1592 { $$ = DeclarationNode::newTypeQualifier( Type::Atomic ); } 1589 | FORALL '(' 1593 | forall 1594 ; 1595 1596 forall: 1597 FORALL '(' 1590 1598 { 1591 1599 typedefTable.enterScope(); … … 2374 2382 $$ = $2; 2375 2383 } 2384 | forall '{' external_definition_list '}' // CFA, namespace 2376 2385 ; 2377 2386 … … 2399 2408 with_clause_opt: 2400 2409 // empty 2401 { $$ = nullptr; } // FIX ME2410 { $$ = nullptr; } 2402 2411 | WITH '(' tuple_expression_list ')' 2403 { $$ = nullptr; }// FIX ME2412 { throw SemanticError("With clause is currently unimplemented."); $$ = nullptr; } // FIX ME 2404 2413 ; 2405 2414 … … 2409 2418 typedefTable.addToEnclosingScope( TypedefTable::ID ); 2410 2419 typedefTable.leaveScope(); 2411 $$ = $1->addFunctionBody( $3 ); 2420 // Add the function body to the last identifier in the function definition list, i.e., foo3: 2421 // [const double] foo1(), foo2( int ), foo3( double ) { return 3.0; } 2422 $1->get_last()->addFunctionBody( $3 ); 2423 $$ = $1; 2412 2424 } 2413 2425 | declaration_specifier function_declarator with_clause_opt compound_statement … … 2418 2430 $$ = $2->addFunctionBody( $4 )->addType( $1 ); 2419 2431 } 2432 // handles default int return type, OBSOLESCENT (see 1) 2420 2433 | type_qualifier_list function_declarator with_clause_opt compound_statement 2421 2434 { … … 2424 2437 $$ = $2->addFunctionBody( $4 )->addQualifiers( $1 ); 2425 2438 } 2439 // handles default int return type, OBSOLESCENT (see 1) 2426 2440 | declaration_qualifier_list function_declarator with_clause_opt compound_statement 2427 2441 { … … 2430 2444 $$ = $2->addFunctionBody( $4 )->addQualifiers( $1 ); 2431 2445 } 2446 // handles default int return type, OBSOLESCENT (see 1) 2432 2447 | declaration_qualifier_list type_qualifier_list function_declarator with_clause_opt compound_statement 2433 2448 { … … 2445 2460 $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5 )->addType( $1 ); 2446 2461 } 2462 // handles default int return type, OBSOLESCENT (see 1) 2447 2463 | type_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement 2448 2464 { … … 2451 2467 $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5 )->addQualifiers( $1 ); 2452 2468 } 2453 2454 // Old-style K&R function definition with "implicit int" type_specifier, OBSOLESCENT (see 4) 2469 // handles default int return type, OBSOLESCENT (see 1) 2455 2470 | declaration_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement 2456 2471 { … … 2459 2474 $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5 )->addQualifiers( $1 ); 2460 2475 } 2476 // handles default int return type, OBSOLESCENT (see 1) 2461 2477 | declaration_qualifier_list type_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement 2462 2478 { -
src/SymTab/Autogen.cc
rcf966b5 r6c2ba38 372 372 continue; 373 373 } 374 memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, 0, field->get_type()->clone(), 0 ) ); 374 // do not carry over field's attributes to parameter type 375 Type * paramType = field->get_type()->clone(); 376 deleteAll( paramType->attributes ); 377 paramType->attributes.clear(); 378 // add a parameter corresponding to this field 379 memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType, nullptr ) ); 375 380 FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting ); 376 381 makeFieldCtorBody( aggregateDecl->members.begin(), aggregateDecl->members.end(), ctor ); … … 503 508 break; 504 509 } 505 memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, field->get_type()->clone(), nullptr ) ); 510 // do not carry over field's attributes to parameter type 511 Type * paramType = field->get_type()->clone(); 512 deleteAll( paramType->attributes ); 513 paramType->attributes.clear(); 514 // add a parameter corresponding to this field 515 memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType, nullptr ) ); 506 516 FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting ); 507 517 ObjectDecl * srcParam = strict_dynamic_cast<ObjectDecl *>( ctor->type->parameters.back() ); -
src/SymTab/Validate.cc
rcf966b5 r6c2ba38 201 201 Declaration * postmutate( TraitDecl * contextDecl ); 202 202 203 void premutate( FunctionType * ftype ); 204 203 205 private: 204 206 template<typename AggDecl> … … 214 216 TypeDeclMap typedeclNames; 215 217 int scopeLevel; 218 bool inFunctionType = false; 216 219 }; 217 220 … … 725 728 Type *ret = def->second.first->base->clone(); 726 729 ret->get_qualifiers() |= typeInst->get_qualifiers(); 730 // attributes are not carried over from typedef to function parameters/return values 731 if ( ! inFunctionType ) { 732 ret->attributes.splice( ret->attributes.end(), typeInst->attributes ); 733 } else { 734 deleteAll( ret->attributes ); 735 ret->attributes.clear(); 736 } 727 737 // place instance parameters on the typedef'd type 728 738 if ( ! typeInst->parameters.empty() ) { … … 901 911 Declaration *EliminateTypedef::postmutate( TraitDecl * traitDecl ) { 902 912 return handleAggregate( traitDecl ); 913 } 914 915 void EliminateTypedef::premutate( FunctionType * ) { 916 GuardValue( inFunctionType ); 917 inFunctionType = true; 903 918 } 904 919 -
src/benchmark/Makefile.am
rcf966b5 r6c2ba38 94 94 ctxswitch-cfa_thread.run \ 95 95 ctxswitch-upp_coroutine.run \ 96 ctxswitch-upp_thread.run 96 ctxswitch-upp_thread.run \ 97 ctxswitch-goroutine.run \ 98 ctxswitch-java_thread.run 97 99 98 100 ctxswitch-cfa_coroutine$(EXEEXT): … … 111 113 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 112 114 115 ctxswitch-goroutine$(EXEEXT): 116 @go build -o a.out ctxswitch/goroutine.go 117 118 ctxswitch-java_thread$(EXEEXT): 119 @javac ctxswitch/JavaThread.java 120 @echo "#!/bin/sh" > a.out 121 @echo "cd ctxswitch && java JavaThread" >> a.out 122 @chmod a+x a.out 123 113 124 ## ========================================================================================================= 114 125 mutex$(EXEEXT) :\ 115 126 mutex-function.run \ 127 mutex-fetch_add.run \ 116 128 mutex-pthread_lock.run \ 117 129 mutex-upp.run \ 118 130 mutex-cfa1.run \ 119 131 mutex-cfa2.run \ 120 mutex-cfa4.run 132 mutex-cfa4.run \ 133 mutex-java_thread.run 121 134 122 135 mutex-function$(EXEEXT): 123 136 @@BACKEND_CC@ mutex/function.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 124 137 138 mutex-fetch_add$(EXEEXT): 139 @@BACKEND_CC@ mutex/fetch_add.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 140 125 141 mutex-pthread_lock$(EXEEXT): 126 142 @@BACKEND_CC@ mutex/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} … … 137 153 mutex-cfa4$(EXEEXT): 138 154 @${CC} mutex/cfa4.c -DBENCH_N=5000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 155 156 mutex-java_thread$(EXEEXT): 157 @javac mutex/JavaThread.java 158 @echo "#!/bin/sh" > a.out 159 @echo "cd mutex && java JavaThread" >> a.out 160 @chmod a+x a.out 139 161 140 162 ## ========================================================================================================= … … 143 165 signal-cfa1.run \ 144 166 signal-cfa2.run \ 145 signal-cfa4.run 167 signal-cfa4.run \ 168 signal-java_thread.run 146 169 147 170 signal-upp$(EXEEXT): … … 156 179 signal-cfa4$(EXEEXT): 157 180 @${CC} schedint/cfa4.c -DBENCH_N=500000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 181 182 signal-java_thread$(EXEEXT): 183 @javac schedint/JavaThread.java 184 @echo "#!/bin/sh" > a.out 185 @echo "cd schedint && java JavaThread" >> a.out 186 @chmod a+x a.out 187 158 188 159 189 ## ========================================================================================================= … … 183 213 creation-cfa_thread.run \ 184 214 creation-upp_coroutine.run \ 185 creation-upp_thread.run 215 creation-upp_thread.run \ 216 creation-goroutine.run \ 217 creation-java_thread.run 186 218 187 219 creation-cfa_coroutine$(EXEEXT): … … 202 234 creation-pthread$(EXEEXT): 203 235 @@BACKEND_CC@ creation/pthreads.c -DBENCH_N=250000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 236 237 creation-goroutine$(EXEEXT): 238 @go build -o a.out creation/goroutine.go 239 240 creation-java_thread$(EXEEXT): 241 @javac creation/JavaThread.java 242 @echo "#!/bin/sh" > a.out 243 @echo "cd creation && java JavaThread" >> a.out 244 @chmod a+x a.out 204 245 205 246 ## ========================================================================================================= -
src/benchmark/Makefile.in
rcf966b5 r6c2ba38 507 507 ctxswitch-cfa_thread.run \ 508 508 ctxswitch-upp_coroutine.run \ 509 ctxswitch-upp_thread.run 509 ctxswitch-upp_thread.run \ 510 ctxswitch-goroutine.run \ 511 ctxswitch-java_thread.run 510 512 511 513 ctxswitch-cfa_coroutine$(EXEEXT): … … 524 526 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 525 527 528 ctxswitch-goroutine$(EXEEXT): 529 @go build -o a.out ctxswitch/goroutine.go 530 531 ctxswitch-java_thread$(EXEEXT): 532 @javac ctxswitch/JavaThread.java 533 @echo "#!/bin/sh" > a.out 534 @echo "cd ctxswitch && java JavaThread" >> a.out 535 @chmod a+x a.out 536 526 537 mutex$(EXEEXT) :\ 527 538 mutex-function.run \ 539 mutex-fetch_add.run \ 528 540 mutex-pthread_lock.run \ 529 541 mutex-upp.run \ 530 542 mutex-cfa1.run \ 531 543 mutex-cfa2.run \ 532 mutex-cfa4.run 544 mutex-cfa4.run \ 545 mutex-java_thread.run 533 546 534 547 mutex-function$(EXEEXT): 535 548 @@BACKEND_CC@ mutex/function.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 536 549 550 mutex-fetch_add$(EXEEXT): 551 @@BACKEND_CC@ mutex/fetch_add.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 552 537 553 mutex-pthread_lock$(EXEEXT): 538 554 @@BACKEND_CC@ mutex/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} … … 549 565 mutex-cfa4$(EXEEXT): 550 566 @${CC} mutex/cfa4.c -DBENCH_N=5000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 567 568 mutex-java_thread$(EXEEXT): 569 @javac mutex/JavaThread.java 570 @echo "#!/bin/sh" > a.out 571 @echo "cd mutex && java JavaThread" >> a.out 572 @chmod a+x a.out 551 573 552 574 signal$(EXEEXT) :\ … … 567 589 signal-cfa4$(EXEEXT): 568 590 @${CC} schedint/cfa4.c -DBENCH_N=500000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 591 592 signal-java_thread$(EXEEXT): 593 @javac schedint/JavaThread.java 594 @echo "#!/bin/sh" > a.out 595 @echo "cd schedint && java JavaThread" >> a.out 596 @chmod a+x a.out 569 597 570 598 waitfor$(EXEEXT) :\ … … 592 620 creation-cfa_thread.run \ 593 621 creation-upp_coroutine.run \ 594 creation-upp_thread.run 622 creation-upp_thread.run \ 623 creation-goroutine.run \ 624 creation-java_thread.run 595 625 596 626 creation-cfa_coroutine$(EXEEXT): … … 611 641 creation-pthread$(EXEEXT): 612 642 @@BACKEND_CC@ creation/pthreads.c -DBENCH_N=250000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 643 644 creation-goroutine$(EXEEXT): 645 @go build -o a.out creation/goroutine.go 646 647 creation-java_thread$(EXEEXT): 648 @javac creation/JavaThread.java 649 @echo "#!/bin/sh" > a.out 650 @echo "cd creation && java JavaThread" >> a.out 651 @chmod a+x a.out 613 652 614 653 compile$(EXEEXT) :\ -
src/benchmark/bench.h
rcf966b5 r6c2ba38 1 1 #pragma once 2 2 3 #if defined(__ CFORALL__)3 #if defined(__cforall) 4 4 extern "C" { 5 5 #endif … … 8 8 #include <sys/times.h> // times 9 9 #include <time.h> 10 #if defined(__ CFORALL__)10 #if defined(__cforall) 11 11 } 12 12 #endif -
src/libcfa/Makefile.am
rcf966b5 r6c2ba38 100 100 math \ 101 101 gmp \ 102 bits/containers.h \ 102 103 bits/defs.h \ 103 104 bits/locks.h \ -
src/libcfa/Makefile.in
rcf966b5 r6c2ba38 264 264 containers/result containers/vector concurrency/coroutine \ 265 265 concurrency/thread concurrency/kernel concurrency/monitor \ 266 ${shell echo stdhdr/*} math gmp bits/ defs.h bits/locks.h \267 concurrency/invoke.h libhdr.h libhdr/libalign.h \266 ${shell echo stdhdr/*} math gmp bits/containers.h bits/defs.h \ 267 bits/locks.h concurrency/invoke.h libhdr.h libhdr/libalign.h \ 268 268 libhdr/libdebug.h libhdr/libtools.h 269 269 HEADERS = $(nobase_cfa_include_HEADERS) … … 437 437 math \ 438 438 gmp \ 439 bits/containers.h \ 439 440 bits/defs.h \ 440 441 bits/locks.h \ -
src/libcfa/bits/containers.h
rcf966b5 r6c2ba38 15 15 #pragma once 16 16 17 #include <stddef.h> 17 #include "bits/defs.h" 18 #include "libhdr.h" 18 19 19 #include "libhdr.h" 20 //----------------------------------------------------------------------------- 21 // Array 22 //----------------------------------------------------------------------------- 23 24 #ifdef __cforall 25 forall(dtype T) 26 #else 27 #define T void 28 #endif 29 struct __small_array { 30 T * data; 31 __lock_size_t size; 32 }; 33 #undef T 34 35 #ifdef __cforall 36 #define __small_array_t(T) __small_array(T) 37 #else 38 #define __small_array_t(T) struct __small_array 39 #endif 40 41 #ifdef __cforall 42 // forall(otype T | sized(T)) 43 // static inline void ?{}(__small_array(T) & this) {} 44 45 forall(dtype T | sized(T)) 46 static inline T& ?[?]( __small_array(T) & this, __lock_size_t idx) { 47 return ((typeof(this.data))this.data)[idx]; 48 } 49 50 forall(dtype T | sized(T)) 51 static inline T& ?[?]( const __small_array(T) & this, __lock_size_t idx) { 52 return ((typeof(this.data))this.data)[idx]; 53 } 54 55 forall(dtype T | sized(T)) 56 static inline T* begin( const __small_array(T) & this ) { 57 return ((typeof(this.data))this.data); 58 } 59 60 forall(dtype T | sized(T)) 61 static inline T* end( const __small_array(T) & this ) { 62 return ((typeof(this.data))this.data) + this.size; 63 } 64 #endif 20 65 21 66 //----------------------------------------------------------------------------- … … 23 68 //----------------------------------------------------------------------------- 24 69 25 #ifdef __ CFORALL__70 #ifdef __cforall 26 71 trait is_node(dtype T) { 27 72 T*& get_next( T& ); … … 32 77 // Stack 33 78 //----------------------------------------------------------------------------- 34 #ifdef __ CFORALL__79 #ifdef __cforall 35 80 forall(dtype TYPE | is_node(TYPE)) 36 81 #define T TYPE … … 41 86 T * top; 42 87 }; 88 #undef T 43 89 44 #ifdef __ CFORALL__90 #ifdef __cforall 45 91 #define __stack_t(T) __stack(T) 46 92 #else … … 48 94 #endif 49 95 50 #ifdef __ CFORALL__96 #ifdef __cforall 51 97 forall(dtype T | is_node(T)) 52 void ?{}( __stack(T) & this ) {53 this.top = NULL;98 static inline void ?{}( __stack(T) & this ) { 99 (this.top){ NULL }; 54 100 } 55 101 56 102 forall(dtype T | is_node(T) | sized(T)) 57 void push( __stack(T) & this, T * val ) {103 static inline void push( __stack(T) & this, T * val ) { 58 104 verify( !get_next( *val ) ); 59 105 get_next( *val ) = this.top; … … 62 108 63 109 forall(dtype T | is_node(T) | sized(T)) 64 T * pop( __stack(T) & this ) {110 static inline T * pop( __stack(T) & this ) { 65 111 T * top = this.top; 66 112 if( top ) { … … 75 121 // Queue 76 122 //----------------------------------------------------------------------------- 77 #ifdef __ CFORALL__78 forall(dtype T | is_node(T))123 #ifdef __cforall 124 forall(dtype TYPE | is_node(TYPE)) 79 125 #define T TYPE 80 126 #else … … 85 131 T ** tail; 86 132 }; 133 #undef T 87 134 88 #ifdef __CFORALL__ 135 #ifdef __cforall 136 #define __queue_t(T) __queue(T) 137 #else 138 #define __queue_t(T) struct __queue 139 #endif 140 141 #ifdef __cforall 89 142 forall(dtype T | is_node(T)) 90 void ?{}( __queue(T) & this ) {91 this.head = NULL;92 this.tail = &this.head;143 static inline void ?{}( __queue(T) & this ) { 144 (this.head){ NULL }; 145 (this.tail){ &this.head }; 93 146 } 94 147 95 148 forall(dtype T | is_node(T) | sized(T)) 96 void append( __queue(T) & this, T * val ) {149 static inline void append( __queue(T) & this, T * val ) { 97 150 verify(this.tail != NULL); 98 151 *this.tail = val; … … 101 154 102 155 forall(dtype T | is_node(T) | sized(T)) 103 T * pop_head( __queue(T) & this ) {156 static inline T * pop_head( __queue(T) & this ) { 104 157 T * head = this.head; 105 158 if( head ) { … … 114 167 115 168 forall(dtype T | is_node(T) | sized(T)) 116 T * remove( __queue(T) & this, T ** it ) {169 static inline T * remove( __queue(T) & this, T ** it ) { 117 170 T * val = *it; 118 171 verify( val ); -
src/libcfa/bits/defs.h
rcf966b5 r6c2ba38 17 17 18 18 #include <stdbool.h> 19 #include <stddef.h> 19 20 #include <stdint.h> 20 21 … … 22 23 #define likely (x) __builtin_expect(!!(x), 1) 23 24 #define thread_local _Thread_local 25 26 typedef void (*fptr_t)(); 27 typedef int_fast16_t __lock_size_t; 28 29 #ifdef __cforall 30 #define __cfa_anonymous_object 31 #else 32 #define __cfa_anonymous_object __cfa_anonymous_object 33 #endif -
src/libcfa/bits/locks.h
rcf966b5 r6c2ba38 56 56 } __ALIGN__; 57 57 58 #ifdef __ CFORALL__58 #ifdef __cforall 59 59 extern void yield( unsigned int ); 60 60 extern thread_local struct thread_desc * volatile this_thread; -
src/libcfa/concurrency/invoke.h
rcf966b5 r6c2ba38 14 14 // 15 15 16 #include "bits/containers.h" 16 17 #include "bits/defs.h" 17 18 #include "bits/locks.h" 18 19 19 #ifdef __ CFORALL__20 #ifdef __cforall 20 21 extern "C" { 21 22 #endif … … 25 26 #define _INVOKE_H_ 26 27 27 typedef void (*fptr_t)(); 28 typedef int_fast16_t __lock_size_t; 29 30 struct __thread_queue_t { 31 struct thread_desc * head; 32 struct thread_desc ** tail; 33 }; 34 35 struct __condition_stack_t { 36 struct __condition_criterion_t * top; 37 }; 38 39 #ifdef __CFORALL__ 28 #ifdef __cforall 40 29 extern "Cforall" { 41 void ?{}( struct __thread_queue_t & ); 42 void append( struct __thread_queue_t &, struct thread_desc * ); 43 struct thread_desc * pop_head( struct __thread_queue_t & ); 44 struct thread_desc * remove( struct __thread_queue_t &, struct thread_desc ** ); 45 46 void ?{}( struct __condition_stack_t & ); 47 void push( struct __condition_stack_t &, struct __condition_criterion_t * ); 48 struct __condition_criterion_t * pop( struct __condition_stack_t & ); 30 static inline struct thread_desc * & get_next( struct thread_desc & this ); 31 static inline struct __condition_criterion_t * & get_next( struct __condition_criterion_t & this ); 49 32 } 50 33 #endif … … 100 83 101 84 // list of acceptable functions, null if any 102 struct __acceptable_t * clauses; 103 104 // number of acceptable functions 105 __lock_size_t size; 85 __small_array_t(struct __acceptable_t) __cfa_anonymous_object; 106 86 }; 107 87 … … 114 94 115 95 // queue of threads that are blocked waiting for the monitor 116 struct __thread_queue_tentry_queue;96 __queue_t(struct thread_desc) entry_queue; 117 97 118 98 // stack of conditions to run next once we exit the monitor 119 struct __condition_stack_tsignal_stack;99 __stack_t(struct __condition_criterion_t) signal_stack; 120 100 121 101 // monitor routines can be called recursively, we need to keep track of that … … 131 111 struct __monitor_group_t { 132 112 // currently held monitors 133 struct monitor_desc ** list; 134 135 // number of currently held monitors 136 __lock_size_t size; 113 __small_array_t(monitor_desc*) __cfa_anonymous_object; 137 114 138 115 // last function that acquired monitors … … 159 136 }; 160 137 161 #ifdef __ CFORALL__138 #ifdef __cforall 162 139 extern "Cforall" { 163 static inline monitor_desc * ?[?]( const __monitor_group_t & this, ptrdiff_t index ) { 164 return this.list[index]; 140 static inline thread_desc * & get_next( thread_desc & this ) { 141 return this.next; 142 } 143 144 static inline struct __condition_criterion_t * & get_next( struct __condition_criterion_t & this ); 145 146 static inline void ?{}(__monitor_group_t & this) { 147 (this.data){NULL}; 148 (this.size){0}; 149 (this.func){NULL}; 150 } 151 152 static inline void ?{}(__monitor_group_t & this, struct monitor_desc ** data, __lock_size_t size, fptr_t func) { 153 (this.data){data}; 154 (this.size){size}; 155 (this.func){func}; 165 156 } 166 157 167 158 static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) { 168 if( (lhs. list != 0) != (rhs.list!= 0) ) return false;159 if( (lhs.data != 0) != (rhs.data != 0) ) return false; 169 160 if( lhs.size != rhs.size ) return false; 170 161 if( lhs.func != rhs.func ) return false; … … 177 168 178 169 return true; 170 } 171 172 static inline void ?=?(__monitor_group_t & lhs, const __monitor_group_t & rhs) { 173 lhs.data = rhs.data; 174 lhs.size = rhs.size; 175 lhs.func = rhs.func; 179 176 } 180 177 } … … 210 207 #endif //_INVOKE_PRIVATE_H_ 211 208 #endif //! defined(__CFA_INVOKE_PRIVATE__) 212 #ifdef __ CFORALL__209 #ifdef __cforall 213 210 } 214 211 #endif -
src/libcfa/concurrency/kernel
rcf966b5 r6c2ba38 26 26 //----------------------------------------------------------------------------- 27 27 // Locks 28 // // Lock the spinlock, spin if already acquired29 // void lock ( spinlock * DEBUG_CTX_PARAM2 );30 31 // // Lock the spinlock, yield repeatedly if already acquired32 // void lock_yield( spinlock * DEBUG_CTX_PARAM2 );33 34 // // Lock the spinlock, return false if already acquired35 // bool try_lock ( spinlock * DEBUG_CTX_PARAM2 );36 37 // // Unlock the spinlock38 // void unlock ( spinlock * );39 40 28 struct semaphore { 41 29 __spinlock_t lock; 42 30 int count; 43 __ thread_queue_twaiting;31 __queue_t(thread_desc) waiting; 44 32 }; 45 33 … … 57 45 58 46 // Ready queue for threads 59 __ thread_queue_tready_queue;47 __queue_t(thread_desc) ready_queue; 60 48 61 49 // Preemption rate on this cluster -
src/libcfa/concurrency/kernel.c
rcf966b5 r6c2ba38 164 164 165 165 void ?{}(cluster & this) { 166 ( this.ready_queue){};166 (this.ready_queue){}; 167 167 ( this.ready_queue_lock ){}; 168 168 … … 611 611 } 612 612 613 //-----------------------------------------------------------------------------614 // Queues615 void ?{}( __thread_queue_t & this ) {616 this.head = NULL;617 this.tail = &this.head;618 }619 620 void append( __thread_queue_t & this, thread_desc * t ) {621 verify(this.tail != NULL);622 *this.tail = t;623 this.tail = &t->next;624 }625 626 thread_desc * pop_head( __thread_queue_t & this ) {627 thread_desc * head = this.head;628 if( head ) {629 this.head = head->next;630 if( !head->next ) {631 this.tail = &this.head;632 }633 head->next = NULL;634 }635 return head;636 }637 638 thread_desc * remove( __thread_queue_t & this, thread_desc ** it ) {639 thread_desc * thrd = *it;640 verify( thrd );641 642 (*it) = thrd->next;643 644 if( this.tail == &thrd->next ) {645 this.tail = it;646 }647 648 thrd->next = NULL;649 650 verify( (this.head == NULL) == (&this.head == this.tail) );651 verify( *this.tail == NULL );652 return thrd;653 }654 655 void ?{}( __condition_stack_t & this ) {656 this.top = NULL;657 }658 659 void push( __condition_stack_t & this, __condition_criterion_t * t ) {660 verify( !t->next );661 t->next = this.top;662 this.top = t;663 }664 665 __condition_criterion_t * pop( __condition_stack_t & this ) {666 __condition_criterion_t * top = this.top;667 if( top ) {668 this.top = top->next;669 top->next = NULL;670 }671 return top;672 }673 674 613 // Local Variables: // 675 614 // mode: c // -
src/libcfa/concurrency/monitor
rcf966b5 r6c2ba38 34 34 this.recursion = 0; 35 35 this.mask.accepted = NULL; 36 this.mask. clauses= NULL;36 this.mask.data = NULL; 37 37 this.mask.size = 0; 38 38 this.dtor_node = NULL; … … 40 40 41 41 struct monitor_guard_t { 42 monitor_desc ** m; 43 __lock_size_t count; 44 monitor_desc ** prev_mntrs; 45 __lock_size_t prev_count; 46 fptr_t prev_func; 42 monitor_desc ** m; 43 __lock_size_t count; 44 __monitor_group_t prev; 47 45 }; 48 46 … … 51 49 52 50 struct monitor_dtor_guard_t { 53 monitor_desc * m; 54 monitor_desc ** prev_mntrs; 55 __lock_size_t prev_count; 56 fptr_t prev_func; 51 monitor_desc * m; 52 __monitor_group_t prev; 57 53 }; 58 54 … … 83 79 }; 84 80 81 static inline __condition_criterion_t * & get_next( __condition_criterion_t & this ) { 82 return this.next; 83 } 84 85 85 struct __condition_node_t { 86 86 // Thread that needs to be woken when all criteria are met … … 100 100 }; 101 101 102 struct __condition_blocked_queue_t { 103 __condition_node_t * head; 104 __condition_node_t ** tail; 105 }; 102 static inline __condition_node_t * & get_next( __condition_node_t & this ) { 103 return this.next; 104 } 106 105 107 106 void ?{}(__condition_node_t & this, thread_desc * waiting_thread, __lock_size_t count, uintptr_t user_info ); … … 109 108 void ?{}(__condition_criterion_t & this, monitor_desc * target, __condition_node_t * owner ); 110 109 111 void ?{}( __condition_blocked_queue_t & );112 void append( __condition_blocked_queue_t &, __condition_node_t * );113 __condition_node_t * pop_head( __condition_blocked_queue_t & );114 115 110 struct condition { 116 111 // Link list which contains the blocked threads as-well as the information needed to unblock them 117 __ condition_blocked_queue_tblocked;112 __queue_t(__condition_node_t) blocked; 118 113 119 114 // Array of monitor pointers (Monitors are NOT contiguous in memory) -
src/libcfa/concurrency/monitor.c
rcf966b5 r6c2ba38 280 280 static inline void enter( __monitor_group_t monitors ) { 281 281 for( __lock_size_t i = 0; i < monitors.size; i++) { 282 __enter_monitor_desc( monitors .list[i], monitors );282 __enter_monitor_desc( monitors[i], monitors ); 283 283 } 284 284 } … … 303 303 304 304 // Save previous thread context 305 this. [prev_mntrs, prev_count, prev_func] = this_thread->monitors.[list, size, func];305 this.prev = this_thread->monitors; 306 306 307 307 // Update thread context (needed for conditions) 308 this_thread->monitors.[list, size, func] = [m, count, func];308 (this_thread->monitors){m, count, func}; 309 309 310 310 // LIB_DEBUG_PRINT_SAFE("MGUARD : enter %d\n", count); … … 328 328 329 329 // Restore thread context 330 this_thread->monitors .[list, size, func] = this.[prev_mntrs, prev_count, prev_func];330 this_thread->monitors = this.prev; 331 331 } 332 332 … … 338 338 339 339 // Save previous thread context 340 this. [prev_mntrs, prev_count, prev_func] = this_thread->monitors.[list, size, func];340 this.prev = this_thread->monitors; 341 341 342 342 // Update thread context (needed for conditions) 343 this_thread->monitors.[list, size, func] = [m, 1, func];343 (this_thread->monitors){m, 1, func}; 344 344 345 345 __enter_monitor_dtor( this.m, func ); … … 352 352 353 353 // Restore thread context 354 this_thread->monitors .[list, size, func] = this.[prev_mntrs, prev_count, prev_func];354 this_thread->monitors = this.prev; 355 355 } 356 356 … … 437 437 438 438 for(int i = 0; i < this.monitor_count; i++) { 439 if ( this.monitors[i] != this_thrd->monitors .list[i] ) {440 abortf( "Signal on condition %p made with different monitor, expected %p got %i", &this, this.monitors[i], this_thrd->monitors .list[i] );439 if ( this.monitors[i] != this_thrd->monitors[i] ) { 440 abortf( "Signal on condition %p made with different monitor, expected %p got %i", &this, this.monitors[i], this_thrd->monitors[i] ); 441 441 } 442 442 } … … 510 510 "Possible cause is not checking if the condition is empty before reading stored data." 511 511 ); 512 return this.blocked.head->user_info;512 return ((typeof(this.blocked.head))this.blocked.head)->user_info; 513 513 } 514 514 … … 554 554 if( next ) { 555 555 *mask.accepted = index; 556 if( mask.clauses[index].is_dtor ) { 556 __acceptable_t& accepted = mask[index]; 557 if( accepted.is_dtor ) { 557 558 LIB_DEBUG_PRINT_BUFFER_LOCAL( "Kernel : dtor already there\n"); 558 verifyf( mask.clauses[index].size == 1 ,"ERROR: Accepted dtor has more than 1 mutex parameter." );559 560 monitor_desc * mon2dtor = mask.clauses[index].list[0];559 verifyf( accepted.size == 1, "ERROR: Accepted dtor has more than 1 mutex parameter." ); 560 561 monitor_desc * mon2dtor = accepted[0]; 561 562 verifyf( mon2dtor->dtor_node, "ERROR: Accepted monitor has no dtor_node." ); 562 563 … … 596 597 597 598 LIB_DEBUG_PRINT_BUFFER_LOCAL( "Kernel : accepted %d\n", *mask.accepted); 598 599 599 return; 600 600 } … … 671 671 static inline void reset_mask( monitor_desc * this ) { 672 672 this->mask.accepted = NULL; 673 this->mask. clauses= NULL;673 this->mask.data = NULL; 674 674 this->mask.size = 0; 675 675 } … … 697 697 698 698 static inline bool is_accepted( monitor_desc * this, const __monitor_group_t & group ) { 699 __acceptable_t * it = this->mask. clauses; // Optim699 __acceptable_t * it = this->mask.data; // Optim 700 700 __lock_size_t count = this->mask.size; 701 701 … … 820 820 if( !this.monitors ) { 821 821 // LIB_DEBUG_PRINT_SAFE("Branding\n"); 822 assertf( thrd->monitors. list != NULL, "No current monitor to brand condition %p", thrd->monitors.list);822 assertf( thrd->monitors.data != NULL, "No current monitor to brand condition %p", thrd->monitors.data ); 823 823 this.monitor_count = thrd->monitors.size; 824 824 825 825 this.monitors = (monitor_desc **)malloc( this.monitor_count * sizeof( *this.monitors ) ); 826 826 for( int i = 0; i < this.monitor_count; i++ ) { 827 this.monitors[i] = thrd->monitors .list[i];827 this.monitors[i] = thrd->monitors[i]; 828 828 } 829 829 } … … 832 832 static inline [thread_desc *, int] search_entry_queue( const __waitfor_mask_t & mask, monitor_desc * monitors [], __lock_size_t count ) { 833 833 834 __ thread_queue_t& entry_queue = monitors[0]->entry_queue;834 __queue_t(thread_desc) & entry_queue = monitors[0]->entry_queue; 835 835 836 836 // For each thread in the entry-queue … … 841 841 // For each acceptable check if it matches 842 842 int i = 0; 843 __acceptable_t * end = mask.clauses + mask.size; 844 for( __acceptable_t * it = mask.clauses; it != end; it++, i++ ) { 843 __acceptable_t * end = end (mask); 844 __acceptable_t * begin = begin(mask); 845 for( __acceptable_t * it = begin; it != end; it++, i++ ) { 845 846 // Check if we have a match 846 847 if( *it == (*thrd_it)->monitors ) { … … 872 873 __lock_size_t max = 0; 873 874 for( __lock_size_t i = 0; i < mask.size; i++ ) { 874 max += mask.clauses[i].size; 875 __acceptable_t & accepted = mask[i]; 876 max += accepted.size; 875 877 } 876 878 return max; … … 880 882 __lock_size_t size = 0; 881 883 for( __lock_size_t i = 0; i < mask.size; i++ ) { 882 __libcfa_small_sort( mask.clauses[i].list, mask.clauses[i].size ); 883 for( __lock_size_t j = 0; j < mask.clauses[i].size; j++) { 884 insert_unique( storage, size, mask.clauses[i].list[j] ); 884 __acceptable_t & accepted = mask[i]; 885 __libcfa_small_sort( accepted.data, accepted.size ); 886 for( __lock_size_t j = 0; j < accepted.size; j++) { 887 insert_unique( storage, size, accepted[j] ); 885 888 } 886 889 } … … 888 891 __libcfa_small_sort( storage, size ); 889 892 return size; 890 }891 892 void ?{}( __condition_blocked_queue_t & this ) {893 this.head = NULL;894 this.tail = &this.head;895 }896 897 void append( __condition_blocked_queue_t & this, __condition_node_t * c ) {898 verify(this.tail != NULL);899 *this.tail = c;900 this.tail = &c->next;901 }902 903 __condition_node_t * pop_head( __condition_blocked_queue_t & this ) {904 __condition_node_t * head = this.head;905 if( head ) {906 this.head = head->next;907 if( !head->next ) {908 this.tail = &this.head;909 }910 head->next = NULL;911 }912 return head;913 893 } 914 894 -
src/libcfa/exception.h
rcf966b5 r6c2ba38 17 17 18 18 19 #ifdef __ CFORALL__19 #ifdef __cforall 20 20 extern "C" { 21 21 #endif … … 68 68 struct __cfaehm__cleanup_hook {}; 69 69 70 #ifdef __ CFORALL__70 #ifdef __cforall 71 71 } 72 72 #endif -
src/libcfa/stdhdr/assert.h
rcf966b5 r6c2ba38 4 4 // The contents of this file are covered under the licence agreement in the 5 5 // file "LICENCE" distributed with Cforall. 6 // 7 // assert.h -- 8 // 6 // 7 // assert.h -- 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Mon Jul 4 23:25:26 2016 … … 12 12 // Last Modified On : Mon Jul 31 23:09:32 2017 13 13 // Update Count : 13 14 // 14 // 15 15 16 #ifdef __ CFORALL__16 #ifdef __cforall 17 17 extern "C" { 18 #endif //__ CFORALL__18 #endif //__cforall 19 19 20 20 #include_next <assert.h> … … 30 30 #endif 31 31 32 #ifdef __ CFORALL__32 #ifdef __cforall 33 33 } // extern "C" 34 #endif //__ CFORALL__34 #endif //__cforall 35 35 36 36 // Local Variables: // -
src/libcfa/virtual.h
rcf966b5 r6c2ba38 16 16 #pragma once 17 17 18 #ifdef __ CFORALL__18 #ifdef __cforall 19 19 extern "C" { 20 20 #endif … … 35 35 struct __cfa__parent_vtable const * const * child ); 36 36 37 #ifdef __ CFORALL__37 #ifdef __cforall 38 38 } 39 39 #endif -
src/tests/Makefile.am
rcf966b5 r6c2ba38 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Tue Oct 10 14:04:40201714 ## Update Count : 4 713 ## Last Modified On : Mon Nov 27 21:34:33 2017 14 ## Update Count : 48 15 15 ############################################################################### 16 16 … … 118 118 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} 119 119 120 functions: functions.c @CFA_BINDIR@/@CFA_NAME@ 121 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} 122 120 123 KRfunctions : KRfunctions.c @CFA_BINDIR@/@CFA_NAME@ 121 124 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} -
src/tests/Makefile.in
rcf966b5 r6c2ba38 871 871 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} 872 872 873 functions: functions.c @CFA_BINDIR@/@CFA_NAME@ 874 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} 875 873 876 KRfunctions : KRfunctions.c @CFA_BINDIR@/@CFA_NAME@ 874 877 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} -
src/tests/designations.c
rcf966b5 r6c2ba38 17 17 // In particular, since the syntax for designations in Cforall differs from that of C, preprocessor substitution 18 18 // is used for the designation syntax 19 #ifdef __ CFORALL__19 #ifdef __cforall 20 20 #define DES : 21 21 #else -
src/tests/functions.c
rcf966b5 r6c2ba38 10 10 // Created On : Wed Aug 17 08:39:58 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Aug 17 08:40:52 201613 // Update Count : 1 12 // Last Modified On : Mon Nov 27 18:08:54 2017 13 // Update Count : 11 14 14 // 15 15 … … 66 66 // Cforall extensions 67 67 68 [] f( );68 // [] f( ); 69 69 [int] f( ); 70 [] f(int);70 // [] f(int); 71 71 [int] f(int); 72 [] f( ) {}72 // [] f( ) {} 73 73 [int] f( ) {} 74 [] f(int) {}74 // [] f(int) {} 75 75 [int] f(int) {} 76 76 77 77 [int x] f( ); 78 [] f(int x);79 [int x] f(int x);80 [int x] f( ) {}81 [] f(int x) {}82 [int x] f(int x) {}78 // [] f(int x); 79 //[int x] f(int x); 80 //[int x] f( ) {} 81 // [] f(int x) {} 82 //[int x] f(int x) {} 83 83 84 84 [int, int x] f( ); 85 [] f(int, int x);85 // [] f(int, int x); 86 86 [int, int x] f(int, int x); 87 87 [int, int x] f( ) {} 88 [] f(int, int x) {}88 // [] f(int, int x) {} 89 89 [int, int x] f(int, int x) {} 90 90 91 91 [int, int x, int] f( ); 92 [] f(int, int x, int);92 // [] f(int, int x, int); 93 93 [int, int x, int] f(int, int x, int); 94 94 [int, int x, int] f( ) {} 95 [] f(int, int x, int) {}95 // [] f(int, int x, int) {} 96 96 [int, int x, int] f(int, int x, int) {} 97 97 98 98 [int, int x, * int y] f( ); 99 [] f(int, int x, * int y);99 // [] f(int, int x, * int y); 100 100 [int, int x, * int y] f(int, int x, * int y); 101 101 [int, int x, * int y] f( ) {} 102 [] f(int, int x, * int y) {}102 // [] f(int, int x, * int y) {} 103 103 [int, int x, * int y] f(int, int x, * int y) {} 104 104 105 [ int ] f11( int ), f12; // => int f11( int ), f12( int ); 105 // function prototypes 106 107 [ int ] f11( int ), f12(); // => int f11( int ), f12( void ); 108 109 const double bar1(), bar2( int ), bar3( double ); // C version 110 [const double] foo(), foo( int ), foo( double ) { return 3.0; } // CFA version 111 struct S { int i; }; 112 [S] rtn( int ) {} 113 106 114 107 115 [int] f( … … 109 117 [int](int) 110 118 ) { 111 int (*(*p )[][10])[][3];119 int (*(*pc)[][10])[][3]; 112 120 * [][10] * [][3] int p; 113 121 * [] * [int](int) p; -
src/tests/polymorphism.c
rcf966b5 r6c2ba38 47 47 S s; 48 48 s.i = i; 49 assert (s.i == i);49 assertf(s.i == i, "struct operation fails in polymorphic context."); 50 50 51 51 B b; … … 73 73 { 74 74 // test aggregates with polymorphic members 75 typedef uint32_t x_type;76 typedef uint64_t y_type;75 typedef __attribute__((aligned(8))) uint32_t x_type; 76 typedef __attribute__((aligned(8))) uint64_t y_type; 77 77 78 78 x_type x = 3; … … 89 89 // ensure that the size of aggregates with polymorphic members 90 90 // matches the size of the aggregates in a monomorphic context 91 assert( struct_size(x, y) == sizeof(S) ); 92 assert( union_size(x, y) == sizeof(U) ); 91 size_t ssz = struct_size(x, y); 92 size_t usz = union_size(x, y); 93 assertf( ssz == sizeof(S), "struct size differs in polymorphic context: %zd / %zd", ssz, sizeof(S)); 94 assertf( usz == sizeof(U), "union size differs in polymorphic context: %zd / %zd", usz, sizeof(U)); 93 95 94 96 y_type ?=?(y_type & this, zero_t) { … … 111 113 u.f2 = 0; 112 114 u.f1 = x; 113 assert (ret == u.f2);115 assertf(ret == u.f2, "union operation fails in polymorphic context."); 114 116 } 115 117 }
Note: See TracChangeset
for help on using the changeset viewer.