Changeset 5600747
- Timestamp:
- Mar 8, 2018, 9:23:32 AM (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:
- 4c11fce, ab0203df
- Parents:
- e5d4e5c (diff), fb11446e (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:
-
- 21 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/bibliography/pl.bib
re5d4e5c r5600747 1439 1439 contributer = {pabuhr@plg}, 1440 1440 author = {Peter A. Buhr}, 1441 title = {$\mu${C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Annotated Reference Manual, Version 6.1.0},1441 title = {$\mu${C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Annotated Reference Manual, Version 7.0.0}, 1442 1442 institution = {School of Computer Science, University of Waterloo}, 1443 1443 address = {Waterloo, Ontario, Canada, N2L 3G1}, 1444 month = jul,1445 year = 201 5,1446 note = {\href{http://plg.uwaterloo.ca/~usystem/pub/uSystem/u++- 6.1.0.sh}{http://\-plg.\-uwaterloo.\-ca/\-$\sim$usystem/\-pub/\-uSystem/\-u++-6.1.0.sh}},1444 month = dec, 1445 year = 2017, 1446 note = {\href{http://plg.uwaterloo.ca/~usystem/pub/uSystem/u++-7.0.0.sh}{http://\-plg.\-uwaterloo.\-ca/\-$\sim$usystem/\-pub/\-uSystem/\-u++-7.0.0.sh}}, 1447 1447 } 1448 1448 -
doc/papers/general/Paper.tex
re5d4e5c r5600747 58 58 \setlength{\parindentlnth}{\parindent} 59 59 60 \newcommand{\LstBasicStyle}[1]{{\lst@basicstyle{\lst@basicstyle{#1}}}} 60 61 \newcommand{\LstKeywordStyle}[1]{{\lst@basicstyle{\lst@keywordstyle{#1}}}} 61 62 \newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}} … … 231 232 All of the features discussed in this paper are working, unless a feature states it is a future feature for completion. 232 233 234 Finally, it is impossible to describe a programming language without usages before definitions. 235 Therefore, syntax and semantics appear before explanations; 236 hence, patience is necessary until details are presented. 237 233 238 234 239 \section{Polymorphic Functions} … … 263 268 \end{cfa} 264 269 \CFA maximizes the ability to reuse names to aggressively address the naming problem. 265 In some cases, hundreds of names can be reduced to tens, resulting in a significant cognitive reduction for a programmer.270 In some cases, hundreds of names can be reduced to tens, resulting in a significant cognitive reduction. 266 271 In the above, the name @max@ has a consistent meaning, and a programmer only needs to remember the single concept: maximum. 267 272 To prevent significant ambiguities, \CFA uses the return type in selecting overloads, \eg in the assignment to @m@, the compiler use @m@'s type to unambiguously select the most appropriate call to function @max@ (as does Ada). 268 273 As is shown later, there are a number of situations where \CFA takes advantage of available type information to disambiguate, where other programming languages generate ambiguities. 269 274 270 \Celeven added @_Generic@ expressions, which can be used in preprocessor macros to provide a form of ad-hoc polymorphism; however, this polymorphism is both functionally and ergonomically inferior to \CFA name overloading. 271 The macro wrapping the generic expression imposes some limitations; as an example, it could not implement the example above, because the variables @max@ would collide with the functions @max@. 272 Ergonomic limitations of @_Generic@ include the necessity to put a fixed list of supported types in a single place and manually dispatch to appropriate overloads, as well as possible namespace pollution from the functions dispatched to, which must all have distinct names. 273 Though name-overloading removes a major use-case for @_Generic@ expressions, \CFA implements @_Generic@ for backwards-compatibility purposes. \TODO{actually implement that} 275 \Celeven added @_Generic@ expressions, which is used in preprocessor macros to provide a form of ad-hoc polymorphism; 276 however, this polymorphism is both functionally and ergonomically inferior to \CFA name overloading. 277 The macro wrapping the generic expression imposes some limitations; 278 \eg, it cannot implement the example above, because the variables @max@ are ambiguous with the functions @max@. 279 Ergonomic limitations of @_Generic@ include the necessity to put a fixed list of supported types in a single place and manually dispatch to appropriate overloads, as well as possible namespace pollution from the dispatch functions, which must all have distinct names. 280 For backwards compatibility, \CFA supports @_Generic@ expressions, but it is an unnecessary mechanism. \TODO{actually implement that} 274 281 275 282 % http://fanf.livejournal.com/144696.html … … 286 293 int forty_two = identity( 42 ); $\C{// T is bound to int, forty\_two == 42}$ 287 294 \end{cfa} 288 Th e @identity@ function abovecan be applied to any complete \newterm{object type} (or @otype@).295 This @identity@ function can be applied to any complete \newterm{object type} (or @otype@). 289 296 The type variable @T@ is transformed into a set of additional implicit parameters encoding sufficient information about @T@ to create and return a variable of that type. 290 297 The \CFA implementation passes the size and alignment of the type represented by an @otype@ parameter, as well as an assignment operator, constructor, copy constructor and destructor. 291 298 If this extra information is not needed, \eg for a pointer, the type parameter can be declared as a \newterm{data type} (or @dtype@). 292 299 293 In \CFA, the polymorphi sm runtime-cost is spread over each polymorphic call, due to passing more argumentsto polymorphic functions;300 In \CFA, the polymorphic runtime-cost is spread over each polymorphic call, because more arguments are passed to polymorphic functions; 294 301 the experiments in Section~\ref{sec:eval} show this overhead is similar to \CC virtual-function calls. 295 302 A design advantage is that, unlike \CC template-functions, \CFA polymorphic-functions are compatible with C \emph{separate compilation}, preventing compilation and code bloat. … … 303 310 which works for any type @T@ with a matching addition operator. 304 311 The polymorphism is achieved by creating a wrapper function for calling @+@ with @T@ bound to @double@, then passing this function to the first call of @twice@. 305 There is now the option of using the same @twice@ and converting the result to @int@ on assignment, or creating another @twice@ with type parameter @T@ bound to @int@ because \CFA uses the return type~\cite{Cormack81,Baker82,Ada} ,in its type analysis.312 There is now the option of using the same @twice@ and converting the result to @int@ on assignment, or creating another @twice@ with type parameter @T@ bound to @int@ because \CFA uses the return type~\cite{Cormack81,Baker82,Ada} in its type analysis. 306 313 The first approach has a late conversion from @double@ to @int@ on the final assignment, while the second has an eager conversion to @int@. 307 314 \CFA minimizes the number of conversions and their potential to lose information, so it selects the first approach, which corresponds with C-programmer intuition. … … 312 319 \begin{cfa} 313 320 void * bsearch( const void * key, const void * base, size_t nmemb, size_t size, 314 int (* compar)( const void *, const void * )); 315 316 int comp( const void * t1, const void * t2 ) { return *(double *)t1 < *(double *)t2 ? -1 : 317 *(double *)t2 < *(double *)t1 ? 1 : 0; } 318 321 int (* compar)( const void *, const void * )); 322 int comp( const void * t1, const void * t2 ) { 323 return *(double *)t1 < *(double *)t2 ? -1 : *(double *)t2 < *(double *)t1 ? 1 : 0; 324 } 319 325 double key = 5.0, vals[10] = { /* 10 sorted float values */ }; 320 326 double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp ); $\C{// search sorted array}$ … … 324 330 forall( otype T | { int ?<?( T, T ); } ) T * bsearch( T key, const T * arr, size_t size ) { 325 331 int comp( const void * t1, const void * t2 ) { /* as above with double changed to T */ } 326 return (T *)bsearch( &key, arr, size, sizeof(T), comp ); }327 332 return (T *)bsearch( &key, arr, size, sizeof(T), comp ); 333 } 328 334 forall( otype T | { int ?<?( T, T ); } ) unsigned int bsearch( T key, const T * arr, size_t size ) { 329 335 T * result = bsearch( key, arr, size ); $\C{// call first version}$ 330 return result ? result - arr : size; }$\C{// pointer subtraction includes sizeof(T)}$331 336 return result ? result - arr : size; $\C{// pointer subtraction includes sizeof(T)}$ 337 } 332 338 double * val = bsearch( 5.0, vals, 10 ); $\C{// selection based on return type}$ 333 339 int posn = bsearch( 5.0, vals, 10 ); … … 336 342 Providing a hidden @comp@ function in \CC is awkward as lambdas do not use C calling-conventions and template declarations cannot appear at block scope. 337 343 As well, an alternate kind of return is made available: position versus pointer to found element. 338 \CC's type-system cannot disambiguate between the two versions of @bsearch@ because it does not use the return type in overload resolution, nor can \CC separately compile a template d@bsearch@.344 \CC's type-system cannot disambiguate between the two versions of @bsearch@ because it does not use the return type in overload resolution, nor can \CC separately compile a template @bsearch@. 339 345 340 346 \CFA has replacement libraries condensing hundreds of existing C functions into tens of \CFA overloaded functions, all without rewriting the actual computations (see Section~\ref{sec:libraries}). … … 382 388 \begin{cfa} 383 389 trait otype( dtype T | sized(T) ) { // sized is a pseudo-trait for types with known size and alignment 384 void ?{}( T *); $\C{// default constructor}$385 void ?{}( T *, T ); $\C{// copy constructor}$386 void ?=?( T *, T ); $\C{// assignment operator}$387 void ^?{}( T *); }; $\C{// destructor}$390 void ?{}( T & ); $\C{// default constructor}$ 391 void ?{}( T &, T ); $\C{// copy constructor}$ 392 void ?=?( T &, T ); $\C{// assignment operator}$ 393 void ^?{}( T & ); }; $\C{// destructor}$ 388 394 \end{cfa} 389 395 Given the information provided for an @otype@, variables of polymorphic type can be treated as if they were a complete type: stack-allocatable, default or copy-initialized, assigned, and deleted. … … 429 435 One approach is to write bespoke data-structures for each context in which they are needed. 430 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. 431 A second approach is to use @void *@--based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@, which allow sreuse of code with common functionality.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. 432 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. 433 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. 434 Furthermore, writing and using preprocessor macros can beunnatural and inflexible.440 Furthermore, writing and using preprocessor macros is unnatural and inflexible. 435 441 436 442 \CC, Java, and other languages use \newterm{generic types} to produce type-safe abstract data-types. … … 444 450 S second; 445 451 }; 446 forall( otype T ) T value( pair( const char *, T ) p ) { return p.second; } 447 forall( dtype F, otype T ) T value( pair( F *, T * ) p ) { return *p.second; } 448 449 pair( const char *, int ) p = { "magic", 42 }; 452 forall( otype T ) T value( pair( const char *, T ) p ) { return p.second; } $\C{// dynamic}$ 453 forall( dtype F, otype T ) T value( pair( F *, T * ) p ) { return *p.second; } $\C{// dtype-static (concrete)}$ 454 455 pair( const char *, int ) p = { "magic", 42 }; $\C{// concrete}$ 450 456 int i = value( p ); 451 pair( void *, int * ) q = { 0, &p.second }; 457 pair( void *, int * ) q = { 0, &p.second }; $\C{// concrete}$ 452 458 i = value( q ); 453 459 double d = 1.0; 454 pair( double *, double * ) r = { &d, &d }; 460 pair( double *, double * ) r = { &d, &d }; $\C{// concrete}$ 455 461 d = value( r ); 456 462 \end{cfa} … … 458 464 \CFA classifies generic types as either \newterm{concrete} or \newterm{dynamic}. 459 465 Concrete types have a fixed memory layout regardless of type parameters, while dynamic types vary in memory layout depending on their type parameters. 460 A type may have polymorphic parameters but still be concrete, called \newterm{dtype-static}.466 A \newterm{dtype-static} type has polymorphic parameters but is still concrete. 461 467 Polymorphic pointers are an example of dtype-static types, \eg @forall(dtype T) T *@ is a polymorphic type, but for any @T@, @T *@ is a fixed-sized pointer, and therefore, can be represented by a @void *@ in code generation. 462 468 … … 475 481 For example, the concrete instantiation for @pair( const char *, int )@ is: 476 482 \begin{cfa} 477 struct _pair_conc 1{483 struct _pair_conc0 { 478 484 const char * first; 479 485 int second; … … 482 488 483 489 A concrete generic-type with dtype-static parameters is also expanded to a structure type, but this type is used for all matching instantiations. 484 In the above example, the @pair( F *, T * )@ parameter to @value _p@ is such a type; its expansion is below and it is used as the type of the variables @q@ and @r@ as well, with casts for member access where appropriate:485 \begin{cfa} 486 struct _pair_conc 0{490 In the above example, the @pair( F *, T * )@ parameter to @value@ is such a type; its expansion is below and it is used as the type of the variables @q@ and @r@ as well, with casts for member access where appropriate: 491 \begin{cfa} 492 struct _pair_conc1 { 487 493 void * first; 488 494 void * second; … … 496 502 As mentioned in Section~\ref{sec:poly-fns}, @otype@ function parameters (in fact all @sized@ polymorphic parameters) come with implicit size and alignment parameters provided by the caller. 497 503 Dynamic generic-types also have an \newterm{offset array} containing structure-member offsets. 498 A dynamic generic- unionneeds no such offset array, as all members are at offset 0, but size and alignment are still necessary.504 A dynamic generic-@union@ needs no such offset array, as all members are at offset 0, but size and alignment are still necessary. 499 505 Access to members of a dynamic structure is provided at runtime via base-displacement addressing with the structure pointer and the member offset (similar to the @offsetof@ macro), moving a compile-time offset calculation to runtime. 500 506 … … 502 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; 503 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. 504 As an example, @p.second@ in the @value@ function above is implemented as @*(p + _offsetof_pair[1])@, where @p@ is a @void *@, and @_offsetof_pair@ is the offset array passed into @value@ for @pair( const char *, T )@. 505 The offset array @_offsetof_pair@ is generated at the call site as @size_t _offsetof_pair[] = { offsetof(_pair_conc1, first), offsetof(_pair_conc1, second) }@. 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. 515 @_offsetof_pair@ is the offset array passed into @value@; this array is generated at the call site as: 516 \begin{cfa} 517 size_t _offsetof_pair[] = { offsetof(_pair_conc0, first), offsetof(_pair_conc0, second) } 518 \end{cfa} 506 519 507 520 In some cases the offset arrays cannot be statically generated. … … 586 599 \subsection{Tuple Expressions} 587 600 588 The addition of multiple-return-value functions (MRVF) are uselesswithout a syntax for accepting multiple values at the call-site.601 The addition of multiple-return-value functions (MRVF) are \emph{useless} without a syntax for accepting multiple values at the call-site. 589 602 The simplest mechanism for capturing the return values is variable assignment, allowing the values to be retrieved directly. 590 603 As such, \CFA allows assigning multiple values from a function into multiple variables, using a square-bracketed list of lvalue expressions (as above), called a \newterm{tuple}. … … 817 830 Hence, function parameter and return lists are flattened for the purposes of type unification allowing the example to pass expression resolution. 818 831 This relaxation is possible by extending the thunk scheme described by Bilson~\cite{Bilson03}. 819 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:820 \begin{cfa}821 int _thunk( int _p0, double _p1, double _p2 ) { return f( [_p0, _p1], _p2 ); }822 \end{cfa}823 so the thunk provides flattening and structuring conversions to inferred functions, improving the compatibility of tuples and polymorphism.824 These thunks take advantage of gcc C nested-functions to produce closures that have the usual function-pointer signature.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 are generated locally using gcc nested-functions, rather hositing them to the external scope, so they can easily access local state. 825 838 826 839 … … 878 891 print(arg); print(rest); 879 892 } 880 void print( c har * x ) { printf( "%s", x ); }893 void print( const char * x ) { printf( "%s", x ); } 881 894 void print( int x ) { printf( "%d", x ); } 882 895 void print( S s ) { print( "{ ", s.x, ",", s.y, " }" ); } … … 887 900 The polymorphic @print@ allows printing any list of types, where as each individual type has a @print@ function. 888 901 The individual print functions can be used to build up more complicated @print@ functions, such as @S@, which cannot be done with @printf@ in C. 902 This mechanism is used to seamlessly print tuples in the \CFA I/O library (see Section~\ref{s:IOLibrary}). 889 903 890 904 Finally, it is possible to use @ttype@ polymorphism to provide arbitrary argument forwarding functions. … … 990 1004 \section{Control Structures} 991 1005 992 \CFA identifies inconsistent, problematic, and missing control structures in C, and extends, modifies, and adds tocontrol structures to increase functionality and safety.1006 \CFA identifies inconsistent, problematic, and missing control structures in C, and extends, modifies, and adds control structures to increase functionality and safety. 993 1007 994 1008 … … 1025 1039 \lstMakeShortInline@% 1026 1040 \end{cquote} 1027 for a contiguous list:\footnote{gcc provides the same mechanism with awkward syntax, \lstinline@2 ... 42@, where spaces are required around the ellipse.}1041 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.} 1028 1042 \begin{cquote} 1029 1043 \lstDeleteShortInline@% … … 1078 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. 1079 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 1080 1095 Collectively, these enhancements reduce programmer burden and increase readability and safety. 1081 1096 … … 1237 1252 \end{figure} 1238 1253 1239 Both labelled @continue@ and @break@ are a @goto@ restricted in the following ways:1254 With respect to safety, both labelled @continue@ and @break@ are a @goto@ restricted in the following ways: 1240 1255 \begin{itemize} 1241 1256 \item … … 1250 1265 With @goto@, the label is at the end of the control structure, which fails to convey this important clue early enough to the reader. 1251 1266 Finally, using an explicit target for the transfer instead of an implicit target allows new constructs to be added or removed without affecting existing constructs. 1252 The implicit targets of the current @continue@ and @break@, \ie the closest enclosing loop or @switch@, change as certain constructs are added or removed.1267 Otherwise, the implicit targets of the current @continue@ and @break@, \ie the closest enclosing loop or @switch@, change as certain constructs are added or removed. 1253 1268 1254 1269 1255 1270 \subsection{Exception Handling} 1256 1271 1257 The following framework for \CFA exception handling is in place, excluding a run-time typeinformation and dynamic casts.1258 \CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling}) .1272 The following framework for \CFA exception handling is in place, excluding some run-time type-information and dynamic casts. 1273 \CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling})~\cite{Buhr92b,Buhr00a}. 1259 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. 1260 1275 \CFA restricts exception types to those defined by aggregate type @exception@. … … 1333 1348 resume( $\emph{alternate-stack}$ ) 1334 1349 \end{cfa} 1335 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another coroutine or task~\cite{Delisle18}.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.} 1336 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. 1337 1352 … … 1358 1373 Specifying no exception type is shorthand for specifying all exception types. 1359 1374 Both @enable@ and @disable@ blocks can be nested, turning propagation on/off on entry, and on exit, the specified exception types are restored to their prior state. 1375 Coroutines and tasks start with non-local exceptions disabled, allowing handlers to be put in place, before non-local exceptions are explicitly enabled. 1376 \begin{cfa} 1377 void main( mytask & c ) { $\C{// thread starts here}$ 1378 // non-local exceptions disabled 1379 try { $\C{// establish handles for non-local exceptions}$ 1380 enable { $\C{// allow non-local exception delivery}$ 1381 // task body 1382 } 1383 // appropriate catchResume/catch handlers 1384 } 1385 } 1386 \end{cfa} 1360 1387 1361 1388 Finally, \CFA provides a Java like @finally@ clause after the catch clauses: … … 1461 1488 Qualification or a cast is used to disambiguate. 1462 1489 1463 There is an interesting problem between parameters and the function @with@, \eg:1490 There is an interesting problem between parameters and the function-body @with@, \eg: 1464 1491 \begin{cfa} 1465 1492 void ?{}( S & s, int i ) with ( s ) { $\C{// constructor}$ … … 1467 1494 } 1468 1495 \end{cfa} 1469 Here, the assignment @s.i = i@ means @s.i = s.i@, which is meaningless, and there is no mechanism to qualify the parameter @i@, making the assignment impossible using the function @with@.1496 Here, the assignment @s.i = i@ means @s.i = s.i@, which is meaningless, and there is no mechanism to qualify the parameter @i@, making the assignment impossible using the function-body @with@. 1470 1497 To solve this problem, parameters are treated like an initialized aggregate: 1471 1498 \begin{cfa} … … 1475 1502 } params; 1476 1503 \end{cfa} 1477 and implicitly opened \emph{after} a function open, to give them higher priority:1478 \begin{cfa} 1479 void ?{}( S & s, int i) with ( s ) `with( $\emph{\color{red}params}$ )` {1480 s.i = i; j = 3; m = 5.5;1504 and implicitly opened \emph{after} a function-body open, to give them higher priority: 1505 \begin{cfa} 1506 void ?{}( S & s, int `i` ) with ( s ) `with( $\emph{\color{red}params}$ )` { 1507 s.i = `i`; j = 3; m = 5.5; 1481 1508 } 1482 1509 \end{cfa} … … 1539 1566 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice. 1540 1567 1541 \CFA provides its own type, variable and function declarations, using a different syntax .1568 \CFA provides its own type, variable and function declarations, using a different syntax~\cite[pp.~856--859]{Buhr94a}. 1542 1569 The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right. 1543 1570 The qualifiers have the same meaning but are ordered left to right to specify a variable's type. … … 1774 1801 int & r = *new( int ); 1775 1802 ... $\C{// non-null reference}$ 1776 delete &r; 1803 delete &r; $\C{// unmanaged (programmer) memory-management}$ 1777 1804 r += 1; $\C{// undefined reference}$ 1778 1805 \end{cfa} … … 1921 1948 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. 1922 1949 1923 In \CFA, a constructor is named @?{}@ and a destructor is named @^?{}@. 1924 The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@\footnote{% 1950 In \CFA, a constructor is named @?{}@ and a destructor is named @^?{}@\footnote{% 1925 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.}. 1952 The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@. 1926 1953 Like other \CFA operators, these names represent the syntax used to call the constructor or destructor, \eg @?{}(x, ...)@ or @^{}(x, ...)@. 1927 1954 The constructor and destructor have return type @void@, and the first parameter is a reference to the object type to be constructed or destructed. … … 1951 1978 } 1952 1979 \end{cfa} 1953 (Note, the example is purposely kept simple byusing shallow-copy semantics.)1980 (Note, the example is purposely simplified using shallow-copy semantics.) 1954 1981 An initialization constructor-call has the same syntax as a C initializer, except the initialization values are passed as arguments to a matching constructor (number and type of paremeters). 1955 1982 \begin{cfa} … … 2004 2031 C already includes limited polymorphism for literals -- @0@ can be either an integer or a pointer literal, depending on context, while the syntactic forms of literals of the various integer and float types are very similar, differing from each other only in suffix. 2005 2032 In keeping with the general \CFA approach of adding features while respecting the ``C-style'' of doing things, C's polymorphic constants and typed literal syntax are extended to interoperate with user-defined types, while maintaining a backwards-compatible semantics. 2006 A trivial example is allowing the underscore, as in Ada, to separate prefixes, digits, and suffixes in all \CFA constants, \eg @0x`_`1.ffff`_`ffff`_`p`_`128`_`l@. 2033 2034 A simple example is allowing the underscore, as in Ada, to separate prefixes, digits, and suffixes in all \CFA constants, \eg @0x`_`1.ffff`_`ffff`_`p`_`128`_`l@, where the underscore is also the standard separator in C identifiers. 2035 \CC uses a single quote as a separator but it is restricted among digits, precluding its use in the literal prefix or suffix, \eg @0x1.ffff@@`'@@ffffp128l@, and causes problems with most IDEs, which must be extended to deal with this alternate use of the single quote. 2007 2036 2008 2037 … … 2014 2043 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}} 2015 2044 \begin{cfa} 2016 20 `_hh` // signed char2017 21 `_hhu` // unsigned char2018 22 `_h` // signed short int2019 23 `_uh` // unsigned short int2020 24 `z`// size_t2021 \end{cfa} 2022 & 2023 \begin{cfa} 2024 20 `_L8` // int8_t2025 21 `_ul8` // uint8_t2026 22 `_l16` // int16_t2027 23 `_ul16` // uint16_t2028 24 `_l32` // int32_t2029 \end{cfa} 2030 & 2031 \begin{cfa} 2032 25 `_ul32` // uint32_t2033 26 `_l64` // int64_t2034 27 `_l64u` // uint64_t2035 26 `_L128` // int1282036 27 `_L128u` // unsigned int1282045 20_`hh` // signed char 2046 21_`hhu` // unsigned char 2047 22_`h` // signed short int 2048 23_`uh` // unsigned short int 2049 24_`z` // size_t 2050 \end{cfa} 2051 & 2052 \begin{cfa} 2053 20_`L8` // int8_t 2054 21_`ul8` // uint8_t 2055 22_`l16` // int16_t 2056 23_`ul16` // uint16_t 2057 24_`l32` // int32_t 2058 \end{cfa} 2059 & 2060 \begin{cfa} 2061 25_`ul32` // uint32_t 2062 26_`l64` // int64_t 2063 27_`l64u` // uint64_t 2064 26_`L128` // int128 2065 27_`L128u` // unsigned int128 2037 2066 \end{cfa} 2038 2067 \end{tabular} … … 2043 2072 \subsection{0/1} 2044 2073 2045 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. 2046 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. 2047 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. 2048 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. 2049 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)@. 2050 \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. 2051 2052 \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. 2053 The addition of @one_t@ allows generic algorithms to handle the unit value uniformly for types where that is meaningful. 2054 \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. 2074 In C, @0@ has the special property that it is the only ``false'' value; 2075 from the standard, any value that compares equal to @0@ is false, while any value that compares unequal to @0@ is true. 2076 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. 2077 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. 2078 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); 2079 @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. 2080 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)@. 2081 \CC makes types truthy by adding a conversion to @bool@; 2082 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; 2083 \CFA avoids this issue. 2084 2085 Similarly, \CFA also has a special type for @1@, @one_t@; 2086 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 @--@. 2087 The addition of @one_t@ allows generic algorithms to handle the unit value uniformly for types where it is meaningful. 2088 \TODO{Make this sentence true} 2089 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)@; 2090 analogous overloads for the decrement operators are present as well. 2055 2091 2056 2092 … … 2060 2096 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. 2061 2097 The backquote is a small character, making the unit (function name) predominate. 2062 For examples, the multi-precision integer s in Section~\ref{s:MultiPrecisionIntegers} make use ofuser literals:2098 For examples, the multi-precision integer-type in Section~\ref{s:MultiPrecisionIntegers} has user literals: 2063 2099 {\lstset{language=CFA,moredelim=**[is][\color{red}]{|}{|},deletedelim=**[is][]{`}{`}} 2064 2100 \begin{cfa} … … 2073 2109 After which, user literals must match (no conversions); 2074 2110 hence, it is necessary to overload the unit with all appropriate types. 2075 Finally, the use of the single quote as a separator is restricted to digits, precluding its use in the literal prefix or suffix, and causes problems with most IDEs, which must be extended to deal with this alternate use of the single quote.2076 2111 2077 2112 \begin{figure} … … 2125 2160 w = 155|_lb|; 2126 2161 w = 0b1111|_lb|; // error, binary unsupported 2127 w = 0${\color{red} '}$233|_lb|; // quote separator2162 w = 0${\color{red}\LstBasicStyle{'}}$233|_lb|; // quote separator 2128 2163 w = 0x9b|_kg|; 2129 2164 w = 5.5d|_st| + 8|_kg| + 25.01|_lb| + heavy; … … 2281 2316 \lstMakeShortInline@% 2282 2317 \end{cquote} 2283 In additon, there are polymorphic functions, like @min@ and @max@, whichwork on any type with operators @?<?@ or @?>?@.2318 In additon, there are polymorphic functions, like @min@ and @max@, that work on any type with operators @?<?@ or @?>?@. 2284 2319 2285 2320 The following shows one example where \CFA \emph{extends} an existing standard C interface to reduce complexity and provide safety. … … 2287 2322 \begin{description}[topsep=3pt,itemsep=2pt,parsep=0pt] 2288 2323 \item[fill] 2289 a fter allocation the storage is filledwith a specified character.2324 an allocation with a specified character. 2290 2325 \item[resize] 2291 an existing allocation is decreased or increased insize.2326 an existing allocation to decreased or increased its size. 2292 2327 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. 2293 2328 For an increase in storage size, new storage after the copied data may be filled. 2294 \item[align ment]2295 an allocation startson a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.2329 \item[align] 2330 an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes. 2296 2331 \item[array] 2297 the allocation size is scaled to the specified number of arrayelements.2332 allocation with a specified number of elements. 2298 2333 An array may be filled, resized, or aligned. 2299 2334 \end{description} 2300 2335 Table~\ref{t:StorageManagementOperations} shows the capabilities provided by C/\Celeven allocation-functions and how all the capabilities can be combined into two \CFA functions. 2301 2336 \CFA storage-management functions extend the C equivalents by overloading, providing shallow type-safety, and removing the need to specify the base allocation-size. 2302 Figure~\ref{f:StorageAllocation} contrasts \CFA and C storage-allocation operationperforming the same operations with the same type safety.2337 Figure~\ref{f:StorageAllocation} contrasts \CFA and C storage-allocation performing the same operations with the same type safety. 2303 2338 2304 2339 \begin{table} … … 2307 2342 \lstMakeShortInline~% 2308 2343 \begin{tabular}{@{}r|r|l|l|l|l@{}} 2309 \multicolumn{1}{c}{}& & \multicolumn{1}{c|}{fill} & resize & align ment& array \\2344 \multicolumn{1}{c}{}& & \multicolumn{1}{c|}{fill} & resize & align & array \\ 2310 2345 \hline 2311 2346 C & ~malloc~ & no & no & no & no \\ … … 2443 2478 \end{cfa} 2444 2479 \\ 2445 \textbf{output:}2446 2480 & 2447 2481 \begin{cfa}[showspaces=true,aboveskip=0pt] … … 2530 2564 \begin{cfa}[xleftmargin=3\parindentlnth,aboveskip=0pt,belowskip=0pt] 2531 2565 int main( int argc, char * argv[] ) { 2532 ofstream out = { "cfa-out.txt" };2533 2566 int max = 0, val = 42; 2534 stack( int ) s, t; 2535 2536 REPEAT_TIMED( "push_int", N, push( s, val ); ) 2537 TIMED( "copy_int", t = s; ) 2538 TIMED( "clear_int", clear( s ); ) 2539 REPEAT_TIMED( "pop_int", N, int v = pop( t ); max = max( v, max ); ) 2540 REPEAT_TIMED( "print_int", N/2, out | val | ':' | val | endl; ) 2541 2542 pair( _Bool, char ) max = { false, '\0' }, val = { true, 'a' }; 2543 stack( pair( _Bool, char ) ) s, t; 2544 2545 REPEAT_TIMED( "push_pair", N, push( s, val ); ) 2546 TIMED( "copy_pair", t = s; ) 2547 TIMED( "clear_pair", clear( s ); ) 2548 REPEAT_TIMED( "pop_pair", N, pair(_Bool, char) v = pop( t ); max = max( v, max ); ) 2549 REPEAT_TIMED( "print_pair", N/2, out | val | ':' | val | endl; ) 2567 stack( int ) si, ti; 2568 2569 REPEAT_TIMED( "push_int", N, push( si, val ); ) 2570 TIMED( "copy_int", ti = si; ) 2571 TIMED( "clear_int", clear( si ); ) 2572 REPEAT_TIMED( "pop_int", N, int x = pop( ti ); if ( x > max ) max = x; ) 2573 2574 pair( _Bool, char ) max = { (_Bool)0, '\0' }, val = { (_Bool)1, 'a' }; 2575 stack( pair( _Bool, char ) ) sp, tp; 2576 2577 REPEAT_TIMED( "push_pair", N, push( sp, val ); ) 2578 TIMED( "copy_pair", tp = sp; ) 2579 TIMED( "clear_pair", clear( sp ); ) 2580 REPEAT_TIMED( "pop_pair", N, pair(_Bool, char) x = pop( tp ); if ( x > max ) max = x; ) 2550 2581 } 2551 2582 \end{cfa} … … 2677 2708 \subsection{Control Structures / Declarations / Literals} 2678 2709 2710 Java has default fall through like C/\CC. 2711 Pascal/Ada/Go/Rust do not have default fall through. 2712 \Csharp does not have fall through but still requires a break. 2713 Python uses dictionary mapping. \\ 2714 \CFA choose is like Rust match. 2715 2716 Java has labelled break/continue. \\ 2717 Languages with and without exception handling. 2718 2719 Alternative C declarations. \\ 2720 Different references \\ 2721 Constructors/destructors 2722 2723 0/1 Literals \\ 2724 user defined: D, Objective-C 2679 2725 2680 2726 \section{Conclusion and Future Work} … … 2683 2729 While other programming languages purport to be a better C, they are in fact new and interesting languages in their own right, but not C extensions. 2684 2730 The purpose of this paper is to introduce \CFA, and showcase language features that illustrate the \CFA type-system and approaches taken to achieve the goal of evolutionary C extension. 2685 The contributions are a powerful type-system using parametric polymorphism and overloading, generic types, and tuples, which all have complex interactions.2731 The contributions are a powerful type-system using parametric polymorphism and overloading, generic types, tuples, advanced control structures, and extended declarations, which all have complex interactions. 2686 2732 The work is a challenging design, engineering, and implementation exercise. 2687 2733 On the surface, the project may appear as a rehash of similar mechanisms in \CC. … … 2690 2736 Finally, we demonstrate that \CFA performance for some idiomatic cases is better than C and close to \CC, showing the design is practically applicable. 2691 2737 2692 There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, exceptions, concurrent primitives, modules, and user-defined conversions.2738 There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, user-defined conversions, concurrent primitives, and modules. 2693 2739 (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.) 2694 2740 In addition, there are interesting future directions for the polymorphism design. … … 2703 2749 \section{Acknowledgments} 2704 2750 2705 The authors would like to recognize the design assistance of Glen Ditchfield, Richard Bilson, and Thierry Delisleon the features described in this paper, and thank Magnus Madsen for feedback in the writing.2706 This work is supported through a corporate partnership with Huawei Ltd.\ (\url{http://www.huawei.com}), and Aaron Moss and Peter Buhr are funded by the Natural Sciences and Engineering Research Council of Canada.2751 The authors would like to recognize the design assistance of Glen Ditchfield, Richard Bilson, Thierry Delisle, and Andrew Beach on the features described in this paper, and thank Magnus Madsen for feedback in the writing. 2752 This work is supported through a corporate partnership with Huawei Ltd.\ (\url{http://www.huawei.com}), and Aaron Moss and Peter Buhr are partially funded by the Natural Sciences and Engineering Research Council of Canada. 2707 2753 2708 2754 % the first author's \grantsponsor{NSERC-PGS}{NSERC PGS D}{http://www.nserc-crsng.gc.ca/Students-Etudiants/PG-CS/BellandPostgrad-BelletSuperieures_eng.asp} scholarship. -
doc/papers/general/evaluation/Makefile
re5d4e5c r5600747 2 2 CFA = cfa 3 3 DEPFLAGS = -MMD -MP 4 ifdef DBG 5 CFLAGS = -O0 -ggdb -DN=500 6 else 4 7 CFLAGS = -O2 5 8 ifdef N 6 9 CFLAGS += -DN=$(N) 10 endif 7 11 endif 8 12 CXXFLAGS = $(CFLAGS) --std=c++14 … … 27 31 $(COMPILE.cfa) $(OUTPUT_OPTION) -c $< 28 32 29 COBJS = c-stack.o c-pair.o c- print.o c-bench.o33 COBJS = c-stack.o c-pair.o c-bench.o 30 34 CPPOBJS = cpp-bench.o 31 35 CPPVOBJS = cpp-vstack.o cpp-vbench.o 32 CFAOBJS = cfa-stack.o cfa-pair.o cfa- print.o cfa-bench.o36 CFAOBJS = cfa-stack.o cfa-pair.o cfa-bench.o 33 37 34 38 ${COBJS} ${CPPOBJS} ${CPPVOBJS} ${CFAOBJS} : ${MAKEFILE_NAME} 35 39 36 40 CFILES = bench.h $(patsubst c-bench.h,,$(COBJS:.o=.h)) $(COBJS:.o=.c) 37 CPPFILES = bench.hpp cpp-stack.hpp cpp-pair.hpp cpp-print.hpp$(CPPOBJS:.o=.cpp)38 CPPVFILES = bench.hpp object.hpp cpp-vprint.hpp$(patsubst cpp-vbench.hpp,,$(CPPVOBJS:.o=.hpp)) $(CPPVOBJS:.o=.cpp)41 CPPFILES = bench.hpp cpp-stack.hpp cpp-pair.hpp $(CPPOBJS:.o=.cpp) 42 CPPVFILES = bench.hpp object.hpp $(patsubst cpp-vbench.hpp,,$(CPPVOBJS:.o=.hpp)) $(CPPVOBJS:.o=.cpp) 39 43 CFAFILES = bench.h $(patsubst cfa-bench.h,,$(CFAOBJS:.o=.h)) $(CFAOBJS:.o=.c) 40 44 -
doc/papers/general/evaluation/bench.h
re5d4e5c r5600747 5 5 long ms_between(clock_t start, clock_t end) { return (end - start) / (CLOCKS_PER_SEC / 1000); } 6 6 7 #ifndef N 7 8 #define N 40000000 9 #endif 10 8 11 #define TIMED(name, code) { \ 9 12 volatile clock_t _start, _end; \ -
doc/papers/general/evaluation/bench.hpp
re5d4e5c r5600747 6 6 long ms_between(clock_t start, clock_t end) { return (end - start) / (CLOCKS_PER_SEC / 1000); } 7 7 8 #ifndef N 8 9 static const int N = 40000000; 10 #endif 11 9 12 #define TIMED(name, code) { \ 10 13 volatile clock_t _start, _end; \ -
doc/papers/general/evaluation/c-bench.c
re5d4e5c r5600747 4 4 #include "c-pair.h" 5 5 #include "c-stack.h" 6 #include "c-print.h"7 6 8 7 _Bool* new_bool( _Bool b ) { … … 39 38 40 39 int main(int argc, char** argv) { 41 FILE * out = fopen("/dev/null", "w");42 40 int maxi = 0, vali = 42; 43 41 struct stack si = new_stack(), ti; … … 50 48 if ( *xi > maxi ) { maxi = *xi; } 51 49 free(xi); ) 52 REPEAT_TIMED( "print_int", N/2, print( out, "dsds", vali, ":", vali, "\n" ); /***/ )53 50 54 51 struct pair * maxp = new_pair( new_bool(0), new_char('\0') ), … … 67 64 free_pair_bool_char( xp ); /***/ 68 65 } ) 69 REPEAT_TIMED( "print_pair", N/2, print( out, "pbcspbcs", *valp, ":", *valp, "\n" ); /***/ )70 66 free_pair_bool_char( maxp ); /***/ 71 67 free_pair_bool_char( valp ); /***/ 72 fclose(out);73 68 } -
doc/papers/general/evaluation/cfa-bench.c
re5d4e5c r5600747 1 #include <fstream>2 #include <stdlib>3 #include <stdbool.h>4 1 #include "bench.h" 5 2 #include "cfa-stack.h" 6 3 #include "cfa-pair.h" 7 #include "cfa-print.h"8 4 9 5 int main( int argc, char * argv[] ) { 10 ofstream out = { "/dev/null" };11 6 int max = 0, val = 42; 12 stack( int ) s , t;7 stack( int ) si, ti; 13 8 14 REPEAT_TIMED( "push_int", N, push( s , val ); )15 TIMED( "copy_int", t = s; )16 TIMED( "clear_int", clear( s ); )17 REPEAT_TIMED( "pop_int", N, int x = pop( t ); max = max( x, max ); )18 REPEAT_TIMED( "print_int", N/2, out | val | ':' | val | endl; )9 REPEAT_TIMED( "push_int", N, push( si, val ); ) 10 TIMED( "copy_int", ti = si; ) 11 TIMED( "clear_int", clear( si ); ) 12 REPEAT_TIMED( "pop_int", N, 13 int x = pop( ti ); if ( x > max ) max = x; ) 19 14 20 pair( _Bool, char ) max = { (_Bool) false, '\0' }, val = { (_Bool)true, 'a' };21 stack( pair( _Bool, char ) ) s , t;15 pair( _Bool, char ) max = { (_Bool)0 /***/, '\0' }, val = { (_Bool)1 /***/, 'a' }; 16 stack( pair( _Bool, char ) ) sp, tp; 22 17 23 REPEAT_TIMED( "push_pair", N, push( s , val ); )24 TIMED( "copy_pair", t = s; )25 TIMED( "clear_pair", clear( s ); )26 REPEAT_TIMED( "pop_pair", N, pair(_Bool, char) x = pop( t ); max = max( x, max ); )27 REPEAT_TIMED( "print_pair", N/2, out | val | ':' | val | endl; )18 REPEAT_TIMED( "push_pair", N, push( sp, val ); ) 19 TIMED( "copy_pair", tp = sp; ) 20 TIMED( "clear_pair", clear( sp ); ) 21 REPEAT_TIMED( "pop_pair", N, 22 pair(_Bool, char) x = pop( tp ); if ( x > max ) max = x; ) 28 23 } -
doc/papers/general/evaluation/cfa-pair.c
re5d4e5c r5600747 36 36 } 37 37 38 forall(otype R, otype S)39 forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, R ); ostype & ?|?( ostype &, S ); })40 ostype & ?|?( ostype & os, pair(R, S) p ) {41 return os | '[' | p.first | ',' | p.second | ']';42 } // ?|?38 // forall(otype R, otype S) 39 // forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, R ); ostype & ?|?( ostype &, S ); }) 40 // ostype & ?|?( ostype & os, pair(R, S) p ) { 41 // return os | '[' | p.first | ',' | p.second | ']'; 42 // } // ?|? -
doc/papers/general/evaluation/cfa-pair.h
re5d4e5c r5600747 30 30 int ?>=?(pair(R, S) p, pair(R, S) q); 31 31 32 forall(otype R, otype S)33 forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, pair(R, S)); })34 ostype & ?|?( ostype & os, pair(R, S) );32 // forall(otype R, otype S) 33 // forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, R ); ostype & ?|?( ostype &, S ); }) 34 // ostype & ?|?( ostype & os, pair(R, S) ); -
doc/papers/general/evaluation/cfa-stack.c
re5d4e5c r5600747 6 6 stack_node(T) * next; 7 7 }; 8 forall(otype T) void ?{}( stack_node(T) & node, T value, stack_node(T) * next ) {9 node.value = value;10 node.next = next;11 }12 8 13 9 forall(otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; } … … 16 12 stack_node(T) ** crnt = &s.head; 17 13 for ( stack_node(T) * next = t.head; next; next = next->next ) { 18 // *crnt = new( next->value, 0 ); 19 stack_node(T)* new_node = ((stack_node(T)*)malloc()); 20 (*new_node){ next->value }; /***/ 14 stack_node(T)* new_node = (stack_node(T)*)malloc(); /***/ 15 (*new_node){ next->value }; 21 16 *crnt = new_node; 22 stack_node(T) * acrnt = *crnt; 23 crnt = &acrnt->next; 17 crnt = &(*crnt)->next; 24 18 } 25 19 *crnt = 0; … … 38 32 39 33 forall(otype T) void push( stack(T) & s, T value ) { 40 // s.head = new( value, s.head ); 41 stack_node(T)* new_node = ((stack_node(T)*)malloc()); 42 (*new_node){ value, s.head }; /***/ 34 stack_node(T)* new_node = (stack_node(T)*)malloc(); /***/ 35 (*new_node){ value, s.head }; 43 36 s.head = new_node; 44 37 } … … 48 41 s.head = n->next; 49 42 T v = n->value; 50 delete( n ); 43 ^(*n){}; 44 free( n ); 51 45 return v; 52 46 } … … 56 50 stack_node(T) * crnt = next; 57 51 next = crnt->next; 58 delete( crnt ); 52 ^(*crnt){}; 53 free(crnt); 59 54 } 60 55 s.head = 0; -
doc/papers/general/evaluation/cpp-bench.cpp
re5d4e5c r5600747 1 1 #include <algorithm> 2 #include <fstream>3 2 #include "bench.hpp" 4 3 #include "cpp-stack.hpp" 5 4 #include "cpp-pair.hpp" 6 #include "cpp-print.hpp"7 5 8 6 int main(int argc, char** argv) { 9 std::ofstream out{"/dev/null"};10 7 int maxi = 0, vali = 42; 11 8 stack<int> si, ti; … … 15 12 TIMED( "clear_int", si.clear(); ) 16 13 REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop() ); ) 17 REPEAT_TIMED( "print_int", N/2, print( out, vali, ":", vali, "\n" ); )18 14 19 15 pair<bool, char> maxp = { false, '\0' }, valp = { true, 'a' }; … … 24 20 TIMED( "clear_pair", sp.clear(); ) 25 21 REPEAT_TIMED( "pop_pair", N, maxp = std::max( maxp, tp.pop() ); ) 26 REPEAT_TIMED( "print_pair", N/2, print( out, valp, ":", valp, "\n" ); )27 22 } -
doc/papers/general/evaluation/cpp-vbench.cpp
re5d4e5c r5600747 1 1 #include <algorithm> 2 #include <fstream>3 2 #include "bench.hpp" 4 3 #include "cpp-vstack.hpp" 5 #include "cpp-vprint.hpp"6 4 #include "object.hpp" 7 5 8 6 int main(int argc, char** argv) { 9 std::ofstream out{"/dev/null"};10 7 integer maxi{ 0 }, vali{ 42 }; 11 8 stack si, ti; … … 15 12 TIMED( "clear_int", si.clear(); ) 16 13 REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop()->as<integer>() ); /***/ ) 17 REPEAT_TIMED( "print_int", N/2, print( out, vali, c_string{":"}, vali, c_string{"\n"} ); )18 14 19 15 ptr<pair> maxp = make<pair>( make<boolean>(false), make<character>('\0') ); … … 27 23 ptr<pair> xp = as_ptr<pair>( tp.pop() ); /***/ 28 24 if ( *xp > *maxp ) { maxp = std::move(xp); } ) 29 REPEAT_TIMED( "print_pair", N/2, print( out, valp, c_string{":"}, valp, c_string{"\n"} ); )30 25 } -
doc/papers/general/evaluation/timing.dat
re5d4e5c r5600747 1 1 "400 million repetitions" "C" "\\CFA{}" "\\CC{}" "\\CC{obj}" 2 "push\nint" 3002 2459 1520 3305 3 "copy\nint" 2985 2057 1521 3152 4 "clear\nint" 1374 827 718 1469 5 "pop\nint" 1416 1221 717 5467 6 "print\nint" 5656 6758 3120 3121 7 "push\npair" 4214 2752 946 6826 8 "copy\npair" 6127 2105 993 7330 9 "clear\npair" 2881 885 711 3564 10 "pop\npair" 3046 5434 783 26538 11 "print\npair" 7514 10714 8717 16525 2 "push\nint" 2976 2225 1522 3266 3 "copy\nnt" 2932 7072 1526 3110 4 "clear\nint" 1380 731 750 1488 5 "pop\nint" 1444 1196 756 5156 6 "push\npair" 3695 2257 953 6840 7 "copy\npair" 6034 6650 994 7224 8 "clear\npair" 2832 848 742 3297 9 "pop\npair" 3009 5348 797 25235 10 -
src/GenPoly/Box.cc
re5d4e5c r5600747 163 163 void premutate( DeclStmt *declStmt ); 164 164 Expression *postmutate( MemberExpr *memberExpr ); 165 void premutate( AddressExpr *addrExpr ); 166 Expression *postmutate( AddressExpr *addrExpr ); 165 167 Expression *postmutate( SizeofExpr *sizeofExpr ); 166 168 Expression *postmutate( AlignofExpr *alignofExpr ); … … 193 195 ScopedSet< std::string > knownOffsets; ///< Set of non-generic types for which the offset array exists in the current scope, indexed by offsetofName 194 196 UniqueName bufNamer; ///< Namer for VLA buffers 197 Expression * addrMember = nullptr; ///< AddressExpr argument is MemberExpr? 195 198 }; 196 199 … … 1174 1177 if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) { 1175 1178 if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) { 1176 if ( name-> get_name()== "*?" ) {1179 if ( name->name == "*?" ) { 1177 1180 Expression *ret = expr->args.front(); 1178 1181 expr->args.clear(); … … 1187 1190 void Pass1::premutate( AddressExpr * ) { visit_children = false; } 1188 1191 Expression * Pass1::postmutate( AddressExpr * addrExpr ) { 1189 assert( addrExpr-> get_arg()->result && ! addrExpr->get_arg()->get_result()->isVoid() );1192 assert( addrExpr->arg->result && ! addrExpr->arg->result->isVoid() ); 1190 1193 1191 1194 bool needs = false; 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());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 ); 1199 1202 assert( function ); 1200 1203 needs = needsAdapter( function, scopeTyVars ); … … 1206 1209 // isPolyType check needs to happen before mutating addrExpr arg, so pull it forward 1207 1210 // out of the if condition. 1208 addrExpr->arg = addrExpr-> get_arg()->acceptMutator( *visitor );1211 addrExpr->arg = addrExpr->arg->acceptMutator( *visitor ); 1209 1212 // ... but must happen after mutate, since argument might change (e.g. intrinsic *?, ?[?]) - re-evaluate above comment 1210 bool polytype = isPolyType( addrExpr-> get_arg()->get_result(), scopeTyVars, env );1213 bool polytype = isPolyType( addrExpr->arg->result, scopeTyVars, env ); 1211 1214 if ( polytype || needs ) { 1212 Expression *ret = addrExpr-> get_arg();1213 delete ret-> get_result();1214 ret-> set_result( addrExpr->get_result()->clone());1215 addrExpr-> set_arg( 0 );1215 Expression *ret = addrExpr->arg; 1216 delete ret->result; 1217 ret->result = addrExpr->result->clone(); 1218 addrExpr->arg = nullptr; 1216 1219 delete addrExpr; 1217 1220 return ret; … … 1250 1253 1251 1254 void Pass2::addAdapters( FunctionType *functionType ) { 1252 std::list< DeclarationWithType *> ¶mList = functionType-> get_parameters();1255 std::list< DeclarationWithType *> ¶mList = functionType->parameters; 1253 1256 std::list< FunctionType *> functions; 1254 1257 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) { … … 1271 1274 1272 1275 DeclarationWithType * Pass2::postmutate( FunctionDecl *functionDecl ) { 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/dtors1276 assert( ftype-> get_returnVals().size() == 1 );1277 DeclarationWithType * retval = ftype-> get_returnVals().front();1278 if ( retval-> get_name()== "" ) {1279 retval-> set_name( "_retval" );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/dtors 1279 assert( ftype->returnVals.size() == 1 ); 1280 DeclarationWithType * retval = ftype->returnVals.front(); 1281 if ( retval->name == "" ) { 1282 retval->name = "_retval"; 1280 1283 } 1281 functionDecl-> get_statements()->get_kids().push_front( new DeclStmt( retval ) );1284 functionDecl->statements->kids.push_front( new DeclStmt( retval ) ); 1282 1285 DeclarationWithType * newRet = retval->clone(); // for ownership purposes 1283 ftype-> get_returnVals().front() = newRet;1286 ftype->returnVals.front() = newRet; 1284 1287 } 1285 1288 } 1286 1289 // errors should have been caught by this point, remove initializers from parameters to allow correct codegen of default arguments 1287 for ( Declaration * param : functionDecl-> get_functionType()->get_parameters()) {1290 for ( Declaration * param : functionDecl->type->parameters ) { 1288 1291 if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( param ) ) { 1289 delete obj-> get_init();1290 obj-> set_init( nullptr );1292 delete obj->init; 1293 obj->init = nullptr; 1291 1294 } 1292 1295 } … … 1584 1587 assert( newMemberExpr ); 1585 1588 1586 Type *memberType = memberExpr->member->get_type(); 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 ); 1587 1598 if ( ! isPolyType( memberType, scopeTyVars ) ) { 1588 1599 // 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 … … 1592 1603 } 1593 1604 1605 delete memberType; 1594 1606 delete memberExpr; 1595 1607 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 mutated 1619 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-of 1622 // 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; 1596 1632 } 1597 1633 -
src/SynTree/Expression.cc
re5d4e5c r5600747 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 362 347 MemberExpr::MemberExpr( DeclarationWithType *member, Expression *aggregate ) : 363 348 Expression(), member(member), aggregate(aggregate) { 364 349 assert( member ); 365 350 assert( aggregate ); 366 367 TypeSubstitution sub( makeSub( aggregate->get_result() ) ); 351 assert( aggregate->result ); 352 353 TypeSubstitution sub = aggregate->result->genericSubstitution(); 368 354 Type * res = member->get_type()->clone(); 369 355 sub.apply( res ); -
src/SynTree/ReferenceToType.cc
re5d4e5c r5600747 14 14 // 15 15 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 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 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 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 25 26 26 27 class Attribute; … … 63 64 std::string StructInstType::typeString() const { return "struct"; } 64 65 66 const std::list<TypeDecl*>* StructInstType::get_baseParameters() const { 67 if ( ! baseStruct ) return nullptr; 68 return &baseStruct->get_parameters(); 69 } 70 65 71 std::list<TypeDecl*>* StructInstType::get_baseParameters() { 66 72 if ( ! baseStruct ) return nullptr; … … 71 77 72 78 AggregateDecl * StructInstType::getAggr() { return baseStruct; } 79 80 TypeSubstitution StructInstType::genericSubstitution() const { 81 return TypeSubstitution( get_baseParameters()->begin(), get_baseParameters()->end(), parameters.begin() ); 82 } 73 83 74 84 void StructInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const { … … 102 112 } 103 113 114 const std::list< TypeDecl * > * UnionInstType::get_baseParameters() const { 115 if ( ! baseUnion ) return nullptr; 116 return &baseUnion->get_parameters(); 117 } 118 104 119 bool UnionInstType::isComplete() const { return baseUnion ? baseUnion->has_body() : false; } 105 120 106 121 AggregateDecl * UnionInstType::getAggr() { return baseUnion; } 122 123 TypeSubstitution UnionInstType::genericSubstitution() const { 124 return TypeSubstitution( get_baseParameters()->begin(), get_baseParameters()->end(), parameters.begin() ); 125 } 107 126 108 127 void UnionInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const { -
src/SynTree/ReferenceType.cc
re5d4e5c r5600747 16 16 #include "Type.h" 17 17 #include "Expression.h" 18 #include "TypeSubstitution.h" 18 19 #include "Common/utility.h" 19 20 … … 35 36 } 36 37 38 TypeSubstitution ReferenceType::genericSubstitution() const { return base->genericSubstitution(); } 39 37 40 void ReferenceType::print( std::ostream &os, Indenter indent ) const { 38 41 Type::print( os, indent ); -
src/SynTree/Type.cc
re5d4e5c r5600747 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 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 22 23 23 24 using namespace std; … … 81 82 int Type::referenceDepth() const { return 0; } 82 83 84 TypeSubstitution Type::genericSubstitution() const { assertf( false, "Non-aggregate type: %s", toCString( this ) ); } 85 83 86 void Type::print( std::ostream &os, Indenter indent ) const { 84 87 if ( ! forall.empty() ) { -
src/SynTree/Type.h
re5d4e5c r5600747 178 178 virtual bool isComplete() const { return true; } 179 179 180 virtual AggregateDecl * getAggr() { assertf( false, "Non-aggregate type: %s", toString( this ).c_str() ); } 180 virtual AggregateDecl * getAggr() { assertf( false, "Non-aggregate type: %s", toCString( this ) ); } 181 182 virtual TypeSubstitution genericSubstitution() const; 181 183 182 184 virtual Type *clone() const = 0; … … 329 331 virtual unsigned size() const override { return base->size(); } 330 332 333 virtual TypeSubstitution genericSubstitution() const override; 334 331 335 virtual ReferenceType *clone() const override { return new ReferenceType( *this ); } 332 336 virtual void accept( Visitor & v ) override { v.visit( this ); } … … 406 410 /// Accesses generic parameters of base struct (NULL if none such) 407 411 std::list<TypeDecl*> * get_baseParameters(); 412 const std::list<TypeDecl*> * get_baseParameters() const; 408 413 409 414 virtual bool isComplete() const override; 410 415 411 416 virtual AggregateDecl * getAggr() override; 417 418 virtual TypeSubstitution genericSubstitution() const override; 412 419 413 420 /// Looks up the members of this struct named "name" and places them into "foundDecls". … … 439 446 440 447 /// Accesses generic parameters of base union (NULL if none such) 441 std::list< TypeDecl * > * get_baseParameters(); 448 std::list<TypeDecl*> * get_baseParameters(); 449 const std::list<TypeDecl*> * get_baseParameters() const; 442 450 443 451 virtual bool isComplete() const override; 444 452 445 453 virtual AggregateDecl * getAggr() override; 454 455 virtual TypeSubstitution genericSubstitution() const override; 446 456 447 457 /// looks up the members of this union named "name" and places them into "foundDecls" -
src/tests/.expect/literals.x86.txt
re5d4e5c r5600747 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)); 524 548 ((void)01234567); 525 549 ((void)01234567u); … … 1017 1041 ((void)(-0X0123456789.0123456789P-09F)); 1018 1042 ((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)))); 1019 1073 ((void)((signed char )01234567)); 1020 1074 ((void)((signed short int )01234567));
Note: See TracChangeset
for help on using the changeset viewer.