Changes in / [9d6f011:28bc8c8]
- Files:
-
- 20 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/papers/general/Paper.tex
r9d6f011 r28bc8c8 267 267 int m = max( max, -max ); $\C{// uses (3) and (1) twice, by matching return type}$ 268 268 \end{cfa} 269 270 269 \CFA maximizes the ability to reuse names to aggressively address the naming problem. 271 270 In some cases, hundreds of names can be reduced to tens, resulting in a significant cognitive reduction. … … 286 285 287 286 288 \subsection{\texorpdfstring{\ protect\lstinline{forall} Functions}{forall Functions}}287 \subsection{\texorpdfstring{\LstKeywordStyle{forall} Functions}{forall Functions}} 289 288 \label{sec:poly-fns} 290 289 … … 436 435 One approach is to write bespoke data-structures for each context in which they are needed. 437 436 While this approach is flexible and supports integration with the C type-checker and tooling, it is also tedious and error-prone, especially for more complex data structures. 438 A second approach is to use @void *@ 437 A second approach is to use @void *@--based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@, which allow reuse of code with common functionality. 439 438 However, basing all polymorphism on @void *@ eliminates the type-checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that is not otherwise needed. 440 439 A third approach to generic code is to use preprocessor macros, which does allow the generated code to be both generic and type-checked, but errors may be difficult to interpret. … … 508 507 The offset arrays are statically generated where possible. 509 508 If a dynamic generic-type is declared to be passed or returned by value from a polymorphic function, the translator can safely assume the generic type is complete (\ie has a known layout) at any call-site, and the offset array is passed from the caller; 510 if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C @offsetof@ macro. 511 As an example, the body of the second @value@ function is implemented as:512 \begin{cfa} 513 _assign_T( _retval, p + _offsetof_pair[1]); $\C{// return *p.second}$514 \end{cfa} 515 @_assign_T@ is passed in as an implicit parameter from @otype T@, and takes two @T *@ (@void*@ in the generated code), a destination and a source; @_retval@ is the pointer to a caller-allocated buffer for the return value, the usual \CFA method to handle dynamically-sized return types.509 if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C @offsetof@ macro. 510 As an example, the body of the second @value@ function is implemented like this: 511 \begin{cfa} 512 _assign_T(_retval, p + _offsetof_pair[1]); $\C{// return *p.second}$ 513 \end{cfa} 514 @_assign_T@ is passed in as an implicit parameter from @otype T@, and takes two @T*@ (@void*@ in the generated code), a destination and a source; @_retval@ is the pointer to a caller-allocated buffer for the return value, the usual \CFA method to handle dynamically-sized return types. 516 515 @_offsetof_pair@ is the offset array passed into @value@; this array is generated at the call site as: 517 516 \begin{cfa} 518 size_t _offsetof_pair[] = { offsetof( _pair_conc0, first ), offsetof( _pair_conc0, second) }517 size_t _offsetof_pair[] = { offsetof(_pair_conc0, first), offsetof(_pair_conc0, second) } 519 518 \end{cfa} 520 519 … … 540 539 The most important such pattern is using @forall(dtype T) T *@ as a type-checked replacement for @void *@, \eg creating a lexicographic comparison for pairs of pointers used by @bsearch@ or @qsort@: 541 540 \begin{cfa} 542 forall( dtype T) int lexcmp( pair( T *, T * ) * a, pair( T *, T * ) * b, int (* cmp)( T *, T * ) ) {541 forall(dtype T) int lexcmp( pair( T *, T * ) * a, pair( T *, T * ) * b, int (* cmp)( T *, T * ) ) { 543 542 return cmp( a->first, b->first ) ? : cmp( a->second, b->second ); 544 543 } 545 544 \end{cfa} 546 Since @pair( 545 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. 547 546 548 547 Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \newterm{tag-structures}. 549 548 Sometimes information is only used for type-checking and can be omitted at runtime, \eg: 550 549 \begin{cfa} 551 forall( dtype Unit) struct scalar { unsigned long value; };550 forall(dtype Unit) struct scalar { unsigned long value; }; 552 551 struct metres {}; 553 552 struct litres {}; 554 553 555 forall( dtype U) scalar(U) ?+?( scalar(U) a, scalar(U) b ) {554 forall(dtype U) scalar(U) ?+?( scalar(U) a, scalar(U) b ) { 556 555 return (scalar(U)){ a.value + b.value }; 557 556 } … … 808 807 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, \eg: 809 808 \begin{cfa} 810 forall( otype T, dtype U) void f( T x, U * y );809 forall(otype T, dtype U) void f( T x, U * y ); 811 810 f( [5, "hello"] ); 812 811 \end{cfa} … … 815 814 For example, a plus operator can be written to add two triples together. 816 815 \begin{cfa} 817 forall( otype T | { T ?+?( T, T ); }) [T, T, T] ?+?( [T, T, T] x, [T, T, T] y ) {816 forall(otype T | { T ?+?( T, T ); }) [T, T, T] ?+?( [T, T, T] x, [T, T, T] y ) { 818 817 return [x.0 + y.0, x.1 + y.1, x.2 + y.2]; 819 818 } … … 826 825 \begin{cfa} 827 826 int f( [int, double], double ); 828 forall( otype T, otype U | { T f( T, U, U ); }) void g( T, U );827 forall(otype T, otype U | { T f( T, U, U ); }) void g( T, U ); 829 828 g( 5, 10.21 ); 830 829 \end{cfa} 831 830 Hence, function parameter and return lists are flattened for the purposes of type unification allowing the example to pass expression resolution. 832 831 This relaxation is possible by extending the thunk scheme described by Bilson~\cite{Bilson03}. 833 %Whenever a candidate's parameter structure does not exactly match the formal parameter's structure, a thunk is generated to specialize calls to the actual function:834 %\begin{cfa}835 %int _thunk( int _p0, double _p1, double _p2 ) { return f( [_p0, _p1], _p2 ); }836 %\end{cfa}837 %so the thunk provides flattening and structuring conversions to inferred functions, improving the compatibility of tuples and polymorphism.838 % These thunks are generated locally using gcc nested-functions, rather hositing them to the external scope, so they can easily access local state.832 Whenever a candidate's parameter structure does not exactly match the formal parameter's structure, a thunk is generated to specialize calls to the actual function: 833 \begin{cfa} 834 int _thunk( int _p0, double _p1, double _p2 ) { return f( [_p0, _p1], _p2 ); } 835 \end{cfa} 836 so the thunk provides flattening and structuring conversions to inferred functions, improving the compatibility of tuples and polymorphism. 837 These thunks take advantage of gcc C nested-functions to produce closures that have the usual function-pointer signature WHAT DOES THIS MEAN???. 839 838 840 839 … … 853 852 \begin{cfa} 854 853 int sum$\(_0\)$() { return 0; } 855 forall( 854 forall(ttype Params | { int sum( Params ); } ) int sum$\(_1\)$( int x, Params rest ) { 856 855 return x + sum( rest ); 857 856 } … … 866 865 \begin{cfa} 867 866 int sum( int x, int y ) { return x + y; } 868 forall( 867 forall(ttype Params | { int sum( int, Params ); } ) int sum( int x, int y, Params rest ) { 869 868 return sum( x + y, rest ); 870 869 } … … 872 871 One more step permits the summation of any summable type with all arguments of the same type: 873 872 \begin{cfa} 874 trait summable( otype T) {873 trait summable(otype T) { 875 874 T ?+?( T, T ); 876 875 }; 877 forall( 876 forall(otype R | summable( R ) ) R sum( R x, R y ) { 878 877 return x + y; 879 878 } 880 forall( 879 forall(otype R, ttype Params | summable(R) | { R sum(R, Params); } ) R sum(R x, R y, Params rest) { 881 880 return sum( x + y, rest ); 882 881 } … … 889 888 \begin{cfa} 890 889 struct S { int x, y; }; 891 forall( otype T, ttype Params | { void print(T); void print(Params); }) void print(T arg, Params rest) {890 forall(otype T, ttype Params | { void print(T); void print(Params); }) void print(T arg, Params rest) { 892 891 print(arg); print(rest); 893 892 } … … 928 927 is transformed into: 929 928 \begin{cfa} 930 forall( dtype T0, dtype T1 | sized(T0) | sized(T1)) struct _tuple2 {929 forall(dtype T0, dtype T1 | sized(T0) | sized(T1)) struct _tuple2 { 931 930 T0 field_0; $\C{// generated before the first 2-tuple}$ 932 931 T1 field_1; … … 934 933 _tuple2(int, int) f() { 935 934 _tuple2(double, double) x; 936 forall( dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2)) struct _tuple3 {935 forall(dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2)) struct _tuple3 { 937 936 T0 field_0; $\C{// generated before the first 3-tuple}$ 938 937 T1 field_1; … … 942 941 } 943 942 \end{cfa} 944 {\sloppy 943 \begin{sloppypar} 945 944 Tuple expressions are then simply converted directly into compound literals, \eg @[5, 'x', 1.24]@ becomes @(_tuple3(int, char, double)){ 5, 'x', 1.24 }@. 946 \ par}%945 \end{sloppypar} 947 946 948 947 \begin{comment} … … 1005 1004 \section{Control Structures} 1006 1005 1007 \CFA identifies inconsistent, problematic, and missing control structures in C, and extends, modifies, and adds control structures to increase functionality and safety.1008 1009 1010 \subsection{\texorpdfstring{\ protect\lstinline{if} Statement}{if Statement}}1006 \CFA identifies inconsistent, problematic, and missing control structures in C, and extends, modifies, and adds to control structures to increase functionality and safety. 1007 1008 1009 \subsection{\texorpdfstring{\LstKeywordStyle{if} Statement}{if Statement}} 1011 1010 1012 1011 The @if@ expression allows declarations, similar to @for@ declaration expression: … … 1020 1019 1021 1020 1022 \subsection{\texorpdfstring{\ protect\lstinline{switch} Statement}{switch Statement}}1021 \subsection{\texorpdfstring{\LstKeywordStyle{switch} Statement}{switch Statement}} 1023 1022 1024 1023 There are a number of deficiencies with the C @switch@ statements: enumerating @case@ lists, placement of @case@ clauses, scope of the switch body, and fall through between case clauses. … … 1040 1039 \lstMakeShortInline@% 1041 1040 \end{cquote} 1042 for a contiguous list:\footnote{gcc has the same mechanism but awkward syntax, \lstinline@2 ...42@, because a space is required after a number, otherwise the period is a decimal point.}1041 for a contiguous list:\footnote{gcc provides the same mechanism with awkward syntax, \lstinline@2 ... 42@, where spaces are required around the ellipse.} 1043 1042 \begin{cquote} 1044 1043 \lstDeleteShortInline@% … … 1091 1090 C @switch@ provides multiple entry points into the statement body, but once an entry point is selected, control continues across \emph{all} @case@ clauses until the end of the @switch@ body, called \newterm{fall through}; 1092 1091 @case@ clauses are made disjoint by the @break@ statement. 1093 While fall through \emph{is} a useful form of control flow, it does not match well with programmer intuition, resulting in errors from missing @break@ statements. 1094 For backwards compatibility, \CFA provides a \emph{new} control structure, @choose@, which mimics @switch@, but reverses the meaning of fall through (see Figure~\ref{f:ChooseSwitchStatements}), similar to Go. 1092 While the ability to fall through \emph{is} a useful form of control flow, it does not match well with programmer intuition, resulting in many errors from missing @break@ statements. 1093 For backwards compatibility, \CFA provides a \emph{new} control structure, @choose@, which mimics @switch@, but reverses the meaning of fall through (see Figure~\ref{f:ChooseSwitchStatements}). 1094 1095 Collectively, these enhancements reduce programmer burden and increase readability and safety. 1095 1096 1096 1097 \begin{figure} … … 1136 1137 \end{figure} 1137 1138 1138 Finally, @fallthrough@ may appear in contexts other than terminating a @case@ clause, and have an explicit transfer label allowing separate cases but common final-code for a set of cases: 1139 \begin{cquote} 1140 \lstDeleteShortInline@% 1141 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1142 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{non-terminator}} & \multicolumn{1}{c}{\textbf{target label}} \\ 1143 \begin{cfa} 1144 choose ( ... ) { 1145 case 3: 1146 if ( ... ) { 1147 ... `fallthrough;` // goto case 4 1148 } else { 1149 ... 1150 } 1151 // implicit break 1152 case 4: 1153 \end{cfa} 1154 & 1155 \begin{cfa} 1156 choose ( ... ) { 1157 case 3: 1158 ... `fallthrough common;` 1159 case 4: 1160 ... `fallthrough common;` 1161 common: 1162 ... // common code for cases 3 and 4 1163 // implicit break 1164 case 4: 1165 \end{cfa} 1166 \end{tabular} 1167 \lstMakeShortInline@% 1168 \end{cquote} 1169 The target label may be case @default@. 1170 1171 Collectively, these control-structure enhancements reduce programmer burden and increase readability and safety. 1172 1173 1174 \subsection{\texorpdfstring{Labelled \protect\lstinline{continue} / \protect\lstinline{break}}{Labelled continue / break}} 1139 \begin{comment} 1140 Forgotten @break@ statements at the end of @switch@ cases are a persistent sort of programmer error in C, and the @break@ statements themselves introduce visual clutter and an un-C-like keyword-based block delimiter. 1141 \CFA addresses this error by introducing a @choose@ statement, which works identically to a @switch@ except that its default end-of-case behaviour is to break rather than to fall through for all non-empty cases. 1142 Since empty cases like @case 7:@ in @case 7: case 11:@ still have fall-through semantics and explicit @break@ is still allowed at the end of a @choose@ case, many idiomatic uses of @switch@ in standard C can be converted to @choose@ statements by simply changing the keyword. 1143 Where fall-through is desired for a non-empty case, it can be specified with the new @fallthrough@ statement, making @choose@ equivalently powerful to @switch@, but more concise in the common case where most non-empty cases end with a @break@ statement, as in the example below: 1144 1145 \begin{cfa} 1146 choose( i ) { 1147 case 2: 1148 printf("even "); 1149 fallthrough; 1150 case 3: case 5: case 7: 1151 printf("small prime\n"); 1152 case 4,6,8,9: 1153 printf("small composite\n"); 1154 case 13~19: 1155 printf("teen\n"); 1156 default: 1157 printf("something else\n"); 1158 } 1159 \end{cfa} 1160 \end{comment} 1161 1162 1163 \subsection{\texorpdfstring{Labelled \LstKeywordStyle{continue} / \LstKeywordStyle{break}}{Labelled continue / break}} 1175 1164 1176 1165 While C provides @continue@ and @break@ statements for altering control flow, both are restricted to one level of nesting for a particular control structure. … … 1281 1270 \subsection{Exception Handling} 1282 1271 1283 The following framework for \CFA exception handling is in place, excluding some run time type-information and virtual functions.1272 The following framework for \CFA exception handling is in place, excluding some run-time type-information and dynamic casts. 1284 1273 \CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling})~\cite{Buhr92b,Buhr00a}. 1285 1274 Both mechanisms provide dynamic call to a handler using dynamic name-lookup, where fix-up has dynamic return and recovery has static return from the handler. … … 1351 1340 catch ( IOError err ) { ... } $\C{// handler error from other files}$ 1352 1341 \end{cfa} 1353 where the throw inserts the failing file-handle in tothe I/O exception.1342 where the throw inserts the failing file-handle in the I/O exception. 1354 1343 Conditional catch cannot be trivially mimicked by other mechanisms because once an exception is caught, handler clauses in that @try@ statement are no longer eligible.. 1355 1344 … … 1359 1348 resume( $\emph{alternate-stack}$ ) 1360 1349 \end{cfa} 1361 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another \CFA coroutine or task \footnote{\CFA coroutine and concurrency features are discussed in a separately submitted paper.}~\cite{Delisle18}.1362 Nonlocal raise is restricted to resumption to provide the exception handler the greatest flexibility because processing the exception does not unwind its stack, allowing it to continue after the handle rreturns.1363 1364 To facilitate nonlocal raise, \CFA provides dynamic enabling and disabling of nonlocal exception-propagation.1350 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another \CFA coroutine or task~\cite{Delisle18}.\footnote{\CFA coroutine and concurrency features are discussed in a separately submitted paper.} 1351 Nonlocal raise is restricted to resumption to provide the exception handler the greatest flexibility because processing the exception does not unwind its stack, allowing it to continue after the handle returns. 1352 1353 To facilitate nonlocal exception, \CFA provides dynamic enabling and disabling of nonlocal exception-propagation. 1365 1354 The constructs for controlling propagation of nonlocal exceptions are the @enable@ and the @disable@ blocks: 1366 1355 \begin{cquote} … … 1369 1358 \begin{cfa} 1370 1359 enable $\emph{exception-type-list}$ { 1371 // allow non-local r aise1360 // allow non-local resumption 1372 1361 } 1373 1362 \end{cfa} … … 1375 1364 \begin{cfa} 1376 1365 disable $\emph{exception-type-list}$ { 1377 // disallow non-local r aise1366 // disallow non-local resumption 1378 1367 } 1379 1368 \end{cfa} … … 1386 1375 Coroutines and tasks start with non-local exceptions disabled, allowing handlers to be put in place, before non-local exceptions are explicitly enabled. 1387 1376 \begin{cfa} 1388 void main( mytask & t ) { $\C{// thread starts here}$ 1389 // non-local exceptions disabled 1390 try { $\C{// establish handles for non-local exceptions}$ 1391 enable { $\C{// allow non-local exception delivery}$ 1377 void main( mytask & c ) { 1378 try { 1379 enable { $\C{// now allow non-local exception delivery}$ 1392 1380 // task body 1393 1381 } 1394 // appropriate catchResume/catch handlers1382 // appropriate catchResume/catch 1395 1383 } 1396 1384 } … … 1412 1400 1413 1401 1414 \subsection{\texorpdfstring{\ protect\lstinline{with} Clause / Statement}{with Clause / Statement}}1402 \subsection{\texorpdfstring{\LstKeywordStyle{with} Clause / Statement}{with Clause / Statement}} 1415 1403 \label{s:WithClauseStatement} 1416 1404 … … 1812 1800 int & r = *new( int ); 1813 1801 ... $\C{// non-null reference}$ 1814 delete &r; $\C{// unmanaged (programmer) memory-management}$1802 delete &r; 1815 1803 r += 1; $\C{// undefined reference}$ 1816 1804 \end{cfa} … … 1959 1947 Constructor calls seamlessly integrate with existing C initialization syntax, providing a simple and familiar syntax to C programmers and allowing constructor calls to be inserted into legacy C code with minimal code changes. 1960 1948 1961 In \CFA, a constructor is named @?{}@ and a destructor is named @^?{}@\footnote{% 1949 In \CFA, a constructor is named @?{}@ and a destructor is named @^?{}@. 1950 The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@\footnote{% 1962 1951 The symbol \lstinline+^+ is used for the destructor name because it was the last binary operator that could be used in a unary context.}. 1963 The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@.1964 1952 Like other \CFA operators, these names represent the syntax used to call the constructor or destructor, \eg @?{}(x, ...)@ or @^{}(x, ...)@. 1965 1953 The constructor and destructor have return type @void@, and the first parameter is a reference to the object type to be constructed or destructed. … … 2083 2071 \subsection{0/1} 2084 2072 2085 In C, @0@ has the special property that it is the only ``false'' value; 2086 from the standard, any value that compares equal to @0@ is false, while any value that compares unequal to @0@ is true. 2087 As such, an expression @x@ in any boolean context (such as the condition of an @if@ or @while@ statement, or the arguments to @&&@, @||@, or @?:@\,) can be rewritten as @x != 0@ without changing its semantics. 2088 Operator overloading in \CFA provides a natural means to implement this truth-value comparison for arbitrary types, but the C type system is not precise enough to distinguish an equality comparison with @0@ from an equality comparison with an arbitrary integer or pointer. 2089 To provide this precision, \CFA introduces a new type @zero_t@ as the type of literal @0@ (somewhat analagous to @nullptr_t@ and @nullptr@ in \CCeleven); 2090 @zero_t@ can only take the value @0@, but has implicit conversions to the integer and pointer types so that C code involving @0@ continues to work. 2091 With this addition, \CFA rewrites @if (x)@ and similar expressions to @if ((x) != 0)@ or the appropriate analogue, and any type @T@ is ``truthy'' by defining an operator overload @int ?!=?(T, zero_t)@. 2092 \CC makes types truthy by adding a conversion to @bool@; 2093 prior to the addition of explicit cast operators in \CCeleven, this approach had the pitfall of making truthy types transitively convertable to any numeric type; 2094 \CFA avoids this issue. 2095 2096 Similarly, \CFA also has a special type for @1@, @one_t@; 2097 like @zero_t@, @one_t@ has built-in implicit conversions to the various integral types so that @1@ maintains its expected semantics in legacy code for operations @++@ and @--@. 2098 The addition of @one_t@ allows generic algorithms to handle the unit value uniformly for types where it is meaningful. 2099 \TODO{Make this sentence true} 2100 In particular, polymorphic functions in the \CFA prelude define @++x@ and @x++@ in terms of @x += 1@, allowing users to idiomatically define all forms of increment for a type @T@ by defining the single function @T & ?+=(T &, one_t)@; 2101 analogous overloads for the decrement operators are present as well. 2073 In C, @0@ has the special property that it is the only ``false'' value; by the standard, any value which compares equal to @0@ is false, while any value that compares unequal to @0@ is true. 2074 As such, an expression @x@ in any boolean context (such as the condition of an @if@ or @while@ statement, or the arguments to @&&@, @||@, or @?:@) can be rewritten as @x != 0@ without changing its semantics. 2075 The operator overloading feature of \CFA provides a natural means to implement this truth value comparison for arbitrary types, but the C type system is not precise enough to distinguish an equality comparison with @0@ from an equality comparison with an arbitrary integer or pointer. 2076 To provide this precision, \CFA introduces a new type @zero_t@ as type type of literal @0@ (somewhat analagous to @nullptr_t@ and @nullptr@ in \CCeleven); @zero_t@ can only take the value @0@, but has implicit conversions to the integer and pointer types so that C code involving @0@ continues to work properly. 2077 With this addition, the \CFA compiler rewrites @if (x)@ and similar expressions to @if ((x) != 0)@ or the appropriate analogue, and any type @T@ can be made ``truthy'' by defining an operator overload @int ?!=?(T, zero_t)@. 2078 \CC makes types truthy by adding a conversion to @bool@; prior to the addition of explicit cast operators in \CCeleven this approach had the pitfall of making truthy types transitively convertable to any numeric type; our design for \CFA avoids this issue. 2079 2080 \CFA also includes a special type for @1@, @one_t@; like @zero_t@, @one_t@ has built-in implicit conversions to the various integral types so that @1@ maintains its expected semantics in legacy code. 2081 The addition of @one_t@ allows generic algorithms to handle the unit value uniformly for types where that is meaningful. 2082 \TODO{Make this sentence true} In particular, polymorphic functions in the \CFA prelude define @++x@ and @x++@ in terms of @x += 1@, allowing users to idiomatically define all forms of increment for a type @T@ by defining the single function @T & ?+=(T &, one_t)@; analogous overloads for the decrement operators are present as well. 2102 2083 2103 2084 … … 2107 2088 The left of Figure~\ref{f:UserLiteral} shows the \CFA alternative call-syntax (literal argument before function name), using the backquote, to convert basic literals into user literals. 2108 2089 The backquote is a small character, making the unit (function name) predominate. 2109 For examples, the multi-precision integer -type in Section~\ref{s:MultiPrecisionIntegers} hasuser literals:2090 For examples, the multi-precision integers in Section~\ref{s:MultiPrecisionIntegers} make use of user literals: 2110 2091 {\lstset{language=CFA,moredelim=**[is][\color{red}]{|}{|},deletedelim=**[is][]{`}{`}} 2111 2092 \begin{cfa} … … 2327 2308 \lstMakeShortInline@% 2328 2309 \end{cquote} 2329 In additon, there are polymorphic functions, like @min@ and @max@, thatwork on any type with operators @?<?@ or @?>?@.2310 In additon, there are polymorphic functions, like @min@ and @max@, which work on any type with operators @?<?@ or @?>?@. 2330 2311 2331 2312 The following shows one example where \CFA \emph{extends} an existing standard C interface to reduce complexity and provide safety. … … 2338 2319 In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied. 2339 2320 For an increase in storage size, new storage after the copied data may be filled. 2340 \item[align ]2321 \item[alignment] 2341 2322 an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes. 2342 2323 \item[array] 2343 allocation with aspecified number of elements.2324 allocation of the specified number of elements. 2344 2325 An array may be filled, resized, or aligned. 2345 2326 \end{description} … … 2353 2334 \lstMakeShortInline~% 2354 2335 \begin{tabular}{@{}r|r|l|l|l|l@{}} 2355 \multicolumn{1}{c}{}& & \multicolumn{1}{c|}{fill} & resize & align & array \\2336 \multicolumn{1}{c}{}& & \multicolumn{1}{c|}{fill} & resize & alignment & array \\ 2356 2337 \hline 2357 2338 C & ~malloc~ & no & no & no & no \\ … … 2581 2562 TIMED( "copy_int", ti{ si }; ) 2582 2563 TIMED( "clear_int", clear( si ); ) 2583 REPEAT_TIMED( "pop_int", N, int x = pop( ti ); if ( x > max ) max = x; ) 2564 REPEAT_TIMED( "pop_int", N, 2565 int x = pop( ti ); if ( x > max ) max = x; ) 2584 2566 2585 2567 pair( short, char ) max = { 0h, '\0' }, val = { 42h, 'a' }; … … 2589 2571 TIMED( "copy_pair", tp{ sp }; ) 2590 2572 TIMED( "clear_pair", clear( sp ); ) 2591 REPEAT_TIMED( "pop_pair", N, pair(short, char) x = pop( tp ); if ( x > max ) max = x; ) 2573 REPEAT_TIMED( "pop_pair", N, 2574 pair(short, char) x = pop( tp ); if ( x > max ) max = x; ) 2592 2575 } 2593 2576 \end{cfa} … … 2622 2605 & \CT{C} & \CT{\CFA} & \CT{\CC} & \CT{\CCV} \\ \hline 2623 2606 maximum memory usage (MB) & 10001 & 2502 & 2503 & 11253 \\ 2624 source code size (lines) & 187 & 18 6& 133 & 303 \\2607 source code size (lines) & 187 & 188 & 133 & 303 \\ 2625 2608 redundant type annotations (lines) & 25 & 0 & 2 & 16 \\ 2626 2609 binary size (KB) & 14 & 257 & 14 & 37 \\ … … 2636 2619 Finally, the binary size for \CFA is larger because of static linking with the \CFA libraries. 2637 2620 2638 \CFA is also competitive in terms of source code size, measured as a proxy for programmer effort. The line counts in Table~\ref{tab:eval} include implementations of @pair@ and @stack@ types for all four languages for purposes of direct comparison, though it should be noted that \CFA and \CC have pre-written data structures in their standard libraries that programmers would generally use instead. Use of these standard library types has minimal impact on the performance benchmarks, but shrinks the \CFA and \CC benchmarks to 39and 42 lines, respectively.2621 \CFA is also competitive in terms of source code size, measured as a proxy for programmer effort. The line counts in Table~\ref{tab:eval} include implementations of @pair@ and @stack@ types for all four languages for purposes of direct comparison, though it should be noted that \CFA and \CC have pre-written data structures in their standard libraries that programmers would generally use instead. Use of these standard library types has minimal impact on the performance benchmarks, but shrinks the \CFA and \CC benchmarks to 41 and 42 lines, respectively. 2639 2622 On the other hand, C does not have a generic collections-library in its standard distribution, resulting in frequent reimplementation of such collection types by C programmers. 2640 2623 \CCV does not use the \CC standard template library by construction, and in fact includes the definition of @object@ and wrapper classes for @char@, @short@, and @int@ in its line count, which inflates this count somewhat, as an actual object-oriented language would include these in the standard library; … … 2742 2725 Finally, we demonstrate that \CFA performance for some idiomatic cases is better than C and close to \CC, showing the design is practically applicable. 2743 2726 2744 There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, runtime type-information, virtual functions,user-defined conversions, concurrent primitives, and modules.2727 There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, user-defined conversions, concurrent primitives, and modules. 2745 2728 (While all examples in the paper compile and run, a public beta-release of \CFA will take another 8--12 months to finalize these additional extensions.) 2746 2729 In addition, there are interesting future directions for the polymorphism design. … … 2777 2760 \CFA 2778 2761 \begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt] 2779 forall( otype T) struct stack_node {2762 forall(otype T) struct stack_node { 2780 2763 T value; 2781 2764 stack_node(T) * next; 2782 2765 }; 2783 forall( otype T) struct stack { stack_node(T) * head; };2784 forall( otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; }2785 forall( otype T) void ?{}( stack(T) & s, stack(T) t ) {2766 forall(otype T) struct stack { stack_node(T) * head; }; 2767 forall(otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; } 2768 forall(otype T) void ?{}( stack(T) & s, stack(T) t ) { 2786 2769 stack_node(T) ** crnt = &s.head; 2787 2770 for ( stack_node(T) * next = t.head; next; next = next->next ) { … … 2792 2775 *crnt = 0; 2793 2776 } 2794 forall( otype T) stack(T) ?=?( stack(T) & s, stack(T) t ) {2777 forall(otype T) stack(T) ?=?( stack(T) & s, stack(T) t ) { 2795 2778 if ( s.head == t.head ) return s; 2796 2779 clear( s ); … … 2798 2781 return s; 2799 2782 } 2800 forall( otype T) void ^?{}( stack(T) & s) { clear( s ); }2801 forall( otype T) _Bool empty( const stack(T) & s ) { return s.head == 0; }2802 forall( otype T ) void push( stack(T) & s, T value ) with( s) {2783 forall(otype T) void ^?{}( stack(T) & s) { clear( s ); } 2784 forall(otype T) _Bool empty( const stack(T) & s ) { return s.head == 0; } 2785 forall(otype T) void push( stack(T) & s, T value ) { 2803 2786 stack_node(T) * n = alloc(); 2804 2787 (*n){ value, head }; 2805 2788 head = n; 2806 2789 } 2807 forall( otype T ) T pop( stack(T) & s ) with(s ) {2790 forall(otype T) T pop( stack(T) & s ) { 2808 2791 stack_node(T) * n = head; 2809 2792 head = n->next; … … 2813 2796 return x; 2814 2797 } 2815 forall( otype T ) void clear( stack(T) & s ) with(s ) {2798 forall(otype T) void clear( stack(T) & s ) { 2816 2799 for ( stack_node(T) * next = head; next; ) { 2817 2800 stack_node(T) * crnt = next; -
doc/papers/general/evaluation/cfa-bench.c
r9d6f011 r28bc8c8 10 10 TIMED( "copy_int", ti{ si }; ) 11 11 TIMED( "clear_int", clear( si ); ) 12 REPEAT_TIMED( "pop_int", N, int x = pop( ti ); if ( x > max ) max = x; ) 12 REPEAT_TIMED( "pop_int", N, 13 int x = pop( ti ); if ( x > max ) max = x; ) 13 14 14 15 pair( short, char ) max = { 0h, '\0' }, val = { 42h, 'a' }; … … 18 19 TIMED( "copy_pair", tp{ sp }; ) 19 20 TIMED( "clear_pair", clear( sp ); ) 20 REPEAT_TIMED( "pop_pair", N, pair(short, char) x = pop( tp ); if ( x > max ) max = x; ) 21 REPEAT_TIMED( "pop_pair", N, 22 pair(short, char) x = pop( tp ); if ( x > max ) max = x; ) 21 23 } -
src/GenPoly/Box.cc
r9d6f011 r28bc8c8 163 163 void premutate( DeclStmt *declStmt ); 164 164 Expression *postmutate( MemberExpr *memberExpr ); 165 void premutate( AddressExpr *addrExpr );166 Expression *postmutate( AddressExpr *addrExpr );167 165 Expression *postmutate( SizeofExpr *sizeofExpr ); 168 166 Expression *postmutate( AlignofExpr *alignofExpr ); … … 195 193 ScopedSet< std::string > knownOffsets; ///< Set of non-generic types for which the offset array exists in the current scope, indexed by offsetofName 196 194 UniqueName bufNamer; ///< Namer for VLA buffers 197 Expression * addrMember = nullptr; ///< AddressExpr argument is MemberExpr?198 195 }; 199 196 … … 1177 1174 if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) { 1178 1175 if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) { 1179 if ( name-> name== "*?" ) {1176 if ( name->get_name() == "*?" ) { 1180 1177 Expression *ret = expr->args.front(); 1181 1178 expr->args.clear(); … … 1190 1187 void Pass1::premutate( AddressExpr * ) { visit_children = false; } 1191 1188 Expression * Pass1::postmutate( AddressExpr * addrExpr ) { 1192 assert( addrExpr-> arg->result && ! addrExpr->arg->result->isVoid() );1189 assert( addrExpr->get_arg()->result && ! addrExpr->get_arg()->get_result()->isVoid() ); 1193 1190 1194 1191 bool needs = false; 1195 if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr-> arg) ) {1196 if ( expr->result && isPolyType( expr-> result, scopeTyVars, env ) ) {1197 if ( NameExpr *name = dynamic_cast< NameExpr *>( expr-> function) ) {1198 if ( name-> name== "*?" ) {1199 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr-> args.front() ) ) {1200 assert( appExpr-> function->result );1201 FunctionType *function = getFunctionType( appExpr-> function->result);1192 if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->get_arg() ) ) { 1193 if ( expr->result && isPolyType( expr->get_result(), scopeTyVars, env ) ) { 1194 if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->get_function() ) ) { 1195 if ( name->get_name() == "*?" ) { 1196 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->get_args().front() ) ) { 1197 assert( appExpr->get_function()->result ); 1198 FunctionType *function = getFunctionType( appExpr->get_function()->get_result() ); 1202 1199 assert( function ); 1203 1200 needs = needsAdapter( function, scopeTyVars ); … … 1209 1206 // isPolyType check needs to happen before mutating addrExpr arg, so pull it forward 1210 1207 // out of the if condition. 1211 addrExpr->arg = addrExpr-> arg->acceptMutator( *visitor );1208 addrExpr->arg = addrExpr->get_arg()->acceptMutator( *visitor ); 1212 1209 // ... but must happen after mutate, since argument might change (e.g. intrinsic *?, ?[?]) - re-evaluate above comment 1213 bool polytype = isPolyType( addrExpr-> arg->result, scopeTyVars, env );1210 bool polytype = isPolyType( addrExpr->get_arg()->get_result(), scopeTyVars, env ); 1214 1211 if ( polytype || needs ) { 1215 Expression *ret = addrExpr-> arg;1216 delete ret-> result;1217 ret-> result = addrExpr->result->clone();1218 addrExpr-> arg = nullptr;1212 Expression *ret = addrExpr->get_arg(); 1213 delete ret->get_result(); 1214 ret->set_result( addrExpr->get_result()->clone() ); 1215 addrExpr->set_arg( 0 ); 1219 1216 delete addrExpr; 1220 1217 return ret; … … 1253 1250 1254 1251 void Pass2::addAdapters( FunctionType *functionType ) { 1255 std::list< DeclarationWithType *> ¶mList = functionType-> parameters;1252 std::list< DeclarationWithType *> ¶mList = functionType->get_parameters(); 1256 1253 std::list< FunctionType *> functions; 1257 1254 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) { … … 1274 1271 1275 1272 DeclarationWithType * Pass2::postmutate( FunctionDecl *functionDecl ) { 1276 FunctionType * ftype = functionDecl-> type;1277 if ( ! ftype-> returnVals.empty() && functionDecl->statements) {1278 if ( ! isPrefix( functionDecl-> name, "_thunk" ) && ! isPrefix( functionDecl->name, "_adapter" ) ) { // xxx - remove check for prefix once thunks properly use ctor/dtors1279 assert( ftype-> returnVals.size() == 1 );1280 DeclarationWithType * retval = ftype-> returnVals.front();1281 if ( retval-> name== "" ) {1282 retval-> name = "_retval";1273 FunctionType * ftype = functionDecl->get_functionType(); 1274 if ( ! ftype->get_returnVals().empty() && functionDecl->get_statements() ) { 1275 if ( ! isPrefix( functionDecl->get_name(), "_thunk" ) && ! isPrefix( functionDecl->get_name(), "_adapter" ) ) { // xxx - remove check for prefix once thunks properly use ctor/dtors 1276 assert( ftype->get_returnVals().size() == 1 ); 1277 DeclarationWithType * retval = ftype->get_returnVals().front(); 1278 if ( retval->get_name() == "" ) { 1279 retval->set_name( "_retval" ); 1283 1280 } 1284 functionDecl-> statements->kids.push_front( new DeclStmt( retval ) );1281 functionDecl->get_statements()->get_kids().push_front( new DeclStmt( retval ) ); 1285 1282 DeclarationWithType * newRet = retval->clone(); // for ownership purposes 1286 ftype-> returnVals.front() = newRet;1283 ftype->get_returnVals().front() = newRet; 1287 1284 } 1288 1285 } 1289 1286 // errors should have been caught by this point, remove initializers from parameters to allow correct codegen of default arguments 1290 for ( Declaration * param : functionDecl-> type->parameters) {1287 for ( Declaration * param : functionDecl->get_functionType()->get_parameters() ) { 1291 1288 if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( param ) ) { 1292 delete obj-> init;1293 obj-> init = nullptr;1289 delete obj->get_init(); 1290 obj->set_init( nullptr ); 1294 1291 } 1295 1292 } … … 1587 1584 assert( newMemberExpr ); 1588 1585 1589 // Must apply the generic substitution to the member type to handle cases where the member is a generic parameter substituted by a known concrete type, e.g. 1590 // forall(otype T) struct Box { T x; } 1591 // forall(otype T) f() { 1592 // Box(T *) b; b.x; 1593 // } 1594 // TODO: memberExpr->result should be exactly memberExpr->member->get_type() after substitution, so it doesn't seem like it should be necessary to apply the substitution manually. For some reason this is not currently the case. This requires more investigation. 1595 Type *memberType = memberExpr->member->get_type()->clone(); 1596 TypeSubstitution sub = objectType->genericSubstitution(); 1597 sub.apply( memberType ); 1586 Type *memberType = memberExpr->member->get_type(); 1598 1587 if ( ! isPolyType( memberType, scopeTyVars ) ) { 1599 1588 // Not all members of a polymorphic type are themselves of polymorphic type; in this case the member expression should be wrapped and dereferenced to form an lvalue … … 1603 1592 } 1604 1593 1605 delete memberType;1606 1594 delete memberExpr; 1607 1595 return newMemberExpr; 1608 }1609 1610 void PolyGenericCalculator::premutate( AddressExpr * addrExpr ) {1611 GuardValue( addrMember );1612 // is the argument a MemberExpr before mutating?1613 addrMember = dynamic_cast< MemberExpr * >( addrExpr->arg );1614 }1615 1616 Expression * PolyGenericCalculator::postmutate( AddressExpr * addrExpr ) {1617 if ( addrMember && addrMember != addrExpr->arg ) {1618 // arg was a MemberExpr and has been mutated1619 if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * >( addrExpr->arg ) ) {1620 if ( InitTweak::getFunctionName( untyped ) == "?+?" ) {1621 // MemberExpr was converted to pointer+offset, and it is not valid C to take the address of an addition, so strip the address-of1622 // TODO: should addrExpr->arg->result be changed to addrExpr->result?1623 Expression * ret = addrExpr->arg;1624 addrExpr->arg = nullptr;1625 std::swap( addrExpr->env, ret->env );1626 delete addrExpr;1627 return ret;1628 }1629 }1630 }1631 return addrExpr;1632 1596 } 1633 1597 -
src/SynTree/Expression.cc
r9d6f011 r28bc8c8 345 345 } 346 346 347 namespace { 348 TypeSubstitution makeSub( Type * t ) { 349 if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( t ) ) { 350 return makeSub( refType->get_base() ); 351 } else if ( StructInstType * aggInst = dynamic_cast< StructInstType * >( t ) ) { 352 return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() ); 353 } else if ( UnionInstType * aggInst = dynamic_cast< UnionInstType * >( t ) ) { 354 return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() ); 355 } else { 356 assertf( false, "makeSub expects struct or union type for aggregate, but got: %s", toString( t ).c_str() ); 357 } 358 } 359 } 360 361 347 362 MemberExpr::MemberExpr( DeclarationWithType *member, Expression *aggregate ) : 348 363 Expression(), member(member), aggregate(aggregate) { 349 364 assert( member ); 350 365 assert( aggregate ); 351 assert( aggregate->result ); 352 353 TypeSubstitution sub = aggregate->result->genericSubstitution(); 366 367 TypeSubstitution sub( makeSub( aggregate->get_result() ) ); 354 368 Type * res = member->get_type()->clone(); 355 369 sub.apply( res ); -
src/SynTree/ReferenceToType.cc
r9d6f011 r28bc8c8 14 14 // 15 15 16 #include <cassert> 17 #include <list> 18 #include <ostream> 19 #include <string> 16 #include <cassert> // for assert 17 #include <list> // for list, _List_const_iterator, list<>::cons... 18 #include <ostream> // for operator<<, basic_ostream, ostream, endl 19 #include <string> // for string, operator<<, char_traits, operator== 20 20 21 #include "Common/utility.h" // for printAll, cloneAll, deleteAll 22 #include "Declaration.h" // for StructDecl, UnionDecl, EnumDecl, Declara... 23 #include "Expression.h" // for Expression 24 #include "Type.h" // for TypeInstType, StructInstType, UnionInstType 25 #include "TypeSubstitution.h" // for TypeSubstitution 21 #include "Common/utility.h" // for printAll, cloneAll, deleteAll 22 #include "Declaration.h" // for StructDecl, UnionDecl, EnumDecl, Declara... 23 #include "Expression.h" // for Expression 24 #include "Type.h" // for TypeInstType, StructInstType, UnionInstType 26 25 27 26 class Attribute; … … 64 63 std::string StructInstType::typeString() const { return "struct"; } 65 64 66 const std::list<TypeDecl*>* StructInstType::get_baseParameters() const {67 if ( ! baseStruct ) return nullptr;68 return &baseStruct->get_parameters();69 }70 71 65 std::list<TypeDecl*>* StructInstType::get_baseParameters() { 72 66 if ( ! baseStruct ) return nullptr; … … 77 71 78 72 AggregateDecl * StructInstType::getAggr() { return baseStruct; } 79 80 TypeSubstitution StructInstType::genericSubstitution() const {81 return TypeSubstitution( get_baseParameters()->begin(), get_baseParameters()->end(), parameters.begin() );82 }83 73 84 74 void StructInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const { … … 112 102 } 113 103 114 const std::list< TypeDecl * > * UnionInstType::get_baseParameters() const {115 if ( ! baseUnion ) return nullptr;116 return &baseUnion->get_parameters();117 }118 119 104 bool UnionInstType::isComplete() const { return baseUnion ? baseUnion->has_body() : false; } 120 105 121 106 AggregateDecl * UnionInstType::getAggr() { return baseUnion; } 122 123 TypeSubstitution UnionInstType::genericSubstitution() const {124 return TypeSubstitution( get_baseParameters()->begin(), get_baseParameters()->end(), parameters.begin() );125 }126 107 127 108 void UnionInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const { -
src/SynTree/ReferenceType.cc
r9d6f011 r28bc8c8 16 16 #include "Type.h" 17 17 #include "Expression.h" 18 #include "TypeSubstitution.h"19 18 #include "Common/utility.h" 20 19 … … 36 35 } 37 36 38 TypeSubstitution ReferenceType::genericSubstitution() const { return base->genericSubstitution(); }39 40 37 void ReferenceType::print( std::ostream &os, Indenter indent ) const { 41 38 Type::print( os, indent ); -
src/SynTree/Type.cc
r9d6f011 r28bc8c8 15 15 #include "Type.h" 16 16 17 #include "Attribute.h" // for Attribute 18 #include "Common/utility.h" // for cloneAll, deleteAll, printAll 19 #include "InitTweak/InitTweak.h" // for getPointerBase 20 #include "SynTree/BaseSyntaxNode.h" // for BaseSyntaxNode 21 #include "SynTree/Declaration.h" // for TypeDecl 22 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 17 #include "Attribute.h" // for Attribute 18 #include "Common/utility.h" // for cloneAll, deleteAll, printAll 19 #include "InitTweak/InitTweak.h" // for getPointerBase 20 #include "SynTree/BaseSyntaxNode.h" // for BaseSyntaxNode 21 #include "SynTree/Declaration.h" // for TypeDecl 23 22 24 23 using namespace std; … … 82 81 int Type::referenceDepth() const { return 0; } 83 82 84 TypeSubstitution Type::genericSubstitution() const { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }85 86 83 void Type::print( std::ostream &os, Indenter indent ) const { 87 84 if ( ! forall.empty() ) { -
src/SynTree/Type.h
r9d6f011 r28bc8c8 178 178 virtual bool isComplete() const { return true; } 179 179 180 virtual AggregateDecl * getAggr() { assertf( false, "Non-aggregate type: %s", toCString( this ) ); } 181 182 virtual TypeSubstitution genericSubstitution() const; 180 virtual AggregateDecl * getAggr() { assertf( false, "Non-aggregate type: %s", toString( this ).c_str() ); } 183 181 184 182 virtual Type *clone() const = 0; … … 331 329 virtual unsigned size() const override { return base->size(); } 332 330 333 virtual TypeSubstitution genericSubstitution() const override;334 335 331 virtual ReferenceType *clone() const override { return new ReferenceType( *this ); } 336 332 virtual void accept( Visitor & v ) override { v.visit( this ); } … … 410 406 /// Accesses generic parameters of base struct (NULL if none such) 411 407 std::list<TypeDecl*> * get_baseParameters(); 412 const std::list<TypeDecl*> * get_baseParameters() const;413 408 414 409 virtual bool isComplete() const override; 415 410 416 411 virtual AggregateDecl * getAggr() override; 417 418 virtual TypeSubstitution genericSubstitution() const override;419 412 420 413 /// Looks up the members of this struct named "name" and places them into "foundDecls". … … 446 439 447 440 /// Accesses generic parameters of base union (NULL if none such) 448 std::list<TypeDecl*> * get_baseParameters(); 449 const std::list<TypeDecl*> * get_baseParameters() const; 441 std::list< TypeDecl * > * get_baseParameters(); 450 442 451 443 virtual bool isComplete() const override; 452 444 453 445 virtual AggregateDecl * getAggr() override; 454 455 virtual TypeSubstitution genericSubstitution() const override;456 446 457 447 /// looks up the members of this union named "name" and places them into "foundDecls" -
src/tests/.expect/literals.x86.txt
r9d6f011 r28bc8c8 522 522 signed int __main__Fi___1(){ 523 523 __attribute__ ((unused)) signed int ___retval_main__i_1; 524 ((void)0b01101011);525 ((void)0b01101011u);526 ((void)0b01101011l);527 ((void)0b01101011ll);528 ((void)0b01101011ul);529 ((void)0b01101011lu);530 ((void)0b01101011ull);531 ((void)0b01101011llu);532 ((void)(+0b01101011));533 ((void)(+0b01101011u));534 ((void)(+0b01101011l));535 ((void)(+0b01101011ll));536 ((void)(+0b01101011ul));537 ((void)(+0b01101011lu));538 ((void)(+0b01101011ull));539 ((void)(+0b01101011llu));540 ((void)(-0b01101011));541 ((void)(-0b01101011u));542 ((void)(-0b01101011l));543 ((void)(-0b01101011ll));544 ((void)(-0b01101011ul));545 ((void)(-0b01101011lu));546 ((void)(-0b01101011ull));547 ((void)(-0b01101011llu));548 524 ((void)01234567); 549 525 ((void)01234567u); … … 1041 1017 ((void)(-0X0123456789.0123456789P-09F)); 1042 1018 ((void)(-0X0123456789.0123456789P-09L)); 1043 ((void)((signed char )0b01101011));1044 ((void)((signed short int )0b01101011));1045 ((void)((signed int )0b01101011));1046 ((void)((signed long long int )0b01101011));1047 ((void)((__int128 )0b01101011));1048 ((void)((unsigned char )0b01101011u));1049 ((void)((signed short int )0b01101011u));1050 ((void)((unsigned int )0b01101011u));1051 ((void)((signed long long int )0b01101011u));1052 ((void)((__int128 )0b01101011u));1053 ((void)(+((signed int )((signed char )0b01101011))));1054 ((void)(+((signed int )((signed short int )0b01101011))));1055 ((void)(+((signed int )0b01101011)));1056 ((void)(+((signed long long int )0b01101011)));1057 ((void)(+((float )((__int128 )0b01101011))));1058 ((void)(+((signed int )((unsigned char )0b01101011u))));1059 ((void)(+((signed int )((signed short int )0b01101011u))));1060 ((void)(+((unsigned int )0b01101011u)));1061 ((void)(+((signed long long int )0b01101011u)));1062 ((void)(+((float )((__int128 )0b01101011u))));1063 ((void)(-((signed int )((signed char )0b01101011))));1064 ((void)(-((signed int )((signed short int )0b01101011))));1065 ((void)(-((signed int )0b01101011)));1066 ((void)(-((signed long long int )0b01101011)));1067 ((void)(-((float )((__int128 )0b01101011))));1068 ((void)(-((signed int )((unsigned char )0b01101011u))));1069 ((void)(-((signed int )((signed short int )0b01101011u))));1070 ((void)(-((unsigned int )0b01101011u)));1071 ((void)(-((signed long long int )0b01101011u)));1072 ((void)(-((float )((__int128 )0b01101011u))));1073 1019 ((void)((signed char )01234567)); 1074 1020 ((void)((signed short int )01234567)); -
src/tests/concurrent/coroutineYield.c
r9d6f011 r28bc8c8 3 3 #include <stdlib> 4 4 #include <thread> 5 6 #ifdef LONG_TEST7 static const unsigned long N = 600_000ul;8 #else9 static const unsigned long N = 1_000ul;10 #endif11 5 12 6 coroutine Coroutine {}; … … 24 18 int main(int argc, char* argv[]) { 25 19 Coroutine c; 26 for(int i = 0; i < N; i++) {20 for(int i = 0; i < 1_000; i++) { 27 21 sout | "Thread 1" | endl; 28 22 resume(c); -
src/tests/concurrent/signal/block.c
r9d6f011 r28bc8c8 15 15 #include <time.h> 16 16 17 #ifdef LONG_TEST18 static const unsigned long N = 150_000ul;19 #else20 17 static const unsigned long N = 5_000ul; 21 #endif22 18 23 19 #ifndef PREEMPTION_RATE -
src/tests/concurrent/signal/disjoint.c
r9d6f011 r28bc8c8 6 6 #include <time.h> 7 7 8 #ifdef LONG_TEST9 static const unsigned long N = 300_000ul;10 #else11 8 static const unsigned long N = 10_000ul; 12 #endif13 9 14 10 #ifndef PREEMPTION_RATE -
src/tests/concurrent/signal/wait.c
r9d6f011 r28bc8c8 13 13 #include <time.h> 14 14 15 #ifdef LONG_TEST16 static const unsigned long N = 375_000ul;17 #else18 15 static const unsigned long N = 2_500ul; 19 #endif20 16 21 17 #ifndef PREEMPTION_RATE -
src/tests/preempt_longrun/Makefile.am
r9d6f011 r28bc8c8 23 23 TIME = /usr/bin/time -f "%E" 24 24 25 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -DLONG_TEST25 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} 26 26 CFLAGS = ${BUILD_FLAGS} 27 27 CC = @CFA_BINDIR@/@CFA_NAME@ -
src/tests/preempt_longrun/Makefile.in
r9d6f011 r28bc8c8 454 454 REPEAT = ${abs_top_srcdir}/tools/repeat 455 455 TIME = /usr/bin/time -f "%E" 456 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -DLONG_TEST456 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} 457 457 TESTS = block coroutine create disjoint enter enter3 processor stack wait yield 458 458 all: all-am -
src/tests/preempt_longrun/create.c
r9d6f011 r28bc8c8 2 2 #include <thread> 3 3 4 static const unsigned long N = 60_000ul;4 static const unsigned long N = 2_000ul; 5 5 6 6 #ifndef PREEMPTION_RATE -
src/tests/preempt_longrun/enter.c
r9d6f011 r28bc8c8 3 3 #include <thread> 4 4 5 static const unsigned long N = 2_100_000ul;5 static const unsigned long N = 70_000ul; 6 6 7 7 #ifndef PREEMPTION_RATE -
src/tests/preempt_longrun/enter3.c
r9d6f011 r28bc8c8 3 3 #include <thread> 4 4 5 static const unsigned long N = 50 0_000ul;5 static const unsigned long N = 50_000ul; 6 6 7 7 #ifndef PREEMPTION_RATE -
src/tests/preempt_longrun/processor.c
r9d6f011 r28bc8c8 12 12 } 13 13 14 thread worker_t {}; 15 16 void main(worker_t & this) {} 17 18 extern processor * mainProcessor; 19 extern thread_desc * mainThread; 20 14 21 int main(int argc, char* argv[]) { 15 processor * p[15]; 16 for ( int pi = 0; pi < 15; pi++ ) { 17 p[pi] = new(); 18 } 19 for ( int i = 0; i < N; i++) { 20 int pi = i % 15; 21 delete( p[pi] ); 22 p[pi] = new(); 22 for(int i = 0; i < N; i++) { 23 assert(this_processor == mainProcessor); 24 assert(this_thread == mainThread); 25 processor p; 23 26 } 24 27 } -
src/tests/preempt_longrun/yield.c
r9d6f011 r28bc8c8 2 2 #include <thread> 3 3 4 #ifdef LONG_TEST5 static const unsigned long N = 9_750_000ul;6 #else7 4 static const unsigned long N = 325_000ul; 8 #endif9 5 10 6 #ifndef PREEMPTION_RATE
Note: See TracChangeset
for help on using the changeset viewer.