Changeset 99cadc60
- Timestamp:
- Jul 31, 2019, 3:26:06 PM (6 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 61cfae2
- Parents:
- c60a664 (diff), 40287c8 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 1 added
- 1 deleted
- 31 edited
Legend:
- Unmodified
- Added
- Removed
-
automake/cfa.m4
rc60a664 r99cadc60 66 66 "x86-64" ) cannon_arch_name="x64";; 67 67 "x86_64" ) cannon_arch_name="x64";; 68 "aarch64" ) cannon_arch_name="x64";; 68 69 "x86" ) cannon_arch_name="x86";; 69 70 "i386" ) cannon_arch_name="x86";; … … 75 76 "armv7l" ) cannon_arch_name="arm";; 76 77 *) 77 >&2 echo "Unk own architecture " $arch_name;78 >&2 echo "Unknown architecture " $arch_name; 78 79 exit 1 79 80 ;; -
benchmark/Makefile.am
rc60a664 r99cadc60 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Mon Ju n 24 16:45:42201914 ## Update Count : 5 313 ## Last Modified On : Mon Jul 29 18:02:19 2019 14 ## Update Count : 54 15 15 ############################################################################### 16 16 … … 50 50 REPEAT = ${abs_top_builddir}/tools/repeat 51 51 STATS = ${abs_top_srcdir}/tools/stat.py 52 repeats = 3 # 30 52 # NEED AT LEAST 4 DATA VALUES FOR BENCHMARKS BECAUSE THE MAX AND MIN VALUES ARE REMOVED 53 repeats = 5 # 31 for benchmarks 53 54 skipcompile = no 54 55 TIME_FORMAT = "%E" -
benchmark/creation/JavaThread.java
rc60a664 r99cadc60 1 1 public class JavaThread { 2 // Simplistic low-quality Marsaglia Shift-XOR pseudo-random number generator. 3 // Bijective 4 // Cycle length for non-zero values is 4G-1. 5 // 0 is absorbing and should be avoided -- fixed point. 6 // The returned value is typically masked to produce a positive value. 7 static volatile int Ticket = 0 ; 8 9 private static int nextRandom (int x) { 10 if (x == 0) { 11 // reseed the PRNG 12 // Ticket is accessed infrequently and does not constitute a coherence hot-spot. 13 // Note that we use a non-atomic racy increment -- the race is rare and benign. 14 // If the race is a concern switch to an AtomicInteger. 15 // In addition accesses to the RW volatile global "Ticket" variable are not 16 // (readily) predictable at compile-time so the JIT will not be able to elide 17 // nextRandom() invocations. 18 x = ++Ticket ; 19 if (x == 0) x = 1 ; 20 } 21 x ^= x << 6; 22 x ^= x >>> 21; 23 x ^= x << 7; 24 return x ; 25 } 26 static int x = 2; 27 28 static private final int NoOfTimes = Integer.parseInt("10000") ; 29 2 30 public static class MyThread extends Thread { 3 31 @Override 4 32 public void run() {} 5 33 } 6 7 public static void main(String[] args) throws InterruptedException { 8 int NoOfTimes = 50000; 9 long start = System.nanoTime(); 34 public static void helper() throws InterruptedException { 10 35 for(int i = 1; i <= NoOfTimes; i += 1) { 11 JavaThread.MyThread m = new JavaThread.MyThread(); 12 m.start(); 36 MyThread m = new MyThread(); 37 x = nextRandom( x ); 38 m.start(); 13 39 m.join(); 14 40 } 41 } 42 public static void InnerMain() throws InterruptedException { 43 long start = System.nanoTime(); 44 helper(); 15 45 long end = System.nanoTime(); 16 System.out.println( (end - start) / NoOfTimes); 46 System.out.println( (end - start) / NoOfTimes ); 47 } 48 public static void main(String[] args) throws InterruptedException { 49 for (int n = Integer.parseInt("5"); --n >= 0 ; ) { 50 InnerMain(); 51 Thread.sleep(2000); // 2 seconds 52 x = nextRandom(x); 53 } 54 if ( x == 0 ) System.out.println(x); 17 55 } 18 56 } -
benchmark/ctxswitch/JavaThread.java
rc60a664 r99cadc60 1 1 public class JavaThread { 2 public static void main(String[] args) { 3 int NoOfTimes = 5000000; 4 long start = System.nanoTime(); 2 // Simplistic low-quality Marsaglia Shift-XOR pseudo-random number generator. 3 // Bijective 4 // Cycle length for non-zero values is 4G-1. 5 // 0 is absorbing and should be avoided -- fixed point. 6 // The returned value is typically masked to produce a positive value. 7 static volatile int Ticket = 0 ; 8 9 private static int nextRandom (int x) { 10 if (x == 0) { 11 // reseed the PRNG 12 // Ticket is accessed infrequently and does not constitute a coherence hot-spot. 13 // Note that we use a non-atomic racy increment -- the race is rare and benign. 14 // If the race is a concern switch to an AtomicInteger. 15 // In addition accesses to the RW volatile global "Ticket" variable are not 16 // (readily) predictable at compile-time so the JIT will not be able to elide 17 // nextRandom() invocations. 18 x = ++Ticket ; 19 if (x == 0) x = 1 ; 20 } 21 x ^= x << 6; 22 x ^= x >>> 21; 23 x ^= x << 7; 24 return x ; 25 } 26 static int x = 2; 27 28 static private final int NoOfTimes = Integer.parseInt("1000000") ; 29 30 public static void helper() { 5 31 for(int i = 1; i <= NoOfTimes; i += 1) { 6 32 Thread.yield(); 7 33 } 34 } 35 public static void InnerMain() { 36 long start = System.nanoTime(); 37 helper(); 8 38 long end = System.nanoTime(); 9 System.out.println( (end - start) / NoOfTimes); 39 System.out.println( (end - start) / NoOfTimes ); 40 } 41 public static void main(String[] args) throws InterruptedException { 42 for (int n = Integer.parseInt("5"); --n >= 0 ; ) { 43 InnerMain(); 44 Thread.sleep(2000); // 2 seconds 45 x = nextRandom(x); 46 } 47 if ( x == 0 ) System.out.println(x); 10 48 } 11 49 } -
benchmark/mutex/JavaThread.java
rc60a664 r99cadc60 1 1 public class JavaThread { 2 public synchronized void noop() {} 2 // Simplistic low-quality Marsaglia Shift-XOR pseudo-random number generator. 3 // Bijective 4 // Cycle length for non-zero values is 4G-1. 5 // 0 is absorbing and should be avoided -- fixed point. 6 // The returned value is typically masked to produce a positive value. 7 static volatile int Ticket = 0 ; 3 8 4 public static void main(String[] args) { 5 int NoOfTimes = 5000000; 9 private static int nextRandom (int x) { 10 if (x == 0) { 11 // reseed the PRNG 12 // Ticket is accessed infrequently and does not constitute a coherence hot-spot. 13 // Note that we use a non-atomic racy increment -- the race is rare and benign. 14 // If the race is a concern switch to an AtomicInteger. 15 // In addition accesses to the RW volatile global "Ticket" variable are not 16 // (readily) predictable at compile-time so the JIT will not be able to elide 17 // nextRandom() invocations. 18 x = ++Ticket ; 19 if (x == 0) x = 1 ; 20 } 21 x ^= x << 6; 22 x ^= x >>> 21; 23 x ^= x << 7; 24 return x ; 25 } 26 static int x = 2; 27 28 static private final int NoOfTimes = Integer.parseInt("100000000") ; 29 30 public synchronized void noop() { 31 x = nextRandom( x ); 32 } 33 public static void helper() throws InterruptedException { 6 34 JavaThread j = new JavaThread(); 7 long start = System.nanoTime(); 35 // Inhibit biased locking ... 36 x = (j.hashCode() ^ System.identityHashCode(j)) | 1 ; 8 37 for(int i = 1; i <= NoOfTimes; i += 1) { 38 x = nextRandom(x); 9 39 j.noop(); 10 40 } 41 } 42 public static void InnerMain() throws InterruptedException { 43 long start = System.nanoTime(); 44 helper(); 11 45 long end = System.nanoTime(); 12 System.out.println( (end - start) / NoOfTimes); 46 System.out.println( (end - start) / NoOfTimes ); 47 } 48 public static void main(String[] args) throws InterruptedException { 49 for (int n = Integer.parseInt("5"); --n >= 0 ; ) { 50 InnerMain(); 51 Thread.sleep(2000); // 2 seconds 52 x = nextRandom(x); 53 } 54 if ( x == 0 ) System.out.println(x); 13 55 } 14 56 } -
benchmark/schedint/JavaThread.java
rc60a664 r99cadc60 1 1 class Monitor { 2 2 public static volatile Boolean go = false; 3 public static volatile Boolean next = false; 3 4 } 4 5 … … 13 14 while( Monitor.go ) { 14 15 synchronized(this.m) { 16 Monitor.next = false; 15 17 this.m.notify(); 16 18 } 19 while( ! Monitor.next && Monitor.go ); // spin until woken 17 20 } 18 21 } … … 20 23 21 24 public class JavaThread { 22 public static void main(String[] args) throws InterruptedException { 23 int NoOfTimes = 50000; 25 // Simplistic low-quality Marsaglia Shift-XOR pseudo-random number generator. 26 // Bijective 27 // Cycle length for non-zero values is 4G-1. 28 // 0 is absorbing and should be avoided -- fixed point. 29 // The returned value is typically masked to produce a positive value. 30 static volatile int Ticket = 0 ; 31 32 private static int nextRandom (int x) { 33 if (x == 0) { 34 // reseed the PRNG 35 // Ticket is accessed infrequently and does not constitute a coherence hot-spot. 36 // Note that we use a non-atomic racy increment -- the race is rare and benign. 37 // If the race is a concern switch to an AtomicInteger. 38 // In addition accesses to the RW volatile global "Ticket" variable are not 39 // (readily) predictable at compile-time so the JIT will not be able to elide 40 // nextRandom() invocations. 41 x = ++Ticket ; 42 if (x == 0) x = 1 ; 43 } 44 x ^= x << 6; 45 x ^= x >>> 21; 46 x ^= x << 7; 47 return x ; 48 } 49 static int x = 2; 50 51 static private final int NoOfTimes = Integer.parseInt("1000000") ; 52 53 public static void helper( Monitor m ) throws InterruptedException { 54 for(int i = 1; i <= NoOfTimes; i += 1) { 55 m.wait(); // relase monitor lock 56 m.next = true; 57 } 58 } 59 public static void InnerMain() throws InterruptedException { 24 60 Monitor m = new Monitor(); 25 61 long start, end; … … 31 67 } 32 68 start = System.nanoTime(); 33 for(int i = 1; i <= NoOfTimes; i += 1) { 34 m.wait(); 35 } 69 helper( m ); 36 70 end = System.nanoTime(); 37 71 } … … 40 74 System.out.println( (end - start) / NoOfTimes); 41 75 } 76 public static void main(String[] args) throws InterruptedException { 77 for (int n = Integer.parseInt("5"); --n >= 0 ; ) { 78 InnerMain(); 79 Thread.sleep(2000); // 2 seconds 80 x = nextRandom(x); 81 } 82 if ( x == 0 ) System.out.println(x); 83 } 42 84 } -
configure
rc60a664 r99cadc60 3433 3433 "x86-64" ) cannon_arch_name="x64";; 3434 3434 "x86_64" ) cannon_arch_name="x64";; 3435 "aarch64" ) cannon_arch_name="x64";; 3435 3436 "x86" ) cannon_arch_name="x86";; 3436 3437 "i386" ) cannon_arch_name="x86";; … … 3442 3443 "armv7l" ) cannon_arch_name="arm";; 3443 3444 *) 3444 >&2 echo "Unk own architecture " $arch_name;3445 >&2 echo "Unknown architecture " $arch_name; 3445 3446 exit 1 3446 3447 ;; … … 3474 3475 "x86-64" ) cannon_arch_name="x64";; 3475 3476 "x86_64" ) cannon_arch_name="x64";; 3477 "aarch64" ) cannon_arch_name="x64";; 3476 3478 "x86" ) cannon_arch_name="x86";; 3477 3479 "i386" ) cannon_arch_name="x86";; … … 3483 3485 "armv7l" ) cannon_arch_name="arm";; 3484 3486 *) 3485 >&2 echo "Unk own architecture " $arch_name;3487 >&2 echo "Unknown architecture " $arch_name; 3486 3488 exit 1 3487 3489 ;; -
doc/papers/concurrency/Paper.tex
rc60a664 r99cadc60 307 307 In many ways, \CFA is to C as Scala~\cite{Scala} is to Java, providing a \emph{research vehicle} for new typing and control-flow capabilities on top of a highly popular programming language allowing immediate dissemination. 308 308 Within the \CFA framework, new control-flow features are created from scratch because ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}. 309 However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}, and \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and a fewlocks, which is low-level and error-prone;309 However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}, and \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and mutex/condition locks, which is low-level and error-prone; 310 310 no high-level language concurrency features are defined. 311 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-9 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach .311 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-9 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach (possibly because the effort to add concurrency to \CC). 312 312 Finally, while the \Celeven standard does not state a threading model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}. 313 313 … … 333 333 334 334 Finally, it is important for a language to provide safety over performance \emph{as the default}, allowing careful reduction of safety for performance when necessary. 335 Two concurrency violations of this philosophy are \emph{spurious wakeup} (random wakeup~\cite[\S~8]{Buhr05a}) and \emph{barging} (signals-as-hints~\cite[\S~8]{Buhr05a}), where one is a consequence of the other, \ie once there is spurious wakeup, signals-as-hints follow. 335 Two concurrency violations of this philosophy are \emph{spurious wakeup} (random wakeup~\cite[\S~8]{Buhr05a}) and \emph{barging}\footnote{ 336 The notion of competitive succession instead of direct handoff, \ie a lock owner releases the lock and an arriving thread acquires it ahead of preexisting waiter threads. 337 } (signals-as-hints~\cite[\S~8]{Buhr05a}), where one is a consequence of the other, \ie once there is spurious wakeup, signals-as-hints follow. 336 338 However, spurious wakeup is \emph{not} a foundational concurrency property~\cite[\S~8]{Buhr05a}, it is a performance design choice. 337 339 Similarly, signals-as-hints are often a performance decision. … … 351 353 We present comparative examples so the reader can judge if the \CFA control-flow extensions are better and safer than those in other concurrent, imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms. 352 354 The main contributions of this work are: 353 \begin{itemize} 355 \begin{itemize}[topsep=3pt,itemsep=1pt] 354 356 \item 355 357 language-level generators, coroutines and user-level threading, which respect the expectations of C programmers. … … 370 372 \end{itemize} 371 373 374 Section~\ref{s:StatefulFunction} begins advanced control by introducing sequential functions that retain data and execution state between calls, which produces constructs @generator@ and @coroutine@. 375 Section~\ref{s:Concurrency} begins concurrency, or how to create (fork) and destroy (join) a thread, which produces the @thread@ construct. 376 Section~\ref{s:MutualExclusionSynchronization} discusses the two mechanisms to restricted nondeterminism when controlling shared access to resources (mutual exclusion) and timing relationships among threads (synchronization). 377 Section~\ref{s:Monitor} shows how both mutual exclusion and synchronization are safely embedded in the @monitor@ and @thread@ constructs. 378 Section~\ref{s:CFARuntimeStructure} describes the large-scale mechanism to structure (cluster) threads and virtual processors (kernel threads). 379 Section~\ref{s:Performance} uses a series of microbenchmarks to compare \CFA threading with pthreads, Java OpenJDK-9, Go 1.12.6 and \uC 7.0.0. 380 372 381 373 382 \section{Stateful Function} 383 \label{s:StatefulFunction} 374 384 375 385 The stateful function is an old idea~\cite{Conway63,Marlin80} that is new again~\cite{C++20Coroutine19}, where execution is temporarily suspended and later resumed, \eg plugin, device driver, finite-state machine. … … 617 627 Figure~\ref{f:CFibonacciSim} shows the C implementation of the \CFA generator only needs one additional field, @next@, to handle retention of execution state. 618 628 The computed @goto@ at the start of the generator main, which branches after the previous suspend, adds very little cost to the resume call. 619 Finally, an explicit generator type provides both design and performance benefits, such as multiple type-safe interface functions taking and returning arbitrary types. 629 Finally, an explicit generator type provides both design and performance benefits, such as multiple type-safe interface functions taking and returning arbitrary types.\footnote{ 630 The \CFA operator syntax uses \lstinline|?| to denote operands, which allows precise definitions for pre, post, and infix operators, \eg \lstinline|++?|, \lstinline|?++|, and \lstinline|?+?|, in addition \lstinline|?\{\}| denotes a constructor, as in \lstinline|foo `f` = `\{`...`\}`|, \lstinline|^?\{\}| denotes a destructor, and \lstinline|?()| is \CC function call \lstinline|operator()|. 631 }% 620 632 \begin{cfa} 621 633 int ?()( Fib & fib ) { return `resume( fib )`.fn; } $\C[3.9in]{// function-call interface}$ … … 1511 1523 1512 1524 \section{Mutual Exclusion / Synchronization} 1525 \label{s:MutualExclusionSynchronization} 1513 1526 1514 1527 Unrestricted nondeterminism is meaningless as there is no way to know when the result is completed without synchronization. … … 1551 1564 higher-level mechanisms often simplify usage by adding better coupling between synchronization and data, \eg receive-specific versus receive-any thread in message passing or offering specialized solutions, \eg barrier lock. 1552 1565 Often synchronization is used to order access to a critical section, \eg ensuring a waiting writer thread enters the critical section before a calling reader thread. 1553 If the calling reader is scheduled before the waiting writer, the reader has \newterm{barged}.1566 If the calling reader is scheduled before the waiting writer, the reader has barged. 1554 1567 Barging can result in staleness/freshness problems, where a reader barges ahead of a writer and reads temporally stale data, or a writer barges ahead of another writer overwriting data with a fresh value preventing the previous value from ever being read (lost computation). 1555 1568 Preventing or detecting barging is an involved challenge with low-level locks, which is made easier through higher-level constructs. … … 2120 2133 2121 2134 2122 \subsection{ Extended \protect\lstinline@waitfor@}2123 2124 Figure~\ref{f:ExtendedWaitfor} show the extended form of the @waitfor@ statement to conditionally accept one of a group of mutex functions, with an optional statement to be performed \emph{after} the mutex function finishes.2135 \subsection{\texorpdfstring{Extended \protect\lstinline@waitfor@}{Extended waitfor}} 2136 2137 Figure~\ref{f:ExtendedWaitfor} shows the extended form of the @waitfor@ statement to conditionally accept one of a group of mutex functions, with an optional statement to be performed \emph{after} the mutex function finishes. 2125 2138 For a @waitfor@ clause to be executed, its @when@ must be true and an outstanding call to its corresponding member(s) must exist. 2126 2139 The \emph{conditional-expression} of a @when@ may call a function, but the function must not block or context switch. … … 2131 2144 Hence, the terminating @else@ clause allows a conditional attempt to accept a call without blocking. 2132 2145 If both @timeout@ and @else@ clause are present, the @else@ must be conditional, or the @timeout@ is never triggered. 2146 There is also a traditional future wait queue (not shown) (\eg Microsoft (@WaitForMultipleObjects@)), to wait for a specified number of future elements in the queue. 2133 2147 2134 2148 \begin{figure} … … 2355 2369 2356 2370 2357 \subsection{\ protect\lstinline@mutex@ Threads}2371 \subsection{\texorpdfstring{\protect\lstinline@mutex@ Threads}{mutex Threads}} 2358 2372 2359 2373 Threads in \CFA can also be monitors to allow \emph{direct communication} among threads, \ie threads can have mutex functions that are called by other threads. … … 2499 2513 \renewcommand{\arraystretch}{1.25} 2500 2514 %\setlength{\tabcolsep}{5pt} 2501 \begin{tabular}{c|c| l|l}2502 \multicolumn{2}{c| }{object properties} & \multicolumn{2}{c}{mutual exclusion} \\2515 \begin{tabular}{c|c||l|l} 2516 \multicolumn{2}{c||}{object properties} & \multicolumn{2}{c}{mutual exclusion} \\ 2503 2517 \hline 2504 2518 thread & stateful & \multicolumn{1}{c|}{No} & \multicolumn{1}{c}{Yes} \\ … … 2605 2619 2606 2620 2607 \section{ \protect\CFARuntime Structure}2621 \section{Runtime Structure} 2608 2622 \label{s:CFARuntimeStructure} 2609 2623 … … 2709 2723 2710 2724 \section{Performance} 2711 \label{ results}2725 \label{s:Performance} 2712 2726 2713 2727 To verify the implementation of the \CFA runtime, a series of microbenchmarks are performed comparing \CFA with pthreads, Java OpenJDK-9, Go 1.12.6 and \uC 7.0.0. … … 2715 2729 The benchmark computer is an AMD Opteron\texttrademark\ 6380 NUMA 64-core, 8 socket, 2.5 GHz processor, running Ubuntu 16.04.6 LTS, and \CFA/\uC are compiled with gcc 6.5. 2716 2730 2717 All benchmarks are run using the following harness. 2731 All benchmarks are run using the following harness. (The Java harness is augmented to circumvent JIT issues.) 2718 2732 \begin{cfa} 2719 2733 unsigned int N = 10_000_000; … … 2754 2768 \begin{tabular}[t]{@{}r*{3}{D{.}{.}{5.2}}@{}} 2755 2769 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2756 \CFA Coroutine Lazy & 14.3 & 14.3 & 0.32 \\ 2757 \CFA Coroutine Eager & 522.8 & 525.3 & 5.81 \\ 2758 \CFA Thread & 1257.8 & 1291.2 & 86.19 \\ 2759 \uC Coroutine & 92.2 & 91.4 & 1.58 \\ 2760 \uC Thread & 499.5 & 500.1 & 5.67 \\ 2761 Goroutine & 4397.0 & 4362.8 & 390.77 \\ 2762 Java Thread & 107405.0 & 107794.8 & 1601.33 \\ 2763 % Qthreads & 159.9 & 159.6 & 0.73 \\ 2764 Pthreads & 32920.9 & 32882.7 & 213.55 2770 \CFA Coroutine Lazy & 13.2 & 13.1 & 0.44 \\ 2771 \CFA Coroutine Eager & 531.3 & 536.0 & 26.54 \\ 2772 \CFA Thread & 2074.9 & 2066.5 & 170.76 \\ 2773 \uC Coroutine & 89.6 & 90.5 & 1.83 \\ 2774 \uC Thread & 528.2 & 528.5 & 4.94 \\ 2775 Goroutine & 4068.0 & 4113.1 & 414.55 \\ 2776 Java Thread & 103848.5 & 104295.4 & 2637.57 \\ 2777 Pthreads & 33112.6 & 33127.1 & 165.90 2778 \end{tabular} 2779 \end{multicols} 2780 2781 2782 \paragraph{Context-Switching} 2783 2784 In procedural programming, the cost of a function call is important as modularization (refactoring) increases. 2785 (In many cases, a compiler inlines function calls to eliminate this cost.) 2786 Similarly, when modularization extends to coroutines/tasks, the time for a context switch becomes a relevant factor. 2787 The coroutine test is from resumer to suspender and from suspender to resumer, which is two context switches. 2788 The thread test is using yield to enter and return from the runtime kernel, which is two context switches. 2789 The difference in performance between coroutine and thread context-switch is the cost of scheduling for threads, whereas coroutines are self-scheduling. 2790 Figure~\ref{f:ctx-switch} only shows the \CFA code for coroutines/threads (other systems are similar) with all results in Table~\ref{tab:ctx-switch}. 2791 2792 \begin{multicols}{2} 2793 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}} 2794 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 2795 @coroutine@ C {} c; 2796 void main( C & ) { for ( ;; ) { @suspend;@ } } 2797 int main() { // coroutine test 2798 BENCH( for ( N ) { @resume( c );@ } ) 2799 sout | result`ns; 2800 } 2801 int main() { // task test 2802 BENCH( for ( N ) { @yield();@ } ) 2803 sout | result`ns; 2804 } 2805 \end{cfa} 2806 \captionof{figure}{\CFA context-switch benchmark} 2807 \label{f:ctx-switch} 2808 2809 \columnbreak 2810 2811 \vspace*{-16pt} 2812 \captionof{table}{Context switch comparison (nanoseconds)} 2813 \label{tab:ctx-switch} 2814 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}} 2815 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2816 C function & 1.8 & 1.8 & 0.01 \\ 2817 \CFA generator & 2.4 & 2.2 & 0.25 \\ 2818 \CFA Coroutine & 36.2 & 36.2 & 0.25 \\ 2819 \CFA Thread & 93.2 & 93.5 & 2.09 \\ 2820 \uC Coroutine & 52.0 & 52.1 & 0.51 \\ 2821 \uC Thread & 96.2 & 96.3 & 0.58 \\ 2822 Goroutine & 141.0 & 141.3 & 3.39 \\ 2823 Java Thread & 374.0 & 375.8 & 10.38 \\ 2824 Pthreads Thread & 361.0 & 365.3 & 13.19 2825 \end{tabular} 2826 \end{multicols} 2827 2828 2829 \paragraph{Mutual-Exclusion} 2830 2831 Uncontented mutual exclusion, which frequently occurs, is measured by entering/leaving a critical section. 2832 For monitors, entering and leaving a monitor function is measured. 2833 To put the results in context, the cost of entering a non-inline function and the cost of acquiring and releasing a @pthread_mutex@ lock is also measured. 2834 Figure~\ref{f:mutex} shows the code for \CFA with all results in Table~\ref{tab:mutex}. 2835 Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects. 2836 2837 \begin{multicols}{2} 2838 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}} 2839 \begin{cfa} 2840 @monitor@ M {} m1/*, m2, m3, m4*/; 2841 void __attribute__((noinline)) 2842 do_call( M & @mutex m/*, m2, m3, m4*/@ ) {} 2843 int main() { 2844 BENCH( 2845 for( N ) do_call( m1/*, m2, m3, m4*/ ); 2846 ) 2847 sout | result`ns; 2848 } 2849 \end{cfa} 2850 \captionof{figure}{\CFA acquire/release mutex benchmark} 2851 \label{f:mutex} 2852 2853 \columnbreak 2854 2855 \vspace*{-16pt} 2856 \captionof{table}{Mutex comparison (nanoseconds)} 2857 \label{tab:mutex} 2858 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}} 2859 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2860 test and test-and-test lock & 19.1 & 18.9 & 0.40 \\ 2861 \CFA @mutex@ function, 1 arg. & 45.9 & 46.6 & 1.45 \\ 2862 \CFA @mutex@ function, 2 arg. & 105.0 & 104.7 & 3.08 \\ 2863 \CFA @mutex@ function, 4 arg. & 165.0 & 167.6 & 5.65 \\ 2864 \uC @monitor@ member rtn. & 54.0 & 53.7 & 0.82 \\ 2865 Java synchronized method & 31.0 & 31.1 & 0.50 \\ 2866 Pthreads Mutex Lock & 33.6 & 32.6 & 1.14 2867 \end{tabular} 2868 \end{multicols} 2869 2870 2871 \paragraph{External Scheduling} 2872 2873 External scheduling is measured using a cycle of two threads calling and accepting the call using the @waitfor@ statement. 2874 Figure~\ref{f:ext-sched} shows the code for \CFA, with results in Table~\ref{tab:ext-sched}. 2875 Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects. 2876 2877 \begin{multicols}{2} 2878 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}} 2879 \vspace*{-16pt} 2880 \begin{cfa} 2881 volatile int go = 0; 2882 @monitor@ M {} m; 2883 thread T {}; 2884 void __attribute__((noinline)) 2885 do_call( M & @mutex@ ) {} 2886 void main( T & ) { 2887 while ( go == 0 ) { yield(); } 2888 while ( go == 1 ) { do_call( m ); } 2889 } 2890 int __attribute__((noinline)) 2891 do_wait( M & @mutex@ m ) { 2892 go = 1; // continue other thread 2893 BENCH( for ( N ) { @waitfor( do_call, m );@ } ) 2894 go = 0; // stop other thread 2895 sout | result`ns; 2896 } 2897 int main() { 2898 T t; 2899 do_wait( m ); 2900 } 2901 \end{cfa} 2902 \captionof{figure}{\CFA external-scheduling benchmark} 2903 \label{f:ext-sched} 2904 2905 \columnbreak 2906 2907 \vspace*{-16pt} 2908 \captionof{table}{External-scheduling comparison (nanoseconds)} 2909 \label{tab:ext-sched} 2910 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}} 2911 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2912 \CFA @waitfor@, 1 @monitor@ & 376.4 & 376.8 & 7.63 \\ 2913 \CFA @waitfor@, 2 @monitor@ & 491.4 & 492.0 & 13.31 \\ 2914 \CFA @waitfor@, 4 @monitor@ & 681.0 & 681.7 & 19.10 \\ 2915 \uC @_Accept@ & 331.1 & 331.4 & 2.66 2765 2916 \end{tabular} 2766 2917 \end{multicols} … … 2810 2961 \begin{tabular}{@{}r*{3}{D{.}{.}{5.2}}@{}} 2811 2962 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2812 \CFA @signal@, 1 @monitor@ & 367.0 & 371.5 & 17.34 \\ 2813 \CFA @signal@, 2 @monitor@ & 477.2 & 478.6 & 8.31 \\ 2814 \CFA @signal@, 4 @monitor@ & 725.8 & 734.0 & 17.98 \\ 2815 \uC @signal@ & 322.8 & 323.0 & 3.64 \\ 2816 Java @notify@ & 16520.0 & 20096.7 & 9378.53 \\ 2817 Pthreads Cond. Variable & 4931.3 & 5057.0 & 326.80 2818 \end{tabular} 2819 \end{multicols} 2820 2821 2822 \paragraph{External Scheduling} 2823 2824 External scheduling is measured using a cycle of two threads calling and accepting the call using the @waitfor@ statement. 2825 Figure~\ref{f:ext-sched} shows the code for \CFA, with results in Table~\ref{tab:ext-sched}. 2826 Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects. 2827 2828 \begin{multicols}{2} 2829 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}} 2830 \vspace*{-16pt} 2831 \begin{cfa} 2832 volatile int go = 0; 2833 @monitor@ M {} m; 2834 thread T {}; 2835 void __attribute__((noinline)) 2836 do_call( M & @mutex@ ) {} 2837 void main( T & ) { 2838 while ( go == 0 ) { yield(); } 2839 while ( go == 1 ) { do_call( m ); } 2840 } 2841 int __attribute__((noinline)) 2842 do_wait( M & @mutex@ m ) { 2843 go = 1; // continue other thread 2844 BENCH( for ( N ) { @waitfor( do_call, m );@ } ) 2845 go = 0; // stop other thread 2846 sout | result`ns; 2847 } 2848 int main() { 2849 T t; 2850 do_wait( m ); 2851 } 2852 \end{cfa} 2853 \captionof{figure}{\CFA external-scheduling benchmark} 2854 \label{f:ext-sched} 2855 2856 \columnbreak 2857 2858 \vspace*{-16pt} 2859 \captionof{table}{External-scheduling comparison (nanoseconds)} 2860 \label{tab:ext-sched} 2861 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}} 2862 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2863 \CFA @waitfor@, 1 @monitor@ & 366.7 & 369.5 & 7.52 \\ 2864 \CFA @waitfor@, 2 @monitor@ & 453.6 & 455.8 & 12.38 \\ 2865 \CFA @waitfor@, 4 @monitor@ & 671.6 & 672.4 & 14.16 \\ 2866 \uC @_Accept@ & 336.0 & 335.8 & 3.22 2867 \end{tabular} 2868 \end{multicols} 2869 2870 2871 \paragraph{Context-Switching} 2872 2873 In procedural programming, the cost of a function call is important as modularization (refactoring) increases. 2874 (In many cases, a compiler inlines function calls to eliminate this cost.) 2875 Similarly, when modularization extends to coroutines/tasks, the time for a context switch becomes a relevant factor. 2876 The coroutine test is from resumer to suspender and from suspender to resumer, which is two context switches. 2877 The thread test is using yield to enter and return from the runtime kernel, which is two context switches. 2878 The difference in performance between coroutine and thread context-switch is the cost of scheduling for threads, whereas coroutines are self-scheduling. 2879 Figure~\ref{f:ctx-switch} only shows the \CFA code for coroutines/threads (other systems are similar) with all results in Table~\ref{tab:ctx-switch}. 2880 2881 \begin{multicols}{2} 2882 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}} 2883 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 2884 @coroutine@ C {} c; 2885 void main( C & ) { for ( ;; ) { @suspend;@ } } 2886 int main() { // coroutine test 2887 BENCH( for ( N ) { @resume( c );@ } ) 2888 sout | result`ns; 2889 } 2890 int main() { // task test 2891 BENCH( for ( N ) { @yield();@ } ) 2892 sout | result`ns; 2893 } 2894 \end{cfa} 2895 \captionof{figure}{\CFA context-switch benchmark} 2896 \label{f:ctx-switch} 2897 2898 \columnbreak 2899 2900 \vspace*{-16pt} 2901 \captionof{table}{Context switch comparison (nanoseconds)} 2902 \label{tab:ctx-switch} 2903 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}} 2904 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2905 C function & 1.8 & 1.8 & 0 \\ 2906 \CFA generator & 2.7 & 2.4 & 0.27 \\ 2907 \CFA Coroutine & 37.8 & 37.7 & 0.22 \\ 2908 \CFA Thread & 93.6 & 93.8 & 1.46 \\ 2909 \uC Coroutine & 52.7 & 52.8 & 0.28 \\ 2910 \uC Thread & 93.4 & 93.7 & 1.04 \\ 2911 Goroutine & 140.0 & 139.7 & 2.93 \\ 2912 Java Thread & 374.0 & 375.8 & 10.38 \\ 2913 % Qthreads Thread & 159.5 & 159.3 & 0.71 \\ 2914 Pthreads Thread & 334.4 & 335.0 & 1.95 \\ 2915 \end{tabular} 2916 \end{multicols} 2917 2918 2919 \paragraph{Mutual-Exclusion} 2920 2921 Uncontented mutual exclusion, which frequently occurs, is measured by entering/leaving a critical section. 2922 For monitors, entering and leaving a monitor function is measured. 2923 To put the results in context, the cost of entering a non-inline function and the cost of acquiring and releasing a @pthread_mutex@ lock is also measured. 2924 Figure~\ref{f:mutex} shows the code for \CFA with all results in Table~\ref{tab:mutex}. 2925 Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects. 2926 2927 \begin{multicols}{2} 2928 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}} 2929 \begin{cfa} 2930 @monitor@ M {} m1/*, m2, m3, m4*/; 2931 void __attribute__((noinline)) 2932 do_call( M & @mutex m/*, m2, m3, m4*/@ ) {} 2933 int main() { 2934 BENCH( 2935 for( N ) do_call( m1/*, m2, m3, m4*/ ); 2936 ) 2937 sout | result`ns; 2938 } 2939 \end{cfa} 2940 \captionof{figure}{\CFA acquire/release mutex benchmark} 2941 \label{f:mutex} 2942 2943 \columnbreak 2944 2945 \vspace*{-16pt} 2946 \captionof{table}{Mutex comparison (nanoseconds)} 2947 \label{tab:mutex} 2948 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}} 2949 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\ 2950 test and test-and-test lock & 19.1 & 19.0 & 0.36 \\ 2951 \CFA @mutex@ function, 1 arg. & 46.6 & 46.8 & 0.86 \\ 2952 \CFA @mutex@ function, 2 arg. & 84.1 & 85.3 & 1.86 \\ 2953 \CFA @mutex@ function, 4 arg. & 158.6 & 160.7 & 3.07 \\ 2954 \uC @monitor@ member rtn. & 54.0 & 53.7 & 0.83 \\ 2955 Java synchronized method & 27.0 & 27.1 & 0.25 \\ 2956 Pthreads Mutex Lock & 33.6 & 32.7 & 1.12 2963 \CFA @signal@, 1 @monitor@ & 372.6 & 374.3 & 14.17 \\ 2964 \CFA @signal@, 2 @monitor@ & 492.7 & 494.1 & 12.99 \\ 2965 \CFA @signal@, 4 @monitor@ & 749.4 & 750.4 & 24.74 \\ 2966 \uC @signal@ & 320.5 & 321.0 & 3.36 \\ 2967 Java @notify@ & 10160.5 & 10169.4 & 267.71 \\ 2968 Pthreads Cond. Variable & 4949.6 & 5065.2 & 363 2957 2969 \end{tabular} 2958 2970 \end{multicols} -
libcfa/prelude/prelude-gen.cc
rc60a664 r99cadc60 1 // 1 // 2 2 // Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo 3 3 // 4 4 // The contents of this file are covered under the licence agreement in the 5 5 // file "LICENCE" distributed with Cforall. 6 // 7 // prelude-gen.cc -- 8 // 6 // 7 // prelude-gen.cc -- 8 // 9 9 // Author : Rob Schluntz and Thierry Delisle 10 10 // Created On : Sat Feb 16 08:44:58 2019 … … 12 12 // Last Modified On : Tue Apr 2 17:18:24 2019 13 13 // Update Count : 37 14 // 14 // 15 15 16 16 #include <algorithm> … … 264 264 for (auto cvq : qualifiersPair) { 265 265 for (auto is_vol : { " ", "volatile" }) { 266 cout << "forall(dtype DT) void ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl;266 cout << "forall(dtype DT) void ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl; 267 267 } 268 268 } 269 for (auto cvq : qualifiersSingle) { 270 for (auto is_vol : { " ", "volatile" }) { 271 cout << "forall(dtype DT) void ?{}(" << cvq << type << " * " << is_vol << " &);" << endl; 272 } 273 for (auto is_vol : { " ", "volatile" }) { 274 cout << "forall(dtype DT) void ^?{}(" << cvq << type << " * " << is_vol << " &);" << endl; 275 } 269 } 270 for (auto cvq : qualifiersSingle) { 271 for (auto is_vol : { " ", "volatile" }) { 272 cout << "void ?{}(" << cvq << "void" << " * " << is_vol << " &);" << endl; 273 } 274 for (auto is_vol : { " ", "volatile" }) { 275 cout << "void ^?{}(" << cvq << "void" << " * " << is_vol << " &);" << endl; 276 } 277 } 278 279 for (auto cvq : qualifiersSingle) { 280 for (auto is_vol : { " ", "volatile" }) { 281 cout << "forall(dtype DT) void ?{}(" << cvq << " DT" << " * " << is_vol << " &);" << endl; 282 } 283 for (auto is_vol : { " ", "volatile" }) { 284 cout << "forall(dtype DT) void ^?{}(" << cvq << " DT" << " * " << is_vol << " &);" << endl; 276 285 } 277 286 } … … 288 297 cout << endl; 289 298 290 cout << "forall(ftype FT) void ?{}( FT * &, zero_t ); 299 cout << "forall(ftype FT) void ?{}( FT * &, zero_t );" << endl; 291 300 cout << "forall(ftype FT) FT * ?=?( FT * &, zero_t );" << endl; 292 301 cout << "forall(ftype FT) FT * ?=?( FT * volatile &, zero_t );" << endl; -
libcfa/src/heap.cfa
rc60a664 r99cadc60 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 19 16:07:46201913 // Update Count : 5 4812 // Last Modified On : Wed Jul 24 13:12:45 2019 13 // Update Count : 550 14 14 // 15 15 … … 248 248 249 249 #ifdef FASTLOOKUP 250 static_assert( 16 == sizeof(HeapManager.Storage), "size of HeapManager Storage wrong" ); // FIX ME 251 enum { LookupSizes = 65_536 + 16 }; // number of fast lookup sizes 250 enum { LookupSizes = 65_536 + sizeof(HeapManager.Storage) }; // number of fast lookup sizes 252 251 static unsigned char lookup[LookupSizes]; // O(1) lookup for small sizes 253 252 #endif // FASTLOOKUP … … 869 868 void * area; 870 869 if ( unlikely( alignment != 0 ) ) { // previous request memalign? 871 area = memalign( alignment, size ); // create new a rea870 area = memalign( alignment, size ); // create new aligned area 872 871 } else { 873 872 area = mallocNoStats( size ); // create new area -
libcfa/src/stdlib.hfa
rc60a664 r99cadc60 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 24 17:35:43201913 // Update Count : 3 5212 // Last Modified On : Tue Jul 23 14:14:59 2019 13 // Update Count : 373 14 14 // 15 15 … … 17 17 18 18 #include "bits/defs.hfa" 19 #include "bits/align.hfa" 19 20 20 21 #include <stdlib.h> // *alloc, strto*, ato* 22 21 23 extern "C" { 22 24 void * memalign( size_t align, size_t size ); // malloc.h … … 39 41 40 42 T * malloc( void ) { 41 return (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc 43 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc 44 else return (T *)memalign( _Alignof(T), sizeof(T) ); 42 45 } // malloc 43 46 44 47 T * calloc( size_t dim ) { 45 return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc 48 if ( _Alignof(T) <= libAlign() )return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc 49 else return (T *)cmemalign( _Alignof(T), dim, sizeof(T) ); 46 50 } // calloc 47 51 48 52 T * realloc( T * ptr, size_t size ) { 53 if ( unlikely( ptr == 0 ) ) return malloc(); 49 54 return (T *)(void *)realloc( (void *)ptr, size ); 50 55 } // realloc … … 66 71 67 72 T * alloc( void ) { 68 return (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc73 return malloc(); 69 74 } // alloc 70 75 71 76 T * alloc( char fill ) { 72 T * ptr = (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc 77 T * ptr; 78 if ( _Alignof(T) <= libAlign() ) ptr = (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc 79 else ptr = (T *)memalign( _Alignof(T), sizeof(T) ); 73 80 return (T *)memset( ptr, (int)fill, sizeof(T) ); // initialize with fill value 74 81 } // alloc 75 82 76 83 T * alloc( size_t dim ) { 77 return (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C malloc 84 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C malloc 85 else return (T *)memalign( _Alignof(T), dim * sizeof(T) ); 78 86 } // alloc 79 87 80 88 T * alloc( size_t dim, char fill ) { 81 T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C calloc 82 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); // initialize with fill value 89 return (T *)memset( (T *)alloc( dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value 83 90 } // alloc 84 91 85 92 T * alloc( T ptr[], size_t dim ) { 86 return (T *)(void *)realloc( (void *)ptr, dim * (size_t)sizeof(T) ); // C realloc 87 } // alloc 88 } // distribution 89 90 91 forall( dtype T | sized(T) ) T * alloc( T ptr[], size_t dim, char fill ); 93 return realloc( ptr, dim * sizeof(T) ); 94 } // alloc 95 } // distribution 92 96 93 97 … … 107 111 108 112 T * align_alloc( size_t align, size_t dim, char fill ) { 109 T * ptr;110 113 if ( fill == '\0' ) { 111 ptr =(T *)cmemalign( align, dim, sizeof(T) );114 return (T *)cmemalign( align, dim, sizeof(T) ); 112 115 } else { 113 ptr = (T *)memalign( align, dim * sizeof(T) ); 114 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); 116 return (T *)memset( (T *)memalign( align, dim * sizeof(T) ), (int)fill, dim * sizeof(T) ); 115 117 } // if 116 return ptr; 117 } // align_alloc 118 } // distribution 118 } // align_alloc 119 } // distribution 120 121 forall( dtype T | sized(T) ) T * alloc( T ptr[], size_t dim, char fill ); 119 122 120 123 -
src/AST/Convert.cpp
rc60a664 r99cadc60 9 9 // Author : Thierry Delisle 10 10 // Created On : Thu May 09 15::37::05 2019 11 // Last Modified By : Andrew Beach12 // Last Modified On : Mon Jun 17 16:44:00201913 // Update Count : 1 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 25 22:21:46 2019 13 // Update Count : 13 14 14 // 15 15 … … 2676 2676 ); 2677 2677 } 2678 2679 virtual void visit( const AttrExpr * ) override final {2680 assertf( false, "AttrExpr deprecated in new AST." );2681 }2682 2678 }; 2683 2679 -
src/AST/porting.md
rc60a664 r99cadc60 171 171 * all existing uses assume `type` set if true and don't use `expr` 172 172 173 `AttrExpr`174 * did not port due to feature deprecation (e.g. `expr@attribute`)175 176 173 `LogicalExpr` 177 174 * un-defaulted constructor parameter determining `&&` or `||` -
src/Common/Eval.cc
rc60a664 r99cadc60 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun May 6 22:24:16 201813 // Update Count : 4012 // Last Modified On : Wed Jul 24 15:09:06 2019 13 // Update Count : 64 14 14 // 15 15 … … 27 27 bool valid = true; 28 28 29 void previsit( BaseSyntaxNode * ) { visit_children = false; }30 void postvisit( BaseSyntaxNode * ) { valid = false; }29 void previsit( const BaseSyntaxNode * ) { visit_children = false; } 30 void postvisit( const BaseSyntaxNode * ) { valid = false; } 31 31 32 void postvisit( ConstantExpr * expr ) { 32 void postvisit( const SizeofExpr * ) { 33 } 34 35 void postvisit( const ConstantExpr * expr ) { 33 36 value = expr->intValue(); 34 37 } 35 38 36 void postvisit( CastExpr * expr ) {39 void postvisit( const CastExpr * expr ) { 37 40 auto arg = eval(expr->arg); 38 41 valid = arg.second; … … 41 44 } 42 45 43 void postvisit( VariableExpr *expr ) {46 void postvisit( const VariableExpr * const expr ) { 44 47 if ( EnumInstType * inst = dynamic_cast<EnumInstType *>(expr->result) ) { 45 48 if ( EnumDecl * decl = inst->baseEnum ) { … … 52 55 } 53 56 54 void postvisit( ApplicationExpr * expr ) {55 DeclarationWithType * function = InitTweak::getFunction( expr);57 void postvisit( const ApplicationExpr * expr ) { 58 DeclarationWithType * function = InitTweak::getFunction(const_cast<ApplicationExpr *>(expr)); 56 59 if ( ! function || function->linkage != LinkageSpec::Intrinsic ) { valid = false; return; } 57 60 const std::string & fname = function->name; … … 94 97 void postvisit( const ast::ConstantExpr * expr ) { 95 98 value = expr->intValue(); 99 } 100 101 void postvisit( const ast::SizeofExpr * expr ) { 102 if ( expr->expr ) value = eval(expr->expr).first; 103 else if ( expr->type ) value = eval(expr->expr).first; 104 else SemanticError( expr->location, ::toString( "Internal error: SizeofExpr has no expression or type value" ) ); 96 105 } 97 106 … … 145 154 }; 146 155 147 std::pair<long long int, bool> eval( Expression * expr) {156 std::pair<long long int, bool> eval( const Expression * expr) { 148 157 PassVisitor<EvalOld> ev; 149 158 if (expr) { -
src/Common/PassVisitor.h
rc60a664 r99cadc60 155 155 virtual void visit( OffsetPackExpr * offsetPackExpr ) override final; 156 156 virtual void visit( const OffsetPackExpr * offsetPackExpr ) override final; 157 virtual void visit( AttrExpr * attrExpr ) override final;158 virtual void visit( const AttrExpr * attrExpr ) override final;159 157 virtual void visit( LogicalExpr * logicalExpr ) override final; 160 158 virtual void visit( const LogicalExpr * logicalExpr ) override final; … … 301 299 virtual Expression * mutate( OffsetofExpr * offsetofExpr ) override final; 302 300 virtual Expression * mutate( OffsetPackExpr * offsetPackExpr ) override final; 303 virtual Expression * mutate( AttrExpr * attrExpr ) override final;304 301 virtual Expression * mutate( LogicalExpr * logicalExpr ) override final; 305 302 virtual Expression * mutate( ConditionalExpr * conditionalExpr ) override final; -
src/Common/PassVisitor.impl.h
rc60a664 r99cadc60 2302 2302 2303 2303 //-------------------------------------------------------------------------- 2304 // AttrExpr2305 template< typename pass_type >2306 void PassVisitor< pass_type >::visit( AttrExpr * node ) {2307 VISIT_START( node );2308 2309 indexerScopedAccept( node->result, *this );2310 if ( node->get_isType() ) {2311 maybeAccept_impl( node->type, *this );2312 } else {2313 maybeAccept_impl( node->expr, *this );2314 }2315 2316 VISIT_END( node );2317 }2318 2319 template< typename pass_type >2320 void PassVisitor< pass_type >::visit( const AttrExpr * node ) {2321 VISIT_START( node );2322 2323 indexerScopedAccept( node->result, *this );2324 if ( node->get_isType() ) {2325 maybeAccept_impl( node->type, *this );2326 } else {2327 maybeAccept_impl( node->expr, *this );2328 }2329 2330 VISIT_END( node );2331 }2332 2333 template< typename pass_type >2334 Expression * PassVisitor< pass_type >::mutate( AttrExpr * node ) {2335 MUTATE_START( node );2336 2337 indexerScopedMutate( node->env , *this );2338 indexerScopedMutate( node->result, *this );2339 if ( node->get_isType() ) {2340 maybeMutate_impl( node->type, *this );2341 } else {2342 maybeMutate_impl( node->expr, *this );2343 }2344 2345 MUTATE_END( Expression, node );2346 }2347 2348 //--------------------------------------------------------------------------2349 2304 // LogicalExpr 2350 2305 template< typename pass_type > -
src/Common/utility.h
rc60a664 r99cadc60 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun May 6 22:24:16 201813 // Update Count : 4 012 // Last Modified On : Wed Jul 24 14:28:19 2019 13 // Update Count : 41 14 14 // 15 15 … … 483 483 // ----------------------------------------------------------------------------- 484 484 /// evaluates expr as a long long int. If second is false, expr could not be evaluated 485 std::pair<long long int, bool> eval( Expression * expr);485 std::pair<long long int, bool> eval(const Expression * expr); 486 486 487 487 namespace ast { -
src/InitTweak/InitTweak.cc
rc60a664 r99cadc60 9 9 // Author : Rob Schluntz 10 10 // Created On : Fri May 13 11:26:36 2016 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Jun 19 14:34:00201913 // Update Count : 611 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 25 22:21:48 2019 13 // Update Count : 7 14 14 // 15 15 … … 957 957 void previsit( OffsetofExpr * ) {} 958 958 void previsit( OffsetPackExpr * ) {} 959 void previsit( AttrExpr * ) {}960 959 void previsit( CommaExpr * ) {} 961 960 void previsit( LogicalExpr * ) {} -
src/Parser/DeclarationNode.cc
rc60a664 r99cadc60 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Feb 1 16:49:17201913 // Update Count : 111 312 // Last Modified On : Thu Jul 25 22:17:10 2019 13 // Update Count : 1116 14 14 // 15 15 … … 49 49 const char * DeclarationNode::aggregateNames[] = { "struct", "union", "trait", "coroutine", "monitor", "thread", "NoAggregateNames" }; 50 50 const char * DeclarationNode::typeClassNames[] = { "otype", "dtype", "ftype", "NoTypeClassNames" }; 51 const char * DeclarationNode::builtinTypeNames[] = { "__builtin_va_list", " zero_t", "one_t", "NoBuiltinTypeNames" };51 const char * DeclarationNode::builtinTypeNames[] = { "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames" }; 52 52 53 53 UniqueName DeclarationNode::anonymous( "__anonymous" ); … … 418 418 return newnode; 419 419 } // DeclarationNode::newBuiltinType 420 421 DeclarationNode * DeclarationNode::newAttr( const string * name, ExpressionNode * expr ) {422 DeclarationNode * newnode = new DeclarationNode;423 newnode->type = nullptr;424 // newnode->attr.name = name;425 newnode->name = name;426 newnode->attr.expr = expr;427 return newnode;428 }429 430 DeclarationNode * DeclarationNode::newAttr( const string * name, DeclarationNode * type ) {431 DeclarationNode * newnode = new DeclarationNode;432 newnode->type = nullptr;433 // newnode->attr.name = name;434 newnode->name = name;435 newnode->attr.type = type;436 return newnode;437 }438 420 439 421 DeclarationNode * DeclarationNode::newAttribute( const string * name, ExpressionNode * expr ) { -
src/Parser/ParseNode.h
rc60a664 r99cadc60 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 15 14:22:39201913 // Update Count : 87 412 // Last Modified On : Thu Jul 25 22:17:10 2019 13 // Update Count : 876 14 14 // 15 15 … … 221 221 enum TypeClass { Otype, Dtype, Ftype, Ttype, NoTypeClass }; 222 222 static const char * typeClassNames[]; 223 enum BuiltinType { Valist, Zero, One, NoBuiltinType };223 enum BuiltinType { Valist, AutoType, Zero, One, NoBuiltinType }; 224 224 static const char * builtinTypeNames[]; 225 225 … … 252 252 static DeclarationNode * newTuple( DeclarationNode * members ); 253 253 static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false ); 254 static DeclarationNode * newAttr( const std::string *, ExpressionNode * expr ); // @ attributes255 static DeclarationNode * newAttr( const std::string *, DeclarationNode * type ); // @ attributes256 254 static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes 257 255 static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement -
src/Parser/lex.ll
rc60a664 r99cadc60 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Wed May 15 21:25:27201913 * Update Count : 7 0812 * Last Modified On : Thu Jul 25 22:08:32 2019 13 * Update Count : 716 14 14 */ 15 15 … … 59 59 #define QKEYWORD_RETURN(x) RETURN_VAL(x); // quasi-keyword 60 60 #define IDENTIFIER_RETURN() RETURN_VAL( typedefTable.isKind( yytext ) ) 61 #define ATTRIBUTE_RETURN() RETURN_VAL( ATTR_IDENTIFIER )62 61 63 62 #ifdef HAVE_KEYWORDS_FLOATXX // GCC >= 7 => keyword, otherwise typedef … … 92 91 // identifier, GCC: $ in identifier 93 92 identifier ([a-zA-Z_$]|{universal_char})([0-9a-zA-Z_$]|{universal_char})* 94 95 // attribute identifier, GCC: $ in identifier96 attr_identifier "@"{identifier}97 93 98 94 // numeric constants, CFA: '_' in constant … … 218 214 __attribute__ { KEYWORD_RETURN(ATTRIBUTE); } // GCC 219 215 auto { KEYWORD_RETURN(AUTO); } 216 __auto_type { KEYWORD_RETURN(AUTO_TYPE); } 220 217 basetypeof { KEYWORD_RETURN(BASETYPEOF); } // CFA 221 218 _Bool { KEYWORD_RETURN(BOOL); } // C99 … … 292 289 __restrict__ { KEYWORD_RETURN(RESTRICT); } // GCC 293 290 return { KEYWORD_RETURN(RETURN); } 291 /* resume { KEYWORD_RETURN(RESUME); } // CFA */ 294 292 short { KEYWORD_RETURN(SHORT); } 295 293 signed { KEYWORD_RETURN(SIGNED); } … … 300 298 _Static_assert { KEYWORD_RETURN(STATICASSERT); } // C11 301 299 struct { KEYWORD_RETURN(STRUCT); } 300 /* suspend { KEYWORD_RETURN(SUSPEND); } // CFA */ 302 301 switch { KEYWORD_RETURN(SWITCH); } 303 302 thread { KEYWORD_RETURN(THREAD); } // C11 … … 333 332 IDENTIFIER_RETURN(); 334 333 } 335 {attr_identifier} { ATTRIBUTE_RETURN(); }336 334 337 335 /* numeric constants */ -
src/Parser/parser.yy
rc60a664 r99cadc60 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jul 14 07:54:30201913 // Update Count : 435 512 // Last Modified On : Thu Jul 25 22:31:38 2019 13 // Update Count : 4359 14 14 // 15 15 … … 272 272 %token ZERO_T ONE_T // CFA 273 273 %token VALIST // GCC 274 %token AUTO_TYPE // GCC 274 275 %token TYPEOF BASETYPEOF LABEL // GCC 275 276 %token ENUM STRUCT UNION … … 288 289 %token<tok> IDENTIFIER QUOTED_IDENTIFIER TYPEDEFname TYPEGENname 289 290 %token<tok> TIMEOUT WOR 290 %token<tok> ATTR_IDENTIFIER ATTR_TYPEDEFname ATTR_TYPEGENname291 291 %token<tok> INTEGERconstant CHARACTERconstant STRINGliteral 292 292 %token<tok> DIRECTIVE … … 312 312 %token ATassign // @= 313 313 314 %type<tok> identifier no_attr_identifier315 %type<tok> identifier_or_type_name no_attr_identifier_or_type_nameattr_name314 %type<tok> identifier 315 %type<tok> identifier_or_type_name attr_name 316 316 %type<tok> quasi_keyword 317 317 %type<constant> string_literal … … 546 546 ; 547 547 548 no_attr_identifier:548 identifier: 549 549 IDENTIFIER 550 550 | quasi_keyword 551 551 | '@' // CFA 552 552 { Token tok = { new string( DeclarationNode::anonymous.newName() ), yylval.tok.loc }; $$ = tok; } 553 ;554 555 identifier:556 no_attr_identifier557 | ATTR_IDENTIFIER // CFA558 553 ; 559 554 … … 594 589 | '(' comma_expression ')' '`' IDENTIFIER // CFA, postfix call 595 590 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $5 ) ), $2 ) ); } 596 | type_name '.' no_attr_identifier// CFA, nested type591 | type_name '.' identifier // CFA, nested type 597 592 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 598 593 | type_name '.' '[' field_name_list ']' // CFA, nested type / tuple field selector … … 647 642 | postfix_expression '(' argument_expression_list ')' 648 643 { $$ = new ExpressionNode( build_func( $1, $3 ) ); } 649 | postfix_expression '.' no_attr_identifier644 | postfix_expression '.' identifier 650 645 { $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); } 651 646 | postfix_expression '.' INTEGERconstant // CFA, tuple index … … 655 650 | postfix_expression '.' '[' field_name_list ']' // CFA, tuple field selector 656 651 { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); } 657 | postfix_expression ARROW no_attr_identifier652 | postfix_expression ARROW identifier 658 653 { $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); } 659 654 | postfix_expression ARROW INTEGERconstant // CFA, tuple index … … 718 713 | FLOATINGconstant fraction_constants_opt 719 714 { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); } 720 | no_attr_identifier fraction_constants_opt715 | identifier fraction_constants_opt 721 716 { 722 717 $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) ); … … 776 771 | ALIGNOF '(' type_no_function ')' // GCC, type alignment 777 772 { $$ = new ExpressionNode( new AlignofExpr( maybeMoveBuildType( $3 ) ) ); } 778 | OFFSETOF '(' type_no_function ',' no_attr_identifier ')'773 | OFFSETOF '(' type_no_function ',' identifier ')' 779 774 { $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) ); } 780 | ATTR_IDENTIFIER781 { $$ = new ExpressionNode( new AttrExpr( build_varref( $1 ), maybeMoveBuild< Expression >( (ExpressionNode *)nullptr ) ) ); }782 | ATTR_IDENTIFIER '(' argument_expression ')'783 { $$ = new ExpressionNode( new AttrExpr( build_varref( $1 ), maybeMoveBuild< Expression >( $3 ) ) ); }784 | ATTR_IDENTIFIER '(' type ')'785 { $$ = new ExpressionNode( new AttrExpr( build_varref( $1 ), maybeMoveBuildType( $3 ) ) ); }786 775 ; 787 776 … … 1018 1007 1019 1008 labeled_statement: 1020 // labels cannot be identifiers 0 or 1 or ATTR_IDENTIFIER1009 // labels cannot be identifiers 0 or 1 1021 1010 identifier_or_type_name ':' attribute_list_opt statement 1022 1011 { $$ = $4->add_label( $1, $3 ); } … … 1386 1375 | type_specifier_nobody variable_abstract_declarator 1387 1376 { $$ = $2->addType( $1 ); } 1388 | cfa_abstract_declarator_tuple no_attr_identifier// CFA1377 | cfa_abstract_declarator_tuple identifier // CFA 1389 1378 { $$ = $1->addName( $2 ); } 1390 1379 | cfa_abstract_declarator_tuple // CFA … … 1450 1439 1451 1440 label_list: 1452 no_attr_identifier1441 identifier 1453 1442 { 1454 1443 $$ = new LabelNode(); $$->labels.push_back( *$1 ); 1455 1444 delete $1; // allocated by lexer 1456 1445 } 1457 | label_list ',' no_attr_identifier1446 | label_list ',' identifier 1458 1447 { 1459 1448 $$ = $1; $1->labels.push_back( *$3 ); … … 1500 1489 1501 1490 local_label_list: // GCC, local label 1502 no_attr_identifier_or_type_name1503 | local_label_list ',' no_attr_identifier_or_type_name1491 identifier_or_type_name 1492 | local_label_list ',' identifier_or_type_name 1504 1493 ; 1505 1494 … … 1623 1612 $$ = $2->addTypedef(); 1624 1613 } 1625 | cfa_typedef_declaration pop ',' push no_attr_identifier1614 | cfa_typedef_declaration pop ',' push identifier 1626 1615 { 1627 1616 typedefTable.addToEnclosingScope( *$5, TYPEDEFname, "3" ); … … 1663 1652 typedef_expression: 1664 1653 // GCC, naming expression type: typedef name = exp; gives a name to the type of an expression 1665 TYPEDEF no_attr_identifier '=' assignment_expression1654 TYPEDEF identifier '=' assignment_expression 1666 1655 { 1667 1656 // $$ = DeclarationNode::newName( 0 ); // unimplemented 1668 1657 SemanticError( yylloc, "Typedef expression is currently unimplemented." ); $$ = nullptr; 1669 1658 } 1670 | typedef_expression pop ',' push no_attr_identifier '=' assignment_expression1659 | typedef_expression pop ',' push identifier '=' assignment_expression 1671 1660 { 1672 1661 // $$ = DeclarationNode::newName( 0 ); // unimplemented … … 1871 1860 | VALIST // GCC, __builtin_va_list 1872 1861 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::Valist ); } 1862 | AUTO_TYPE 1863 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::AutoType ); } 1873 1864 ; 1874 1865 … … 1912 1903 | BASETYPEOF '(' comma_expression ')' // CFA: basetypeof( a+b ) y; 1913 1904 { $$ = DeclarationNode::newTypeof( $3, true ); } 1914 | ATTR_TYPEGENname '(' type ')' // CFA: e.g., @type( x ) y;1915 { $$ = DeclarationNode::newAttr( $1, $3 ); }1916 | ATTR_TYPEGENname '(' comma_expression ')' // CFA: e.g., @type( a+b ) y;1917 { $$ = DeclarationNode::newAttr( $1, $3 ); }1918 1905 | ZERO_T // CFA 1919 1906 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::Zero ); } … … 2024 2011 '{' field_declaration_list_opt '}' type_parameters_opt 2025 2012 { $$ = DeclarationNode::newAggregate( $1, nullptr, $7, $5, true )->addQualifiers( $2 ); } 2026 | aggregate_key attribute_list_opt no_attr_identifier fred2013 | aggregate_key attribute_list_opt identifier fred 2027 2014 { 2028 2015 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef … … 2050 2037 2051 2038 aggregate_type_nobody: // struct, union - {...} 2052 aggregate_key attribute_list_opt no_attr_identifier fred2039 aggregate_key attribute_list_opt identifier fred 2053 2040 { 2054 2041 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); … … 2151 2138 cfa_field_declaring_list: // CFA, new style field declaration 2152 2139 // bit-fields are handled by C declarations 2153 cfa_abstract_declarator_tuple no_attr_identifier_or_type_name2140 cfa_abstract_declarator_tuple identifier_or_type_name 2154 2141 { $$ = $1->addName( $2 ); } 2155 | cfa_field_declaring_list ',' no_attr_identifier_or_type_name2142 | cfa_field_declaring_list ',' identifier_or_type_name 2156 2143 { $$ = $1->appendList( $1->cloneType( $3 ) ); } 2157 2144 ; … … 2178 2165 ENUM attribute_list_opt '{' enumerator_list comma_opt '}' 2179 2166 { $$ = DeclarationNode::newEnum( nullptr, $4, true )->addQualifiers( $2 ); } 2180 | ENUM attribute_list_opt no_attr_identifier2167 | ENUM attribute_list_opt identifier 2181 2168 { typedefTable.makeTypedef( *$3 ); } 2182 2169 '{' enumerator_list comma_opt '}' … … 2189 2176 2190 2177 enum_type_nobody: // enum - {...} 2191 ENUM attribute_list_opt no_attr_identifier2178 ENUM attribute_list_opt identifier 2192 2179 { 2193 2180 typedefTable.makeTypedef( *$3 ); … … 2202 2189 2203 2190 enumerator_list: 2204 no_attr_identifier_or_type_name enumerator_value_opt2191 identifier_or_type_name enumerator_value_opt 2205 2192 { $$ = DeclarationNode::newEnumConstant( $1, $2 ); } 2206 | enumerator_list ',' no_attr_identifier_or_type_name enumerator_value_opt2193 | enumerator_list ',' identifier_or_type_name enumerator_value_opt 2207 2194 { $$ = $1->appendList( DeclarationNode::newEnumConstant( $3, $4 ) ); } 2208 2195 ; … … 2312 2299 2313 2300 identifier_list: // K&R-style parameter list => no types 2314 no_attr_identifier2301 identifier 2315 2302 { $$ = DeclarationNode::newName( $1 ); } 2316 | identifier_list ',' no_attr_identifier2303 | identifier_list ',' identifier 2317 2304 { $$ = $1->appendList( DeclarationNode::newName( $3 ) ); } 2318 2305 ; … … 2320 2307 identifier_or_type_name: 2321 2308 identifier 2322 | TYPEDEFname2323 | TYPEGENname2324 ;2325 2326 no_attr_identifier_or_type_name:2327 no_attr_identifier2328 2309 | TYPEDEFname 2329 2310 | TYPEGENname … … 2380 2361 designation: 2381 2362 designator_list ':' // C99, CFA uses ":" instead of "=" 2382 | no_attr_identifier ':'// GCC, field name2363 | identifier ':' // GCC, field name 2383 2364 { $$ = new ExpressionNode( build_varref( $1 ) ); } 2384 2365 ; … … 2392 2373 2393 2374 designator: 2394 '.' no_attr_identifier// C99, field name2375 '.' identifier // C99, field name 2395 2376 { $$ = new ExpressionNode( build_varref( $2 ) ); } 2396 2377 | '[' push assignment_expression pop ']' // C99, single array element … … 2437 2418 2438 2419 type_parameter: // CFA 2439 type_class no_attr_identifier_or_type_name2420 type_class identifier_or_type_name 2440 2421 { typedefTable.addToScope( *$2, TYPEDEFname, "9" ); } 2441 2422 type_initializer_opt assertion_list_opt … … 2470 2451 2471 2452 assertion: // CFA 2472 '|' no_attr_identifier_or_type_name '(' type_list ')'2453 '|' identifier_or_type_name '(' type_list ')' 2473 2454 { $$ = DeclarationNode::newTraitUse( $2, $4 ); } 2474 2455 | '|' '{' push trait_declaration_list pop '}' … … 2507 2488 2508 2489 type_declarator_name: // CFA 2509 no_attr_identifier_or_type_name2490 identifier_or_type_name 2510 2491 { 2511 2492 typedefTable.addToEnclosingScope( *$1, TYPEDEFname, "10" ); 2512 2493 $$ = DeclarationNode::newTypeDecl( $1, 0 ); 2513 2494 } 2514 | no_attr_identifier_or_type_name '(' type_parameter_list ')'2495 | identifier_or_type_name '(' type_parameter_list ')' 2515 2496 { 2516 2497 typedefTable.addToEnclosingScope( *$1, TYPEGENname, "11" ); … … 2520 2501 2521 2502 trait_specifier: // CFA 2522 TRAIT no_attr_identifier_or_type_name '(' type_parameter_list ')' '{' '}'2503 TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' '}' 2523 2504 { $$ = DeclarationNode::newTrait( $2, $4, 0 ); } 2524 | TRAIT no_attr_identifier_or_type_name '(' type_parameter_list ')' '{' push trait_declaration_list pop '}'2505 | TRAIT identifier_or_type_name '(' type_parameter_list ')' '{' push trait_declaration_list pop '}' 2525 2506 { $$ = DeclarationNode::newTrait( $2, $4, $8 ); } 2526 2507 ; -
src/ResolvExpr/AlternativeFinder.cc
rc60a664 r99cadc60 10 10 // Created On : Sat May 16 23:52:08 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Nov 1 21:00:56 201813 // Update Count : 3 512 // Last Modified On : Thu Jul 25 22:37:46 2019 13 // Update Count : 37 14 14 // 15 15 … … 79 79 void postvisit( OffsetofExpr * offsetofExpr ); 80 80 void postvisit( OffsetPackExpr * offsetPackExpr ); 81 void postvisit( AttrExpr * attrExpr );82 81 void postvisit( LogicalExpr * logicalExpr ); 83 82 void postvisit( ConditionalExpr * conditionalExpr ); … … 1404 1403 } 1405 1404 1406 namespace {1407 void resolveAttr( SymTab::Indexer::IdData data, const FunctionType * function, Type * argType, const TypeEnvironment &env, AlternativeFinder & finder ) {1408 // assume no polymorphism1409 // assume no implicit conversions1410 assert( function->parameters.size() == 1 );1411 PRINT(1412 std::cerr << "resolvAttr: funcDecl is ";1413 data.id->print( std::cerr );1414 std::cerr << " argType is ";1415 argType->print( std::cerr );1416 std::cerr << std::endl;1417 )1418 const SymTab::Indexer & indexer = finder.get_indexer();1419 AltList & alternatives = finder.get_alternatives();1420 if ( typesCompatibleIgnoreQualifiers( argType, function->parameters.front()->get_type(), indexer, env ) ) {1421 Cost cost = Cost::zero;1422 Expression * newExpr = data.combine( cost );1423 alternatives.push_back( Alternative{1424 new AttrExpr{ newExpr, argType->clone() }, env, OpenVarSet{},1425 AssertionList{}, Cost::zero, cost } );1426 for ( DeclarationWithType * retVal : function->returnVals ) {1427 alternatives.back().expr->result = retVal->get_type()->clone();1428 } // for1429 } // if1430 }1431 }1432 1433 void AlternativeFinder::Finder::postvisit( AttrExpr * attrExpr ) {1434 // assume no 'pointer-to-attribute'1435 NameExpr * nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );1436 assert( nameExpr );1437 std::list< SymTab::Indexer::IdData > attrList;1438 indexer.lookupId( nameExpr->get_name(), attrList );1439 if ( attrExpr->get_isType() || attrExpr->get_expr() ) {1440 for ( auto & data : attrList ) {1441 const DeclarationWithType * id = data.id;1442 // check if the type is function1443 if ( const FunctionType * function = dynamic_cast< const FunctionType * >( id->get_type() ) ) {1444 // assume exactly one parameter1445 if ( function->parameters.size() == 1 ) {1446 if ( attrExpr->get_isType() ) {1447 resolveAttr( data, function, attrExpr->get_type(), env, altFinder);1448 } else {1449 AlternativeFinder finder( indexer, env );1450 finder.find( attrExpr->get_expr() );1451 for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {1452 if ( choice->expr->get_result()->size() == 1 ) {1453 resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );1454 } // fi1455 } // for1456 } // if1457 } // if1458 } // if1459 } // for1460 } else {1461 for ( auto & data : attrList ) {1462 Cost cost = Cost::zero;1463 Expression * newExpr = data.combine( cost );1464 alternatives.push_back( Alternative{1465 newExpr, env, OpenVarSet{}, AssertionList{}, Cost::zero, cost } );1466 renameTypes( alternatives.back().expr );1467 } // for1468 } // if1469 }1470 1471 1405 void AlternativeFinder::Finder::postvisit( LogicalExpr * logicalExpr ) { 1472 1406 AlternativeFinder firstFinder( indexer, env ); -
src/SymTab/Demangle.cc
rc60a664 r99cadc60 9 9 // Author : Rob Schluntz 10 10 // Created On : Thu Jul 19 12:52:41 2018 11 // Last Modified By : Rob Schluntz12 // Last Modified On : T hu Jul 19 12:54:35 201813 // Update Count : 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jul 30 13:46:33 2019 13 // Update Count : 3 14 14 // 15 15 … … 313 313 typeString = "_Atomic " + typeString; 314 314 } // if 315 if ( type->get_lvalue() ) {316 // when not generating C code, print lvalue for debugging.317 typeString = "lvalue " + typeString;318 }319 315 } 320 316 } -
src/SymTab/Mangler.cc
rc60a664 r99cadc60 10 10 // Created On : Sun May 17 21:40:29 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Sep 25 15:49:26 201713 // Update Count : 2 312 // Last Modified On : Tue Jul 30 13:46:10 2019 13 // Update Count : 26 14 14 // 15 15 #include "Mangler.h" … … 377 377 mangleName << Encoding::qualifiers.at(Type::Mutex); 378 378 } // if 379 if ( type->get_lvalue() ) {380 // mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues381 mangleName << Encoding::qualifiers.at(Type::Lvalue);382 }383 384 379 if ( inFunctionType ) { 385 380 // turn off inFunctionType so that types can be differentiated for nested qualifiers … … 724 719 mangleName << Encoding::qualifiers.at(Type::Mutex); 725 720 } // if 726 if ( type->is_lvalue() ) {727 // mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues728 mangleName << Encoding::qualifiers.at(Type::Lvalue);729 }730 731 721 if ( inFunctionType ) { 732 722 // turn off inFunctionType so that types can be differentiated for nested qualifiers -
src/SynTree/Expression.cc
rc60a664 r99cadc60 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Feb 19 18:10:55201913 // Update Count : 6 012 // Last Modified On : Thu Jul 25 22:21:48 2019 13 // Update Count : 61 14 14 // 15 15 … … 249 249 os << "Offset pack expression on "; 250 250 type->print(os, indent+1); 251 Expression::print( os, indent );252 }253 254 AttrExpr::AttrExpr( Expression * attr, Expression * expr_ ) :255 Expression(), attr( attr ), expr(expr_), type(0), isType(false) {256 }257 258 AttrExpr::AttrExpr( Expression * attr, Type * type_ ) :259 Expression(), attr( attr ), expr(0), type(type_), isType(true) {260 }261 262 AttrExpr::AttrExpr( const AttrExpr & other ) :263 Expression( other ), attr( maybeClone( other.attr ) ), expr( maybeClone( other.expr ) ), type( maybeClone( other.type ) ), isType( other.isType ) {264 }265 266 AttrExpr::~AttrExpr() {267 delete attr;268 delete expr;269 delete type;270 }271 272 void AttrExpr::print( std::ostream & os, Indenter indent) const {273 os << "Attr ";274 attr->print( os, indent+1);275 if ( isType || expr ) {276 os << "applied to: ";277 if (isType) type->print(os, indent+1);278 else expr->print(os, indent+1);279 } // if280 251 Expression::print( os, indent ); 281 252 } -
src/SynTree/Expression.h
rc60a664 r99cadc60 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Feb 18 18:29:51201913 // Update Count : 4912 // Last Modified On : Thu Jul 25 22:21:44 2019 13 // Update Count : 50 14 14 // 15 15 … … 463 463 }; 464 464 465 /// AttrExpr represents an @attribute expression (like sizeof, but user-defined)466 class AttrExpr : public Expression {467 public:468 Expression * attr;469 Expression * expr;470 Type * type;471 bool isType;472 473 AttrExpr(Expression * attr, Expression * expr );474 AttrExpr( const AttrExpr & other );475 AttrExpr( Expression * attr, Type * type );476 virtual ~AttrExpr();477 478 Expression * get_attr() const { return attr; }479 void set_attr( Expression * newValue ) { attr = newValue; }480 Expression * get_expr() const { return expr; }481 void set_expr( Expression * newValue ) { expr = newValue; }482 Type * get_type() const { return type; }483 void set_type( Type * newValue ) { type = newValue; }484 bool get_isType() const { return isType; }485 void set_isType( bool newValue ) { isType = newValue; }486 487 virtual AttrExpr * clone() const override { return new AttrExpr( * this ); }488 virtual void accept( Visitor & v ) override { v.visit( this ); }489 virtual void accept( Visitor & v ) const override { v.visit( this ); }490 virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }491 virtual void print( std::ostream & os, Indenter indent = {} ) const override;492 };493 494 465 /// LogicalExpr represents a short-circuit boolean expression (&& or ||) 495 466 class LogicalExpr : public Expression { -
src/SynTree/Mutator.h
rc60a664 r99cadc60 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Mon Jul 24 16:31:00 201713 // Update Count : 1 611 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 25 22:37:46 2019 13 // Update Count : 17 14 14 // 15 15 #pragma once … … 74 74 virtual Expression * mutate( OffsetofExpr * offsetofExpr ) = 0; 75 75 virtual Expression * mutate( OffsetPackExpr * offsetPackExpr ) = 0; 76 virtual Expression * mutate( AttrExpr * attrExpr ) = 0;77 76 virtual Expression * mutate( LogicalExpr * logicalExpr ) = 0; 78 77 virtual Expression * mutate( ConditionalExpr * conditionalExpr ) = 0; -
src/SynTree/SynTree.h
rc60a664 r99cadc60 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Mon Jul 24 16:54:00 201713 // Update Count : 1 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 25 22:37:45 2019 13 // Update Count : 12 14 14 // 15 15 … … 79 79 class OffsetofExpr; 80 80 class OffsetPackExpr; 81 class AttrExpr;82 81 class LogicalExpr; 83 82 class ConditionalExpr; -
src/SynTree/Visitor.h
rc60a664 r99cadc60 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Mon Jul 24 16:28:00 201713 // Update Count : 1 311 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 25 22:21:49 2019 13 // Update Count : 14 14 14 // 15 15 … … 123 123 virtual void visit( OffsetPackExpr * node ) { visit( const_cast<const OffsetPackExpr *>(node) ); } 124 124 virtual void visit( const OffsetPackExpr * offsetPackExpr ) = 0; 125 virtual void visit( AttrExpr * node ) { visit( const_cast<const AttrExpr *>(node) ); }126 virtual void visit( const AttrExpr * attrExpr ) = 0;127 125 virtual void visit( LogicalExpr * node ) { visit( const_cast<const LogicalExpr *>(node) ); } 128 126 virtual void visit( const LogicalExpr * logicalExpr ) = 0; -
tests/pybin/settings.py
rc60a664 r99cadc60 22 22 'x86-64' : 'x64', 23 23 'x86_64' : 'x64', 24 'aarch64' : 'x64', 24 25 'x86' : 'x86', 25 26 'i386' : 'x86', … … 40 41 canonical_host = Architecture.make_canonical( config.HOSTARCH ) 41 42 except KeyError: 42 print("Unk own host architecture %s" % config.HOSTARCH, file=sys.stderr)43 print("Unknown host architecture %s" % config.HOSTARCH, file=sys.stderr) 43 44 sys.exit(1) 44 45 … … 47 48 arch = Architecture.make_canonical( arch ) 48 49 except KeyError: 49 print("Unk own architecture %s" % arch, file=sys.stderr)50 print("Unknown architecture %s" % arch, file=sys.stderr) 50 51 sys.exit(1) 51 52
Note: See TracChangeset
for help on using the changeset viewer.