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