Changeset 03606ce
- Timestamp:
- Mar 8, 2024, 12:25:49 AM (19 months ago)
- 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. - Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/papers/llheap/Makefile
r06601401 r03606ce 17 17 18 18 FIGURES = ${addsuffix .tex, \ 19 AddressSpace \20 19 AllocatorComponents \ 21 20 AllocatedObject \ … … 57 56 58 57 PICTURES = ${addsuffix .pstex, \ 58 AddressSpace \ 59 59 MultipleHeapsOwnershipStorage \ 60 60 PrivatePublicHeaps \ -
doc/papers/llheap/Paper.tex
r06601401 r03606ce 82 82 xleftmargin=\parindentlnth, % indent code to paragraph indentation 83 83 escapechar=\$, % LaTeX escape in CFA code 84 %mathescape=true, %LaTeX math escape in CFA code $...$84 mathescape=false, % disable LaTeX math escape in CFA code $...$ 85 85 keepspaces=true, % 86 86 showstringspaces=false, % do not show spaces with cup … … 90 90 numberstyle=\footnotesize\sf, % numbering style 91 91 moredelim=**[is][\color{red}]{@}{@}, 92 % replace/adjust listing characters that look bad in sanserif 93 literate= 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, 92 103 }% lstset 93 104 … … 95 106 \lstdefinelanguage{CFA}[ANSI]{C}{ 96 107 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 }, 105 118 moredirectives={defined,include_next}, 106 % replace/adjust listing characters that look bad in sanserif107 literate={-}{\makebox[1ex][c]{\raisebox{0.5ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1108 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 % {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1109 {<}{\textrm{\textless}}1 {>}{\textrm{\textgreater}}1110 {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.5ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex{\textrm{\textgreater}}}2,111 119 } 112 120 113 121 % uC++ programming language, based on ANSI C++ 114 \lstdefinelanguage{uC++}[ ANSI]{C++}{122 \lstdefinelanguage{uC++}[GNU]{C++}{ 115 123 morekeywords={ 116 _Accept, _AcceptReturn, _AcceptWait, _Actor, _At, _Catch Resume, _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}, 119 127 } 120 128 … … 133 141 morestring=[b]", 134 142 morestring=[s]{`}{`}, 135 % replace/adjust listing characters that look bad in sanserif136 literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1137 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 % {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1138 {<}{\textrm{\textless}}1 {>}{\textrm{\textgreater}}1139 {<-}{\makebox[2ex][c]{\textrm{\textless}\raisebox{0.5ex}{\rule{0.8ex}{0.075ex}}}}2,140 143 } 141 144 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}}{} 160 151 161 152 % inline code @...@ … … 193 184 194 185 \author[1]{Mubeen Zulfiqar} 186 \author[1]{Ayelet Wasik} 195 187 \author[1]{Peter A. Buhr*} 196 \author[1]{Thierry Delisle} 197 \author[1]{Ayelet Wasik} 188 \author[2]{Bryan Chan} 198 189 \authormark{ZULFIQAR \textsc{et al.}} 199 190 200 191 \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}}} 201 193 202 194 \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}} … … 204 196 % \fundingInfo{Natural Sciences and Engineering Research Council of Canada} 205 197 206 \abstract[Summary]{ 207 A new C-based concurrent memory-allocator is presented, called llheap .198 \abstract[Summary]{% 199 A new C-based concurrent memory-allocator is presented, called llheap (low latency). 208 200 It can be used standalone in C/\CC applications with multiple kernel threads, or embedded into high-performance user-threading programming languages. 209 201 llheap extends the feature set of existing C allocation by remembering zero-filled (\lstinline{calloc}) and aligned properties (\lstinline{memalign}) in an allocation. 210 202 These 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. 203 As well, \lstinline{realloc} preserves these properties when adjusting storage size, again increasing future allocation safety. 204 llheap 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; 205 hence, programmers do have to code missing combinations. 206 The llheap allocator also provides a contention-free statistics gathering mode, and a debugging mode for dynamically checking allocation pre/post conditions and invariants. 207 These modes are invaluable for understanding and debugging a program's dynamic allocation behaviour, with low enough cost to be used in production code. 208 The 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. 209 Finally, performance results across a number of benchmarks show llheap is competitive with the best memory allocators. 210 }% abstract 211 220 212 % 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 %223 213 % 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. 224 214 % These micro-benchmarks have adjustment knobs to simulate allocation patterns hard-coded into arbitrary test programs. 225 215 % 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} 229 218 230 219 … … 237 226 \section{Introduction} 238 227 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 outputis rarely optimal.241 However, memory allocators do take advantage of regularities in allocation patterns fortypical 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 optimizingspecific allocation patterns.243 Nevertheless, memoryallocators are a series of compromises, occasionally with some static or dynamic tuning parameters to optimize specific program-request patterns.228 Memory 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. 229 A general-purpose dynamic-allocation algorithm cannot anticipate allocation requests so its time and space performance is rarely optimal. 230 However, allocators take advantage of regular allocation patterns in typical programs to produce excellent results, both in time and space (similar to LRU paging). 231 Allocators use a number of similar techniques, but each optimizes specific allocation patterns. 232 Nevertheless, allocators are a series of compromises, occasionally with some static or dynamic tuning parameters to optimize specific program-request patterns. 244 233 245 234 … … 247 236 \label{s:MemoryStructure} 248 237 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}.238 Figure~\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}. 250 239 Static 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.253 240 Dynamic 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}. 254 241 However, changes to the dynamic code/data space are typically infrequent, many occurring at program startup, and are largely outside of a program's control. 255 242 Stack memory is managed by the program call/return-mechanism using a LIFO technique, which works well for sequential programs. 256 243 For stackful coroutines and user threads, a new stack is commonly created in the dynamic-allocation memory. 244 The 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. 245 The programming-language's runtime manages this area, where management complexity is a function of the mechanism for deleting variables. 257 246 This work focuses solely on management of the dynamic-allocation memory. 258 247 259 248 \begin{figure} 260 249 \centering 261 \input{AddressSpace }250 \input{AddressSpace.pstex_t} 262 251 \vspace{-5pt} 263 252 \caption{Program Address Space Divided into Zones} … … 269 258 \label{s:DynamicMemoryManagement} 270 259 271 Modern programming languages manage dynamic -allocationmemory in different ways.260 Modern programming languages manage dynamic memory in different ways. 272 261 Some 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}. 273 262 In 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 reflectnew data locations.263 However, moving data requires finding and updating pointers to it to reflect the new data locations. 275 264 Programming languages such as C~\cite{C}, \CC~\cite{C++}, and Rust~\cite{Rust} provide the programmer with explicit allocation \emph{and} deallocation of data. 276 265 These 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. 277 266 Attempts have been made to perform quasi garbage collection in C/\CC~\cite{Boehm88}, but it is a compromise. 278 This work only examines dynamic m emory-management with \emph{explicit} deallocation.267 This work only examines dynamic management with \emph{explicit} deallocation. 279 268 While garbage collection and compaction are not part this work, many of the results are applicable to the allocation phase in any memory-management approach. 280 269 281 Most programs use a general-purpose allocator, often the one provided implicitlyby 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.270 Most programs use a general-purpose allocator, usually the one provided by the programming-language's runtime. 271 In certain languages, programmers can write specialize allocators for specific needs. 272 C and \CC allow easy replacement of the default memory allocator through a standard API. 284 273 Jikes 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 writtenfor C/\CC with the goal of scaling in a multi-threaded program~\cite{Berger00,mtmalloc,streamflow,tcmalloc}.274 As well, new languages support concurrency (kernel and/or user threading), which must be safely handled by the allocator. 275 Hence, several alternative allocators exist for C/\CC with the goal of scaling in a multi-threaded program~\cite{Berger00,mtmalloc,streamflow,tcmalloc}. 287 276 This work examines the design of high-performance allocators for use by kernel and user multi-threaded applications written in C/\CC. 288 277 … … 294 283 \begin{enumerate}[leftmargin=*,itemsep=0pt] 295 284 \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 programminglanguages \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 allocationalignment.285 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 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 288 Extend the standard C heap functionality by preserving with each allocation its request size, the amount allocated, whether it is zero fill, and its alignment. 300 289 301 290 \item 302 291 Use 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] 292 Without this extension, it is unsafe to @realloc@ storage these allocations if the properties are not preserved when copying. 293 This silent problem is unintuitive to programmers and difficult to locate because it is transient. 294 295 \item 296 Provide 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. 309 304 \item 310 305 @resize( oaddr, size )@ re-purpose an old allocation for a new type \emph{without} preserving fill or alignment. … … 313 308 \item 314 309 @realloc( oaddr, alignment, size )@ same as @realloc@ but adding or changing alignment. 315 \item316 @aalloc( dim, elemSize )@ same as @calloc@ except memory is \emph{not} zero filled.317 \item318 @amemalign( alignment, dim, elemSize )@ same as @aalloc@ with memory alignment.319 \item320 @cmemalign( alignment, dim, elemSize )@ same as @calloc@ with memory alignment.321 310 \end{itemize} 322 323 \item324 Provide additional heap wrapper functions in \CFA creating a more usable set of allocation operations and properties.325 311 326 312 \item … … 328 314 \begin{itemize}[topsep=3pt,itemsep=2pt,parsep=0pt] 329 315 \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. 331 317 If the allocation is not aligned or @addr@ is @NULL@, the minimal alignment is returned. 332 318 \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 )@. 338 324 \end{itemize} 339 325 340 326 \item 341 Provide complete, fast, and contention-free allocation statistics to help understand allocation behaviour:327 Provide optional extensive, fast, and contention-free allocation statistics to understand allocation behaviour, accessed by: 342 328 \begin{itemize}[topsep=3pt,itemsep=2pt,parsep=0pt] 343 329 \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@). 349 335 This file descriptor is used implicitly by @malloc_stats@ and @malloc_info@. 350 336 \end{itemize} … … 355 341 \item 356 342 Build 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. 343 A program may link to any of these 8 versions of the allocator often without recompilation (@LD_PRELOAD@). 344 345 \item 346 Provide additional heap wrapper functions in \CFA creating a more usable set of allocation operations and properties. 358 347 359 348 \item … … 365 354 \section{Background} 366 355 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 356 The following is a quick overview of allocator design options that affect memory usage and performance (see~\cite{Zulfiqar22} for more details). 357 Dynamic 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. 371 358 A \newterm{memory allocator} contains a complex data-structure and code that manages the layout of objects in the dynamic-allocation zone. 372 359 The 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.360 Since objects in C/\CC cannot be moved to aid the packing process, only adjacent free storage can be \newterm{coalesced} into larger free areas. 374 361 The 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. 375 362 … … 383 370 The \newterm{storage data} is composed of allocated and freed objects, and \newterm{reserved memory}. 384 371 Allocated 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 easylocation of new allocations.372 \ie only the program knows the location of allocated storage. 373 Freed objects (white) represent memory deallocated by the program, which are linked into one or more lists facilitating location of new allocations. 387 374 Reserved memory (dark grey) is one or more blocks of memory obtained from the \newterm{operating system} (OS) but not yet allocated to the program; 388 375 if there are multiple reserved blocks, they are also chained together. … … 401 388 An object may be preceded by padding to ensure proper alignment. 402 389 Some 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.404 390 When padding and spacing are necessary, neither can be used to satisfy a future allocation request while the current allocation exists. 405 391 … … 407 393 Often 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. 408 394 For 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. 395 Often the minimum storage alignment and free-node size are the same. 409 396 The 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. 410 397 … … 420 407 \label{s:SingleThreadedMemoryAllocator} 421 408 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 409 In a sequential (single threaded) program, the program thread performs all allocation operations and concurrency issues do not exist. 410 However, interrupts logically introduce concurrency, if the signal handler performs allocation/deallocation (serially reusable problem~\cite{SeriallyReusable}). 411 In general, the primary issues in a single-threaded allocator are fragmentation and locality. 426 412 427 413 \subsubsection{Fragmentation} 428 414 \label{s:Fragmentation} 429 415 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. 416 Fragmentation is memory requested from the OS but not used allocated objects in by the program. 417 Figure~\ref{f:InternalExternalFragmentation} shows fragmentation is divided into two forms: \emph{internal} or \emph{external}. 433 418 434 419 \begin{figure} … … 439 424 \end{figure} 440 425 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 s hould striveto keep internal management information to a minimum.444 445 \newterm{External fragmentation} is all memory space reserved from the OS but not allocated tothe 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. 427 Internal fragmentation is problematic when management space becomes a significant proportion of an allocated object, \eg for objects $<$16 bytes, memory usage doubles. 428 An 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. 446 431 This memory is problematic in two ways: heap blowup and highly fragmented memory. 447 432 \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.433 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 are to small to service requests. 449 434 % 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.435 Heap 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. 451 436 % Blocks of free memory become smaller and non-contiguous making them less useful in serving allocation requests. 452 437 % Memory is highly fragmented when most free blocks are unusable because of their sizes. … … 479 464 480 465 The 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 spac ingafter the object.466 When an object is allocated, the requested size is rounded up to the nearest bin-size, often leading to space after the object. 482 467 A 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). 468 Fewer 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). 469 More 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. 470 Allowing 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). 487 471 % 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. 488 472 % 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. 489 473 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 onelarger block.474 The third approach is a \newterm{splitting} and \newterm{coalescing} algorithms. 475 When 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. 476 For 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. 477 When 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. 494 478 Coalescing 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.479 However, coalescing increases allocation latency (unbounded delays), both for allocation and deallocation. 496 480 While coalescing does not reduce external fragmentation, the coalesced blocks improve fragmentation quality so future allocations are less likely to cause heap blowup. 497 481 % Splitting and coalescing can be used with other algorithms to avoid highly fragmented memory. … … 504 488 % 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. 505 489 % 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.490 Hardware takes advantage of the working set through multiple levels of caching and paging, \ie memory hierarchy. 507 491 % 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. 508 492 For example, entire cache lines are transferred between cache and memory, and entire virtual-memory pages are transferred between memory and disk. 509 493 % 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.}. 510 494 511 Temporal locality is largely controlled by how a program accessesits variables~\cite{Feng05}.512 Nevertheless, a memory allocator can have some indirect influence on temporal locality andlargely dictates spatial locality.513 For temporal locality, an allocator can return storage for new allocations that was just freed as these memory locations arestill \emph{warm} in the memory hierarchy.514 For spatial locality, an allocator can placeobjects used together close together in memory, so the working set of the program fits into the fewest possible cache lines and pages.495 Temporal locality is largely controlled by program accesses to its variables~\cite{Feng05}. 496 An allocator has only indirect influence on temporal locality but largely dictates spatial locality. 497 For temporal locality, an allocator tries to return recently freed storage for new allocations, as this memory is still \emph{warm} in the memory hierarchy. 498 For 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. 515 499 % However, usage patterns are different for every program as is the underlying hardware memory architecture; 516 500 % hence, no general-purpose memory-allocator can provide ideal locality for every program on every computer. 517 501 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. 502 An allocator can easily degrade locality by increasing the working set. 503 An allocator can access an unbounded number of free objects when matching an allocation or coalescing, causing multiple cache or page misses~\cite{Grunwald93}. 504 An allocator can spatially separate related data by binning free storage anywhere in memory, so the related objects are highly separated. 522 505 523 506 … … 525 508 \label{s:MultiThreadedMemoryAllocator} 526 509 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 asmutual exclusion, false sharing, and additional forms of heap blowup.510 In a concurrent (multi-threaded) program, multiple program threads performs allocation operations and all concurrency issues arise. 511 Along with fragmentation and locality issues, a multi-threaded allocator must deal with mutual exclusion, false sharing, and additional forms of heap blowup. 529 512 530 513 … … 534 517 \newterm{Mutual exclusion} provides sequential access to the shared-management data of the heap. 535 518 There are two performance issues for mutual exclusion. 536 First is the overhead necessary to perform (at least) ahardware 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.519 First is the cost of performing at least one hardware atomic operation every time a shared resource is accessed. 520 Second is \emph{contention} on simultaneous access, so some threads must wait until the resource is released. 538 521 Contention 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 oflocks.540 2) Using trylock and generating new storage if the lock is busy , yielding a classic space versus time tradeoff.522 1) Using multiple fine-grained locks versus a single lock to spread the contention across the locks. 523 2) Using trylock and generating new storage if the lock is busy (classic space versus time tradeoff). 541 524 3) 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.525 However, all approaches have degenerate cases where program contention to the heap is high, which is beyond the allocator's control. 543 526 544 527 … … 546 529 \label{s:FalseSharing} 547 530 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$. 531 False sharing occurs when two or more threads simultaneously modify different objects sharing a cache line. 532 Changes now invalidate each thread's cache, even though the threads may be uninterested in the other modified object. 533 False sharing can occur three ways: 534 1) 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$; 535 both threads now simultaneously modifying the objects on the same cache line. 536 2) 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. 537 3) 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$. 538 In all three cases, the allocator performs a hidden and possibly transient (non-determinism) operation, making it extremely difficult to find and fix the issue. 583 539 584 540 … … 586 542 \label{s:HeapBlowup} 587 543 588 In a multi-threaded program, heap blowup can occurwhen memory freed by one thread is inaccessible to other threads due to the allocation strategy.544 In a multi-threaded program, heap blowup occurs when memory freed by one thread is inaccessible to other threads due to the allocation strategy. 589 545 Specific examples are presented in later subsections. 590 546 591 547 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 551 The following features are used in the construction of multi-threaded allocators. 600 552 601 553 \subsubsection{Multiple Heaps} 602 554 \label{s:MultipleHeaps} 603 555 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. 556 Figure~\ref{f:ThreadHeapRelationship} shows how a multi-threaded allocator can subdivide a single global heap into multiple heaps to reduce contention among threads. 607 557 608 558 \begin{figure} … … 626 576 } % subfloat 627 577 \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. 631 583 Memory is obtained from the freed objects, or reserved memory in the heap, or from the OS; 632 584 the 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.585 The arrows indicate the direction memory moves for each alocation/deallocation operation. 634 586 To 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. 587 Regardless, 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. 590 The decision to create a heap and which heap a thread allocates/deallocates during its lifetime depends on the allocator design. 591 Locking is required within each heap because of multiple tread access, but contention is reduced because fewer threads access a specific heap. 592 The goal is to have mininal heaps (storage) and thread contention per heap (time). 593 However, 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. 643 594 644 595 % 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. … … 693 644 In general, the cost is minimal since the majority of memory operations are completed without the use of the global heap. 694 645 695 \ paragraph{1:1 model (see Figure~\ref{f:PerThreadHeap})} where each thread has its own heapeliminating 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}). 696 647 An additional benefit of thread heaps is improved locality due to better memory layout. 697 648 As 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. 698 649 In 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 foranother thread's heap.650 Thread heaps can also reduces false-sharing, except at crucial boundaries overlapping memory from another thread's heap. 700 651 For 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. 701 652 % Hence, allocator-induced active false-sharing cannot occur because the memory for thread heaps never overlaps. … … 706 657 Destroying 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. 707 658 Alternatively, 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} 708 660 709 661 -
doc/papers/llheap/figures/AddressSpace.fig
r06601401 r03606ce 9 9 1200 2 10 10 2 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 12 2 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 16 14 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 17 15 1 1 1.00 45.00 90.00 18 2100 1 725 2400 172516 2100 1500 2400 1500 19 17 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 20 18 1 1 1.00 45.00 90.00 21 3000 1725 2700 1725 19 3000 1500 2700 1500 20 2 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 22 2 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 22 24 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 23 25 1 1 1.00 45.00 90.00 24 3900 1 725 4200 172526 3900 1500 4200 1500 25 27 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 26 28 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 30 30 2 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 135032 2 2 0 1 0 7 60 -1 170.000 0 0 -1 0 0 533 3900 1350 4800 1350 4800 2100 3900 2100 3900 135034 4 0 0 50 -1 0 10 0.0000 2 1 80 900 1200 2325 high address\00135 4 2 0 50 -1 0 10 0.0000 2 1 35 855 6600 2325 low address\00136 4 1 0 50 -1 0 10 0.0000 2 120 3 30 6150 2025 Data\00137 4 1 0 50 -1 0 10 0.0000 2 1 35 675 6150 1800 Code and\00138 4 1 0 50 -1 0 10 0.0000 2 120 3 90 6150 1575 Static\00139 4 1 0 50 -1 0 10 0.0000 2 1 35 390 1650 1800 Stack\00140 4 1 0 50 -1 0 10 0.0000 2 1 65 615 2550 1950 Memory\00141 4 1 0 50 -1 0 10 0.0000 2 1 65 615 4350 1950 Memory\00142 4 1 0 50 -1 0 10 0.0000 2 120 3 15 2550 1650Free\00143 4 1 0 50 -1 0 10 0.0000 2 1 20 330 3450 2025 Data\00144 4 1 0 50 -1 0 10 0.0000 2 135 675 3450 1800 Code and\00145 4 1 0 50 -1 0 10 0.0000 2 1 65 645 3450 1575 Dynamic\00146 4 1 0 50 -1 0 10 0.0000 2 120 315 4350 1650 Free\00147 4 1 0 50 -1 0 10 0.0000 2 120 735 5250 1950 Allocation\00148 4 1 0 50 -1 0 10 0.0000 2 165 645 5250 1650 Dynamic\00131 4800 1200 5700 1200 5700 1800 4800 1800 4800 1200 32 2 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 34 4 0 0 50 -1 0 10 0.0000 2 165 870 1200 2025 high address\001 35 4 2 0 50 -1 0 10 0.0000 2 120 810 6600 2025 low address\001 36 4 1 0 50 -1 0 10 0.0000 2 120 375 1650 1575 Stack\001 37 4 1 0 50 -1 0 10 0.0000 2 150 600 2550 1725 Memory\001 38 4 1 0 50 -1 0 10 0.0000 2 120 300 2550 1425 Free\001 39 4 1 0 50 -1 0 10 0.0000 2 120 660 3450 1575 Code and\001 40 4 1 0 50 -1 0 10 0.0000 2 150 630 3450 1350 Dynamic\001 41 4 1 0 50 -1 0 10 0.0000 2 120 315 3450 1775 Data\001 42 4 1 0 50 -1 0 10 0.0000 2 120 300 4350 1425 Free\001 43 4 1 0 50 -1 0 10 0.0000 2 150 600 4350 1725 Memory\001 44 4 1 4 50 -1 0 10 0.0000 2 150 630 5250 1425 Dynamic\001 45 4 1 0 50 -1 0 10 0.0000 2 120 315 6150 1775 Data\001 46 4 1 0 50 -1 0 10 0.0000 2 120 660 6150 1575 Code and\001 47 4 1 0 50 -1 0 10 0.0000 2 120 375 6150 1350 Static\001 48 4 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 144 144 sout | xstr(D2_s1_abcd) | "\t\\\\"; 145 145 146 #define D2_s1mid_s1 string s1_mid = s1(1, 3)`shareEdits146 #define D2_s1mid_s1 string s1_mid = s1(1,2)`shareEdits 147 147 D2_s1mid_s1; 148 148 sout | xstr(D2_s1mid_s1) | "\t\\\\"; 149 149 150 #define D2_s2_s1 string s2 = s1(1, 3)150 #define D2_s2_s1 string s2 = s1(1,2) 151 151 D2_s2_s1; 152 152 assert( s1 == "abcd" ); … … 257 257 sout | xstr(D2_s1bgn_s1) | "\t\\\\"; 258 258 259 #define D2_s1end_s1 string s1_end = s1(3, 4)`shareEdits259 #define D2_s1end_s1 string s1_end = s1(3, 1)`shareEdits 260 260 D2_s1end_s1; 261 261 assert( s1 == "ajjd" ); … … 280 280 sout | "\t\t\t\t& @s1@\t& @s1_bgn@\t& @s1_crs@\t& @s1_mid@\t& @s1_end@\t\\\\"; 281 281 282 #define D2_s1crs_s1 string s1_crs = s1(3, 5)`shareEdits282 #define D2_s1crs_s1 string s1_crs = s1(3, 2)`shareEdits 283 283 D2_s1crs_s1; 284 284 assert( s1 == "zzzzjjd" ); … … 305 305 string word = "Phi"; 306 306 string consonants = word(0,2)`shareEdits; 307 string miniscules = word(1, 3)`shareEdits;307 string miniscules = word(1,2)`shareEdits; 308 308 assert( word == "Phi" ); 309 309 assert( consonants == "Ph" ); … … 318 318 319 319 string all = "They said hello again"; 320 string greet = all(10, 15)`shareEdits;321 string greet_bgn = all(10,1 1)`shareEdits;322 string greet_end = all(14,1 5)`shareEdits;320 string greet = all(10,5)`shareEdits; 321 string greet_bgn = all(10,1)`shareEdits; 322 string greet_end = all(14,1)`shareEdits; 323 323 324 324 assert( all == "They said hello again" ); -
src/Parser/DeclarationNode.cc
r06601401 r03606ce 177 177 } 178 178 179 DeclarationNode * DeclarationNode::newFromTypeData( TypeData * type ) { 180 DeclarationNode * newnode = new DeclarationNode; 181 newnode->type = type; 182 return newnode; 183 } // DeclarationNode::newFromTypeData 184 179 185 DeclarationNode * DeclarationNode::newStorageClass( ast::Storage::Classes sc ) { 180 186 DeclarationNode * newnode = new DeclarationNode; … … 188 194 return newnode; 189 195 } // 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::newQualifier197 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::newBasicType204 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::newComplexType211 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::newSignedNess218 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::newLength225 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::newForall232 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 }250 196 251 197 DeclarationNode * DeclarationNode::newAggregate( ast::AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) { … … 312 258 } 313 259 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::newFromTypedef322 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::newFromTypeGen331 332 260 DeclarationNode * DeclarationNode::newTypeParam( ast::TypeDecl::Kind tc, const string * name ) { 333 261 DeclarationNode * newnode = newName( name ); … … 423 351 return newnode; 424 352 } 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::newBuiltinType439 353 440 354 DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) { -
src/Parser/DeclarationNode.h
r06601401 r03606ce 40 40 static const char * builtinTypeNames[]; 41 41 42 static DeclarationNode * newFromTypeData( TypeData * ); 42 43 static DeclarationNode * newStorageClass( ast::Storage::Classes ); 43 44 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 * );54 45 static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ); 55 46 static DeclarationNode * newAggregate( ast::AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ); … … 59 50 static DeclarationNode * newEnumInLine( const std::string name ); 60 51 static DeclarationNode * newName( const std::string * ); 61 static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params );62 52 static DeclarationNode * newTypeParam( ast::TypeDecl::Kind, const std::string * ); 63 53 static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts ); … … 70 60 static DeclarationNode * newTuple( DeclarationNode * members ); 71 61 static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false ); 72 static DeclarationNode * newVtableType( DeclarationNode * expr );73 62 static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes 74 63 static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement … … 163 152 }; // DeclarationNode 164 153 165 ast::Type * buildType( TypeData * type );166 167 154 static inline ast::Type * maybeMoveBuildType( const DeclarationNode * orig ) { 168 155 ast::Type * ret = orig ? orig->buildType() : nullptr; -
src/Parser/ExpressionNode.cc
r06601401 r03606ce 29 29 #include "DeclarationNode.h" // for DeclarationNode 30 30 #include "InitializerNode.h" // for InitializerNode 31 #include "TypeData.h" // for addType, build_basic_type, build_c... 31 32 #include "parserutility.h" // for notZeroExpr 32 33 … … 316 317 v2 ); 317 318 ret = build_compoundLiteral( location, 318 DeclarationNode::new BasicType(319 DeclarationNode::Int128320 )->addType(321 DeclarationNode::newSignedNess( DeclarationNode::Unsigned) ),319 DeclarationNode::newFromTypeData( 320 addType( 321 build_basic_type( DeclarationNode::Int128 ), 322 build_signedness( DeclarationNode::Unsigned ) ) ), 322 323 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 ) 324 325 ); 325 326 } else { // explicit length, (length_type)constant -
src/Parser/TypeData.cc
r06601401 r03606ce 478 478 } 479 479 480 481 480 TypeData * TypeData::getLastBase() { 482 481 TypeData * cur = this; … … 487 486 void TypeData::setLastBase( TypeData * newBase ) { 488 487 getLastBase()->base = newBase; 488 } 489 490 491 TypeData * build_type_qualifier( ast::CV::Qualifiers tq ) { 492 TypeData * type = new TypeData; 493 type->qualifiers = tq; 494 return type; 495 } 496 497 TypeData * build_basic_type( DeclarationNode::BasicType basic ) { 498 TypeData * type = new TypeData( TypeData::Basic ); 499 type->basictype = basic; 500 return type; 501 } 502 503 TypeData * build_complex_type( DeclarationNode::ComplexType complex ) { 504 TypeData * type = new TypeData( TypeData::Basic ); 505 type->complextype = complex; 506 return type; 507 } 508 509 TypeData * build_signedness( DeclarationNode::Signedness signedness ) { 510 TypeData * type = new TypeData( TypeData::Basic ); 511 type->signedness = signedness; 512 return type; 513 } 514 515 TypeData * build_builtin_type( DeclarationNode::BuiltinType bit ) { 516 TypeData * type = new TypeData( TypeData::Builtin ); 517 type->builtintype = bit; 518 return type; 519 } 520 521 TypeData * build_length( DeclarationNode::Length length ) { 522 TypeData * type = new TypeData( TypeData::Basic ); 523 type->length = length; 524 return type; 525 } 526 527 TypeData * build_forall( DeclarationNode * forall ) { 528 TypeData * type = new TypeData( TypeData::Unknown ); 529 type->forall = forall; 530 return type; 531 } 532 533 TypeData * build_global_scope() { 534 return new TypeData( TypeData::GlobalScope ); 535 } 536 537 TypeData * 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 544 TypeData * 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 552 TypeData * 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 560 TypeData * build_vtable_type( TypeData * base ) { 561 TypeData * type = new TypeData( TypeData::Vtable ); 562 type->base = base; 563 return type; 489 564 } 490 565 … … 627 702 return rtype; 628 703 } // if 704 } 705 706 TypeData * addType( TypeData * ltype, TypeData * rtype ) { 707 std::vector<ast::ptr<ast::Attribute>> attributes; 708 return addType( ltype, rtype, attributes ); 629 709 } 630 710 -
src/Parser/TypeData.h
r06601401 r03606ce 116 116 }; 117 117 118 119 TypeData * build_type_qualifier( ast::CV::Qualifiers ); 120 TypeData * build_basic_type( DeclarationNode::BasicType ); 121 TypeData * build_complex_type( DeclarationNode::ComplexType ); 122 TypeData * build_signedness( DeclarationNode::Signedness ); 123 TypeData * build_builtin_type( DeclarationNode::BuiltinType ); 124 TypeData * build_length( DeclarationNode::Length ); 125 TypeData * build_forall( DeclarationNode * ); 126 TypeData * build_global_scope(); 127 TypeData * build_qualified_type( TypeData *, TypeData * ); 128 TypeData * build_typedef( const std::string * name ); 129 TypeData * build_type_gen( const std::string * name, ExpressionNode * params ); 130 TypeData * build_vtable_type( TypeData * ); 131 118 132 TypeData * addQualifiers( TypeData * ltype, TypeData * rtype ); 119 133 TypeData * addType( TypeData * ltype, TypeData * rtype, std::vector<ast::ptr<ast::Attribute>> & ); 134 TypeData * addType( TypeData * ltype, TypeData * rtype ); 120 135 TypeData * cloneBaseType( TypeData * type, TypeData * other ); 121 136 TypeData * makeNewBase( TypeData * type ); 137 122 138 123 139 ast::Type * typebuild( const TypeData * ); … … 144 160 void buildKRFunction( const TypeData::Function_t & function ); 145 161 162 static inline ast::Type * maybeMoveBuildType( TypeData * type ) { 163 ast::Type * ret = type ? typebuild( type ) : nullptr; 164 delete type; 165 return ret; 166 } 167 146 168 // Local Variables: // 147 169 // tab-width: 4 // -
src/Parser/TypedefTable.cc
r06601401 r03606ce 20 20 #include <string> // for string 21 21 #include <iostream> // for iostream 22 23 struct TypeData; 22 24 23 25 #include "ExpressionNode.h" // for LabelNode -
src/Parser/parser.yy
r06601401 r03606ce 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 4 08:44:25 202413 // Update Count : 65 6212 // Last Modified On : Wed Mar 6 10:51:55 2024 13 // Update Count : 6588 14 14 // 15 15 … … 317 317 318 318 %union { 319 // A raw token can be used. 319 320 Token tok; 321 322 // The general node types hold some generic node or list of nodes. 323 DeclarationNode * decl; 324 InitializerNode * init; 320 325 ExpressionNode * expr; 321 DeclarationNode * decl;322 ast::AggregateDecl::Aggregate aggKey;323 ast::TypeDecl::Kind tclass;324 326 StatementNode * stmt; 325 327 ClauseNode * clause; 326 ast::WaitForStmt * wfs; 327 ast::WaitUntilStmt::ClauseNode * wucn; 328 TypeData * type; 329 330 // Special "nodes" containing compound information. 328 331 CondCtl * ifctl; 329 332 ForCtrl * forctl; 330 333 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; 332 338 OperKinds oper; 333 std::string * str;334 339 bool is_volatile; 335 340 EnumHiding enum_hiding; 336 341 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; 337 348 ast::GenericExpr * genexpr; 338 349 } … … 464 475 465 476 %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 467 479 468 480 %type<decl> trait_declaration trait_declaration_list trait_declaring_list trait_specifier … … 519 531 %type<decl> type_declarator type_declarator_name type_declaring_list 520 532 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 522 535 %type<decl> typedef_name typedef_declaration typedef_expression 523 536 … … 532 545 %type<expr> type_parameters_opt type_list array_type_list // array_dimension_list 533 546 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 535 549 %type<decl> type_specifier type_specifier_nobody 536 550 … … 687 701 { $$ = new ExpressionNode( build_varref( yylloc, $1 ) ); } 688 702 | TYPEDIMname // CFA, generic length argument 689 // { $$ = new ExpressionNode( new TypeExpr( maybeMoveBuildType( DeclarationNode::newFromTypedef( $1 ) ) ) ); }690 // { $$ = new ExpressionNode( build_varref( $1 ) ); }691 703 { $$ = new ExpressionNode( build_dimensionref( yylloc, $1 ) ); } 692 704 | tuple … … 696 708 { $$ = new ExpressionNode( new ast::StmtExpr( yylloc, dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( $2 ) ) ) ); } 697 709 | 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 ) ) ); } 699 711 | type_name '.' '[' field_name_list ']' // CFA, nested type / tuple field selector 700 712 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } … … 751 763 // Switching to this behaviour may help check if a C compatibilty case uses comma-exprs in subscripts. 752 764 // 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 ) ) ) ) ); } 754 766 | postfix_expression '[' assignment_expression ']' 755 767 // CFA, comma_expression disallowed in this context because it results in a common user error: subscripting a … … 766 778 Token fn; 767 779 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 ) ) ) ); 769 781 } 770 782 | postfix_expression '(' argument_expression_list_opt ')' … … 772 784 | VA_ARG '(' primary_expression ',' declaration_specifier_nobody abstract_parameter_declarator_opt ')' 773 785 // { 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) ) ) ); } 776 788 | postfix_expression '`' identifier // CFA, postfix call 777 789 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); } … … 831 843 Token fn; 832 844 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 ) ) ); 834 846 } 835 847 ; … … 844 856 argument_expression 845 857 | argument_expression_list_opt ',' argument_expression 846 { $$ = (ExpressionNode *)($1->set_last( $3 )); }858 { $$ = $1->set_last( $3 ); } 847 859 ; 848 860 … … 856 868 field_name_list: // CFA, tuple field selector 857 869 field 858 | field_name_list ',' field { $$ = (ExpressionNode *)($1->set_last( $3 )); }870 | field_name_list ',' field { $$ = $1->set_last( $3 ); } 859 871 ; 860 872 … … 938 950 | ALIGNOF '(' type_no_function ')' // GCC, type alignment 939 951 { $$ = 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 940 960 | OFFSETOF '(' type_no_function ',' identifier ')' 941 961 { $$ = new ExpressionNode( build_offsetOf( yylloc, $3, build_varref( yylloc, $5 ) ) ); } 942 | TYPEID '(' type _no_function')'962 | TYPEID '(' type ')' 943 963 { 944 964 SemanticError( yylloc, "typeid name is currently unimplemented." ); $$ = nullptr; … … 970 990 { $$ = new ExpressionNode( build_keyword_cast( yylloc, $2, $5 ) ); } 971 991 | '(' 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 ) ); } 973 993 | '(' VIRTUAL type_no_function ')' cast_expression // CFA 974 994 { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $5 ), maybeMoveBuildType( $3 ) ) ); } … … 1142 1162 // { $$ = new ExpressionNode( build_tuple( $3 ) ); } 1143 1163 '[' ',' 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 ) ) ); } 1145 1165 | '[' 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 ) ) ); } 1147 1167 ; 1148 1168 … … 1152 1172 { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; } 1153 1173 | tuple_expression_list ',' assignment_expression 1154 { $$ = (ExpressionNode *)($1->set_last( $3 )); }1174 { $$ = $1->set_last( $3 ); } 1155 1175 | tuple_expression_list ',' '@' 1156 1176 { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; } … … 1238 1258 { assert( $1 ); $1->set_last( $2 ); $$ = $1; } 1239 1259 | 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; } 1241 1262 ; 1242 1263 … … 1246 1267 ; 1247 1268 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. 1253 1292 1254 1293 selection_statement: … … 1268 1307 // therefore, are removed from the grammar even though C allows it. The change also applies to choose 1269 1308 // 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; 1271 1310 } 1272 1311 | SWITCH '(' comma_expression ')' '{' error '}' // CFA, invalid syntax rule error … … 1277 1316 { 1278 1317 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; 1280 1319 } 1281 1320 | CHOOSE '(' comma_expression ')' '{' error '}' // CFA, invalid syntax rule … … 1679 1718 cast_expression 1680 1719 | cast_expression_list ',' cast_expression 1681 // { $$ = (ExpressionNode *)($1->set_last( $3 )); }1682 1720 { SemanticError( yylloc, "List of mutex member is currently unimplemented." ); $$ = nullptr; } 1683 1721 ; … … 1695 1733 { $$ = $3; } 1696 1734 | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')' 1697 { $$ = (ExpressionNode *)($3->set_last( $5 )); }1735 { $$ = $3->set_last( $5 ); } 1698 1736 ; 1699 1737 … … 1851 1889 asm_operand 1852 1890 | asm_operands_list ',' asm_operand 1853 { $$ = (ExpressionNode *)($1->set_last( $3 )); }1891 { $$ = $1->set_last( $3 ); } 1854 1892 ; 1855 1893 … … 1870 1908 { $$ = $1; } 1871 1909 | asm_clobbers_list_opt ',' string_literal 1872 { $$ = (ExpressionNode *)( $1->set_last( $3 )); }1910 { $$ = $1->set_last( $3 ); } 1873 1911 ; 1874 1912 … … 2188 2226 type_qualifier: 2189 2227 type_qualifier_name 2228 { $$ = DeclarationNode::newFromTypeData( $1 ); } 2190 2229 | attribute // trick handles most attribute locations 2191 2230 ; … … 2193 2232 type_qualifier_name: 2194 2233 CONST 2195 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Const ); }2234 { $$ = build_type_qualifier( ast::CV::Const ); } 2196 2235 | RESTRICT 2197 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Restrict ); }2236 { $$ = build_type_qualifier( ast::CV::Restrict ); } 2198 2237 | VOLATILE 2199 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Volatile ); }2238 { $$ = build_type_qualifier( ast::CV::Volatile ); } 2200 2239 | 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) 2202 2246 | forall 2203 { $$ = DeclarationNode::newForall( $1 ); }2247 { $$ = build_forall( $1 ); } 2204 2248 ; 2205 2249 … … 2251 2295 2252 2296 basic_type_name: 2297 basic_type_name_type 2298 { $$ = DeclarationNode::newFromTypeData( $1 ); } 2299 ; 2300 2301 // Just an intermediate value for conversion. 2302 basic_type_name_type: 2253 2303 VOID 2254 { $$ = DeclarationNode::newBasicType( DeclarationNode::Void ); }2304 { $$ = build_basic_type( DeclarationNode::Void ); } 2255 2305 | BOOL // C99 2256 { $$ = DeclarationNode::newBasicType( DeclarationNode::Bool ); }2306 { $$ = build_basic_type( DeclarationNode::Bool ); } 2257 2307 | CHAR 2258 { $$ = DeclarationNode::newBasicType( DeclarationNode::Char ); }2308 { $$ = build_basic_type( DeclarationNode::Char ); } 2259 2309 | INT 2260 { $$ = DeclarationNode::newBasicType( DeclarationNode::Int ); }2310 { $$ = build_basic_type( DeclarationNode::Int ); } 2261 2311 | INT128 2262 { $$ = DeclarationNode::newBasicType( DeclarationNode::Int128 ); }2312 { $$ = build_basic_type( DeclarationNode::Int128 ); } 2263 2313 | UINT128 2264 { $$ = DeclarationNode::newBasicType( DeclarationNode::Int128 )->addType( DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ); }2314 { $$ = addType( build_basic_type( DeclarationNode::Int128 ), build_signedness( DeclarationNode::Unsigned ) ); } 2265 2315 | FLOAT 2266 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float ); }2316 { $$ = build_basic_type( DeclarationNode::Float ); } 2267 2317 | DOUBLE 2268 { $$ = DeclarationNode::newBasicType( DeclarationNode::Double ); }2318 { $$ = build_basic_type( DeclarationNode::Double ); } 2269 2319 | uuFLOAT80 2270 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat80 ); }2320 { $$ = build_basic_type( DeclarationNode::uuFloat80 ); } 2271 2321 | uuFLOAT128 2272 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat128 ); }2322 { $$ = build_basic_type( DeclarationNode::uuFloat128 ); } 2273 2323 | uFLOAT16 2274 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat16 ); }2324 { $$ = build_basic_type( DeclarationNode::uFloat16 ); } 2275 2325 | uFLOAT32 2276 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32 ); }2326 { $$ = build_basic_type( DeclarationNode::uFloat32 ); } 2277 2327 | uFLOAT32X 2278 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32x ); }2328 { $$ = build_basic_type( DeclarationNode::uFloat32x ); } 2279 2329 | uFLOAT64 2280 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64 ); }2330 { $$ = build_basic_type( DeclarationNode::uFloat64 ); } 2281 2331 | uFLOAT64X 2282 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64x ); }2332 { $$ = build_basic_type( DeclarationNode::uFloat64x ); } 2283 2333 | uFLOAT128 2284 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat128 ); }2334 { $$ = build_basic_type( DeclarationNode::uFloat128 ); } 2285 2335 | DECIMAL32 2286 2336 { SemanticError( yylloc, "_Decimal32 is currently unimplemented." ); $$ = nullptr; } … … 2290 2340 { SemanticError( yylloc, "_Decimal128 is currently unimplemented." ); $$ = nullptr; } 2291 2341 | COMPLEX // C99 2292 { $$ = DeclarationNode::newComplexType( DeclarationNode::Complex ); }2342 { $$ = build_complex_type( DeclarationNode::Complex ); } 2293 2343 | IMAGINARY // C99 2294 { $$ = DeclarationNode::newComplexType( DeclarationNode::Imaginary ); }2344 { $$ = build_complex_type( DeclarationNode::Imaginary ); } 2295 2345 | SIGNED 2296 { $$ = DeclarationNode::newSignedNess( DeclarationNode::Signed ); }2346 { $$ = build_signedness( DeclarationNode::Signed ); } 2297 2347 | UNSIGNED 2298 { $$ = DeclarationNode::newSignedNess( DeclarationNode::Unsigned ); }2348 { $$ = build_signedness( DeclarationNode::Unsigned ); } 2299 2349 | SHORT 2300 { $$ = DeclarationNode::newLength( DeclarationNode::Short ); }2350 { $$ = build_length( DeclarationNode::Short ); } 2301 2351 | LONG 2302 { $$ = DeclarationNode::newLength( DeclarationNode::Long ); }2352 { $$ = build_length( DeclarationNode::Long ); } 2303 2353 | VA_LIST // GCC, __builtin_va_list 2304 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::Valist ); }2354 { $$ = build_builtin_type( DeclarationNode::Valist ); } 2305 2355 | AUTO_TYPE 2306 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::AutoType ); }2356 { $$ = build_builtin_type( DeclarationNode::AutoType ); } 2307 2357 | vtable 2308 2358 ; … … 2316 2366 vtable: 2317 2367 VTABLE '(' type_name ')' default_opt 2318 { $$ = DeclarationNode::newVtableType( $3 ); } 2319 // { SemanticError( yylloc, "vtable is currently unimplemented." ); $$ = nullptr; } 2368 { $$ = build_vtable_type( $3 ); } 2320 2369 ; 2321 2370 … … 2367 2416 { $$ = DeclarationNode::newTypeof( $3, true ); } 2368 2417 | ZERO_T // CFA 2369 { $$ = DeclarationNode::new BuiltinType( DeclarationNode::Zero); }2418 { $$ = DeclarationNode::newFromTypeData( build_builtin_type( DeclarationNode::Zero ) ); } 2370 2419 | ONE_T // CFA 2371 { $$ = DeclarationNode::new BuiltinType( DeclarationNode::One); }2420 { $$ = DeclarationNode::newFromTypeData( build_builtin_type( DeclarationNode::One ) ); } 2372 2421 ; 2373 2422 … … 2425 2474 type_type_specifier: // typedef types 2426 2475 type_name 2476 { $$ = DeclarationNode::newFromTypeData( $1 ); } 2427 2477 | type_qualifier_list type_name 2428 { $$ = $2->addQualifiers( $1 ); }2478 { $$ = DeclarationNode::newFromTypeData( $2 )->addQualifiers( $1 ); } 2429 2479 | type_type_specifier type_qualifier 2430 2480 { $$ = $1->addQualifiers( $2 ); } … … 2433 2483 type_name: 2434 2484 TYPEDEFname 2435 { $$ = DeclarationNode::newFromTypedef( $1 ); }2485 { $$ = build_typedef( $1 ); } 2436 2486 | '.' TYPEDEFname 2437 { $$ = DeclarationNode::newQualifiedType( DeclarationNode::newFromGlobalScope(), DeclarationNode::newFromTypedef( $2 ) ); }2487 { $$ = build_qualified_type( build_global_scope(), build_typedef( $2 ) ); } 2438 2488 | type_name '.' TYPEDEFname 2439 { $$ = DeclarationNode::newQualifiedType( $1, DeclarationNode::newFromTypedef( $3 ) ); }2489 { $$ = build_qualified_type( $1, build_typedef( $3 ) ); } 2440 2490 | typegen_name 2441 2491 | '.' typegen_name 2442 { $$ = DeclarationNode::newQualifiedType( DeclarationNode::newFromGlobalScope(), $2 ); }2492 { $$ = build_qualified_type( build_global_scope(), $2 ); } 2443 2493 | type_name '.' typegen_name 2444 { $$ = DeclarationNode::newQualifiedType( $1, $3 ); }2494 { $$ = build_qualified_type( $1, $3 ); } 2445 2495 ; 2446 2496 2447 2497 typegen_name: // CFA 2448 2498 TYPEGENname 2449 { $$ = DeclarationNode::newFromTypeGen( $1, nullptr ); }2499 { $$ = build_type_gen( $1, nullptr ); } 2450 2500 | TYPEGENname '(' ')' 2451 { $$ = DeclarationNode::newFromTypeGen( $1, nullptr ); }2501 { $$ = build_type_gen( $1, nullptr ); } 2452 2502 | TYPEGENname '(' type_list ')' 2453 { $$ = DeclarationNode::newFromTypeGen( $1, $3 ); }2503 { $$ = build_type_gen( $1, $3 ); } 2454 2504 ; 2455 2505 … … 2463 2513 | enum_type_nobody 2464 2514 ; 2515 2516 // ************************** AGGREGATE ******************************* 2465 2517 2466 2518 aggregate_type: // struct, union … … 2485 2537 '{' field_declaration_list_opt '}' type_parameters_opt 2486 2538 { 2487 DeclarationNode::newFromType def( $3);2539 DeclarationNode::newFromTypeData( build_typedef( $3 ) ); 2488 2540 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); 2489 2541 } … … 2495 2547 '{' field_declaration_list_opt '}' type_parameters_opt 2496 2548 { 2497 DeclarationNode::newFromType Gen( $3, nullptr);2549 DeclarationNode::newFromTypeData( build_type_gen( $3, nullptr ) ); 2498 2550 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); 2499 2551 } … … 2520 2572 // Create new generic declaration with same name as previous forward declaration, where the IDENTIFIER is 2521 2573 // 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 ); 2525 2576 } 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; 2529 2580 delete $3; 2530 2581 } … … 2544 2595 | EXCEPTION // CFA 2545 2596 { $$ = ast::AggregateDecl::Exception; } 2546 // { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = ast::AggregateDecl::NoAggregate; }2547 2597 ; 2548 2598 … … 2683 2733 ; 2684 2734 2685 // *********** 2686 // Enumeration 2687 // *********** 2735 // ************************** ENUMERATION ******************************* 2688 2736 2689 2737 enum_type: … … 2754 2802 | ENUM attribute_list_opt type_name 2755 2803 { 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 ); 2758 2806 } 2759 2807 ; … … 2763 2811 { $$ = DeclarationNode::newEnumValueGeneric( $2, $3 ); } 2764 2812 | INLINE type_name 2765 { $$ = DeclarationNode::newEnumInLine( *$2-> type->symbolic.name ); }2813 { $$ = DeclarationNode::newEnumInLine( *$2->symbolic.name ); } 2766 2814 | enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt 2767 2815 { $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); } … … 2785 2833 ; 2786 2834 2787 // ******************* 2788 // Function parameters 2789 // ******************* 2835 // ************************** FUNCTION PARAMETERS ******************************* 2790 2836 2791 2837 parameter_list_ellipsis_opt: … … 2810 2856 cfa_parameter_list_ellipsis_opt: // CFA, abstract + real 2811 2857 // empty 2812 { $$ = DeclarationNode::new BasicType( DeclarationNode::Void); }2858 { $$ = DeclarationNode::newFromTypeData( build_basic_type( DeclarationNode::Void ) ); } 2813 2859 | ELLIPSIS 2814 2860 { $$ = nullptr; } … … 2868 2914 | type_qualifier_list cfa_abstract_tuple identifier_or_type_name default_initializer_opt 2869 2915 { $$ = $2->addName( $3 )->addQualifiers( $1 ); } 2870 | cfa_function_specifier 2916 | cfa_function_specifier // int f( "int fp()" ); 2871 2917 ; 2872 2918 … … 2878 2924 | type_qualifier_list cfa_abstract_tuple 2879 2925 { $$ = $2->addQualifiers( $1 ); } 2880 | cfa_abstract_function 2926 | cfa_abstract_function // int f( "int ()" ); 2881 2927 ; 2882 2928 … … 2928 2974 | initializer 2929 2975 | 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 ) ); } 2932 2978 ; 2933 2979 … … 2951 2997 designator 2952 2998 | designator_list designator 2953 { $$ = (ExpressionNode *)($1->set_last( $2 )); }2999 { $$ = $1->set_last( $2 ); } 2954 3000 //| designator_list designator { $$ = new ExpressionNode( $1, $2 ); } 2955 3001 ; … … 3036 3082 { $$ = ast::TypeDecl::Dtype; } 3037 3083 | '*' 3038 { $$ = ast::TypeDecl::DStype; } // dtype + sized3039 // | '(' '*' ')' 3040 // { $$ = ast::TypeDecl::Ftype; }3084 { $$ = ast::TypeDecl::DStype; } // Dtype + sized 3085 // | '(' '*' ')' // Gregor made me do it 3086 // { $$ = ast::TypeDecl::Ftype; } 3041 3087 | ELLIPSIS 3042 3088 { $$ = ast::TypeDecl::Ttype; } … … 3080 3126 | assignment_expression 3081 3127 | 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 ) ) ) ); } 3083 3129 | type_list ',' assignment_expression 3084 { $$ = (ExpressionNode *)( $1->set_last( $3 )); }3130 { $$ = $1->set_last( $3 ); } 3085 3131 ; 3086 3132 … … 3244 3290 $$ = $6; 3245 3291 } 3246 // global distribution3292 // global distribution 3247 3293 | type_qualifier_list 3248 3294 { … … 3369 3415 ; 3370 3416 3417 // **************************** ASM ***************************** 3418 3371 3419 asm_name_opt: // GCC 3372 3420 // empty … … 3379 3427 } 3380 3428 ; 3429 3430 // **************************** ATTRIBUTE ***************************** 3381 3431 3382 3432 attribute_list_opt: // GCC … … 3742 3792 { $$ = $1->addQualifiers( $2 ); } 3743 3793 | '&' MUTEX paren_identifier attribute_list_opt 3744 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::new TypeQualifier( ast::CV::Mutex),3794 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newFromTypeData( build_type_qualifier( ast::CV::Mutex ) ), 3745 3795 OperKinds::AddressOf ) )->addQualifiers( $4 ); } 3746 3796 | identifier_parameter_ptr … … 3793 3843 { $$ = $1->addQualifiers( $2 ); } 3794 3844 | '&' MUTEX typedef_name attribute_list_opt 3795 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::new TypeQualifier( ast::CV::Mutex),3845 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newFromTypeData( build_type_qualifier( ast::CV::Mutex ) ), 3796 3846 OperKinds::AddressOf ) )->addQualifiers( $4 ); } 3797 3847 | type_parameter_ptr … … 3826 3876 3827 3877 type_parameter_function: 3828 typedef_name '(' parameter_list_ellipsis_opt ')' 3878 typedef_name '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3) 3829 3879 { $$ = $1->addParamList( $3 ); } 3830 3880 | '(' type_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3) … … 3876 3926 3877 3927 abstract_function: 3878 '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)3928 '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3) 3879 3929 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); } 3880 3930 | '(' abstract_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3) … … 3915 3965 | assignment_expression upupeq assignment_expression 3916 3966 | 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 ) ) ) ); } 3918 3968 | 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 ) ) ) ); } 3920 3970 | array_type_list ',' assignment_expression upupeq assignment_expression 3921 3971 ; … … 3977 4027 abstract_parameter_ptr 3978 4028 | '&' MUTEX attribute_list_opt 3979 { $$ = DeclarationNode::newPointer( DeclarationNode::new TypeQualifier( ast::CV::Mutex), OperKinds::AddressOf )->addQualifiers( $3 ); }4029 { $$ = DeclarationNode::newPointer( DeclarationNode::newFromTypeData( build_type_qualifier( ast::CV::Mutex ) ), OperKinds::AddressOf )->addQualifiers( $3 ); } 3980 4030 | abstract_parameter_array attribute_list_opt 3981 4031 { $$ = $1->addQualifiers( $2 ); } … … 4008 4058 4009 4059 abstract_parameter_function: 4010 '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)4060 '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3) 4011 4061 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); } 4012 4062 | '(' abstract_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3) … … 4280 4330 // mode: c++ // 4281 4331 // tab-width: 4 // 4282 // compile-command: " make install" //4332 // compile-command: "bison -Wcounterexamples parser.yy" // 4283 4333 // End: // -
tests/.expect/functions.arm64.txt
r06601401 r03606ce 94 94 __attribute__ ((unused)) const signed int _X11_retval_fO5Ki_1; 95 95 } 96 void _X1fFv___1(void); 97 void _X1fFv___1(void); 96 98 signed int _X1fFi___1(void); 97 signed int _X1fFi_i__1(signed int __anonymous_object4); 99 void _X1fFv_i__1(signed int __anonymous_object4); 100 void _X1fFv_i__1(signed int __anonymous_object5); 101 signed int _X1fFi_i__1(signed int __anonymous_object6); 102 void _X1fFv___1(void){ 103 } 104 void _X2fvFv___1(void){ 105 } 98 106 signed int _X1fFi___1(void){ 99 107 __attribute__ ((unused)) signed int _X9_retval_fi_1; 100 108 } 101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object5){ 109 void _X1fFv_i__1(__attribute__ ((unused)) signed int __anonymous_object7){ 110 } 111 void _X2fvFv_i__1(__attribute__ ((unused)) signed int __anonymous_object8){ 112 } 113 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object9){ 102 114 __attribute__ ((unused)) signed int _X9_retval_fi_1; 103 115 } 104 116 signed int _X1fFi___1(void); 117 void _X1fFv_i__1(signed int _X1xi_1); 118 void _X2fvFv_i__1(signed int _X1xi_1); 119 void _X2f2Fv_i__1(signed int _X1xi_1){ 120 } 121 void _X3fv1Fv_i__1(signed int _X1xi_1){ 122 } 105 123 struct _tuple2_ { 106 124 }; … … 127 145 }; 128 146 struct _conc__tuple2_0 _X1fFT2ii___1(void); 129 struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object6, signed int _X1xi_1); 147 void _X1fFv_ii__1(signed int __anonymous_object10, signed int _X1xi_1); 148 void _X2fvFv_ii__1(signed int __anonymous_object11, signed int _X1xi_1); 149 struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object12, signed int _X1xi_1); 130 150 struct _conc__tuple2_0 _X1fFT2ii___1(void){ 131 151 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 132 152 } 133 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object7, signed int _X1xi_1){ 153 void _X1fFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1){ 154 } 155 void _X2fvFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object14, signed int _X1xi_1){ 156 } 157 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1){ 134 158 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 135 159 } … … 165 189 }; 166 190 struct _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); 191 void _X1fFv_iii__1(signed int __anonymous_object16, signed int _X1xi_1, signed int __anonymous_object17); 192 void _X2fvFv_iii__1(signed int __anonymous_object18, signed int _X1xi_1, signed int __anonymous_object19); 193 struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object20, signed int _X1xi_1, signed int __anonymous_object21); 168 194 struct _conc__tuple3_1 _X1fFT3iii___1(void){ 169 195 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 170 196 } 171 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object10, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object11){ 197 void _X1fFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object22, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object23){ 198 } 199 void _X2fvFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object24, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object25){ 200 } 201 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object26, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object27){ 172 202 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 173 203 } … … 179 209 }; 180 210 struct _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); 211 void _X1fFv_iiPi__1(signed int __anonymous_object28, signed int _X1xi_1, signed int *_X1yPi_1); 212 void _X2fvFv_iiPi__1(signed int __anonymous_object29, signed int _X1xi_1, signed int *_X1yPi_1); 213 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object30, signed int _X1xi_1, signed int *_X1yPi_1); 182 214 struct _conc__tuple3_2 _X1fFT3iiPi___1(void){ 183 215 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 184 216 } 185 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1, signed int *_X1yPi_1){ 217 void _X1fFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object31, signed int _X1xi_1, signed int *_X1yPi_1){ 218 } 219 void _X2fvFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object32, signed int _X1xi_1, signed int *_X1yPi_1){ 220 } 221 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object33, signed int _X1xi_1, signed int *_X1yPi_1){ 186 222 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 187 223 } 188 signed int _X3f11Fi_i__1(signed int __anonymous_object 14);224 signed int _X3f11Fi_i__1(signed int __anonymous_object34); 189 225 signed int _X3f12Fi___1(void); 190 226 const double _X4bar1Fd___1(); 191 const double _X4bar2Fd_i__1(signed int __anonymous_object 15);192 const double _X4bar3Fd_d__1(double __anonymous_object 16);227 const double _X4bar2Fd_i__1(signed int __anonymous_object35); 228 const double _X4bar3Fd_d__1(double __anonymous_object36); 193 229 const double _X3fooFd___1(void); 194 const double _X3fooFd_i__1(signed int __anonymous_object 17);195 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object 18){230 const double _X3fooFd_i__1(signed int __anonymous_object37); 231 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object38){ 196 232 __attribute__ ((unused)) const double _X11_retval_fooKd_1; 197 233 { … … 245 281 246 282 } 247 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object 19){283 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object39){ 248 284 __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1; 249 285 } 250 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object 20)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object21)(signed int __param_0)){286 signed 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)){ 251 287 __attribute__ ((unused)) signed int _X9_retval_fi_1; 252 288 signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)]; … … 274 310 __attribute__ ((unused)) const struct _conc__tuple2_3 _X10_retval_f5KT2PiKi_1; 275 311 } 276 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object 22)(), 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_object 37)(), __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]){312 signed 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]); 313 signed 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]){ 278 314 __attribute__ ((unused)) signed int _X9_retval_fi_1; 279 315 } -
tests/.expect/functions.x64.txt
r06601401 r03606ce 94 94 __attribute__ ((unused)) const signed int _X11_retval_fO5Ki_1; 95 95 } 96 void _X1fFv___1(void); 97 void _X1fFv___1(void); 96 98 signed int _X1fFi___1(void); 97 signed int _X1fFi_i__1(signed int __anonymous_object4); 99 void _X1fFv_i__1(signed int __anonymous_object4); 100 void _X1fFv_i__1(signed int __anonymous_object5); 101 signed int _X1fFi_i__1(signed int __anonymous_object6); 102 void _X1fFv___1(void){ 103 } 104 void _X2fvFv___1(void){ 105 } 98 106 signed int _X1fFi___1(void){ 99 107 __attribute__ ((unused)) signed int _X9_retval_fi_1; 100 108 } 101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object5){ 109 void _X1fFv_i__1(__attribute__ ((unused)) signed int __anonymous_object7){ 110 } 111 void _X2fvFv_i__1(__attribute__ ((unused)) signed int __anonymous_object8){ 112 } 113 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object9){ 102 114 __attribute__ ((unused)) signed int _X9_retval_fi_1; 103 115 } 104 116 signed int _X1fFi___1(void); 117 void _X1fFv_i__1(signed int _X1xi_1); 118 void _X2fvFv_i__1(signed int _X1xi_1); 119 void _X2f2Fv_i__1(signed int _X1xi_1){ 120 } 121 void _X3fv1Fv_i__1(signed int _X1xi_1){ 122 } 105 123 struct _tuple2_ { 106 124 }; … … 127 145 }; 128 146 struct _conc__tuple2_0 _X1fFT2ii___1(void); 129 struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object6, signed int _X1xi_1); 147 void _X1fFv_ii__1(signed int __anonymous_object10, signed int _X1xi_1); 148 void _X2fvFv_ii__1(signed int __anonymous_object11, signed int _X1xi_1); 149 struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object12, signed int _X1xi_1); 130 150 struct _conc__tuple2_0 _X1fFT2ii___1(void){ 131 151 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 132 152 } 133 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object7, signed int _X1xi_1){ 153 void _X1fFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1){ 154 } 155 void _X2fvFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object14, signed int _X1xi_1){ 156 } 157 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1){ 134 158 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 135 159 } … … 165 189 }; 166 190 struct _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); 191 void _X1fFv_iii__1(signed int __anonymous_object16, signed int _X1xi_1, signed int __anonymous_object17); 192 void _X2fvFv_iii__1(signed int __anonymous_object18, signed int _X1xi_1, signed int __anonymous_object19); 193 struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object20, signed int _X1xi_1, signed int __anonymous_object21); 168 194 struct _conc__tuple3_1 _X1fFT3iii___1(void){ 169 195 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 170 196 } 171 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object10, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object11){ 197 void _X1fFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object22, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object23){ 198 } 199 void _X2fvFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object24, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object25){ 200 } 201 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object26, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object27){ 172 202 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 173 203 } … … 179 209 }; 180 210 struct _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); 211 void _X1fFv_iiPi__1(signed int __anonymous_object28, signed int _X1xi_1, signed int *_X1yPi_1); 212 void _X2fvFv_iiPi__1(signed int __anonymous_object29, signed int _X1xi_1, signed int *_X1yPi_1); 213 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object30, signed int _X1xi_1, signed int *_X1yPi_1); 182 214 struct _conc__tuple3_2 _X1fFT3iiPi___1(void){ 183 215 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 184 216 } 185 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1, signed int *_X1yPi_1){ 217 void _X1fFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object31, signed int _X1xi_1, signed int *_X1yPi_1){ 218 } 219 void _X2fvFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object32, signed int _X1xi_1, signed int *_X1yPi_1){ 220 } 221 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object33, signed int _X1xi_1, signed int *_X1yPi_1){ 186 222 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 187 223 } 188 signed int _X3f11Fi_i__1(signed int __anonymous_object 14);224 signed int _X3f11Fi_i__1(signed int __anonymous_object34); 189 225 signed int _X3f12Fi___1(void); 190 226 const double _X4bar1Fd___1(); 191 const double _X4bar2Fd_i__1(signed int __anonymous_object 15);192 const double _X4bar3Fd_d__1(double __anonymous_object 16);227 const double _X4bar2Fd_i__1(signed int __anonymous_object35); 228 const double _X4bar3Fd_d__1(double __anonymous_object36); 193 229 const double _X3fooFd___1(void); 194 const double _X3fooFd_i__1(signed int __anonymous_object 17);195 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object 18){230 const double _X3fooFd_i__1(signed int __anonymous_object37); 231 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object38){ 196 232 __attribute__ ((unused)) const double _X11_retval_fooKd_1; 197 233 { … … 245 281 246 282 } 247 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object 19){283 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object39){ 248 284 __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1; 249 285 } 250 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object 20)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object21)(signed int __param_0)){286 signed 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)){ 251 287 __attribute__ ((unused)) signed int _X9_retval_fi_1; 252 288 signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)]; … … 274 310 __attribute__ ((unused)) const struct _conc__tuple2_3 _X10_retval_f5KT2PiKi_1; 275 311 } 276 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object 22)(), 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_object 37)(), __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]){312 signed 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]); 313 signed 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]){ 278 314 __attribute__ ((unused)) signed int _X9_retval_fi_1; 279 315 } -
tests/.expect/functions.x86.txt
r06601401 r03606ce 94 94 __attribute__ ((unused)) const signed int _X11_retval_fO5Ki_1; 95 95 } 96 void _X1fFv___1(void); 97 void _X1fFv___1(void); 96 98 signed int _X1fFi___1(void); 97 signed int _X1fFi_i__1(signed int __anonymous_object4); 99 void _X1fFv_i__1(signed int __anonymous_object4); 100 void _X1fFv_i__1(signed int __anonymous_object5); 101 signed int _X1fFi_i__1(signed int __anonymous_object6); 102 void _X1fFv___1(void){ 103 } 104 void _X2fvFv___1(void){ 105 } 98 106 signed int _X1fFi___1(void){ 99 107 __attribute__ ((unused)) signed int _X9_retval_fi_1; 100 108 } 101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object5){ 109 void _X1fFv_i__1(__attribute__ ((unused)) signed int __anonymous_object7){ 110 } 111 void _X2fvFv_i__1(__attribute__ ((unused)) signed int __anonymous_object8){ 112 } 113 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object9){ 102 114 __attribute__ ((unused)) signed int _X9_retval_fi_1; 103 115 } 104 116 signed int _X1fFi___1(void); 117 void _X1fFv_i__1(signed int _X1xi_1); 118 void _X2fvFv_i__1(signed int _X1xi_1); 119 void _X2f2Fv_i__1(signed int _X1xi_1){ 120 } 121 void _X3fv1Fv_i__1(signed int _X1xi_1){ 122 } 105 123 struct _tuple2_ { 106 124 }; … … 127 145 }; 128 146 struct _conc__tuple2_0 _X1fFT2ii___1(void); 129 struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object6, signed int _X1xi_1); 147 void _X1fFv_ii__1(signed int __anonymous_object10, signed int _X1xi_1); 148 void _X2fvFv_ii__1(signed int __anonymous_object11, signed int _X1xi_1); 149 struct _conc__tuple2_0 _X1fFT2ii_ii__1(signed int __anonymous_object12, signed int _X1xi_1); 130 150 struct _conc__tuple2_0 _X1fFT2ii___1(void){ 131 151 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 132 152 } 133 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object7, signed int _X1xi_1){ 153 void _X1fFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1){ 154 } 155 void _X2fvFv_ii__1(__attribute__ ((unused)) signed int __anonymous_object14, signed int _X1xi_1){ 156 } 157 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1){ 134 158 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 135 159 } … … 165 189 }; 166 190 struct _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); 191 void _X1fFv_iii__1(signed int __anonymous_object16, signed int _X1xi_1, signed int __anonymous_object17); 192 void _X2fvFv_iii__1(signed int __anonymous_object18, signed int _X1xi_1, signed int __anonymous_object19); 193 struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object20, signed int _X1xi_1, signed int __anonymous_object21); 168 194 struct _conc__tuple3_1 _X1fFT3iii___1(void){ 169 195 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 170 196 } 171 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object10, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object11){ 197 void _X1fFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object22, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object23){ 198 } 199 void _X2fvFv_iii__1(__attribute__ ((unused)) signed int __anonymous_object24, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object25){ 200 } 201 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object26, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object27){ 172 202 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 173 203 } … … 179 209 }; 180 210 struct _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); 211 void _X1fFv_iiPi__1(signed int __anonymous_object28, signed int _X1xi_1, signed int *_X1yPi_1); 212 void _X2fvFv_iiPi__1(signed int __anonymous_object29, signed int _X1xi_1, signed int *_X1yPi_1); 213 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(signed int __anonymous_object30, signed int _X1xi_1, signed int *_X1yPi_1); 182 214 struct _conc__tuple3_2 _X1fFT3iiPi___1(void){ 183 215 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 184 216 } 185 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object13, signed int _X1xi_1, signed int *_X1yPi_1){ 217 void _X1fFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object31, signed int _X1xi_1, signed int *_X1yPi_1){ 218 } 219 void _X2fvFv_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object32, signed int _X1xi_1, signed int *_X1yPi_1){ 220 } 221 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object33, signed int _X1xi_1, signed int *_X1yPi_1){ 186 222 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 187 223 } 188 signed int _X3f11Fi_i__1(signed int __anonymous_object 14);224 signed int _X3f11Fi_i__1(signed int __anonymous_object34); 189 225 signed int _X3f12Fi___1(void); 190 226 const double _X4bar1Fd___1(); 191 const double _X4bar2Fd_i__1(signed int __anonymous_object 15);192 const double _X4bar3Fd_d__1(double __anonymous_object 16);227 const double _X4bar2Fd_i__1(signed int __anonymous_object35); 228 const double _X4bar3Fd_d__1(double __anonymous_object36); 193 229 const double _X3fooFd___1(void); 194 const double _X3fooFd_i__1(signed int __anonymous_object 17);195 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object 18){230 const double _X3fooFd_i__1(signed int __anonymous_object37); 231 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object38){ 196 232 __attribute__ ((unused)) const double _X11_retval_fooKd_1; 197 233 { … … 245 281 246 282 } 247 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object 19){283 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object39){ 248 284 __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1; 249 285 } 250 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object 20)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object21)(signed int __param_0)){286 signed 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)){ 251 287 __attribute__ ((unused)) signed int _X9_retval_fi_1; 252 288 signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned int )10)])[][((unsigned int )3)]; … … 274 310 __attribute__ ((unused)) const struct _conc__tuple2_3 _X10_retval_f5KT2PiKi_1; 275 311 } 276 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object 22)(), 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_object 37)(), __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]){312 signed 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]); 313 signed 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]){ 278 314 __attribute__ ((unused)) signed int _X9_retval_fi_1; 279 315 } -
tests/functions.cfa
r06601401 r03606ce 10 10 // Created On : Wed Aug 17 08:39:58 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Nov 6 17:54:09 201813 // Update Count : 1312 // Last Modified On : Tue Mar 5 11:02:25 2024 13 // Update Count : 34 14 14 // 15 15 16 16 // ANSI function definitions 17 17 18 void h( void) {}18 void h( void ) {} 19 19 20 20 int f ( 21 int ( void),22 int ( int),23 int (( void)),24 int (( int)),25 void g( void)26 27 (* 21 int ( void ), 22 int ( int ), 23 int (( void )), 24 int (( int )), 25 void g( void ) 26 ) { 27 (*g)(); 28 28 g(); 29 29 g = h; … … 32 32 int f1() {} 33 33 int (f2()) {} 34 int (* 34 int (*f3())() {} 35 35 int * ((f4())) {} 36 int ((* 36 int ((*f5()))() {} 37 37 int * f6() {} 38 int * ( f7)() {}38 int * ( f7)() {} 39 39 int ** f8() {} 40 int * const * ( f9)() {}40 int * const * ( f9)() {} 41 41 int (* f10())[] {} 42 42 int (* f11())[][3] {} … … 66 66 // Cforall extensions 67 67 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 ) {} 104 116 105 117 // function prototypes … … 116 128 int ( int, int p ), 117 129 [int](int) 118 119 int (* (* pc )[][10])[][3];130 ) { 131 int (* (* pc )[][10])[][3]; 120 132 * [][10] * [][3] int p; 121 * [] * [int]( int) p;133 * [] * [int]( int ) p; 122 134 } 123 135 … … 149 161 int * const * const ([]), 150 162 int * const * const ([10]) 151 163 ); 152 164 153 165 int f( … … 170 182 int * const * const ([]), 171 183 int * const * const ([10]) 172 ) { 173 } 184 ) {} 174 185 175 186 typedef int T; 176 187 177 int f( T ( * f), T t ) {178 T ( T);188 int f( T ( *f ), T t ) { 189 T ( T ); 179 190 } 180 191
Note:
See TracChangeset
for help on using the changeset viewer.