Changeset 03606ce


Ignore:
Timestamp:
Mar 8, 2024, 12:25:49 AM (19 months ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
266732e
Parents:
06601401 (diff), 169496e1 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Files:
15 edited

Legend:

Unmodified
Added
Removed
  • doc/papers/llheap/Makefile

    r06601401 r03606ce  
    1717
    1818FIGURES = ${addsuffix .tex, \
    19 AddressSpace \
    2019AllocatorComponents \
    2120AllocatedObject \
     
    5756
    5857PICTURES = ${addsuffix .pstex, \
     58AddressSpace \
    5959MultipleHeapsOwnershipStorage \
    6060PrivatePublicHeaps \
  • doc/papers/llheap/Paper.tex

    r06601401 r03606ce  
    8282xleftmargin=\parindentlnth,                             % indent code to paragraph indentation
    8383escapechar=\$,                                                  % LaTeX escape in CFA code
    84 %mathescape=true,                                               % LaTeX math escape in CFA code $...$
     84mathescape=false,                                               % disable LaTeX math escape in CFA code $...$
    8585keepspaces=true,                                                %
    8686showstringspaces=false,                                 % do not show spaces with cup
     
    9090numberstyle=\footnotesize\sf,                   % numbering style
    9191moredelim=**[is][\color{red}]{@}{@},
     92% replace/adjust listing characters that look bad in sanserif
     93literate=
     94%  {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1
     95  {-}{\raisebox{-1pt}{\ttfamily-}}1
     96  {^}{\raisebox{0.6ex}{\(\scriptstyle\land\,\)}}1
     97  {~}{\raisebox{0.3ex}{\(\scriptstyle\sim\,\)}}1
     98  {'}{\ttfamily'\hspace*{-0.4ex}}1
     99  {`}{\ttfamily\upshape\hspace*{-0.3ex}`}1
     100  {<-}{$\leftarrow$}2
     101  {=>}{$\Rightarrow$}2
     102%  {->}{\raisebox{-1pt}{\texttt{-}}\kern-0.1ex\textgreater}2,
    92103}% lstset
    93104
     
    95106\lstdefinelanguage{CFA}[ANSI]{C}{
    96107        morekeywords={
    97                 _Alignas, _Alignof, __alignof, __alignof__, asm, __asm, __asm__, __attribute, __attribute__,
    98                 auto, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,
    99                 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally,
    100                 __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__,
    101                 inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or,
    102                 otype, restrict, resume, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend, thread,
    103                 _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
    104                 virtual, __volatile, __volatile__, waitfor, when, with, zero_t},
     108                _Alignas, _Alignof, __alignof, __alignof__, and, asm, __asm, __asm__, _Atomic, __attribute, __attribute__,
     109                __auto_type, basetypeof, _Bool, catch, catchResume, choose, coerce, _Complex, __complex, __complex__, __const, __const__,
     110                coroutine, _Decimal32, _Decimal64, _Decimal128, disable, enable, exception, __extension__, fallthrough, fallthru, finally, fixup,
     111                __float80, float80, __float128, float128, _Float16, _Float32, _Float32x, _Float64, _Float64x, _Float128, _Float128x,
     112                forall, fortran, generator, _Generic, _Imaginary, __imag, __imag__, inline, __inline, __inline__, int128, __int128, __int128_t,
     113                __label__, monitor, mutex, _Noreturn, __builtin_offsetof, one_t, or, recover, report, restrict, __restrict, __restrict__,
     114                __signed, __signed__, _Static_assert, suspend, thread, __thread, _Thread_local, throw, throwResume, timeout, trait, try,
     115                typeof, __typeof, __typeof__, typeid, __uint128_t, __builtin_va_arg, __builtin_va_list, virtual, __volatile, __volatile__,
     116                vtable, waitfor, waituntil, when, with, zero_t,
     117    },
    105118        moredirectives={defined,include_next},
    106         % replace/adjust listing characters that look bad in sanserif
    107         literate={-}{\makebox[1ex][c]{\raisebox{0.5ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
    108                 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 % {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
    109                 {<}{\textrm{\textless}}1 {>}{\textrm{\textgreater}}1
    110                 {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.5ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex{\textrm{\textgreater}}}2,
    111119}
    112120
    113121% uC++ programming language, based on ANSI C++
    114 \lstdefinelanguage{uC++}[ANSI]{C++}{
     122\lstdefinelanguage{uC++}[GNU]{C++}{
    115123        morekeywords={
    116                 _Accept, _AcceptReturn, _AcceptWait, _Actor, _At, _CatchResume, _Cormonitor, _Coroutine, _Disable,
    117                 _Else, _Enable, _Event, _Finally, _Monitor, _Mutex, _Nomutex, _PeriodicTask, _RealTimeTask,
    118                 _Resume, _Select, _SporadicTask, _Task, _Timeout, _When, _With, _Throw},
     124                _Accept, _AcceptReturn, _AcceptWait, _Actor, _At, _Catch, _CatchResume, _CorActor, _Cormonitor, _Coroutine,
     125                _Disable, _Else, _Enable, _Event, _Exception, _Finally, _Monitor, _Mutex, _Nomutex, _PeriodicTask, _RealTimeTask,
     126                _Resume, _ResumeTop, _Select, _SporadicTask, _Task, _Timeout, _When, _With, _Throw},
    119127}
    120128
     
    133141        morestring=[b]",
    134142        morestring=[s]{`}{`},
    135         % replace/adjust listing characters that look bad in sanserif
    136         literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
    137                 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 % {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
    138                 {<}{\textrm{\textless}}1 {>}{\textrm{\textgreater}}1
    139                 {<-}{\makebox[2ex][c]{\textrm{\textless}\raisebox{0.5ex}{\rule{0.8ex}{0.075ex}}}}2,
    140143}
    141144
    142 \lstnewenvironment{cfa}[1][]
    143 {\lstset{language=CFA,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}
    144 {}
    145 \lstnewenvironment{C++}[1][]                            % use C++ style
    146 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}
    147 {}
    148 \lstnewenvironment{uC++}[1][]
    149 {\lstset{language=uC++,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}
    150 {}
    151 \lstnewenvironment{Go}[1][]
    152 {\lstset{language=Golang,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}
    153 {}
    154 \lstnewenvironment{python}[1][]
    155 {\lstset{language=python,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}
    156 {}
    157 \lstnewenvironment{java}[1][]
    158 {\lstset{language=java,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}
    159 {}
     145\lstnewenvironment{cfa}[1][]{\lstset{language=CFA,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}{}
     146\lstnewenvironment{C++}[1][]{\lstset{language=C++,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}{}
     147\lstnewenvironment{uC++}[1][]{\lstset{language=uC++,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}{}
     148\lstnewenvironment{Go}[1][]{\lstset{language=Golang,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}{}
     149\lstnewenvironment{python}[1][]{\lstset{language=python,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}{}
     150\lstnewenvironment{java}[1][]{\lstset{language=java,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}{}
    160151
    161152% inline code @...@
     
    193184
    194185\author[1]{Mubeen Zulfiqar}
     186\author[1]{Ayelet Wasik}
    195187\author[1]{Peter A. Buhr*}
    196 \author[1]{Thierry Delisle}
    197 \author[1]{Ayelet Wasik}
     188\author[2]{Bryan Chan}
    198189\authormark{ZULFIQAR \textsc{et al.}}
    199190
    200191\address[1]{\orgdiv{Cheriton School of Computer Science}, \orgname{University of Waterloo}, \orgaddress{\state{Waterloo, ON}, \country{Canada}}}
     192\address[2]{\orgdiv{Huawei Compiler Lab}, \orgname{Huawei}, \orgaddress{\state{Markham, ON}, \country{Canada}}}
    201193
    202194\corres{*Peter A. Buhr, Cheriton School of Computer Science, University of Waterloo, 200 University Avenue West, Waterloo, ON N2L 3G1, Canada. \email{pabuhr{\char`\@}uwaterloo.ca}}
     
    204196% \fundingInfo{Natural Sciences and Engineering Research Council of Canada}
    205197
    206 \abstract[Summary]{
    207 A new C-based concurrent memory-allocator is presented, called llheap.
     198\abstract[Summary]{%
     199A new C-based concurrent memory-allocator is presented, called llheap (low latency).
    208200It can be used standalone in C/\CC applications with multiple kernel threads, or embedded into high-performance user-threading programming languages.
    209201llheap extends the feature set of existing C allocation by remembering zero-filled (\lstinline{calloc}) and aligned properties (\lstinline{memalign}) in an allocation.
    210202These properties can be queried, allowing programmers to write safer programs by preserving these properties in future allocations.
    211 As well, \lstinline{realloc} preserves these properties when enlarging storage requests, again increasing future allocation safety.
    212 llheap also extends the C allocation API with \lstinline{resize}, extended \lstinline{realloc}, \lstinline{aalloc}, \lstinline{amemalign}, and \lstinline{cmemalign} providing orthongoal ac, so programmers do not make mistakes writing theses useful allocation operations.
    213 It is competitive with the best current memory allocators,
    214 The ability to use \CFA's advanced type-system (and possibly \CC's too) to combine advanced memory operations into one allocation routine using named arguments shows how far the allocation API can be pushed, which increases safety and greatly simplifies programmer's use of dynamic allocation.
    215  low-latency
    216  without a performance loss
    217 The llheap allocator also provides comprehensive statistics for all allocation operations, which are invaluable in understanding and debugging a program's dynamic behaviour.
    218 As well, llheap provides a debugging mode where allocations are checked with internal pre/post conditions and invariants. It is extremely useful, especially for students.
    219 % No other memory allocator examined in the work provides such comprehensive statistics gathering.
     203As well, \lstinline{realloc} preserves these properties when adjusting storage size, again increasing future allocation safety.
     204llheap also extends the C allocation API with \lstinline{aalloc}, \lstinline{amemalign}, \lstinline{cmemalign}, \lstinline{resize}, and extended \lstinline{realloc}, providing orthogonal access to allocation features;
     205hence, programmers do have to code missing combinations.
     206The llheap allocator also provides a contention-free statistics gathering mode, and a debugging mode for dynamically checking allocation pre/post conditions and invariants.
     207These modes are invaluable for understanding and debugging a program's dynamic allocation behaviour, with low enough cost to be used in production code.
     208The llheap API is further extended with the \CFA advanced type-system, providing a single type-safe allocation routine using named arguments, increasing safety and simplifying usage.
     209Finally, performance results across a number of benchmarks show llheap is competitive with the best memory allocators.
     210}% abstract
     211
    220212% While not as powerful as the \lstinline{valgrind} interpreter, a large number of allocations mistakes are detected.
    221 % Finally, contention-free statistics gathering and debugging have a low enough cost to be used in production code.
    222 %
    223213% A micro-benchmark test-suite is started for comparing allocators, rather than relying on a suite of arbitrary programs. It has been an interesting challenge.
    224214% These micro-benchmarks have adjustment knobs to simulate allocation patterns hard-coded into arbitrary test programs.
    225215% Existing memory allocators, glibc, dlmalloc, hoard, jemalloc, ptmalloc3, rpmalloc, tbmalloc, and the new allocator llheap are all compared using the new micro-benchmark test-suite.
    226 }% aabstract
    227 
    228 \keywords{C \CFA (Cforall) coroutine concurrency generator monitor parallelism runtime thread}
     216
     217\keywords{memory allocation, (user-level) concurrency, type-safety, statistics, debugging, high performance}
    229218
    230219
     
    237226\section{Introduction}
    238227
    239 Memory management takes a sequence of program generated allocation/deallocation requests and attempts to satisfy them within a fixed-sized block of memory while minimizing the total amount of memory used.
    240 A general-purpose dynamic-allocation algorithm cannot anticipate future allocation requests so its output is rarely optimal.
    241 However, memory allocators do take advantage of regularities in allocation patterns for typical programs to produce excellent results, both in time and space (similar to LRU paging).
    242 In general, allocators use a number of similar techniques, each optimizing specific allocation patterns.
    243 Nevertheless, memory allocators are a series of compromises, occasionally with some static or dynamic tuning parameters to optimize specific program-request patterns.
     228Memory management services a series of program allocation/deallocation requests and attempts to satisfy them from a variable-sized block of memory, while minimizing total memory usage.
     229A general-purpose dynamic-allocation algorithm cannot anticipate allocation requests so its time and space performance is rarely optimal.
     230However, allocators take advantage of regular allocation patterns in typical programs to produce excellent results, both in time and space (similar to LRU paging).
     231Allocators use a number of similar techniques, but each optimizes specific allocation patterns.
     232Nevertheless, allocators are a series of compromises, occasionally with some static or dynamic tuning parameters to optimize specific program-request patterns.
    244233
    245234
     
    247236\label{s:MemoryStructure}
    248237
    249 Figure~\ref{f:ProgramAddressSpace} shows the typical layout of a program's address space divided into the following zones (right to left): static code/data, dynamic allocation, dynamic code/data, and stack, with free memory surrounding the dynamic code/data~\cite{memlayout}.
     238Figure~\ref{f:ProgramAddressSpace} shows the typical layout of a program's address space (high to low) divided into a number of zones, with free memory surrounding the dynamic code/data~\cite{memlayout}.
    250239Static code and data are placed into memory at load time from the executable and are fixed-sized at runtime.
    251 Dynamic-allocation memory starts empty and grows/shrinks as the program dynamically creates/deletes variables with independent lifetime.
    252 The programming-language's runtime manages this area, where management complexity is a function of the mechanism for deleting variables.
    253240Dynamic code/data memory is managed by the dynamic loader for libraries loaded at runtime, which is complex especially in a multi-threaded program~\cite{Huang06}.
    254241However, changes to the dynamic code/data space are typically infrequent, many occurring at program startup, and are largely outside of a program's control.
    255242Stack memory is managed by the program call/return-mechanism using a LIFO technique, which works well for sequential programs.
    256243For stackful coroutines and user threads, a new stack is commonly created in the dynamic-allocation memory.
     244The dynamic-allocation memory is often a contiguous area (can be memory mapped as multiple areas), which starts empty and grows/shrinks as the program creates/deletes variables with independent lifetime.
     245The programming-language's runtime manages this area, where management complexity is a function of the mechanism for deleting variables.
    257246This work focuses solely on management of the dynamic-allocation memory.
    258247
    259248\begin{figure}
    260249\centering
    261 \input{AddressSpace}
     250\input{AddressSpace.pstex_t}
    262251\vspace{-5pt}
    263252\caption{Program Address Space Divided into Zones}
     
    269258\label{s:DynamicMemoryManagement}
    270259
    271 Modern programming languages manage dynamic-allocation memory in different ways.
     260Modern programming languages manage dynamic memory in different ways.
    272261Some languages, such as Lisp~\cite{CommonLisp}, Java~\cite{Java}, Haskell~\cite{Haskell}, Go~\cite{Go}, provide explicit allocation but \emph{implicit} deallocation of data through garbage collection~\cite{Wilson92}.
    273262In general, garbage collection supports memory compaction, where dynamic (live) data is moved during runtime to better utilize space.
    274 However, moving data requires finding pointers to it and updating them to reflect new data locations.
     263However, moving data requires finding and updating pointers to it to reflect the new data locations.
    275264Programming languages such as C~\cite{C}, \CC~\cite{C++}, and Rust~\cite{Rust} provide the programmer with explicit allocation \emph{and} deallocation of data.
    276265These languages cannot find and subsequently move live data because pointers can be created to any storage zone, including internal components of allocated objects, and may contain temporary invalid values generated by pointer arithmetic.
    277266Attempts have been made to perform quasi garbage collection in C/\CC~\cite{Boehm88}, but it is a compromise.
    278 This work only examines dynamic memory-management with \emph{explicit} deallocation.
     267This work only examines dynamic management with \emph{explicit} deallocation.
    279268While garbage collection and compaction are not part this work, many of the results are applicable to the allocation phase in any memory-management approach.
    280269
    281 Most programs use a general-purpose allocator, often the one provided implicitly by the programming-language's runtime.
    282 When this allocator proves inadequate, programmers often write specialize allocators for specific needs.
    283 C and \CC allow easy replacement of the default memory allocator with an alternative specialized or general-purpose memory-allocator.
     270Most programs use a general-purpose allocator, usually the one provided by the programming-language's runtime.
     271In certain languages, programmers can write specialize allocators for specific needs.
     272C and \CC allow easy replacement of the default memory allocator through a standard API.
    284273Jikes RVM MMTk~\cite{MMTk} provides a similar generalization for the Java virtual machine.
    285 However, high-performance memory-allocators for kernel and user multi-threaded programs are still being designed and improved.
    286 For this reason, several alternative general-purpose allocators have been written for C/\CC with the goal of scaling in a multi-threaded program~\cite{Berger00,mtmalloc,streamflow,tcmalloc}.
     274As well, new languages support concurrency (kernel and/or user threading), which must be safely handled by the allocator.
     275Hence, several alternative allocators exist for C/\CC with the goal of scaling in a multi-threaded program~\cite{Berger00,mtmalloc,streamflow,tcmalloc}.
    287276This work examines the design of high-performance allocators for use by kernel and user multi-threaded applications written in C/\CC.
    288277
     
    294283\begin{enumerate}[leftmargin=*,itemsep=0pt]
    295284\item
    296 Implementation of a new stand-alone concurrent low-latency memory-allocator ($\approx$1,200 lines of code) for C/\CC programs using kernel threads (1:1 threading), and specialized versions of the allocator for the programming languages \uC~\cite{uC++} and \CFA~\cite{Moss18,Delisle21} using user-level threads running on multiple kernel threads (M:N threading).
    297 
    298 \item
    299 Extend the standard C heap functionality by preserving with each allocation: its request size plus the amount allocated, whether an allocation is zero fill and/or allocation alignment.
     285Implementation of a new stand-alone concurrent low-latency memory-allocator ($\approx$1,200 lines of code) for C/\CC programs using kernel threads (1:1 threading), and specialized versions for the concurrent languages \uC~\cite{uC++} and \CFA~\cite{Moss18,Delisle21} using user-level threads running on multiple kernel threads (M:N threading).
     286
     287\item
     288Extend the standard C heap functionality by preserving with each allocation its request size, the amount allocated, whether it is zero fill, and its alignment.
    300289
    301290\item
    302291Use the preserved zero fill and alignment as \emph{sticky} properties for @realloc@ to zero-fill and align when storage is extended or copied.
    303 Without this extension, it is unsafe to @realloc@ storage initially allocated with zero-fill/alignment as these properties are not preserved when copying.
    304 This silent generation of a problem is unintuitive to programmers and difficult to locate because it is transient.
    305 
    306 \item
    307 Provide additional heap operations to complete programmer expectation with respect to accessing different allocation properties.
    308 \begin{itemize}[topsep=3pt,itemsep=2pt,parsep=0pt]
     292Without this extension, it is unsafe to @realloc@ storage these allocations if the properties are not preserved when copying.
     293This silent problem is unintuitive to programmers and difficult to locate because it is transient.
     294
     295\item
     296Provide additional heap operations to make allocation properties orthogonally accessible.
     297\begin{itemize}[topsep=2pt,itemsep=2pt,parsep=0pt]
     298\item
     299@aalloc( dim, elemSize )@ same as @calloc@ except memory is \emph{not} zero filled.
     300\item
     301@amemalign( alignment, dim, elemSize )@ same as @aalloc@ with memory alignment.
     302\item
     303@cmemalign( alignment, dim, elemSize )@ same as @calloc@ with memory alignment.
    309304\item
    310305@resize( oaddr, size )@ re-purpose an old allocation for a new type \emph{without} preserving fill or alignment.
     
    313308\item
    314309@realloc( oaddr, alignment, size )@ same as @realloc@ but adding or changing alignment.
    315 \item
    316 @aalloc( dim, elemSize )@ same as @calloc@ except memory is \emph{not} zero filled.
    317 \item
    318 @amemalign( alignment, dim, elemSize )@ same as @aalloc@ with memory alignment.
    319 \item
    320 @cmemalign( alignment, dim, elemSize )@ same as @calloc@ with memory alignment.
    321310\end{itemize}
    322 
    323 \item
    324 Provide additional heap wrapper functions in \CFA creating a more usable set of allocation operations and properties.
    325311
    326312\item
     
    328314\begin{itemize}[topsep=3pt,itemsep=2pt,parsep=0pt]
    329315\item
    330 @malloc_alignment( addr )@ returns the alignment of the allocation pointed-to by @addr@.
     316@malloc_alignment( addr )@ returns the alignment of the allocation.
    331317If the allocation is not aligned or @addr@ is @NULL@, the minimal alignment is returned.
    332318\item
    333 @malloc_zero_fill( addr )@ returns a boolean result indicating if the memory pointed-to by @addr@ is allocated with zero fill, e.g., by @calloc@/@cmemalign@.
    334 \item
    335 @malloc_size( addr )@ returns the size of the memory allocation pointed-to by @addr@.
    336 \item
    337 @malloc_usable_size( addr )@ returns the usable (total) size of the memory pointed-to by @addr@, i.e., the bin size containing the allocation, where @malloc_size( addr )@ $\le$ @malloc_usable_size( addr )@.
     319@malloc_zero_fill( addr )@ returns a boolean result indicating if the memory is allocated with zero fill, e.g., by @calloc@/@cmemalign@.
     320\item
     321@malloc_size( addr )@ returns the size of the memory allocation.
     322\item
     323@malloc_usable_size( addr )@ returns the usable (total) size of the memory, i.e., the bin size containing the allocation, where @malloc_size( addr )@ $\le$ @malloc_usable_size( addr )@.
    338324\end{itemize}
    339325
    340326\item
    341 Provide complete, fast, and contention-free allocation statistics to help understand allocation behaviour:
     327Provide optional extensive, fast, and contention-free allocation statistics to understand allocation behaviour, accessed by:
    342328\begin{itemize}[topsep=3pt,itemsep=2pt,parsep=0pt]
    343329\item
    344 @malloc_stats()@ print memory-allocation statistics on the file-descriptor set by @malloc_stats_fd@.
    345 \item
    346 @malloc_info( options, stream )@ print memory-allocation statistics as an XML string on the specified file-descriptor set by @malloc_stats_fd@.
    347 \item
    348 @malloc_stats_fd( fd )@ set file-descriptor number for printing memory-allocation statistics (default @STDERR_FILENO@).
     330@malloc_stats()@ print memory-allocation statistics on the file-descriptor set by @malloc_stats_fd@ (default @stderr@).
     331\item
     332@malloc_info( options, stream )@ print memory-allocation statistics as an XML string on the specified file-descriptor set by @malloc_stats_fd@ (default @stderr@).
     333\item
     334@malloc_stats_fd( fd )@ set file-descriptor number for printing memory-allocation statistics (default @stderr@).
    349335This file descriptor is used implicitly by @malloc_stats@ and @malloc_info@.
    350336\end{itemize}
     
    355341\item
    356342Build 8 different versions of the allocator: static or dynamic linking, with or without statistics or debugging.
    357 A program may link to any of these 8 versions of the allocator often without recompilation.
     343A program may link to any of these 8 versions of the allocator often without recompilation (@LD_PRELOAD@).
     344
     345\item
     346Provide additional heap wrapper functions in \CFA creating a more usable set of allocation operations and properties.
    358347
    359348\item
     
    365354\section{Background}
    366355
    367 The following discussion is a quick overview of the moving-pieces that affect the design of a memory allocator and its performance.
    368 Dynamic acquires and releases obtain storage for a program variable, called an \newterm{object}, through calls such as @malloc@ and @free@ in C, and @new@ and @delete@ in \CC.
    369 Space for each allocated object comes from the dynamic-allocation zone.
    370 
     356The following is a quick overview of allocator design options that affect memory usage and performance (see~\cite{Zulfiqar22} for more details).
     357Dynamic acquires and releases obtain storage for a program variable, called an \newterm{object}, through calls such as @malloc@/@new@ and @free@/@delete@ in C/\CC.
    371358A \newterm{memory allocator} contains a complex data-structure and code that manages the layout of objects in the dynamic-allocation zone.
    372359The management goals are to make allocation/deallocation operations as fast as possible while densely packing objects to make efficient use of memory.
    373 Objects in C/\CC cannot be moved to aid the packing process, only adjacent free storage can be \newterm{coalesced} into larger free areas.
     360Since objects in C/\CC cannot be moved to aid the packing process, only adjacent free storage can be \newterm{coalesced} into larger free areas.
    374361The allocator grows or shrinks the dynamic-allocation zone to obtain storage for objects and reduce memory usage via operating-system calls, such as @mmap@ or @sbrk@ in UNIX.
    375362
     
    383370The \newterm{storage data} is composed of allocated and freed objects, and \newterm{reserved memory}.
    384371Allocated objects (light grey) are variable sized, and are allocated and maintained by the program;
    385 \ie only the program knows the location of allocated storage not the memory allocator.
    386 Freed objects (white) represent memory deallocated by the program, which are linked into one or more lists facilitating easy location of new allocations.
     372\ie only the program knows the location of allocated storage.
     373Freed objects (white) represent memory deallocated by the program, which are linked into one or more lists facilitating location of new allocations.
    387374Reserved memory (dark grey) is one or more blocks of memory obtained from the \newterm{operating system} (OS) but not yet allocated to the program;
    388375if there are multiple reserved blocks, they are also chained together.
     
    401388An object may be preceded by padding to ensure proper alignment.
    402389Some algorithms quantize allocation requests, resulting in additional space after an object less than the quantized value.
    403 % The buckets are often organized as an array of ascending bucket sizes for fast searching, \eg binary search, and the array is stored in the heap management-area, where each bucket is a top point to the freed objects of that size.
    404390When padding and spacing are necessary, neither can be used to satisfy a future allocation request while the current allocation exists.
    405391
     
    407393Often the free list is chained internally so it does not consume additional storage, \ie the link fields are placed at known locations in the unused memory blocks.
    408394For internal chaining, the amount of management data for a free node defines the minimum allocation size, \eg if 16 bytes are needed for a free-list node, allocation requests less than 16 bytes are rounded up.
     395Often the minimum storage alignment and free-node size are the same.
    409396The information in an allocated or freed object is overwritten when it transitions from allocated to freed and vice-versa by new program data and/or management information.
    410397
     
    420407\label{s:SingleThreadedMemoryAllocator}
    421408
    422 A single-threaded memory-allocator does not run any threads itself, but is used by a single-threaded program.
    423 Because the memory allocator is only executed by a single thread, concurrency issues do not exist.
    424 The primary issues in designing a single-threaded memory-allocator are fragmentation and locality.
    425 
     409In a sequential (single threaded) program, the program thread performs all allocation operations and concurrency issues do not exist.
     410However, interrupts logically introduce concurrency, if the signal handler performs allocation/deallocation (serially reusable problem~\cite{SeriallyReusable}).
     411In general, the primary issues in a single-threaded allocator are fragmentation and locality.
    426412
    427413\subsubsection{Fragmentation}
    428414\label{s:Fragmentation}
    429415
    430 Fragmentation is memory requested from the OS but not used by the program;
    431 hence, allocated objects are not fragmentation.
    432 Figure~\ref{f:InternalExternalFragmentation} shows fragmentation is divided into two forms: internal or external.
     416Fragmentation is memory requested from the OS but not used allocated objects in by the program.
     417Figure~\ref{f:InternalExternalFragmentation} shows fragmentation is divided into two forms: \emph{internal} or \emph{external}.
    433418
    434419\begin{figure}
     
    439424\end{figure}
    440425
    441 \newterm{Internal fragmentation} is memory space that is allocated to the program, but is not intended to be accessed by the program, such as headers, trailers, padding, and spacing around an allocated object.
    442 Internal fragmentation is problematic when management space is a significant proportion of an allocated object, \eg for small objects ($<$16 bytes), memory usage is doubled.
    443 An allocator should strive to keep internal management information to a minimum.
    444 
    445 \newterm{External fragmentation} is all memory space reserved from the OS but not allocated to the program~\cite{Wilson95,Lim98,Siebert00}, which includes all external management data, freed objects, and reserved memory.
     426\newterm{Internal fragmentation} is unaccessible allocated memory, such as headers, trailers, padding, and spacing around an allocated object.
     427Internal fragmentation is problematic when management space becomes a significant proportion of an allocated object, \eg for objects $<$16 bytes, memory usage doubles.
     428An allocator strives to keep internal management information to a minimum.
     429
     430\newterm{External fragmentation} is memory not allocated in the program~\cite{Wilson95,Lim98,Siebert00}, which includes all external management data, freed objects, and reserved memory.
    446431This memory is problematic in two ways: heap blowup and highly fragmented memory.
    447432\newterm{Heap blowup} occurs when freed memory cannot be reused for future allocations leading to potentially unbounded external fragmentation growth~\cite{Berger00}.
    448 Memory can become \newterm{highly fragmented} after multiple allocations and deallocations of objects, resulting in a checkerboard of adjacent allocated and free areas, where the free blocks have become to small to service requests.
     433Memory can become \newterm{highly fragmented} after multiple allocations and deallocations of objects, resulting in a checkerboard of adjacent allocated and free areas, where the free blocks are to small to service requests.
    449434% Figure~\ref{f:MemoryFragmentation} shows an example of how a small block of memory fragments as objects are allocated and deallocated over time.
    450 Heap blowup can occur due to allocator policies that are too restrictive in reusing freed memory (the allocated size cannot use a larger free block) and/or no coalescing of free storage.
     435Heap blowup occurs with allocator policies that are too restrictive in reusing freed memory, \eg the allocated size cannot use a larger free block and/or no coalescing of free storage.
    451436% Blocks of free memory become smaller and non-contiguous making them less useful in serving allocation requests.
    452437% Memory is highly fragmented when most free blocks are unusable because of their sizes.
     
    479464
    480465The second approach is a \newterm{segregated} or \newterm{binning algorithm} with a set of lists for different sized freed objects.
    481 When an object is allocated, the requested size is rounded up to the nearest bin-size, often leading to spacing after the object.
     466When an object is allocated, the requested size is rounded up to the nearest bin-size, often leading to space after the object.
    482467A binning algorithm is fast at finding free memory of the appropriate size and allocating it, since the first free object on the free list is used.
    483 The fewer bin sizes, the fewer lists need to be searched and maintained;
    484 however, unusable space after object increases, leading to more internal fragmentation.
    485 The more bin sizes, the longer the search and the less likely a matching free objects is found, leading to more external fragmentation and potentially heap blowup.
    486 A variation of the binning algorithm allows objects to be allocated from larger bin sizes when the matching bins is empty, and the freed object can be returned to the matching or larger bin (some advantages to either scheme).
     468Fewer bin sizes means a faster search to find a matching bin, but larger differences between allocation and bin size, which increases unusable space after objects (internal fragmentation).
     469More bin sizes means a slower search but smaller differences matching between allocation and bin size resulting in less internal fragmentation but more external fragmentation if larger bins cannot service smaller requests.
     470Allowing larger bins to service smaller allocations when the matching bin is empty means the freed object can be returned to the matching or larger bin (some advantages to either scheme).
    487471% For example, with bin sizes of 8 and 16 bytes, a request for 12 bytes allocates only 12 bytes, but when the object is freed, it is placed on the 8-byte bin-list.
    488472% For subsequent requests, the bin free-lists contain objects of different sizes, ranging from one bin-size to the next (8-16 in this example), and a sequential-fit algorithm may be used to find an object large enough for the requested size on the associated bin list.
    489473
    490 The third approach is \newterm{splitting} and \newterm{coalescing algorithms}.
    491 When an object is allocated, if there are no free objects of the requested size, a larger free object is split into two smaller objects to satisfy the allocation request rather than obtaining more memory from the OS.
    492 For example, in the \newterm{buddy system}, a block of free memory is split into equal chunks, one of those chunks is again split, and so on until a minimal block is created that fits the requested object.
    493 When an object is deallocated, it is coalesced with the objects immediately before and after it in memory, if they are free, turning them into one larger block.
     474The third approach is a \newterm{splitting} and \newterm{coalescing} algorithms.
     475When an object is allocated, if there is no matching free storage, a larger free object is split into two smaller objects, one matching the allocation size.
     476For example, in the \newterm{buddy system}, a block of free memory is split into equal chunks, splitting continues until a minimal block is created that fits the allocation.
     477When an object is deallocated, it is coalesced with the objects immediately before/after it in memory, if they are free, turning them into a larger block.
    494478Coalescing can be done eagerly at each deallocation or lazily when an allocation cannot be fulfilled.
    495 In all cases, coalescing increases allocation latency, hence some allocations can cause unbounded delays.
     479However, coalescing increases allocation latency (unbounded delays), both for allocation and deallocation.
    496480While coalescing does not reduce external fragmentation, the coalesced blocks improve fragmentation quality so future allocations are less likely to cause heap blowup.
    497481% Splitting and coalescing can be used with other algorithms to avoid highly fragmented memory.
     
    504488% Temporal clustering implies a group of objects are accessed repeatedly within a short time period, while spatial clustering implies a group of objects physically close together (nearby addresses) are accessed repeatedly within a short time period.
    505489% Temporal locality commonly occurs during an iterative computation with a fixed set of disjoint variables, while spatial locality commonly occurs when traversing an array.
    506 Hardware takes advantage of the working set through multiple levels of caching, \ie memory hierarchy.
     490Hardware takes advantage of the working set through multiple levels of caching and paging, \ie memory hierarchy.
    507491% When an object is accessed, the memory physically located around the object is also cached with the expectation that the current and nearby objects will be referenced within a short period of time.
    508492For example, entire cache lines are transferred between cache and memory, and entire virtual-memory pages are transferred between memory and disk.
    509493% A program exhibiting good locality has better performance due to fewer cache misses and page faults\footnote{With the advent of large RAM memory, paging is becoming less of an issue in modern programming.}.
    510494
    511 Temporal locality is largely controlled by how a program accesses its variables~\cite{Feng05}.
    512 Nevertheless, a memory allocator can have some indirect influence on temporal locality and largely dictates spatial locality.
    513 For temporal locality, an allocator can return storage for new allocations that was just freed as these memory locations are still \emph{warm} in the memory hierarchy.
    514 For spatial locality, an allocator can place objects used together close together in memory, so the working set of the program fits into the fewest possible cache lines and pages.
     495Temporal locality is largely controlled by program accesses to its variables~\cite{Feng05}.
     496An allocator has only indirect influence on temporal locality but largely dictates spatial locality.
     497For temporal locality, an allocator tries to return recently freed storage for new allocations, as this memory is still \emph{warm} in the memory hierarchy.
     498For spatial locality, an allocator places objects used together close together in memory, so the working set of the program fits into the fewest possible cache lines and pages.
    515499% However, usage patterns are different for every program as is the underlying hardware memory architecture;
    516500% hence, no general-purpose memory-allocator can provide ideal locality for every program on every computer.
    517501
    518 There are a number of ways a memory allocator can degrade locality by increasing the working set.
    519 For example, a memory allocator may access multiple free objects before finding one to satisfy an allocation request, \eg sequential-fit algorithm, which can perturb the program's memory hierarchy causing multiple cache or page misses~\cite{Grunwald93}.
    520 Another way locality can be degraded is by spatially separating related data.
    521 For example, in a binning allocator, objects of different sizes are allocated from different bins that may be located in different pages of memory.
     502An allocator can easily degrade locality by increasing the working set.
     503An allocator can access an unbounded number of free objects when matching an allocation or coalescing, causing multiple cache or page misses~\cite{Grunwald93}.
     504An allocator can spatially separate related data by binning free storage anywhere in memory, so the related objects are highly separated.
    522505
    523506
     
    525508\label{s:MultiThreadedMemoryAllocator}
    526509
    527 A multi-threaded memory-allocator does not run any threads itself, but is used by a multi-threaded program.
    528 In addition to single-threaded design issues of fragmentation and locality, a multi-threaded allocator is simultaneously accessed by multiple threads, and hence, must deal with concurrency issues such as mutual exclusion, false sharing, and additional forms of heap blowup.
     510In a concurrent (multi-threaded) program, multiple program threads performs allocation operations and all concurrency issues arise.
     511Along with fragmentation and locality issues, a multi-threaded allocator must deal with mutual exclusion, false sharing, and additional forms of heap blowup.
    529512
    530513
     
    534517\newterm{Mutual exclusion} provides sequential access to the shared-management data of the heap.
    535518There are two performance issues for mutual exclusion.
    536 First is the overhead necessary to perform (at least) a hardware atomic operation every time a shared resource is accessed.
    537 Second is when multiple threads contend for a shared resource simultaneously, and hence, some threads must wait until the resource is released.
     519First is the cost of performing at least one hardware atomic operation every time a shared resource is accessed.
     520Second is \emph{contention} on simultaneous access, so some threads must wait until the resource is released.
    538521Contention can be reduced in a number of ways:
    539 1) Using multiple fine-grained locks versus a single lock to spread the contention across a number of locks.
    540 2) Using trylock and generating new storage if the lock is busy, yielding a classic space versus time tradeoff.
     5221) Using multiple fine-grained locks versus a single lock to spread the contention across the locks.
     5232) Using trylock and generating new storage if the lock is busy (classic space versus time tradeoff).
    5415243) Using one of the many lock-free approaches for reducing contention on basic data-structure operations~\cite{Oyama99}.
    542 However, all of these approaches have degenerate cases where program contention is high, which occurs outside of the allocator.
     525However, all approaches have degenerate cases where program contention to the heap is high, which is beyond the allocator's control.
    543526
    544527
     
    546529\label{s:FalseSharing}
    547530
    548 False sharing is a dynamic phenomenon leading to cache thrashing.
    549 When two or more threads on separate CPUs simultaneously change different objects sharing a cache line, the change invalidates the other thread's associated cache, even though these threads may be uninterested in the other modified object.
    550 False sharing can occur in three different ways: program induced, allocator-induced active, and allocator-induced passive;
    551 a memory allocator can only affect the latter two.
    552 
    553 Specifically, assume two objects, O$_1$ and O$_2$, share a cache line, with threads, T$_1$ and T$_2$.
    554 \newterm{Program-induced false-sharing} occurs when T$_1$ passes a reference to O$_2$ to T$_2$, and then T$_1$ modifies O$_1$ while T$_2$ modifies O$_2$.
    555 % Figure~\ref{f:ProgramInducedFalseSharing} shows when Thread$_1$ passes Object$_2$ to Thread$_2$, a false-sharing situation forms when Thread$_1$ modifies Object$_1$ and Thread$_2$ modifies Object$_2$.
    556 % Changes to Object$_1$ invalidate CPU$_2$'s cache line, and changes to Object$_2$ invalidate CPU$_1$'s cache line.
    557 % \begin{figure}
    558 % \centering
    559 % \subfloat[Program-Induced False-Sharing]{
    560 %       \input{ProgramFalseSharing}
    561 %       \label{f:ProgramInducedFalseSharing}
    562 % } \\
    563 % \vspace{5pt}
    564 % \subfloat[Allocator-Induced Active False-Sharing]{
    565 %       \input{AllocInducedActiveFalseSharing}
    566 %       \label{f:AllocatorInducedActiveFalseSharing}
    567 % } \\
    568 % \vspace{5pt}
    569 % \subfloat[Allocator-Induced Passive False-Sharing]{
    570 %       \input{AllocInducedPassiveFalseSharing}
    571 %       \label{f:AllocatorInducedPassiveFalseSharing}
    572 % } subfloat
    573 % \caption{False Sharing}
    574 % \label{f:FalseSharing}
    575 % \end{figure}
    576 \newterm{Allocator-induced active false-sharing}\label{s:AllocatorInducedActiveFalseSharing} occurs when O$_1$ and O$_2$ are heap allocated and their references are passed to T$_1$ and T$_2$, which modify the objects.
    577 % For example, in Figure~\ref{f:AllocatorInducedActiveFalseSharing}, each thread allocates an object and loads a cache-line of memory into its associated cache.
    578 % Again, changes to Object$_1$ invalidate CPU$_2$'s cache line, and changes to Object$_2$ invalidate CPU$_1$'s cache line.
    579 \newterm{Allocator-induced passive false-sharing}\label{s:AllocatorInducedPassiveFalseSharing} occurs
    580 % is another form of allocator-induced false-sharing caused by program-induced false-sharing.
    581 % When an object in a program-induced false-sharing situation is deallocated, a future allocation of that object may cause passive false-sharing.
    582 when T$_1$ passes O$_2$ to T$_2$, and T$_2$ subsequently deallocates O$_2$, and then O$_2$ is reallocated to T$_2$ while T$_1$ is still using O$_1$.
     531False sharing occurs when two or more threads simultaneously modify different objects sharing a cache line.
     532Changes now invalidate each thread's cache, even though the threads may be uninterested in the other modified object.
     533False sharing can occur three ways:
     5341) Thread T$_1$ allocates objects O$_1$ and O$_2$ on the same cache line and passes O$_2$'s reference to thread T$_2$;
     535both threads now simultaneously modifying the objects on the same cache line.
     5362) Objects O$_1$ and O$_2$ are allocated on the same cache line by thread T$_3$ and their references are passed to T$_1$ and T$_2$, which simultaneously modify the objects.
     5373) T$_2$ deallocates O$_2$, T$_1$ allocates O$_1$ on the same cache line as O$_2$, and T$_2$ reallocated O$_2$ while T$_1$ is using O$_1$.
     538In all three cases, the allocator performs a hidden and possibly transient (non-determinism) operation, making it extremely difficult to find and fix the issue.
    583539
    584540
     
    586542\label{s:HeapBlowup}
    587543
    588 In a multi-threaded program, heap blowup can occur when memory freed by one thread is inaccessible to other threads due to the allocation strategy.
     544In a multi-threaded program, heap blowup occurs when memory freed by one thread is inaccessible to other threads due to the allocation strategy.
    589545Specific examples are presented in later subsections.
    590546
    591547
    592 \subsection{Multi-Threaded Memory-Allocator Features}
    593 \label{s:MultiThreadedMemoryAllocatorFeatures}
    594 
    595 The following features are used in the construction of multi-threaded memory-allocators: multiple heaps, user-level threading, ownership, object containers, allocation buffer, lock-free operations.
    596 The first feature, multiple heaps, pertains to different kinds of heaps.
    597 The second feature, object containers, pertains to the organization of objects within the storage area.
    598 The remaining features apply to different parts of the allocator design or implementation.
    599 
     548\subsection{Multi-Threaded Allocator Features}
     549\label{s:MultiThreadedAllocatorFeatures}
     550
     551The following features are used in the construction of multi-threaded allocators.
    600552
    601553\subsubsection{Multiple Heaps}
    602554\label{s:MultipleHeaps}
    603555
    604 A multi-threaded allocator has potentially multiple threads and heaps.
    605 The multiple threads cause complexity, and multiple heaps are a mechanism for dealing with the complexity.
    606 The spectrum ranges from multiple threads using a single heap, denoted as T:1, to multiple threads sharing multiple heaps, denoted as T:H, to one thread per heap, denoted as 1:1, which is almost back to a single-threaded allocator.
     556Figure~\ref{f:ThreadHeapRelationship} shows how a multi-threaded allocator can subdivide a single global heap into multiple heaps to reduce contention among threads.
    607557
    608558\begin{figure}
     
    626576} % subfloat
    627577\caption{Multiple Heaps, Thread:Heap Relationship}
    628 \end{figure}
    629 
    630 \paragraph{T:1 model (see Figure~\ref{f:SingleHeap})} where all threads allocate and deallocate objects from one heap.
     578\label{f:ThreadHeapRelationship}
     579\end{figure}
     580
     581\begin{description}[leftmargin=*]
     582\item[T:1 model (Figure~\ref{f:SingleHeap})] has all threads allocating and deallocating objects from one heap.
    631583Memory is obtained from the freed objects, or reserved memory in the heap, or from the OS;
    632584the heap may also return freed memory to the OS.
    633 The arrows indicate the direction memory conceptually moves for each kind of operation: allocation moves memory along the path from the heap/operating-system to the user application, while deallocation moves memory along the path from the application back to the heap/operating-system.
     585The arrows indicate the direction memory moves for each alocation/deallocation operation.
    634586To safely handle concurrency, a single lock may be used for all heap operations or fine-grained locking for different operations.
    635 Regardless, a single heap may be a significant source of contention for programs with a large amount of memory allocation.
    636 
    637 \paragraph{T:H model (see Figure~\ref{f:SharedHeaps})} where each thread allocates storage from several heaps depending on certain criteria, with the goal of reducing contention by spreading allocations/deallocations across the heaps.
    638 The decision on when to create a new heap and which heap a thread allocates from depends on the allocator design.
    639 To determine which heap to access, each thread must point to its associated heap in some way.
    640 The performance goal is to reduce the ratio of heaps to threads.
    641 However, the worse case can result in more heaps than threads, \eg if the number of threads is large at startup with many allocations creating a large number of heaps and then the number of threads reduces.
    642 Locking is required, since more than one thread may concurrently access a heap during its lifetime, but contention is reduced because fewer threads access a specific heap.
     587Regardless, a single heap is a significant source of contention for threaded programs with a large amount of memory allocations.
     588
     589\item[T:H model (Figure~\ref{f:SharedHeaps})] subdivides the heap independently from the threads.
     590The decision to create a heap and which heap a thread allocates/deallocates during its lifetime depends on the allocator design.
     591Locking is required within each heap because of multiple tread access, but contention is reduced because fewer threads access a specific heap.
     592The goal is to have mininal heaps (storage) and thread contention per heap (time).
     593However, the worst case results in more heaps than threads, \eg if the number of threads is large at startup creating a large number of heaps and then the number of threads reduces.
    643594
    644595% For example, multiple heaps are managed in a pool, starting with a single or a fixed number of heaps that increase\-/decrease depending on contention\-/space issues.
     
    693644In general, the cost is minimal since the majority of memory operations are completed without the use of the global heap.
    694645
    695 \paragraph{1:1 model (see Figure~\ref{f:PerThreadHeap})} where each thread has its own heap eliminating most contention and locking because threads seldom access another thread's heap (see Section~\ref{s:Ownership}).
     646\item[1:1 model (Figure~\ref{f:PerThreadHeap})] has each thread with its own heap, eliminating most contention and locking because threads seldom access another thread's heap (see Section~\ref{s:Ownership}).
    696647An additional benefit of thread heaps is improved locality due to better memory layout.
    697648As each thread only allocates from its heap, all objects are consolidated in the storage area for that heap, better utilizing each CPUs cache and accessing fewer pages.
    698649In contrast, the T:H model spreads each thread's objects over a larger area in different heaps.
    699 Thread heaps can also eliminate allocator-induced active false-sharing, if memory is acquired so it does not overlap at crucial boundaries with memory for another thread's heap.
     650Thread heaps can also reduces false-sharing, except at crucial boundaries overlapping memory from another thread's heap.
    700651For example, assume page boundaries coincide with cache line boundaries, if a thread heap always acquires pages of memory then no two threads share a page or cache line unless pointers are passed among them.
    701652% Hence, allocator-induced active false-sharing cannot occur because the memory for thread heaps never overlaps.
     
    706657Destroying the thread heap immediately may reduce external fragmentation sooner, since all free objects are freed to the global heap and may be reused by other threads.
    707658Alternatively, reusing thread heaps may improve performance if the inheriting thread makes similar allocation requests as the thread that previously held the thread heap because any unfreed storage is immediately accessible.
     659\end{description}
    708660
    709661
  • doc/papers/llheap/figures/AddressSpace.fig

    r06601401 r03606ce  
    991200 2
    10102 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    11          5700 1350 6600 1350 6600 2100 5700 2100 5700 1350
    12 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    13          1200 1350 2100 1350 2100 2100 1200 2100 1200 1350
    14 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    15          4800 1350 5700 1350 5700 2100 4800 2100 4800 1350
     11         1200 1200 2100 1200 2100 1800 1200 1800 1200 1200
     122 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
     13         2100 1200 3000 1200 3000 1800 2100 1800 2100 1200
    16142 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    1715        1 1 1.00 45.00 90.00
    18          2100 1725 2400 1725
     16         2100 1500 2400 1500
    19172 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    2018        1 1 1.00 45.00 90.00
    21          3000 1725 2700 1725
     19         3000 1500 2700 1500
     202 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
     21         3000 1200 3900 1200 3900 1800 3000 1800 3000 1200
     222 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
     23         3900 1200 4800 1200 4800 1800 3900 1800 3900 1200
    22242 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    2325        1 1 1.00 45.00 90.00
    24          3900 1725 4200 1725
     26         3900 1500 4200 1500
    25272 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    2628        1 1 1.00 45.00 90.00
    27          4800 1725 4500 1725
    28 2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
    29          2100 1350 3000 1350 3000 2100 2100 2100 2100 1350
     29         4800 1500 4500 1500
    30302 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    31          3000 1350 3900 1350 3900 2100 3000 2100 3000 1350
    32 2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
    33          3900 1350 4800 1350 4800 2100 3900 2100 3900 1350
    34 4 0 0 50 -1 0 10 0.0000 2 180 900 1200 2325 high address\001
    35 4 2 0 50 -1 0 10 0.0000 2 135 855 6600 2325 low address\001
    36 4 1 0 50 -1 0 10 0.0000 2 120 330 6150 2025 Data\001
    37 4 1 0 50 -1 0 10 0.0000 2 135 675 6150 1800 Code and\001
    38 4 1 0 50 -1 0 10 0.0000 2 120 390 6150 1575 Static\001
    39 4 1 0 50 -1 0 10 0.0000 2 135 390 1650 1800 Stack\001
    40 4 1 0 50 -1 0 10 0.0000 2 165 615 2550 1950 Memory\001
    41 4 1 0 50 -1 0 10 0.0000 2 165 615 4350 1950 Memory\001
    42 4 1 0 50 -1 0 10 0.0000 2 120 315 2550 1650 Free\001
    43 4 1 0 50 -1 0 10 0.0000 2 120 330 3450 2025 Data\001
    44 4 1 0 50 -1 0 10 0.0000 2 135 675 3450 1800 Code and\001
    45 4 1 0 50 -1 0 10 0.0000 2 165 645 3450 1575 Dynamic\001
    46 4 1 0 50 -1 0 10 0.0000 2 120 315 4350 1650 Free\001
    47 4 1 0 50 -1 0 10 0.0000 2 120 735 5250 1950 Allocation\001
    48 4 1 0 50 -1 0 10 0.0000 2 165 645 5250 1650 Dynamic\001
     31         4800 1200 5700 1200 5700 1800 4800 1800 4800 1200
     322 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
     33         5700 1200 6600 1200 6600 1800 5700 1800 5700 1200
     344 0 0 50 -1 0 10 0.0000 2 165 870 1200 2025 high address\001
     354 2 0 50 -1 0 10 0.0000 2 120 810 6600 2025 low address\001
     364 1 0 50 -1 0 10 0.0000 2 120 375 1650 1575 Stack\001
     374 1 0 50 -1 0 10 0.0000 2 150 600 2550 1725 Memory\001
     384 1 0 50 -1 0 10 0.0000 2 120 300 2550 1425 Free\001
     394 1 0 50 -1 0 10 0.0000 2 120 660 3450 1575 Code and\001
     404 1 0 50 -1 0 10 0.0000 2 150 630 3450 1350 Dynamic\001
     414 1 0 50 -1 0 10 0.0000 2 120 315 3450 1775 Data\001
     424 1 0 50 -1 0 10 0.0000 2 120 300 4350 1425 Free\001
     434 1 0 50 -1 0 10 0.0000 2 150 600 4350 1725 Memory\001
     444 1 4 50 -1 0 10 0.0000 2 150 630 5250 1425 Dynamic\001
     454 1 0 50 -1 0 10 0.0000 2 120 315 6150 1775 Data\001
     464 1 0 50 -1 0 10 0.0000 2 120 660 6150 1575 Code and\001
     474 1 0 50 -1 0 10 0.0000 2 120 375 6150 1350 Static\001
     484 1 4 50 -1 0 10 0.0000 2 120 720 5250 1725 Allocation\001
  • doc/theses/mike_brooks_MMath/programs/sharing-demo.cfa

    r06601401 r03606ce  
    144144        sout | xstr(D2_s1_abcd) | "\t\\\\";
    145145
    146         #define D2_s1mid_s1 string s1_mid = s1(1,3)`shareEdits
     146        #define D2_s1mid_s1 string s1_mid = s1(1,2)`shareEdits
    147147        D2_s1mid_s1;
    148148        sout | xstr(D2_s1mid_s1) | "\t\\\\";
    149149
    150         #define D2_s2_s1 string s2     = s1(1,3)
     150        #define D2_s2_s1 string s2     = s1(1,2)
    151151        D2_s2_s1;     
    152152        assert( s1 == "abcd" );
     
    257257        sout  | xstr(D2_s1bgn_s1)  | "\t\\\\";
    258258
    259         #define D2_s1end_s1 string s1_end = s1(3, 4)`shareEdits
     259        #define D2_s1end_s1 string s1_end = s1(3, 1)`shareEdits
    260260        D2_s1end_s1;
    261261        assert( s1 == "ajjd" );
     
    280280        sout | "\t\t\t\t& @s1@\t& @s1_bgn@\t& @s1_crs@\t& @s1_mid@\t& @s1_end@\t\\\\";
    281281   
    282         #define D2_s1crs_s1 string s1_crs = s1(3, 5)`shareEdits
     282        #define D2_s1crs_s1 string s1_crs = s1(3, 2)`shareEdits
    283283        D2_s1crs_s1;
    284284        assert( s1 == "zzzzjjd" );
     
    305305        string word = "Phi";
    306306        string consonants = word(0,2)`shareEdits;
    307         string miniscules = word(1,3)`shareEdits;
     307        string miniscules = word(1,2)`shareEdits;
    308308        assert( word == "Phi" );
    309309        assert( consonants == "Ph" );
     
    318318   
    319319        string all = "They said hello again";
    320         string greet     = all(10,15)`shareEdits;
    321         string greet_bgn = all(10,11)`shareEdits;
    322         string greet_end = all(14,15)`shareEdits;
     320        string greet     = all(10,5)`shareEdits;
     321        string greet_bgn = all(10,1)`shareEdits;
     322        string greet_end = all(14,1)`shareEdits;
    323323     
    324324        assert( all == "They said hello again" );
  • src/Parser/DeclarationNode.cc

    r06601401 r03606ce  
    177177}
    178178
     179DeclarationNode * DeclarationNode::newFromTypeData( TypeData * type ) {
     180        DeclarationNode * newnode = new DeclarationNode;
     181        newnode->type = type;
     182        return newnode;
     183} // DeclarationNode::newFromTypeData
     184
    179185DeclarationNode * DeclarationNode::newStorageClass( ast::Storage::Classes sc ) {
    180186        DeclarationNode * newnode = new DeclarationNode;
     
    188194        return newnode;
    189195} // DeclarationNode::newFuncSpecifier
    190 
    191 DeclarationNode * DeclarationNode::newTypeQualifier( ast::CV::Qualifiers tq ) {
    192         DeclarationNode * newnode = new DeclarationNode;
    193         newnode->type = new TypeData();
    194         newnode->type->qualifiers = tq;
    195         return newnode;
    196 } // DeclarationNode::newQualifier
    197 
    198 DeclarationNode * DeclarationNode::newBasicType( BasicType bt ) {
    199         DeclarationNode * newnode = new DeclarationNode;
    200         newnode->type = new TypeData( TypeData::Basic );
    201         newnode->type->basictype = bt;
    202         return newnode;
    203 } // DeclarationNode::newBasicType
    204 
    205 DeclarationNode * DeclarationNode::newComplexType( ComplexType ct ) {
    206         DeclarationNode * newnode = new DeclarationNode;
    207         newnode->type = new TypeData( TypeData::Basic );
    208         newnode->type->complextype = ct;
    209         return newnode;
    210 } // DeclarationNode::newComplexType
    211 
    212 DeclarationNode * DeclarationNode::newSignedNess( Signedness sn ) {
    213         DeclarationNode * newnode = new DeclarationNode;
    214         newnode->type = new TypeData( TypeData::Basic );
    215         newnode->type->signedness = sn;
    216         return newnode;
    217 } // DeclarationNode::newSignedNess
    218 
    219 DeclarationNode * DeclarationNode::newLength( Length lnth ) {
    220         DeclarationNode * newnode = new DeclarationNode;
    221         newnode->type = new TypeData( TypeData::Basic );
    222         newnode->type->length = lnth;
    223         return newnode;
    224 } // DeclarationNode::newLength
    225 
    226 DeclarationNode * DeclarationNode::newForall( DeclarationNode * forall ) {
    227         DeclarationNode * newnode = new DeclarationNode;
    228         newnode->type = new TypeData( TypeData::Unknown );
    229         newnode->type->forall = forall;
    230         return newnode;
    231 } // DeclarationNode::newForall
    232 
    233 DeclarationNode * DeclarationNode::newFromGlobalScope() {
    234         DeclarationNode * newnode = new DeclarationNode;
    235         newnode->type = new TypeData( TypeData::GlobalScope );
    236         return newnode;
    237 }
    238 
    239 DeclarationNode * DeclarationNode::newQualifiedType( DeclarationNode * parent, DeclarationNode * child) {
    240         DeclarationNode * newnode = new DeclarationNode;
    241         newnode->type = new TypeData( TypeData::Qualified );
    242         newnode->type->qualified.parent = parent->type;
    243         newnode->type->qualified.child = child->type;
    244         parent->type = nullptr;
    245         child->type = nullptr;
    246         delete parent;
    247         delete child;
    248         return newnode;
    249 }
    250196
    251197DeclarationNode * DeclarationNode::newAggregate( ast::AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
     
    312258}
    313259
    314 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) {
    315         DeclarationNode * newnode = new DeclarationNode;
    316         newnode->type = new TypeData( TypeData::SymbolicInst );
    317         newnode->type->symbolic.name = name;
    318         newnode->type->symbolic.isTypedef = true;
    319         newnode->type->symbolic.params = nullptr;
    320         return newnode;
    321 } // DeclarationNode::newFromTypedef
    322 
    323 DeclarationNode * DeclarationNode::newFromTypeGen( const string * name, ExpressionNode * params ) {
    324         DeclarationNode * newnode = new DeclarationNode;
    325         newnode->type = new TypeData( TypeData::SymbolicInst );
    326         newnode->type->symbolic.name = name;
    327         newnode->type->symbolic.isTypedef = false;
    328         newnode->type->symbolic.actuals = params;
    329         return newnode;
    330 } // DeclarationNode::newFromTypeGen
    331 
    332260DeclarationNode * DeclarationNode::newTypeParam( ast::TypeDecl::Kind tc, const string * name ) {
    333261        DeclarationNode * newnode = newName( name );
     
    423351        return newnode;
    424352}
    425 
    426 DeclarationNode * DeclarationNode::newVtableType( DeclarationNode * decl ) {
    427         DeclarationNode * newnode = new DeclarationNode;
    428         newnode->type = new TypeData( TypeData::Vtable );
    429         newnode->setBase( decl->type );
    430         return newnode;
    431 }
    432 
    433 DeclarationNode * DeclarationNode::newBuiltinType( BuiltinType bt ) {
    434         DeclarationNode * newnode = new DeclarationNode;
    435         newnode->type = new TypeData( TypeData::Builtin );
    436         newnode->type->builtintype = bt;
    437         return newnode;
    438 } // DeclarationNode::newBuiltinType
    439353
    440354DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {
  • src/Parser/DeclarationNode.h

    r06601401 r03606ce  
    4040        static const char * builtinTypeNames[];
    4141
     42        static DeclarationNode * newFromTypeData( TypeData * );
    4243        static DeclarationNode * newStorageClass( ast::Storage::Classes );
    4344        static DeclarationNode * newFuncSpecifier( ast::Function::Specs );
    44         static DeclarationNode * newTypeQualifier( ast::CV::Qualifiers );
    45         static DeclarationNode * newBasicType( BasicType );
    46         static DeclarationNode * newComplexType( ComplexType );
    47         static DeclarationNode * newSignedNess( Signedness );
    48         static DeclarationNode * newLength( Length );
    49         static DeclarationNode * newBuiltinType( BuiltinType );
    50         static DeclarationNode * newForall( DeclarationNode * );
    51         static DeclarationNode * newFromTypedef( const std::string * );
    52         static DeclarationNode * newFromGlobalScope();
    53         static DeclarationNode * newQualifiedType( DeclarationNode *, DeclarationNode * );
    5445        static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
    5546        static DeclarationNode * newAggregate( ast::AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
     
    5950        static DeclarationNode * newEnumInLine( const std::string name );
    6051        static DeclarationNode * newName( const std::string * );
    61         static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params );
    6252        static DeclarationNode * newTypeParam( ast::TypeDecl::Kind, const std::string * );
    6353        static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts );
     
    7060        static DeclarationNode * newTuple( DeclarationNode * members );
    7161        static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );
    72         static DeclarationNode * newVtableType( DeclarationNode * expr );
    7362        static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes
    7463        static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement
     
    163152}; // DeclarationNode
    164153
    165 ast::Type * buildType( TypeData * type );
    166 
    167154static inline ast::Type * maybeMoveBuildType( const DeclarationNode * orig ) {
    168155        ast::Type * ret = orig ? orig->buildType() : nullptr;
  • src/Parser/ExpressionNode.cc

    r06601401 r03606ce  
    2929#include "DeclarationNode.h"       // for DeclarationNode
    3030#include "InitializerNode.h"       // for InitializerNode
     31#include "TypeData.h"              // for addType, build_basic_type, build_c...
    3132#include "parserutility.h"         // for notZeroExpr
    3233
     
    316317                                v2 );
    317318                        ret = build_compoundLiteral( location,
    318                                 DeclarationNode::newBasicType(
    319                                         DeclarationNode::Int128
    320                                 )->addType(
    321                                         DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ),
     319                                DeclarationNode::newFromTypeData(
     320                                        addType(
     321                                                build_basic_type( DeclarationNode::Int128 ),
     322                                                build_signedness( DeclarationNode::Unsigned ) ) ),
    322323                                new InitializerNode(
    323                                         (InitializerNode *)(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true )
     324                                        (new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true )
    324325                        );
    325326                } else {                                                                                // explicit length, (length_type)constant
  • src/Parser/TypeData.cc

    r06601401 r03606ce  
    478478}
    479479
    480 
    481480TypeData * TypeData::getLastBase() {
    482481        TypeData * cur = this;
     
    487486void TypeData::setLastBase( TypeData * newBase ) {
    488487        getLastBase()->base = newBase;
     488}
     489
     490
     491TypeData * build_type_qualifier( ast::CV::Qualifiers tq ) {
     492        TypeData * type = new TypeData;
     493        type->qualifiers = tq;
     494        return type;
     495}
     496
     497TypeData * build_basic_type( DeclarationNode::BasicType basic ) {
     498        TypeData * type = new TypeData( TypeData::Basic );
     499        type->basictype = basic;
     500        return type;
     501}
     502
     503TypeData * build_complex_type( DeclarationNode::ComplexType complex ) {
     504        TypeData * type = new TypeData( TypeData::Basic );
     505        type->complextype = complex;
     506        return type;
     507}
     508
     509TypeData * build_signedness( DeclarationNode::Signedness signedness ) {
     510        TypeData * type = new TypeData( TypeData::Basic );
     511        type->signedness = signedness;
     512        return type;
     513}
     514
     515TypeData * build_builtin_type( DeclarationNode::BuiltinType bit ) {
     516        TypeData * type = new TypeData( TypeData::Builtin );
     517        type->builtintype = bit;
     518        return type;
     519}
     520
     521TypeData * build_length( DeclarationNode::Length length ) {
     522        TypeData * type = new TypeData( TypeData::Basic );
     523        type->length = length;
     524        return type;
     525}
     526
     527TypeData * build_forall( DeclarationNode * forall ) {
     528        TypeData * type = new TypeData( TypeData::Unknown );
     529        type->forall = forall;
     530        return type;
     531}
     532
     533TypeData * build_global_scope() {
     534        return new TypeData( TypeData::GlobalScope );
     535}
     536
     537TypeData * build_qualified_type( TypeData * parent, TypeData * child ) {
     538        TypeData * type = new TypeData( TypeData::Qualified );
     539        type->qualified.parent = parent;
     540        type->qualified.child = child;
     541        return type;
     542}
     543
     544TypeData * build_typedef( const std::string * name ) {
     545        TypeData * type = new TypeData( TypeData::SymbolicInst );
     546        type->symbolic.name = name;
     547        type->symbolic.isTypedef = true;
     548        type->symbolic.actuals = nullptr;
     549        return type;
     550}
     551
     552TypeData * build_type_gen( const std::string * name, ExpressionNode * params ) {
     553        TypeData * type = new TypeData( TypeData::SymbolicInst );
     554        type->symbolic.name = name;
     555        type->symbolic.isTypedef = false;
     556        type->symbolic.actuals = params;
     557        return type;
     558}
     559
     560TypeData * build_vtable_type( TypeData * base ) {
     561        TypeData * type = new TypeData( TypeData::Vtable );
     562        type->base = base;
     563        return type;
    489564}
    490565
     
    627702                return rtype;
    628703        } // if
     704}
     705
     706TypeData * addType( TypeData * ltype, TypeData * rtype ) {
     707        std::vector<ast::ptr<ast::Attribute>> attributes;
     708        return addType( ltype, rtype, attributes );
    629709}
    630710
  • src/Parser/TypeData.h

    r06601401 r03606ce  
    116116};
    117117
     118
     119TypeData * build_type_qualifier( ast::CV::Qualifiers );
     120TypeData * build_basic_type( DeclarationNode::BasicType );
     121TypeData * build_complex_type( DeclarationNode::ComplexType );
     122TypeData * build_signedness( DeclarationNode::Signedness );
     123TypeData * build_builtin_type( DeclarationNode::BuiltinType );
     124TypeData * build_length( DeclarationNode::Length );
     125TypeData * build_forall( DeclarationNode * );
     126TypeData * build_global_scope();
     127TypeData * build_qualified_type( TypeData *, TypeData * );
     128TypeData * build_typedef( const std::string * name );
     129TypeData * build_type_gen( const std::string * name, ExpressionNode * params );
     130TypeData * build_vtable_type( TypeData * );
     131
    118132TypeData * addQualifiers( TypeData * ltype, TypeData * rtype );
    119133TypeData * addType( TypeData * ltype, TypeData * rtype, std::vector<ast::ptr<ast::Attribute>> & );
     134TypeData * addType( TypeData * ltype, TypeData * rtype );
    120135TypeData * cloneBaseType( TypeData * type, TypeData * other );
    121136TypeData * makeNewBase( TypeData * type );
     137
    122138
    123139ast::Type * typebuild( const TypeData * );
     
    144160void buildKRFunction( const TypeData::Function_t & function );
    145161
     162static inline ast::Type * maybeMoveBuildType( TypeData * type ) {
     163        ast::Type * ret = type ? typebuild( type ) : nullptr;
     164        delete type;
     165        return ret;
     166}
     167
    146168// Local Variables: //
    147169// tab-width: 4 //
  • src/Parser/TypedefTable.cc

    r06601401 r03606ce  
    2020#include <string>                                                                               // for string
    2121#include <iostream>                                                                             // for iostream
     22
     23struct TypeData;
    2224
    2325#include "ExpressionNode.h"                                                             // for LabelNode
  • src/Parser/parser.yy

    r06601401 r03606ce  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar  4 08:44:25 2024
    13 // Update Count     : 6562
     12// Last Modified On : Wed Mar  6 10:51:55 2024
     13// Update Count     : 6588
    1414//
    1515
     
    317317
    318318%union {
     319        // A raw token can be used.
    319320        Token tok;
     321
     322        // The general node types hold some generic node or list of nodes.
     323        DeclarationNode * decl;
     324        InitializerNode * init;
    320325        ExpressionNode * expr;
    321         DeclarationNode * decl;
    322         ast::AggregateDecl::Aggregate aggKey;
    323         ast::TypeDecl::Kind tclass;
    324326        StatementNode * stmt;
    325327        ClauseNode * clause;
    326         ast::WaitForStmt * wfs;
    327     ast::WaitUntilStmt::ClauseNode * wucn;
     328        TypeData * type;
     329
     330        // Special "nodes" containing compound information.
    328331        CondCtl * ifctl;
    329332        ForCtrl * forctl;
    330333        LabelNode * labels;
    331         InitializerNode * init;
     334
     335        // Various flags and single values that become fields later.
     336        ast::AggregateDecl::Aggregate aggKey;
     337        ast::TypeDecl::Kind tclass;
    332338        OperKinds oper;
    333         std::string * str;
    334339        bool is_volatile;
    335340        EnumHiding enum_hiding;
    336341        ast::ExceptionKind except_kind;
     342        // String passes ownership with it.
     343        std::string * str;
     344
     345        // Narrower node types are used to avoid constant unwrapping.
     346        ast::WaitForStmt * wfs;
     347        ast::WaitUntilStmt::ClauseNode * wucn;
    337348        ast::GenericExpr * genexpr;
    338349}
     
    464475
    465476%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
    466 %type<decl> vtable vtable_opt default_opt
     477%type<type> basic_type_name_type
     478%type<type> vtable vtable_opt default_opt
    467479
    468480%type<decl> trait_declaration trait_declaration_list trait_declaring_list trait_specifier
     
    519531%type<decl> type_declarator type_declarator_name type_declaring_list
    520532
    521 %type<decl> type_declaration_specifier type_type_specifier type_name typegen_name
     533%type<decl> type_declaration_specifier type_type_specifier
     534%type<type> type_name typegen_name
    522535%type<decl> typedef_name typedef_declaration typedef_expression
    523536
     
    532545%type<expr> type_parameters_opt type_list array_type_list // array_dimension_list
    533546
    534 %type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
     547%type<decl> type_qualifier forall type_qualifier_list_opt type_qualifier_list
     548%type<type> type_qualifier_name
    535549%type<decl> type_specifier type_specifier_nobody
    536550
     
    687701                { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); }
    688702        | TYPEDIMname                                                                           // CFA, generic length argument
    689                 // { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( DeclarationNode::newFromTypedef( $1 ) ) ) ); }
    690                 // { $$ = new ExpressionNode( build_varref( $1 ) ); }
    691703                { $$ = new ExpressionNode( build_dimensionref( yylloc, $1 ) ); }
    692704        | tuple
     
    696708                { $$ = new ExpressionNode( new ast::StmtExpr( yylloc, dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( $2 ) ) ) ); }
    697709        | type_name '.' identifier                                                      // CFA, nested type
    698                 { $$ = new ExpressionNode( build_qualified_expr( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
     710                { $$ = new ExpressionNode( build_qualified_expr( yylloc, DeclarationNode::newFromTypeData( $1 ), build_varref( yylloc, $3 ) ) ); }
    699711        | type_name '.' '[' field_name_list ']'                         // CFA, nested type / tuple field selector
    700712                { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
     
    751763                // Switching to this behaviour may help check if a C compatibilty case uses comma-exprs in subscripts.
    752764                // Current: Commas in subscripts make tuples.
    753                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)($3->set_last( $5 ) ) )) ) ); }
     765                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, new ExpressionNode( build_tuple( yylloc, $3->set_last( $5 ) ) ) ) ); }
    754766        | postfix_expression '[' assignment_expression ']'
    755767                // CFA, comma_expression disallowed in this context because it results in a common user error: subscripting a
     
    766778                        Token fn;
    767779                        fn.str = new std::string( "?{}" );                      // location undefined - use location of '{'?
    768                         $$ = new ExpressionNode( new ast::ConstructorExpr( yylloc, build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );
     780                        $$ = new ExpressionNode( new ast::ConstructorExpr( yylloc, build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), $1->set_last( $3 ) ) ) );
    769781                }
    770782        | postfix_expression '(' argument_expression_list_opt ')'
     
    772784        | VA_ARG '(' primary_expression ',' declaration_specifier_nobody abstract_parameter_declarator_opt ')'
    773785                // { SemanticError( yylloc, "va_arg is currently unimplemented." ); $$ = nullptr; }
    774                 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, new string( "__builtin_va_arg") ) ),
    775                                                                                            (ExpressionNode *)($3->set_last( (ExpressionNode *)($6 ? $6->addType( $5 ) : $5) )) ) ); }
     786                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, new string( "__builtin_va_arg" ) ) ),
     787                                                                                           $3->set_last( (ExpressionNode *)($6 ? $6->addType( $5 ) : $5) ) ) ); }
    776788        | postfix_expression '`' identifier                                     // CFA, postfix call
    777789                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
     
    831843                        Token fn;
    832844                        fn.str = new string( "^?{}" );                          // location undefined
    833                         $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), (ExpressionNode *)( $2 )->set_last( $4 ) ) );
     845                        $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, fn ) ), $2->set_last( $4 ) ) );
    834846                }
    835847        ;
     
    844856        argument_expression
    845857        | argument_expression_list_opt ',' argument_expression
    846                 { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     858                { $$ = $1->set_last( $3 ); }
    847859        ;
    848860
     
    856868field_name_list:                                                                                // CFA, tuple field selector
    857869        field
    858         | field_name_list ',' field                                     { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     870        | field_name_list ',' field                                     { $$ = $1->set_last( $3 ); }
    859871        ;
    860872
     
    938950        | ALIGNOF '(' type_no_function ')'                                      // GCC, type alignment
    939951                { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); }
     952
     953                // Cannot use rule "type", which includes cfa_abstract_function, for sizeof/alignof, because of S/R problems on
     954                // look ahead, so the cfa_abstract_function is factored out.
     955        | SIZEOF '(' cfa_abstract_function ')'
     956                { $$ = new ExpressionNode( new ast::SizeofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); }
     957        | ALIGNOF '(' cfa_abstract_function ')'                         // GCC, type alignment
     958                { $$ = new ExpressionNode( new ast::AlignofExpr( yylloc, maybeMoveBuildType( $3 ) ) ); }
     959
    940960        | OFFSETOF '(' type_no_function ',' identifier ')'
    941961                { $$ = new ExpressionNode( build_offsetOf( yylloc, $3, build_varref( yylloc, $5 ) ) ); }
    942         | TYPEID '(' type_no_function ')'
     962        | TYPEID '(' type ')'
    943963                {
    944964                        SemanticError( yylloc, "typeid name is currently unimplemented." ); $$ = nullptr;
     
    970990                { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); }
    971991        | '(' VIRTUAL ')' cast_expression                                       // CFA
    972                 { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $4 ), maybeMoveBuildType( nullptr ) ) ); }
     992                { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $4 ), nullptr ) ); }
    973993        | '(' VIRTUAL type_no_function ')' cast_expression      // CFA
    974994                { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $5 ), maybeMoveBuildType( $3 ) ) ); }
     
    11421162//              { $$ = new ExpressionNode( build_tuple( $3 ) ); }
    11431163        '[' ',' tuple_expression_list ']'
    1144                 { $$ = new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
     1164                { $$ = new ExpressionNode( build_tuple( yylloc, (new ExpressionNode( nullptr ))->set_last( $3 ) ) ); }
    11451165        | '[' push assignment_expression pop ',' tuple_expression_list ']'
    1146                 { $$ = new ExpressionNode( build_tuple( yylloc, (ExpressionNode *)($3->set_last( $6 ) ) )); }
     1166                { $$ = new ExpressionNode( build_tuple( yylloc, $3->set_last( $6 ) ) ); }
    11471167        ;
    11481168
     
    11521172                { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; }
    11531173        | tuple_expression_list ',' assignment_expression
    1154                 { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     1174                { $$ = $1->set_last( $3 ); }
    11551175        | tuple_expression_list ',' '@'
    11561176                { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; }
     
    12381258                { assert( $1 ); $1->set_last( $2 ); $$ = $1; }
    12391259        | statement_list_nodecl error                                           // invalid syntax rule
    1240                 { SemanticError( yylloc, "syntax error, declarations only allowed at the start of the switch body, i.e., after the '{'." ); $$ = nullptr; }
     1260                { SemanticError( yylloc, "syntax error, declarations only allowed at the start of the switch body,"
     1261                                                 " i.e., after the '{'." ); $$ = nullptr; }
    12411262        ;
    12421263
     
    12461267        ;
    12471268
    1248 // if, switch, and choose require parenthesis around the conditional because it can be followed by a statement.
    1249 // For example, without parenthesis:
    1250 //
    1251 //    if x + y + z; => "if ( x + y ) + z" or "if ( x ) + y + z"
    1252 //    switch ( S ) { ... } => switch ( S ) { compound literal... } ... or
     1269// "if", "switch", and "choose" require parenthesis around the conditional. See the following ambiguities without
     1270// parenthesis:
     1271//
     1272//   if x + y + z; => "if ( x + y ) + z" or "if ( x ) + y + z"
     1273//
     1274//   switch O { }
     1275//
     1276//     O{} => object-constructor for conditional, switch body ???
     1277//     O{} => O for conditional followed by switch body
     1278//
     1279//     C++ has this problem, as it has the same constructor syntax.
     1280//
     1281//   switch sizeof ( T ) { }
     1282//
     1283//     sizeof ( T ) => sizeof of T for conditional followed by switch body
     1284//     sizeof ( T ) => sizeof of compound literal (T){ }, closing parenthesis ???
     1285//
     1286//     Note the two grammar rules for sizeof (alignof)
     1287//
     1288//       | SIZEOF unary_expression
     1289//       | SIZEOF '(' type_no_function ')'
     1290//
     1291//     where the first DOES NOT require parenthesis! And C++ inherits this problem from C.
    12531292
    12541293selection_statement:
     
    12681307                        // therefore, are removed from the grammar even though C allows it. The change also applies to choose
    12691308                        // statement.
    1270                         $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
     1309                        $$ = $7 ? new StatementNode( build_compound( yylloc, (new StatementNode( $7 ))->set_last( sw ) ) ) : sw;
    12711310                }
    12721311        | SWITCH '(' comma_expression ')' '{' error '}'         // CFA, invalid syntax rule error
     
    12771316                {
    12781317                        StatementNode *sw = new StatementNode( build_switch( yylloc, false, $3, $8 ) );
    1279                         $$ = $7 ? new StatementNode( build_compound( yylloc, (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
     1318                        $$ = $7 ? new StatementNode( build_compound( yylloc, (new StatementNode( $7 ))->set_last( sw ) ) ) : sw;
    12801319                }
    12811320        | CHOOSE '(' comma_expression ')' '{' error '}'         // CFA, invalid syntax rule
     
    16791718        cast_expression
    16801719        | cast_expression_list ',' cast_expression
    1681                 // { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    16821720                { SemanticError( yylloc, "List of mutex member is currently unimplemented." ); $$ = nullptr; }
    16831721        ;
     
    16951733                { $$ = $3; }
    16961734        | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')'
    1697                 { $$ = (ExpressionNode *)($3->set_last( $5 )); }
     1735                { $$ = $3->set_last( $5 ); }
    16981736        ;
    16991737
     
    18511889        asm_operand
    18521890        | asm_operands_list ',' asm_operand
    1853                 { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     1891                { $$ = $1->set_last( $3 ); }
    18541892        ;
    18551893
     
    18701908                { $$ = $1; }
    18711909        | asm_clobbers_list_opt ',' string_literal
    1872                 { $$ = (ExpressionNode *)( $1->set_last( $3 ) ); }
     1910                { $$ = $1->set_last( $3 ); }
    18731911        ;
    18741912
     
    21882226type_qualifier:
    21892227        type_qualifier_name
     2228                { $$ = DeclarationNode::newFromTypeData( $1 ); }
    21902229        | attribute                                                                                     // trick handles most attribute locations
    21912230        ;
     
    21932232type_qualifier_name:
    21942233        CONST
    2195                 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Const ); }
     2234                { $$ = build_type_qualifier( ast::CV::Const ); }
    21962235        | RESTRICT
    2197                 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Restrict ); }
     2236                { $$ = build_type_qualifier( ast::CV::Restrict ); }
    21982237        | VOLATILE
    2199                 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Volatile ); }
     2238                { $$ = build_type_qualifier( ast::CV::Volatile ); }
    22002239        | ATOMIC
    2201                 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Atomic ); }
     2240                { $$ = build_type_qualifier( ast::CV::Atomic ); }
     2241
     2242                // forall must be a CV qualifier because it can appear in places where SC qualifiers are disallowed.
     2243                //
     2244                //   void foo( forall( T ) T (*)( T ) ); // forward declaration
     2245                //   void bar( static int ); // static disallowed (gcc/CFA)
    22022246        | forall
    2203                 { $$ = DeclarationNode::newForall( $1 ); }
     2247                { $$ = build_forall( $1 ); }
    22042248        ;
    22052249
     
    22512295
    22522296basic_type_name:
     2297        basic_type_name_type
     2298                { $$ = DeclarationNode::newFromTypeData( $1 ); }
     2299        ;
     2300
     2301// Just an intermediate value for conversion.
     2302basic_type_name_type:
    22532303        VOID
    2254                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Void ); }
     2304                { $$ = build_basic_type( DeclarationNode::Void ); }
    22552305        | BOOL                                                                                          // C99
    2256                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Bool ); }
     2306                { $$ = build_basic_type( DeclarationNode::Bool ); }
    22572307        | CHAR
    2258                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Char ); }
     2308                { $$ = build_basic_type( DeclarationNode::Char ); }
    22592309        | INT
    2260                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Int ); }
     2310                { $$ = build_basic_type( DeclarationNode::Int ); }
    22612311        | INT128
    2262                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Int128 ); }
     2312                { $$ = build_basic_type( DeclarationNode::Int128 ); }
    22632313        | UINT128
    2264                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Int128 )->addType( DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ); }
     2314                { $$ = addType( build_basic_type( DeclarationNode::Int128 ), build_signedness( DeclarationNode::Unsigned ) ); }
    22652315        | FLOAT
    2266                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float ); }
     2316                { $$ = build_basic_type( DeclarationNode::Float ); }
    22672317        | DOUBLE
    2268                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Double ); }
     2318                { $$ = build_basic_type( DeclarationNode::Double ); }
    22692319        | uuFLOAT80
    2270                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat80 ); }
     2320                { $$ = build_basic_type( DeclarationNode::uuFloat80 ); }
    22712321        | uuFLOAT128
    2272                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat128 ); }
     2322                { $$ = build_basic_type( DeclarationNode::uuFloat128 ); }
    22732323        | uFLOAT16
    2274                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat16 ); }
     2324                { $$ = build_basic_type( DeclarationNode::uFloat16 ); }
    22752325        | uFLOAT32
    2276                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32 ); }
     2326                { $$ = build_basic_type( DeclarationNode::uFloat32 ); }
    22772327        | uFLOAT32X
    2278                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32x ); }
     2328                { $$ = build_basic_type( DeclarationNode::uFloat32x ); }
    22792329        | uFLOAT64
    2280                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64 ); }
     2330                { $$ = build_basic_type( DeclarationNode::uFloat64 ); }
    22812331        | uFLOAT64X
    2282                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64x ); }
     2332                { $$ = build_basic_type( DeclarationNode::uFloat64x ); }
    22832333        | uFLOAT128
    2284                 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat128 ); }
     2334                { $$ = build_basic_type( DeclarationNode::uFloat128 ); }
    22852335        | DECIMAL32
    22862336                { SemanticError( yylloc, "_Decimal32 is currently unimplemented." ); $$ = nullptr; }
     
    22902340                { SemanticError( yylloc, "_Decimal128 is currently unimplemented." ); $$ = nullptr; }
    22912341        | COMPLEX                                                                                       // C99
    2292                 { $$ = DeclarationNode::newComplexType( DeclarationNode::Complex ); }
     2342                { $$ = build_complex_type( DeclarationNode::Complex ); }
    22932343        | IMAGINARY                                                                                     // C99
    2294                 { $$ = DeclarationNode::newComplexType( DeclarationNode::Imaginary ); }
     2344                { $$ = build_complex_type( DeclarationNode::Imaginary ); }
    22952345        | SIGNED
    2296                 { $$ = DeclarationNode::newSignedNess( DeclarationNode::Signed ); }
     2346                { $$ = build_signedness( DeclarationNode::Signed ); }
    22972347        | UNSIGNED
    2298                 { $$ = DeclarationNode::newSignedNess( DeclarationNode::Unsigned ); }
     2348                { $$ = build_signedness( DeclarationNode::Unsigned ); }
    22992349        | SHORT
    2300                 { $$ = DeclarationNode::newLength( DeclarationNode::Short ); }
     2350                { $$ = build_length( DeclarationNode::Short ); }
    23012351        | LONG
    2302                 { $$ = DeclarationNode::newLength( DeclarationNode::Long ); }
     2352                { $$ = build_length( DeclarationNode::Long ); }
    23032353        | VA_LIST                                                                                       // GCC, __builtin_va_list
    2304                 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::Valist ); }
     2354                { $$ = build_builtin_type( DeclarationNode::Valist ); }
    23052355        | AUTO_TYPE
    2306                 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::AutoType ); }
     2356                { $$ = build_builtin_type( DeclarationNode::AutoType ); }
    23072357        | vtable
    23082358        ;
     
    23162366vtable:
    23172367        VTABLE '(' type_name ')' default_opt
    2318                 { $$ = DeclarationNode::newVtableType( $3 ); }
    2319                 // { SemanticError( yylloc, "vtable is currently unimplemented." ); $$ = nullptr; }
     2368                { $$ = build_vtable_type( $3 ); }
    23202369        ;
    23212370
     
    23672416                { $$ = DeclarationNode::newTypeof( $3, true ); }
    23682417        | ZERO_T                                                                                        // CFA
    2369                 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::Zero ); }
     2418                { $$ = DeclarationNode::newFromTypeData( build_builtin_type( DeclarationNode::Zero ) ); }
    23702419        | ONE_T                                                                                         // CFA
    2371                 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::One ); }
     2420                { $$ = DeclarationNode::newFromTypeData( build_builtin_type( DeclarationNode::One ) ); }
    23722421        ;
    23732422
     
    24252474type_type_specifier:                                                                    // typedef types
    24262475        type_name
     2476                { $$ = DeclarationNode::newFromTypeData( $1 ); }
    24272477        | type_qualifier_list type_name
    2428                 { $$ = $2->addQualifiers( $1 ); }
     2478                { $$ = DeclarationNode::newFromTypeData( $2 )->addQualifiers( $1 ); }
    24292479        | type_type_specifier type_qualifier
    24302480                { $$ = $1->addQualifiers( $2 ); }
     
    24332483type_name:
    24342484        TYPEDEFname
    2435                 { $$ = DeclarationNode::newFromTypedef( $1 ); }
     2485                { $$ = build_typedef( $1 ); }
    24362486        | '.' TYPEDEFname
    2437                 { $$ = DeclarationNode::newQualifiedType( DeclarationNode::newFromGlobalScope(), DeclarationNode::newFromTypedef( $2 ) ); }
     2487                { $$ = build_qualified_type( build_global_scope(), build_typedef( $2 ) ); }
    24382488        | type_name '.' TYPEDEFname
    2439                 { $$ = DeclarationNode::newQualifiedType( $1, DeclarationNode::newFromTypedef( $3 ) ); }
     2489                { $$ = build_qualified_type( $1, build_typedef( $3 ) ); }
    24402490        | typegen_name
    24412491        | '.' typegen_name
    2442                 { $$ = DeclarationNode::newQualifiedType( DeclarationNode::newFromGlobalScope(), $2 ); }
     2492                { $$ = build_qualified_type( build_global_scope(), $2 ); }
    24432493        | type_name '.' typegen_name
    2444                 { $$ = DeclarationNode::newQualifiedType( $1, $3 ); }
     2494                { $$ = build_qualified_type( $1, $3 ); }
    24452495        ;
    24462496
    24472497typegen_name:                                                                                   // CFA
    24482498        TYPEGENname
    2449                 { $$ = DeclarationNode::newFromTypeGen( $1, nullptr ); }
     2499                { $$ = build_type_gen( $1, nullptr ); }
    24502500        | TYPEGENname '(' ')'
    2451                 { $$ = DeclarationNode::newFromTypeGen( $1, nullptr ); }
     2501                { $$ = build_type_gen( $1, nullptr ); }
    24522502        | TYPEGENname '(' type_list ')'
    2453                 { $$ = DeclarationNode::newFromTypeGen( $1, $3 ); }
     2503                { $$ = build_type_gen( $1, $3 ); }
    24542504        ;
    24552505
     
    24632513        | enum_type_nobody
    24642514        ;
     2515
     2516// ************************** AGGREGATE *******************************
    24652517
    24662518aggregate_type:                                                                                 // struct, union
     
    24852537          '{' field_declaration_list_opt '}' type_parameters_opt
    24862538                {
    2487                         DeclarationNode::newFromTypedef( $3 );
     2539                        DeclarationNode::newFromTypeData( build_typedef( $3 ) );
    24882540                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
    24892541                }
     
    24952547          '{' field_declaration_list_opt '}' type_parameters_opt
    24962548                {
    2497                         DeclarationNode::newFromTypeGen( $3, nullptr );
     2549                        DeclarationNode::newFromTypeData( build_type_gen( $3, nullptr ) );
    24982550                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
    24992551                }
     
    25202572                        // Create new generic declaration with same name as previous forward declaration, where the IDENTIFIER is
    25212573                        // switched to a TYPEGENname. Link any generic arguments from typegen_name to new generic declaration and
    2522                         // delete newFromTypeGen.
    2523                         if ( $3->type->kind == TypeData::SymbolicInst && ! $3->type->symbolic.isTypedef ) {
    2524                                 $$ = $3->addQualifiers( $2 );
     2574                        if ( $3->kind == TypeData::SymbolicInst && ! $3->symbolic.isTypedef ) {
     2575                                $$ = DeclarationNode::newFromTypeData( $3 )->addQualifiers( $2 );
    25252576                        } else {
    2526                                 $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $3->type->symbolic.actuals, nullptr, false )->addQualifiers( $2 );
    2527                                 $3->type->symbolic.name = nullptr;                      // copied to $$
    2528                                 $3->type->symbolic.actuals = nullptr;
     2577                                $$ = DeclarationNode::newAggregate( $1, $3->symbolic.name, $3->symbolic.actuals, nullptr, false )->addQualifiers( $2 );
     2578                                $3->symbolic.name = nullptr;                    // copied to $$
     2579                                $3->symbolic.actuals = nullptr;
    25292580                                delete $3;
    25302581                        }
     
    25442595        | EXCEPTION                                                                                     // CFA
    25452596                { $$ = ast::AggregateDecl::Exception; }
    2546           //            { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = ast::AggregateDecl::NoAggregate; }
    25472597        ;
    25482598
     
    26832733        ;
    26842734
    2685 // ***********
    2686 // Enumeration
    2687 // ***********
     2735// ************************** ENUMERATION *******************************
    26882736
    26892737enum_type:
     
    27542802        | ENUM attribute_list_opt type_name
    27552803                {
    2756                         typedefTable.makeTypedef( *$3->type->symbolic.name, "enum_type_nobody 2" );
    2757                         $$ = DeclarationNode::newEnum( $3->type->symbolic.name, nullptr, false, false )->addQualifiers( $2 );
     2804                        typedefTable.makeTypedef( *$3->symbolic.name, "enum_type_nobody 2" );
     2805                        $$ = DeclarationNode::newEnum( $3->symbolic.name, nullptr, false, false )->addQualifiers( $2 );
    27582806                }
    27592807        ;
     
    27632811                { $$ = DeclarationNode::newEnumValueGeneric( $2, $3 ); }
    27642812        | INLINE type_name
    2765                 { $$ = DeclarationNode::newEnumInLine( *$2->type->symbolic.name ); }
     2813                { $$ = DeclarationNode::newEnumInLine( *$2->symbolic.name ); }
    27662814        | enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt
    27672815                { $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
     
    27852833        ;
    27862834
    2787 // *******************
    2788 // Function parameters
    2789 // *******************
     2835// ************************** FUNCTION PARAMETERS *******************************
    27902836
    27912837parameter_list_ellipsis_opt:
     
    28102856cfa_parameter_list_ellipsis_opt:                                                // CFA, abstract + real
    28112857        // empty
    2812                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Void ); }
     2858                { $$ = DeclarationNode::newFromTypeData( build_basic_type( DeclarationNode::Void ) ); }
    28132859        | ELLIPSIS
    28142860                { $$ = nullptr; }
     
    28682914        | type_qualifier_list cfa_abstract_tuple identifier_or_type_name default_initializer_opt
    28692915                { $$ = $2->addName( $3 )->addQualifiers( $1 ); }
    2870         | cfa_function_specifier
     2916        | cfa_function_specifier                                                        // int f( "int fp()" );
    28712917        ;
    28722918
     
    28782924        | type_qualifier_list cfa_abstract_tuple
    28792925                { $$ = $2->addQualifiers( $1 ); }
    2880         | cfa_abstract_function
     2926        | cfa_abstract_function                                                         // int f( "int ()" );
    28812927        ;
    28822928
     
    29282974        | initializer
    29292975        | designation initializer                                       { $$ = $2->set_designators( $1 ); }
    2930         | initializer_list_opt ',' initializer          { $$ = (InitializerNode *)( $1->set_last( $3 ) ); }
    2931         | initializer_list_opt ',' designation initializer { $$ = (InitializerNode *)($1->set_last( $4->set_designators( $3 ) )); }
     2976        | initializer_list_opt ',' initializer          { $$ = $1->set_last( $3 ); }
     2977        | initializer_list_opt ',' designation initializer { $$ = $1->set_last( $4->set_designators( $3 ) ); }
    29322978        ;
    29332979
     
    29512997        designator
    29522998        | designator_list designator
    2953                 { $$ = (ExpressionNode *)($1->set_last( $2 )); }
     2999                { $$ = $1->set_last( $2 ); }
    29543000        //| designator_list designator                                          { $$ = new ExpressionNode( $1, $2 ); }
    29553001        ;
     
    30363082                { $$ = ast::TypeDecl::Dtype; }
    30373083        | '*'
    3038                 { $$ = ast::TypeDecl::DStype; }                                         // dtype + sized
    3039         // | '(' '*' ')'
    3040         //      { $$ = ast::TypeDecl::Ftype; }
     3084                { $$ = ast::TypeDecl::DStype; }                                 // Dtype + sized
     3085        // | '(' '*' ')'                                                                        // Gregor made me do it
     3086        //      { $$ = ast::TypeDecl::Ftype; }
    30413087        | ELLIPSIS
    30423088                { $$ = ast::TypeDecl::Ttype; }
     
    30803126        | assignment_expression
    30813127        | type_list ',' type
    3082                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
     3128                { $$ = $1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) ); }
    30833129        | type_list ',' assignment_expression
    3084                 { $$ = (ExpressionNode *)( $1->set_last( $3 )); }
     3130                { $$ = $1->set_last( $3 ); }
    30853131        ;
    30863132
     
    32443290                        $$ = $6;
    32453291                }
    3246         // global distribution
     3292                // global distribution
    32473293        | type_qualifier_list
    32483294                {
     
    33693415        ;
    33703416
     3417// **************************** ASM *****************************
     3418
    33713419asm_name_opt:                                                                                   // GCC
    33723420        // empty
     
    33793427                }
    33803428        ;
     3429
     3430// **************************** ATTRIBUTE *****************************
    33813431
    33823432attribute_list_opt:                                                                             // GCC
     
    37423792                { $$ = $1->addQualifiers( $2 ); }
    37433793        | '&' MUTEX paren_identifier attribute_list_opt
    3744                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ),
     3794                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newFromTypeData( build_type_qualifier( ast::CV::Mutex ) ),
    37453795                                                                                                                        OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37463796        | identifier_parameter_ptr
     
    37933843                { $$ = $1->addQualifiers( $2 ); }
    37943844        | '&' MUTEX typedef_name attribute_list_opt
    3795                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ),
     3845                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newFromTypeData( build_type_qualifier( ast::CV::Mutex ) ),
    37963846                                                                                                                        OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37973847        | type_parameter_ptr
     
    38263876
    38273877type_parameter_function:
    3828         typedef_name '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3878        typedef_name '(' parameter_list_ellipsis_opt ')'        // empty parameter list OBSOLESCENT (see 3)
    38293879                { $$ = $1->addParamList( $3 ); }
    38303880        | '(' type_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     
    38763926
    38773927abstract_function:
    3878         '(' parameter_list_ellipsis_opt ')'                     // empty parameter list OBSOLESCENT (see 3)
     3928        '(' parameter_list_ellipsis_opt ')'                                     // empty parameter list OBSOLESCENT (see 3)
    38793929                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
    38803930        | '(' abstract_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     
    39153965        | assignment_expression upupeq assignment_expression
    39163966        | array_type_list ',' basic_type_name
    3917                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
     3967                { $$ = $1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) ); }
    39183968        | array_type_list ',' type_name
    3919                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) )); }
     3969                { $$ = $1->set_last( new ExpressionNode( new ast::TypeExpr( yylloc, maybeMoveBuildType( $3 ) ) ) ); }
    39203970        | array_type_list ',' assignment_expression upupeq assignment_expression
    39213971        ;
     
    39774027        abstract_parameter_ptr
    39784028        | '&' MUTEX attribute_list_opt
    3979                 { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); }
     4029                { $$ = DeclarationNode::newPointer( DeclarationNode::newFromTypeData( build_type_qualifier( ast::CV::Mutex ) ), OperKinds::AddressOf )->addQualifiers( $3 ); }
    39804030        | abstract_parameter_array attribute_list_opt
    39814031                { $$ = $1->addQualifiers( $2 ); }
     
    40084058
    40094059abstract_parameter_function:
    4010         '(' parameter_list_ellipsis_opt ')'                     // empty parameter list OBSOLESCENT (see 3)
     4060        '(' parameter_list_ellipsis_opt ')'                                     // empty parameter list OBSOLESCENT (see 3)
    40114061                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
    40124062        | '(' abstract_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     
    42804330// mode: c++ //
    42814331// tab-width: 4 //
    4282 // compile-command: "make install" //
     4332// compile-command: "bison -Wcounterexamples parser.yy" //
    42834333// End: //
  • tests/.expect/functions.arm64.txt

    r06601401 r03606ce  
    9494    __attribute__ ((unused)) const signed int _X11_retval_fO5Ki_1;
    9595}
     96void _X1fFv___1(void);
     97void _X1fFv___1(void);
    9698signed int _X1fFi___1(void);
    97 signed int _X1fFi_i__1(signed int __anonymous_object4);
     99void _X1fFv_i__1(signed int __anonymous_object4);
     100void _X1fFv_i__1(signed int __anonymous_object5);
     101signed int _X1fFi_i__1(signed int __anonymous_object6);
     102void _X1fFv___1(void){
     103}
     104void _X2fvFv___1(void){
     105}
    98106signed int _X1fFi___1(void){
    99107    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    100108}
    101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object5){
     109void _X1fFv_i__1(__attribute__ ((unused)) signed int __anonymous_object7){
     110}
     111void _X2fvFv_i__1(__attribute__ ((unused)) signed int __anonymous_object8){
     112}
     113signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object9){
    102114    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    103115}
    104116signed int _X1fFi___1(void);
     117void _X1fFv_i__1(signed int _X1xi_1);
     118void _X2fvFv_i__1(signed int _X1xi_1);
     119void _X2f2Fv_i__1(signed int _X1xi_1){
     120}
     121void _X3fv1Fv_i__1(signed int _X1xi_1){
     122}
    105123struct _tuple2_ {
    106124};
     
    127145};
    128146struct _conc__tuple2_0 _X1fFT2ii___1(void);
    129 struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object6, signed int _X1xi_1);
     147void _X1fFv_ii__1(signed int __anonymous_object10, signed int _X1xi_1);
     148void _X2fvFv_ii__1(signed int __anonymous_object11, signed int _X1xi_1);
     149struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object12, signed int _X1xi_1);
    130150struct _conc__tuple2_0 _X1fFT2ii___1(void){
    131151    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    132152}
    133 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object7, signed int _X1xi_1){
     153void _X1fFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1){
     154}
     155void _X2fvFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object14, signed int _X1xi_1){
     156}
     157struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1){
    134158    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    135159}
     
    165189};
    166190struct _conc__tuple3_1 _X1fFT3iii___1(void);
    167 struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object8, signed int _X1xi_1, signed int __anonymous_object9);
     191void _X1fFv_iii__1(signed int __anonymous_object16, signed int _X1xi_1, signed int __anonymous_object17);
     192void _X2fvFv_iii__1(signed int __anonymous_object18, signed int _X1xi_1, signed int __anonymous_object19);
     193struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object20, signed int _X1xi_1, signed int __anonymous_object21);
    168194struct _conc__tuple3_1 _X1fFT3iii___1(void){
    169195    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    170196}
    171 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object10, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object11){
     197void _X1fFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object22, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object23){
     198}
     199void _X2fvFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object24, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object25){
     200}
     201struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object26, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object27){
    172202    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    173203}
     
    179209};
    180210struct _conc__tuple3_2 _X1fFT3iiPi___1(void);
    181 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object12, signed int _X1xi_1, signed int *_X1yPi_1);
     211void _X1fFv_iiPi__1(signed int __anonymous_object28, signed int _X1xi_1, signed int *_X1yPi_1);
     212void _X2fvFv_iiPi__1(signed int __anonymous_object29, signed int _X1xi_1, signed int *_X1yPi_1);
     213struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object30, signed int _X1xi_1, signed int *_X1yPi_1);
    182214struct _conc__tuple3_2 _X1fFT3iiPi___1(void){
    183215    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    184216}
    185 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1, signed int *_X1yPi_1){
     217void _X1fFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object31, signed int _X1xi_1, signed int *_X1yPi_1){
     218}
     219void _X2fvFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object32, signed int _X1xi_1, signed int *_X1yPi_1){
     220}
     221struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object33, signed int _X1xi_1, signed int *_X1yPi_1){
    186222    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    187223}
    188 signed int _X3f11Fi_i__1(signed int __anonymous_object14);
     224signed int _X3f11Fi_i__1(signed int __anonymous_object34);
    189225signed int _X3f12Fi___1(void);
    190226const double _X4bar1Fd___1();
    191 const double _X4bar2Fd_i__1(signed int __anonymous_object15);
    192 const double _X4bar3Fd_d__1(double __anonymous_object16);
     227const double _X4bar2Fd_i__1(signed int __anonymous_object35);
     228const double _X4bar3Fd_d__1(double __anonymous_object36);
    193229const double _X3fooFd___1(void);
    194 const double _X3fooFd_i__1(signed int __anonymous_object17);
    195 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object18){
     230const double _X3fooFd_i__1(signed int __anonymous_object37);
     231const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object38){
    196232    __attribute__ ((unused)) const double _X11_retval_fooKd_1;
    197233    {
     
    245281
    246282}
    247 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object19){
     283struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object39){
    248284    __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1;
    249285}
    250 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object20)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object21)(signed int __param_0)){
     286signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object40)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object41)(signed int __param_0)){
    251287    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    252288    signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)];
     
    274310    __attribute__ ((unused)) const struct _conc__tuple2_3 _X10_retval_f5KT2PiKi_1;
    275311}
    276 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object22)(), signed int *(*__anonymous_object23)(), signed int **(*__anonymous_object24)(), signed int *const *(*__anonymous_object25)(), signed int *const *const (*__anonymous_object26)(), signed int *__anonymous_object27, signed int __anonymous_object28[10], signed int **__anonymous_object29, signed int *__anonymous_object30[10], signed int ***__anonymous_object31, signed int **__anonymous_object32[10], signed int *const **__anonymous_object33, signed int *const *__anonymous_object34[10], signed int *const *const *__anonymous_object35, signed int *const *const __anonymous_object36[10]);
    277 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object37)(), __attribute__ ((unused)) signed int *(*__anonymous_object38)(), __attribute__ ((unused)) signed int **(*__anonymous_object39)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object40)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object41)(), __attribute__ ((unused)) signed int *__anonymous_object42, __attribute__ ((unused)) signed int __anonymous_object43[10], __attribute__ ((unused)) signed int **__anonymous_object44, __attribute__ ((unused)) signed int *__anonymous_object45[10], __attribute__ ((unused)) signed int ***__anonymous_object46, __attribute__ ((unused)) signed int **__anonymous_object47[10], __attribute__ ((unused)) signed int *const **__anonymous_object48, __attribute__ ((unused)) signed int *const *__anonymous_object49[10], __attribute__ ((unused)) signed int *const *const *__anonymous_object50, __attribute__ ((unused)) signed int *const *const __anonymous_object51[10]){
     312signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object42)(), signed int *(*__anonymous_object43)(), signed int **(*__anonymous_object44)(), signed int *const *(*__anonymous_object45)(), signed int *const *const (*__anonymous_object46)(), signed int *__anonymous_object47, signed int __anonymous_object48[10], signed int **__anonymous_object49, signed int *__anonymous_object50[10], signed int ***__anonymous_object51, signed int **__anonymous_object52[10], signed int *const **__anonymous_object53, signed int *const *__anonymous_object54[10], signed int *const *const *__anonymous_object55, signed int *const *const __anonymous_object56[10]);
     313signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object57)(), __attribute__ ((unused)) signed int *(*__anonymous_object58)(), __attribute__ ((unused)) signed int **(*__anonymous_object59)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object60)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object61)(), __attribute__ ((unused)) signed int *__anonymous_object62, __attribute__ ((unused)) signed int __anonymous_object63[10], __attribute__ ((unused)) signed int **__anonymous_object64, __attribute__ ((unused)) signed int *__anonymous_object65[10], __attribute__ ((unused)) signed int ***__anonymous_object66, __attribute__ ((unused)) signed int **__anonymous_object67[10], __attribute__ ((unused)) signed int *const **__anonymous_object68, __attribute__ ((unused)) signed int *const *__anonymous_object69[10], __attribute__ ((unused)) signed int *const *const *__anonymous_object70, __attribute__ ((unused)) signed int *const *const __anonymous_object71[10]){
    278314    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    279315}
  • tests/.expect/functions.x64.txt

    r06601401 r03606ce  
    9494    __attribute__ ((unused)) const signed int _X11_retval_fO5Ki_1;
    9595}
     96void _X1fFv___1(void);
     97void _X1fFv___1(void);
    9698signed int _X1fFi___1(void);
    97 signed int _X1fFi_i__1(signed int __anonymous_object4);
     99void _X1fFv_i__1(signed int __anonymous_object4);
     100void _X1fFv_i__1(signed int __anonymous_object5);
     101signed int _X1fFi_i__1(signed int __anonymous_object6);
     102void _X1fFv___1(void){
     103}
     104void _X2fvFv___1(void){
     105}
    98106signed int _X1fFi___1(void){
    99107    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    100108}
    101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object5){
     109void _X1fFv_i__1(__attribute__ ((unused)) signed int __anonymous_object7){
     110}
     111void _X2fvFv_i__1(__attribute__ ((unused)) signed int __anonymous_object8){
     112}
     113signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object9){
    102114    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    103115}
    104116signed int _X1fFi___1(void);
     117void _X1fFv_i__1(signed int _X1xi_1);
     118void _X2fvFv_i__1(signed int _X1xi_1);
     119void _X2f2Fv_i__1(signed int _X1xi_1){
     120}
     121void _X3fv1Fv_i__1(signed int _X1xi_1){
     122}
    105123struct _tuple2_ {
    106124};
     
    127145};
    128146struct _conc__tuple2_0 _X1fFT2ii___1(void);
    129 struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object6, signed int _X1xi_1);
     147void _X1fFv_ii__1(signed int __anonymous_object10, signed int _X1xi_1);
     148void _X2fvFv_ii__1(signed int __anonymous_object11, signed int _X1xi_1);
     149struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object12, signed int _X1xi_1);
    130150struct _conc__tuple2_0 _X1fFT2ii___1(void){
    131151    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    132152}
    133 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object7, signed int _X1xi_1){
     153void _X1fFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1){
     154}
     155void _X2fvFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object14, signed int _X1xi_1){
     156}
     157struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1){
    134158    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    135159}
     
    165189};
    166190struct _conc__tuple3_1 _X1fFT3iii___1(void);
    167 struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object8, signed int _X1xi_1, signed int __anonymous_object9);
     191void _X1fFv_iii__1(signed int __anonymous_object16, signed int _X1xi_1, signed int __anonymous_object17);
     192void _X2fvFv_iii__1(signed int __anonymous_object18, signed int _X1xi_1, signed int __anonymous_object19);
     193struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object20, signed int _X1xi_1, signed int __anonymous_object21);
    168194struct _conc__tuple3_1 _X1fFT3iii___1(void){
    169195    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    170196}
    171 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object10, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object11){
     197void _X1fFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object22, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object23){
     198}
     199void _X2fvFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object24, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object25){
     200}
     201struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object26, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object27){
    172202    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    173203}
     
    179209};
    180210struct _conc__tuple3_2 _X1fFT3iiPi___1(void);
    181 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object12, signed int _X1xi_1, signed int *_X1yPi_1);
     211void _X1fFv_iiPi__1(signed int __anonymous_object28, signed int _X1xi_1, signed int *_X1yPi_1);
     212void _X2fvFv_iiPi__1(signed int __anonymous_object29, signed int _X1xi_1, signed int *_X1yPi_1);
     213struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object30, signed int _X1xi_1, signed int *_X1yPi_1);
    182214struct _conc__tuple3_2 _X1fFT3iiPi___1(void){
    183215    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    184216}
    185 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1, signed int *_X1yPi_1){
     217void _X1fFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object31, signed int _X1xi_1, signed int *_X1yPi_1){
     218}
     219void _X2fvFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object32, signed int _X1xi_1, signed int *_X1yPi_1){
     220}
     221struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object33, signed int _X1xi_1, signed int *_X1yPi_1){
    186222    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    187223}
    188 signed int _X3f11Fi_i__1(signed int __anonymous_object14);
     224signed int _X3f11Fi_i__1(signed int __anonymous_object34);
    189225signed int _X3f12Fi___1(void);
    190226const double _X4bar1Fd___1();
    191 const double _X4bar2Fd_i__1(signed int __anonymous_object15);
    192 const double _X4bar3Fd_d__1(double __anonymous_object16);
     227const double _X4bar2Fd_i__1(signed int __anonymous_object35);
     228const double _X4bar3Fd_d__1(double __anonymous_object36);
    193229const double _X3fooFd___1(void);
    194 const double _X3fooFd_i__1(signed int __anonymous_object17);
    195 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object18){
     230const double _X3fooFd_i__1(signed int __anonymous_object37);
     231const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object38){
    196232    __attribute__ ((unused)) const double _X11_retval_fooKd_1;
    197233    {
     
    245281
    246282}
    247 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object19){
     283struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object39){
    248284    __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1;
    249285}
    250 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object20)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object21)(signed int __param_0)){
     286signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object40)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object41)(signed int __param_0)){
    251287    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    252288    signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)];
     
    274310    __attribute__ ((unused)) const struct _conc__tuple2_3 _X10_retval_f5KT2PiKi_1;
    275311}
    276 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object22)(), signed int *(*__anonymous_object23)(), signed int **(*__anonymous_object24)(), signed int *const *(*__anonymous_object25)(), signed int *const *const (*__anonymous_object26)(), signed int *__anonymous_object27, signed int __anonymous_object28[10], signed int **__anonymous_object29, signed int *__anonymous_object30[10], signed int ***__anonymous_object31, signed int **__anonymous_object32[10], signed int *const **__anonymous_object33, signed int *const *__anonymous_object34[10], signed int *const *const *__anonymous_object35, signed int *const *const __anonymous_object36[10]);
    277 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object37)(), __attribute__ ((unused)) signed int *(*__anonymous_object38)(), __attribute__ ((unused)) signed int **(*__anonymous_object39)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object40)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object41)(), __attribute__ ((unused)) signed int *__anonymous_object42, __attribute__ ((unused)) signed int __anonymous_object43[10], __attribute__ ((unused)) signed int **__anonymous_object44, __attribute__ ((unused)) signed int *__anonymous_object45[10], __attribute__ ((unused)) signed int ***__anonymous_object46, __attribute__ ((unused)) signed int **__anonymous_object47[10], __attribute__ ((unused)) signed int *const **__anonymous_object48, __attribute__ ((unused)) signed int *const *__anonymous_object49[10], __attribute__ ((unused)) signed int *const *const *__anonymous_object50, __attribute__ ((unused)) signed int *const *const __anonymous_object51[10]){
     312signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object42)(), signed int *(*__anonymous_object43)(), signed int **(*__anonymous_object44)(), signed int *const *(*__anonymous_object45)(), signed int *const *const (*__anonymous_object46)(), signed int *__anonymous_object47, signed int __anonymous_object48[10], signed int **__anonymous_object49, signed int *__anonymous_object50[10], signed int ***__anonymous_object51, signed int **__anonymous_object52[10], signed int *const **__anonymous_object53, signed int *const *__anonymous_object54[10], signed int *const *const *__anonymous_object55, signed int *const *const __anonymous_object56[10]);
     313signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object57)(), __attribute__ ((unused)) signed int *(*__anonymous_object58)(), __attribute__ ((unused)) signed int **(*__anonymous_object59)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object60)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object61)(), __attribute__ ((unused)) signed int *__anonymous_object62, __attribute__ ((unused)) signed int __anonymous_object63[10], __attribute__ ((unused)) signed int **__anonymous_object64, __attribute__ ((unused)) signed int *__anonymous_object65[10], __attribute__ ((unused)) signed int ***__anonymous_object66, __attribute__ ((unused)) signed int **__anonymous_object67[10], __attribute__ ((unused)) signed int *const **__anonymous_object68, __attribute__ ((unused)) signed int *const *__anonymous_object69[10], __attribute__ ((unused)) signed int *const *const *__anonymous_object70, __attribute__ ((unused)) signed int *const *const __anonymous_object71[10]){
    278314    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    279315}
  • tests/.expect/functions.x86.txt

    r06601401 r03606ce  
    9494    __attribute__ ((unused)) const signed int _X11_retval_fO5Ki_1;
    9595}
     96void _X1fFv___1(void);
     97void _X1fFv___1(void);
    9698signed int _X1fFi___1(void);
    97 signed int _X1fFi_i__1(signed int __anonymous_object4);
     99void _X1fFv_i__1(signed int __anonymous_object4);
     100void _X1fFv_i__1(signed int __anonymous_object5);
     101signed int _X1fFi_i__1(signed int __anonymous_object6);
     102void _X1fFv___1(void){
     103}
     104void _X2fvFv___1(void){
     105}
    98106signed int _X1fFi___1(void){
    99107    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    100108}
    101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object5){
     109void _X1fFv_i__1(__attribute__ ((unused)) signed int __anonymous_object7){
     110}
     111void _X2fvFv_i__1(__attribute__ ((unused)) signed int __anonymous_object8){
     112}
     113signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object9){
    102114    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    103115}
    104116signed int _X1fFi___1(void);
     117void _X1fFv_i__1(signed int _X1xi_1);
     118void _X2fvFv_i__1(signed int _X1xi_1);
     119void _X2f2Fv_i__1(signed int _X1xi_1){
     120}
     121void _X3fv1Fv_i__1(signed int _X1xi_1){
     122}
    105123struct _tuple2_ {
    106124};
     
    127145};
    128146struct _conc__tuple2_0 _X1fFT2ii___1(void);
    129 struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object6, signed int _X1xi_1);
     147void _X1fFv_ii__1(signed int __anonymous_object10, signed int _X1xi_1);
     148void _X2fvFv_ii__1(signed int __anonymous_object11, signed int _X1xi_1);
     149struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object12, signed int _X1xi_1);
    130150struct _conc__tuple2_0 _X1fFT2ii___1(void){
    131151    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    132152}
    133 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object7, signed int _X1xi_1){
     153void _X1fFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1){
     154}
     155void _X2fvFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object14, signed int _X1xi_1){
     156}
     157struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1){
    134158    __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = {  };
    135159}
     
    165189};
    166190struct _conc__tuple3_1 _X1fFT3iii___1(void);
    167 struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object8, signed int _X1xi_1, signed int __anonymous_object9);
     191void _X1fFv_iii__1(signed int __anonymous_object16, signed int _X1xi_1, signed int __anonymous_object17);
     192void _X2fvFv_iii__1(signed int __anonymous_object18, signed int _X1xi_1, signed int __anonymous_object19);
     193struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object20, signed int _X1xi_1, signed int __anonymous_object21);
    168194struct _conc__tuple3_1 _X1fFT3iii___1(void){
    169195    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    170196}
    171 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object10, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object11){
     197void _X1fFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object22, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object23){
     198}
     199void _X2fvFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object24, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object25){
     200}
     201struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object26, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object27){
    172202    __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
    173203}
     
    179209};
    180210struct _conc__tuple3_2 _X1fFT3iiPi___1(void);
    181 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object12, signed int _X1xi_1, signed int *_X1yPi_1);
     211void _X1fFv_iiPi__1(signed int __anonymous_object28, signed int _X1xi_1, signed int *_X1yPi_1);
     212void _X2fvFv_iiPi__1(signed int __anonymous_object29, signed int _X1xi_1, signed int *_X1yPi_1);
     213struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object30, signed int _X1xi_1, signed int *_X1yPi_1);
    182214struct _conc__tuple3_2 _X1fFT3iiPi___1(void){
    183215    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    184216}
    185 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1, signed int *_X1yPi_1){
     217void _X1fFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object31, signed int _X1xi_1, signed int *_X1yPi_1){
     218}
     219void _X2fvFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object32, signed int _X1xi_1, signed int *_X1yPi_1){
     220}
     221struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object33, signed int _X1xi_1, signed int *_X1yPi_1){
    186222    __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = {  };
    187223}
    188 signed int _X3f11Fi_i__1(signed int __anonymous_object14);
     224signed int _X3f11Fi_i__1(signed int __anonymous_object34);
    189225signed int _X3f12Fi___1(void);
    190226const double _X4bar1Fd___1();
    191 const double _X4bar2Fd_i__1(signed int __anonymous_object15);
    192 const double _X4bar3Fd_d__1(double __anonymous_object16);
     227const double _X4bar2Fd_i__1(signed int __anonymous_object35);
     228const double _X4bar3Fd_d__1(double __anonymous_object36);
    193229const double _X3fooFd___1(void);
    194 const double _X3fooFd_i__1(signed int __anonymous_object17);
    195 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object18){
     230const double _X3fooFd_i__1(signed int __anonymous_object37);
     231const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object38){
    196232    __attribute__ ((unused)) const double _X11_retval_fooKd_1;
    197233    {
     
    245281
    246282}
    247 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object19){
     283struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object39){
    248284    __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1;
    249285}
    250 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object20)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object21)(signed int __param_0)){
     286signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object40)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object41)(signed int __param_0)){
    251287    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    252288    signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned int )10)])[][((unsigned int )3)];
     
    274310    __attribute__ ((unused)) const struct _conc__tuple2_3 _X10_retval_f5KT2PiKi_1;
    275311}
    276 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object22)(), signed int *(*__anonymous_object23)(), signed int **(*__anonymous_object24)(), signed int *const *(*__anonymous_object25)(), signed int *const *const (*__anonymous_object26)(), signed int *__anonymous_object27, signed int __anonymous_object28[10], signed int **__anonymous_object29, signed int *__anonymous_object30[10], signed int ***__anonymous_object31, signed int **__anonymous_object32[10], signed int *const **__anonymous_object33, signed int *const *__anonymous_object34[10], signed int *const *const *__anonymous_object35, signed int *const *const __anonymous_object36[10]);
    277 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object37)(), __attribute__ ((unused)) signed int *(*__anonymous_object38)(), __attribute__ ((unused)) signed int **(*__anonymous_object39)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object40)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object41)(), __attribute__ ((unused)) signed int *__anonymous_object42, __attribute__ ((unused)) signed int __anonymous_object43[10], __attribute__ ((unused)) signed int **__anonymous_object44, __attribute__ ((unused)) signed int *__anonymous_object45[10], __attribute__ ((unused)) signed int ***__anonymous_object46, __attribute__ ((unused)) signed int **__anonymous_object47[10], __attribute__ ((unused)) signed int *const **__anonymous_object48, __attribute__ ((unused)) signed int *const *__anonymous_object49[10], __attribute__ ((unused)) signed int *const *const *__anonymous_object50, __attribute__ ((unused)) signed int *const *const __anonymous_object51[10]){
     312signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object42)(), signed int *(*__anonymous_object43)(), signed int **(*__anonymous_object44)(), signed int *const *(*__anonymous_object45)(), signed int *const *const (*__anonymous_object46)(), signed int *__anonymous_object47, signed int __anonymous_object48[10], signed int **__anonymous_object49, signed int *__anonymous_object50[10], signed int ***__anonymous_object51, signed int **__anonymous_object52[10], signed int *const **__anonymous_object53, signed int *const *__anonymous_object54[10], signed int *const *const *__anonymous_object55, signed int *const *const __anonymous_object56[10]);
     313signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object57)(), __attribute__ ((unused)) signed int *(*__anonymous_object58)(), __attribute__ ((unused)) signed int **(*__anonymous_object59)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object60)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object61)(), __attribute__ ((unused)) signed int *__anonymous_object62, __attribute__ ((unused)) signed int __anonymous_object63[10], __attribute__ ((unused)) signed int **__anonymous_object64, __attribute__ ((unused)) signed int *__anonymous_object65[10], __attribute__ ((unused)) signed int ***__anonymous_object66, __attribute__ ((unused)) signed int **__anonymous_object67[10], __attribute__ ((unused)) signed int *const **__anonymous_object68, __attribute__ ((unused)) signed int *const *__anonymous_object69[10], __attribute__ ((unused)) signed int *const *const *__anonymous_object70, __attribute__ ((unused)) signed int *const *const __anonymous_object71[10]){
    278314    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    279315}
  • tests/functions.cfa

    r06601401 r03606ce  
    1010// Created On       : Wed Aug 17 08:39:58 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Nov  6 17:54:09 2018
    13 // Update Count     : 13
     12// Last Modified On : Tue Mar  5 11:02:25 2024
     13// Update Count     : 34
    1414//
    1515
    1616// ANSI function definitions
    1717
    18 void h(void) {}
     18void h( void ) {}
    1919
    2020int f (
    21         int (void),
    22         int (int),
    23         int ((void)),
    24         int ((int)),
    25         void g(void)
    26         ) {
    27         (* g)();
     21        int ( void ),
     22        int ( int ),
     23        int (( void )),
     24        int (( int )),
     25        void g( void )
     26) {
     27        (*g)();
    2828        g();
    2929        g = h;
     
    3232int f1() {}
    3333int (f2()) {}
    34 int (* f3())() {}
     34int (*f3())() {}
    3535int * ((f4())) {}
    36 int ((* f5()))() {}
     36int ((*f5()))() {}
    3737int * f6() {}
    38 int * (f7)() {}
     38int * ( f7)() {}
    3939int ** f8() {}
    40 int * const * (f9)() {}
     40int * const * ( f9)() {}
    4141int (* f10())[] {}
    4242int (* f11())[][3] {}
     
    6666// Cforall extensions
    6767
    68 // [] f( );
    69 [int] f( );
    70 // [] f(int);
    71 [int] f(int);
    72 // [] f( ) {}
    73 [int] f( ) {}
    74 // [] f(int) {}
    75 [int] f(int) {}
    76 
    77 [int x] f( );
    78 // [] f(int x);
    79 //[int x] f(int x);
    80 //[int x] f( ) {}
    81 // [] f(int x) {}
    82 //[int x] f(int x) {}
    83 
    84 [int, int x] f( );
    85 // [] f(int, int x);
    86 [int, int x] f(int, int x);
    87 [int, int x] f( ) {}
    88 // [] f(int, int x) {}
    89 [int, int x] f(int, int x) {}
    90 
    91 [int, int x, int] f( );
    92 // [] f(int, int x, int);
    93 [int, int x, int] f(int, int x, int);
    94 [int, int x, int] f( ) {}
    95 // [] f(int, int x, int) {}
    96 [int, int x, int] f(int, int x, int) {}
    97 
    98 [int, int x, * int y] f( );
    99 // [] f(int, int x, * int y);
    100 [int, int x, * int y] f(int, int x, * int y);
    101 [int, int x, * int y] f( ) {}
    102 // [] f(int, int x, * int y) {}
    103 [int, int x, * int y] f(int, int x, * int y) {}
     68[] f();
     69[void] f();
     70[int] f();
     71[] f( int );
     72[void] f( int );
     73[int] f( int );
     74[] f() {}
     75[void] fv() {}
     76[int] f() {}
     77[] f( int ) {}
     78[void] fv( int ) {}
     79[int] f( int ) {}
     80
     81[int x] f();
     82[] f( int x );
     83[void] fv( int x );
     84//[int x] f( int x );
     85//[int x] f() {}
     86[] f2( int x ) {}
     87[void] fv1( int x ) {}
     88//[int x] f( int x ) {}
     89
     90[int, int x] f();
     91[] f( int, int x );
     92[void] fv( int, int x );
     93[int, int x] f( int, int x );
     94[int, int x] f() {}
     95[] f( int, int x ) {}
     96[void] fv( int, int x ) {}
     97[int, int x] f( int, int x ) {}
     98
     99[int, int x, int] f();
     100[] f( int, int x, int );
     101[void] fv( int, int x, int );
     102[int, int x, int] f( int, int x, int );
     103[int, int x, int] f() {}
     104[] f( int, int x, int ) {}
     105[void] fv( int, int x, int ) {}
     106[int, int x, int] f( int, int x, int ) {}
     107
     108[int, int x, * int y] f();
     109[] f( int, int x, * int y );
     110[void] fv( int, int x, * int y );
     111[int, int x, * int y] f( int, int x, * int y );
     112[int, int x, * int y] f() {}
     113[] f( int, int x, * int y ) {}
     114[void] fv( int, int x, * int y ) {}
     115[int, int x, * int y] f( int, int x, * int y ) {}
    104116
    105117// function prototypes
     
    116128        int ( int, int p ),
    117129        [int](int)
    118         ) {
    119         int (* (* pc)[][10])[][3];
     130) {
     131        int (* (* pc )[][10])[][3];
    120132        * [][10] * [][3] int p;
    121         * [] * [int](int) p;
     133        * [] * [int]( int ) p;
    122134}
    123135
     
    149161        int * const * const ([]),
    150162        int * const * const ([10])
    151         );
     163);
    152164
    153165int f(
     
    170182        int * const * const ([]),
    171183        int * const * const ([10])
    172         ) {
    173 }
     184) {}
    174185
    175186typedef int T;
    176187
    177 int f( T (* f), T t ) {
    178         T (T);
     188int f( T ( *f ), T t ) {
     189        T ( T );
    179190}
    180191
Note: See TracChangeset for help on using the changeset viewer.