Changeset 28f3a19
- Timestamp:
- Jun 27, 2018, 3:28:41 PM (7 years ago)
- Branches:
- new-env, with_gc
- Children:
- b21c77a
- Parents:
- 0182bfa (diff), 63238a4 (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:
-
- 19 added
- 4 deleted
- 121 edited
- 3 moved
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified Jenkins/TestRegen ¶
r0182bfa r28f3a19 33 33 email() 34 34 } 35 } 35 } 36 36 catch (Exception caughtError) { 37 37 email_error() … … 65 65 66 66 def install_dir = pwd tmp: true 67 67 68 68 //Configure the conpilation (Output is not relevant) 69 69 //Use the current directory as the installation target so nothing … … 101 101 def email_subject = "[cforall dashboard][TEST REGEN# ${env.BUILD_NUMBER}] - Result" 102 102 def email_body = """This is an automated email from the Jenkins build machine. It was 103 generated http ://plg2:8082/dashboard.103 generated https://cforall.uwaterloo.ca:8082/dashboard.html. 104 104 105 105 Please apply the required changes using the following method : … … 118 118 def email_subject = "[cforall dashboard][TEST REGEN# ${env.BUILD_NUMBER}] - FAILURE" 119 119 def email_body = """This is an automated email from the Jenkins build machine. It was 120 generated http ://plg2:8082/dashboard.120 generated https://cforall.uwaterloo.ca:8082/dashboard.html. 121 121 122 122 Test generation encoutered an error please see attached logs -
TabularUnified Jenkinsfile ¶
r0182bfa r28f3a19 174 174 175 175 def notify_server(int wait) { 176 sh """curl --data "wait=${wait}" -X POST http ://plg2:8082/jenkins/notify > /dev/null || true"""176 sh """curl --data "wait=${wait}" -X POST https://cforall.uwaterloo.ca:8082/jenkins/notify > /dev/null || true""" 177 177 return 178 178 } … … 329 329 330 330 //Then publish the results 331 sh 'curl -H \'Content-Type: application/json\' --data @bench.json http ://plg2:8082/jenkins/publish > /dev/null || true'331 sh 'curl -H \'Content-Type: application/json\' --data @bench.json https://cforall.uwaterloo.ca:8082/jenkins/publish > /dev/null || true' 332 332 } 333 333 } -
TabularUnified README ¶
r0182bfa r28f3a19 107 107 - the implicit coercion of structure types to the type of their first member is 108 108 not implemented 109 109 110 110 Who is responsible for cfa-cc? 111 111 ------------------------------ … … 115 115 The Cforall project maintains a web page: 116 116 117 http ://plg.uwaterloo.ca/~cforall117 https://cforall.uwaterloo.ca -
TabularUnified doc/papers/OOPSLA17/Makefile ¶
r0182bfa r28f3a19 33 33 34 34 DOCUMENT = generic_types.pdf 35 BASE = ${basename ${DOCUMENT}} 35 36 36 37 # Directives # … … 41 42 42 43 clean : 43 @rm -frv ${DOCUMENT} ${ basename ${DOCUMENT}}.ps ${Build}44 @rm -frv ${DOCUMENT} ${BASE}.ps ${Build} 44 45 45 46 # File Dependencies # 46 47 47 ${DOCUMENT} : ${ basename ${DOCUMENT}}.ps48 ${DOCUMENT} : ${BASE}.ps 48 49 ps2pdf $< 49 50 50 ${ basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi51 ${BASE}.ps : ${BASE}.dvi 51 52 dvips ${Build}/$< -o $@ 52 53 53 ${basename ${DOCUMENT}}.dvi : Makefile ${Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ../../bibliography/pl.bib 54 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 55 ../../bibliography/pl.bib | ${Build} 54 56 # Must have *.aux file containing citations for bibtex 55 57 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi … … 63 65 ## Define the default recipes. 64 66 65 ${Build} :67 ${Build} : 66 68 mkdir -p ${Build} 67 69 … … 69 71 gnuplot -e Build="'${Build}/'" evaluation/timing.gp 70 72 71 %.tex : %.fig 73 %.tex : %.fig | ${Build} 72 74 fig2dev -L eepic $< > ${Build}/$@ 73 75 74 %.ps : %.fig 76 %.ps : %.fig | ${Build} 75 77 fig2dev -L ps $< > ${Build}/$@ 76 78 77 %.pstex : %.fig 79 %.pstex : %.fig | ${Build} 78 80 fig2dev -L pstex $< > ${Build}/$@ 79 81 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t -
TabularUnified doc/papers/concurrency/Makefile ¶
r0182bfa r28f3a19 20 20 21 21 FIGURES = ${addsuffix .tex, \ 22 monitor \23 ext_monitor \24 22 int_monitor \ 25 23 dependency \ … … 27 25 28 26 PICTURES = ${addsuffix .pstex, \ 27 monitor \ 28 ext_monitor \ 29 29 system \ 30 30 monitor_structs \ … … 59 59 dvips ${Build}/$< -o $@ 60 60 61 ${BASE}.dvi : Makefile ${B uild} ${BASE}.out.ps WileyNJD-AMA.bst ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \62 annex/local.bib ../../bibliography/pl.bib 61 ${BASE}.dvi : Makefile ${BASE}.out.ps WileyNJD-AMA.bst ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 62 annex/local.bib ../../bibliography/pl.bib | ${Build} 63 63 # Must have *.aux file containing citations for bibtex 64 64 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi 65 ${BibTeX} ${Build}/${basename $@}65 -${BibTeX} ${Build}/${basename $@} 66 66 # Some citations reference others so run again to resolve these citations 67 67 ${LaTeX} ${basename $@}.tex 68 ${BibTeX} ${Build}/${basename $@}68 -${BibTeX} ${Build}/${basename $@} 69 69 # Run again to finish citations 70 70 ${LaTeX} ${basename $@}.tex … … 72 72 ## Define the default recipes. 73 73 74 ${Build} :74 ${Build} : 75 75 mkdir -p ${Build} 76 76 77 ${BASE}.out.ps :${Build}77 ${BASE}.out.ps : | ${Build} 78 78 ln -fs ${Build}/Paper.out.ps . 79 79 80 WileyNJD-AMA.bst :80 WileyNJD-AMA.bst : 81 81 ln -fs ../AMA/AMA-stix/ama/WileyNJD-AMA.bst . 82 82 83 %.tex : %.fig ${Build}83 %.tex : %.fig | ${Build} 84 84 fig2dev -L eepic $< > ${Build}/$@ 85 85 86 %.ps : %.fig ${Build}86 %.ps : %.fig | ${Build} 87 87 fig2dev -L ps $< > ${Build}/$@ 88 88 89 %.pstex : %.fig ${Build}89 %.pstex : %.fig | ${Build} 90 90 fig2dev -L pstex $< > ${Build}/$@ 91 91 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t -
TabularUnified doc/papers/concurrency/Paper.tex ¶
r0182bfa r28f3a19 56 56 \newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}} 57 57 \newcommand{\Emph}[2][red]{{\color{#1}\textbf{\emph{#2}}}} 58 \newcommand{\R}[1]{\Textbf{#1}}59 \newcommand{\B}[1]{{\Textbf[blue]{#1}}}60 \newcommand{\G}[1]{{\Textbf[OliveGreen]{#1}}}61 58 \newcommand{\uC}{$\mu$\CC} 62 \newcommand{\cit}{\textsuperscript{[Citation Needed]}\xspace} 63 \newcommand{\TODO}{{\Textbf{TODO}}} 59 \newcommand{\TODO}[1]{{\Textbf{#1}}} 64 60 65 61 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% … … 258 254 \section{Introduction} 259 255 260 This paper provides a minimal concurrency \newterm{A bstractProgram Interface} (API) that is simple, efficient and can be used to build other concurrency features.256 This paper provides a minimal concurrency \newterm{Application Program Interface} (API) that is simple, efficient and can be used to build other concurrency features. 261 257 While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master. 262 258 An easier approach for programmers is to support higher-level constructs as the basis of concurrency. … … 275 271 Hence, there are two problems to be solved: concurrency and parallelism. 276 272 While these two concepts are often combined, they are distinct, requiring different tools~\cite[\S~2]{Buhr05a}. 277 Concurrency tools handle synchronization and mutual exclusion, while parallelism tools handle performance, costand resource utilization.273 Concurrency tools handle mutual exclusion and synchronization, while parallelism tools handle performance, cost, and resource utilization. 278 274 279 275 The proposed concurrency API is implemented in a dialect of C, called \CFA. … … 286 282 Extended versions and explanation of the following code examples are available at the \CFA website~\cite{Cforall} or in Moss~\etal~\cite{Moss18}. 287 283 288 \CFA is a nextension of ISO-C, and hence, supports all C paradigms.284 \CFA is a non-object-oriented extension of ISO-C, and hence, supports all C paradigms. 289 285 %It is a non-object-oriented system-language, meaning most of the major abstractions have either no runtime overhead or can be opted out easily. 290 Like C, the b asics of \CFA revolve around structures and functions.286 Like C, the building blocks of \CFA are structures and routines. 291 287 Virtually all of the code generated by the \CFA translator respects C memory layouts and calling conventions. 292 288 While \CFA is not an object-oriented language, lacking the concept of a receiver (\eg @this@) and nominal inheritance-relationships, C does have a notion of objects: ``region of data storage in the execution environment, the contents of which can represent values''~\cite[3.15]{C11}. … … 300 296 int x = 1, y = 2, z = 3; 301 297 int * p1 = &x, ** p2 = &p1, *** p3 = &p2, $\C{// pointers to x}$ 302 `&` r1 = x, `&&` r2 = r1,`&&&` r3 = r2; $\C{// references to x}$298 `&` r1 = x, `&&` r2 = r1, `&&&` r3 = r2; $\C{// references to x}$ 303 299 int * p4 = &z, `&` r4 = z; 304 300 … … 349 345 'with' '(' $\emph{expression-list}$ ')' $\emph{compound-statement}$ 350 346 \end{cfa} 351 and may appear as the body of a function or nested within a functionbody.347 and may appear as the body of a routine or nested within a routine body. 352 348 Each expression in the expression-list provides a type and object. 353 349 The type must be an aggregate type. … … 360 356 361 357 \CFA maximizes the ability to reuse names via overloading to aggressively address the naming problem. 362 Both variables and functions may be overloaded, where selection is based on types, and number of returns (as in Ada~\cite{Ada}) and arguments.358 Both variables and routines may be overloaded, where selection is based on types, and number of returns (as in Ada~\cite{Ada}) and arguments. 363 359 \begin{cquote} 364 360 \vspace*{-\baselineskip}%??? … … 415 411 \end{cquote} 416 412 Overloading is important for \CFA concurrency since the runtime system relies on creating different types to represent concurrency objects. 417 Therefore, overloading is necessary to prevent the need for long prefixes and other naming conventions to prevent name clashes. 418 As seen in Section~\ref{basics}, function @main@ is heavily overloaded. 419 420 Variable overloading is useful in the parallel semantics of the @with@ statement for fields with the same name: 413 Therefore, overloading eliminates long prefixes and other naming conventions to prevent name clashes. 414 As seen in Section~\ref{basics}, routine @main@ is heavily overloaded. 415 For example, variable overloading is useful in the parallel semantics of the @with@ statement for fields with the same name: 421 416 \begin{cfa} 422 417 struct S { int `i`; int j; double m; } s; … … 432 427 } 433 428 \end{cfa} 434 For parallel semantics, both @s.i@ and @t.i@ are visible the same type, so only @i@ is ambiguous without qualification.429 For parallel semantics, both @s.i@ and @t.i@ are visible with the same type, so only @i@ is ambiguous without qualification. 435 430 436 431 … … 438 433 439 434 Overloading also extends to operators. 440 Operator-overloading syntax names a routine with theoperator symbol and question marks for the operands:435 Operator-overloading syntax creates a routine name with an operator symbol and question marks for the operands: 441 436 \begin{cquote} 442 437 \lstDeleteShortInline@% … … 472 467 \end{cquote} 473 468 While concurrency does not use operator overloading directly, it provides an introduction for the syntax of constructors. 474 475 476 \subsection{Parametric Polymorphism}477 \label{s:ParametricPolymorphism}478 479 The signature feature of \CFA is parametric-polymorphic functions~\cite{} with functions generalized using a @forall@ clause (giving the language its name), which allow separately compiled routines to support generic usage over multiple types.480 For example, the following sum function works for any type that supports construction from 0 and addition:481 \begin{cfa}482 forall( otype T | { void `?{}`( T *, zero_t ); T `?+?`( T, T ); } ) // constraint type, 0 and +483 T sum( T a[$\,$], size_t size ) {484 `T` total = { `0` }; $\C{// initialize by 0 constructor}$485 for ( size_t i = 0; i < size; i += 1 )486 total = total `+` a[i]; $\C{// select appropriate +}$487 return total;488 }489 S sa[5];490 int i = sum( sa, 5 ); $\C{// use S's 0 construction and +}$491 \end{cfa}492 493 \CFA provides \newterm{traits} to name a group of type assertions, where the trait name allows specifying the same set of assertions in multiple locations, preventing repetition mistakes at each function declaration:494 \begin{cfa}495 trait `sumable`( otype T ) {496 void `?{}`( T &, zero_t ); $\C{// 0 literal constructor}$497 T `?+?`( T, T ); $\C{// assortment of additions}$498 T ?+=?( T &, T );499 T ++?( T & );500 T ?++( T & );501 };502 forall( otype T `| sumable( T )` ) $\C{// use trait}$503 T sum( T a[$\,$], size_t size );504 \end{cfa}505 506 Assertions can be @otype@ or @dtype@.507 @otype@ refers to a ``complete'' object, \ie an object has a size, default constructor, copy constructor, destructor and an assignment operator.508 @dtype@ only guarantees an object has a size and alignment.509 510 Using the return type for discrimination, it is possible to write a type-safe @alloc@ based on the C @malloc@:511 \begin{cfa}512 forall( dtype T | sized(T) ) T * alloc( void ) { return (T *)malloc( sizeof(T) ); }513 int * ip = alloc(); $\C{// select type and size from left-hand side}$514 double * dp = alloc();515 struct S {...} * sp = alloc();516 \end{cfa}517 where the return type supplies the type/size of the allocation, which is impossible in most type systems.518 469 519 470 … … 544 495 \CFA also provides @new@ and @delete@, which behave like @malloc@ and @free@, in addition to constructing and destructing objects: 545 496 \begin{cfa} 546 { struct S s = {10}; $\C{// allocation, call constructor}$547 ... 497 { 498 ... struct S s = {10}; ... $\C{// allocation, call constructor}$ 548 499 } $\C{// deallocation, call destructor}$ 549 500 struct S * s = new(); $\C{// allocation, call constructor}$ … … 551 502 delete( s ); $\C{// deallocation, call destructor}$ 552 503 \end{cfa} 553 \CFA concurrency uses object lifetime as a means of synchronization and/or mutual exclusion. 504 \CFA concurrency uses object lifetime as a means of mutual exclusion and/or synchronization. 505 506 507 \subsection{Parametric Polymorphism} 508 \label{s:ParametricPolymorphism} 509 510 The signature feature of \CFA is parametric-polymorphic routines~\cite{} with routines generalized using a @forall@ clause (giving the language its name), which allow separately compiled routines to support generic usage over multiple types. 511 For example, the following sum routine works for any type that supports construction from 0 and addition: 512 \begin{cfa} 513 forall( otype T | { void `?{}`( T *, zero_t ); T `?+?`( T, T ); } ) // constraint type, 0 and + 514 T sum( T a[$\,$], size_t size ) { 515 `T` total = { `0` }; $\C{// initialize by 0 constructor}$ 516 for ( size_t i = 0; i < size; i += 1 ) 517 total = total `+` a[i]; $\C{// select appropriate +}$ 518 return total; 519 } 520 S sa[5]; 521 int i = sum( sa, 5 ); $\C{// use S's 0 construction and +}$ 522 \end{cfa} 523 The builtin type @zero_t@ (and @one_t@) overload constant 0 (and 1) for a new types, where both 0 and 1 have special meaning in C. 524 525 \CFA provides \newterm{traits} to name a group of type assertions, where the trait name allows specifying the same set of assertions in multiple locations, preventing repetition mistakes at each routine declaration: 526 \begin{cfa} 527 trait `sumable`( otype T ) { 528 void `?{}`( T &, zero_t ); $\C{// 0 literal constructor}$ 529 T `?+?`( T, T ); $\C{// assortment of additions}$ 530 T ?+=?( T &, T ); 531 T ++?( T & ); 532 T ?++( T & ); 533 }; 534 forall( otype T `| sumable( T )` ) $\C{// use trait}$ 535 T sum( T a[$\,$], size_t size ); 536 \end{cfa} 537 538 Assertions can be @otype@ or @dtype@. 539 @otype@ refers to a ``complete'' object, \ie an object has a size, default constructor, copy constructor, destructor and an assignment operator. 540 @dtype@ only guarantees an object has a size and alignment. 541 542 Using the return type for discrimination, it is possible to write a type-safe @alloc@ based on the C @malloc@: 543 \begin{cfa} 544 forall( dtype T | sized(T) ) T * alloc( void ) { return (T *)malloc( sizeof(T) ); } 545 int * ip = alloc(); $\C{// select type and size from left-hand side}$ 546 double * dp = alloc(); 547 struct S {...} * sp = alloc(); 548 \end{cfa} 549 where the return type supplies the type/size of the allocation, which is impossible in most type systems. 554 550 555 551 … … 584 580 \subsection{\protect\CFA's Thread Building Blocks} 585 581 586 An important missing feature in C is threading\footnote{While the C11 standard defines a ``threads.h''header, it is minimal and defined as optional.582 An important missing feature in C is threading\footnote{While the C11 standard defines a \protect\lstinline@threads.h@ header, it is minimal and defined as optional. 587 583 As such, library support for threading is far from widespread. 588 At the time of writing the paper, neither \protect\lstinline |gcc| nor \protect\lstinline|clang| support ``threads.h''in their standard libraries.}.589 On modern architectures, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore existing and new programming languages must have tools for writing efficient concurrent programs to take advantage of parallelism.584 At the time of writing the paper, neither \protect\lstinline@gcc@ nor \protect\lstinline@clang@ support \protect\lstinline@threads.h@ in their standard libraries.}. 585 In modern programming languages, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore existing and new programming languages must have tools for writing efficient concurrent programs to take advantage of parallelism. 590 586 As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers familiar with imperative languages. 591 587 Furthermore, because C is a system-level language, programmers expect to choose precisely which features they need and which cost they are willing to pay. … … 625 621 \newbox\myboxA 626 622 \begin{lrbox}{\myboxA} 627 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]623 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 628 624 `int f1, f2, state = 1;` // single global variables 629 625 int fib() { … … 642 638 } 643 639 } 644 \end{ lstlisting}640 \end{cfa} 645 641 \end{lrbox} 646 642 647 643 \newbox\myboxB 648 644 \begin{lrbox}{\myboxB} 649 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]645 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 650 646 #define FIB_INIT `{ 0, 1 }` 651 647 typedef struct { int f2, f1; } Fib; … … 664 660 } 665 661 } 666 \end{ lstlisting}662 \end{cfa} 667 663 \end{lrbox} 668 664 … … 677 673 \newbox\myboxA 678 674 \begin{lrbox}{\myboxA} 679 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]675 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 680 676 `coroutine` Fib { int fn; }; 681 677 void main( Fib & fib ) with( fib ) { … … 697 693 } 698 694 } 699 \end{ lstlisting}695 \end{cfa} 700 696 \end{lrbox} 701 697 \newbox\myboxB 702 698 \begin{lrbox}{\myboxB} 703 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]699 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 704 700 `coroutine` Fib { int ret; }; 705 701 void main( Fib & f ) with( fib ) { … … 721 717 722 718 723 \end{ lstlisting}719 \end{cfa} 724 720 \end{lrbox} 725 721 \subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA} … … 731 727 732 728 Using a coroutine, it is possible to express the Fibonacci formula directly without any of the C problems. 733 Figure~\ref{f:Coroutine3States} creates a @coroutine@ type: 734 \begin{cfa} 735 `coroutine` Fib { int fn; }; 736 \end{cfa} 737 which provides communication, @fn@, for the \newterm{coroutine main}, @main@, which runs on the coroutine stack, and possibly multiple interface functions, @next@. 729 Figure~\ref{f:Coroutine3States} creates a @coroutine@ type, @`coroutine` Fib { int fn; }@, which provides communication, @fn@, for the \newterm{coroutine main}, @main@, which runs on the coroutine stack, and possibly multiple interface routines, \eg @next@. 738 730 Like the structure in Figure~\ref{f:ExternalState}, the coroutine type allows multiple instances, where instances of this type are passed to the (overloaded) coroutine main. 739 The coroutine main's stack holds the state for the next generation, @f1@ and @f2@, and the code has the three suspend points, representing the three states in the Fibonacci formula, to context switch back to the caller's resume.740 The interface function,@next@, takes a Fibonacci instance and context switches to it using @resume@;731 The coroutine main's stack holds the state for the next generation, @f1@ and @f2@, and the code has the three suspend points, representing the three states in the Fibonacci formula, to context switch back to the caller's @resume@. 732 The interface routine @next@, takes a Fibonacci instance and context switches to it using @resume@; 741 733 on restart, the Fibonacci field, @fn@, contains the next value in the sequence, which is returned. 742 734 The first @resume@ is special because it cocalls the coroutine at its coroutine main and allocates the stack; … … 769 761 \newbox\myboxA 770 762 \begin{lrbox}{\myboxA} 771 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]763 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 772 764 `coroutine` Format { 773 765 char ch; // used for communication … … 801 793 } 802 794 } 803 \end{ lstlisting}795 \end{cfa} 804 796 \end{lrbox} 805 797 806 798 \newbox\myboxB 807 799 \begin{lrbox}{\myboxB} 808 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]800 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 809 801 struct Format { 810 802 char ch; … … 838 830 format( &fmt ); 839 831 } 840 \end{ lstlisting}832 \end{cfa} 841 833 \end{lrbox} 842 834 \subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA} … … 847 839 \end{figure} 848 840 849 The previous examples are \newterm{asymmetric (semi) coroutine}s because one coroutine always calls a resuming function for another coroutine, and the resumed coroutine always suspends back to its last resumer, similar to call/return for normal functions.850 However, there is no stack growth because @resume@/@suspend@ context switch to existing stack-frames rather than create new ones.851 \newterm{Symmetric (full) coroutine}s have a coroutine call a resuming functionfor another coroutine, which eventually forms a resuming-call cycle.841 The previous examples are \newterm{asymmetric (semi) coroutine}s because one coroutine always calls a resuming routine for another coroutine, and the resumed coroutine always suspends back to its last resumer, similar to call/return for normal routines. 842 However,@resume@/@suspend@ context switch to existing stack-frames rather than create new ones so there is no stack growth. 843 \newterm{Symmetric (full) coroutine}s have a coroutine call a resuming routine for another coroutine, which eventually forms a resuming-call cycle. 852 844 (The trivial cycle is a coroutine resuming itself.) 853 845 This control flow is similar to recursion for normal routines, but again there is no stack growth from the context switch. … … 931 923 Figure~\ref{f:ProdCons} shows a producer/consumer symmetric-coroutine performing bi-directional communication. 932 924 Since the solution involves a full-coroutining cycle, the program main creates one coroutine in isolation, passes this coroutine to its partner, and closes the cycle at the call to @start@. 933 The @start@ functioncommunicates both the number of elements to be produced and the consumer into the producer's coroutine structure.925 The @start@ routine communicates both the number of elements to be produced and the consumer into the producer's coroutine structure. 934 926 Then the @resume@ to @prod@ creates @prod@'s stack with a frame for @prod@'s coroutine main at the top, and context switches to it. 935 927 @prod@'s coroutine main starts, creates local variables that are retained between coroutine activations, and executes $N$ iterations, each generating two random values, calling the consumer to deliver the values, and printing the status returned from the consumer. … … 937 929 The producer call to @delivery@ transfers values into the consumer's communication variables, resumes the consumer, and returns the consumer status. 938 930 For the first resume, @cons@'s stack is initialized, creating local variables retained between subsequent activations of the coroutine. 939 The consumer iterates until the @done@ flag is set, prints , increments status, and calls back to the producer via @payment@, and on return from @payment@, prints the receipt from the producer and increments @money@ (inflation).931 The consumer iterates until the @done@ flag is set, prints the values delivered by the producer, increments status, and calls back to the producer via @payment@, and on return from @payment@, prints the receipt from the producer and increments @money@ (inflation). 940 932 The call from the consumer to the @payment@ introduces the cycle between producer and consumer. 941 933 When @payment@ is called, the consumer copies values into the producer's communication variable and a resume is executed. … … 967 959 \end{cfa} 968 960 and the programming language (and possibly its tool set, \eg debugger) may need to understand @baseCoroutine@ because of the stack. 969 Furthermore, the execution of constructs/destructors is in the wrong order for certain operations , \eg for threads;970 \eg,if the thread is implicitly started, it must start \emph{after} all constructors, because the thread relies on a completely initialized object, but the inherited constructor runs \emph{before} the derived.961 Furthermore, the execution of constructs/destructors is in the wrong order for certain operations. 962 For example, for threads if the thread is implicitly started, it must start \emph{after} all constructors, because the thread relies on a completely initialized object, but the inherited constructor runs \emph{before} the derived. 971 963 972 964 An alternatively is composition: … … 980 972 However, there is nothing preventing wrong placement or multiple declarations. 981 973 982 For coroutines as for threads, many implementations are based on routine pointers or functionobjects~\cite{Butenhof97, C++14, MS:VisualC++, BoostCoroutines15}.974 For coroutines as for threads, many implementations are based on routine pointers or routine objects~\cite{Butenhof97, C++14, MS:VisualC++, BoostCoroutines15}. 983 975 For example, Boost implements coroutines in terms of four functor object-types: 984 976 \begin{cfa} … … 988 980 symmetric_coroutine<>::yield_type 989 981 \end{cfa} 990 Similarly, the canonical threading paradigm is often based on function pointers, \eg @pthread@~\cite{pthreads}, \Csharp~\cite{Csharp}, Go~\cite{Go}, and Scala~\cite{Scala}.982 Similarly, the canonical threading paradigm is often based on routine pointers, \eg @pthreads@~\cite{pthreads}, \Csharp~\cite{Csharp}, Go~\cite{Go}, and Scala~\cite{Scala}. 991 983 However, the generic thread-handle (identifier) is limited (few operations), unless it is wrapped in a custom type. 992 984 \begin{cfa} … … 1002 994 \end{cfa} 1003 995 Since the custom type is simple to write in \CFA and solves several issues, added support for routine/lambda-based coroutines adds very little. 996 997 Note, the type @coroutine_t@ must be an abstract handle to the coroutine, because the coroutine descriptor and its stack are non-copyable. 998 Copying the coroutine descriptor results in copies being out of date with the current state of the stack. 999 Correspondingly, copying the stack results is copies being out of date with the coroutine descriptor, and pointers in the stack being out of date to data on the stack. 1000 (There is no mechanism in C to find all stack-specific pointers and update them as part of a copy.) 1004 1001 1005 1002 The selected approach is to use language support by introducing a new kind of aggregate (structure): … … 1014 1011 Furthermore, implementing coroutines without language supports also displays the power of a programming language. 1015 1012 While this is ultimately the option used for idiomatic \CFA code, coroutines and threads can still be constructed without using the language support. 1016 The reserved keyword eases use for the common cases.1017 1018 Part of the mechanism to generalize coroutines is using a \CFA trait, which defines a coroutine as anything satisfying the trait @is_coroutine@, and this trait is used to restrict coroutine-manipulation functions:1019 \begin{cfa} 1020 trait is_coroutine( dtypeT ) {1021 void main( T & this);1022 coroutine_desc * get_coroutine( T & this);1013 The reserved keyword simply eases use for the common cases. 1014 1015 Part of the mechanism to generalize coroutines is using a \CFA trait, which defines a coroutine as anything satisfying the trait @is_coroutine@, and this trait is used to restrict coroutine-manipulation routines: 1016 \begin{cfa} 1017 trait is_coroutine( `dtype` T ) { 1018 void main( T & ); 1019 coroutine_desc * get_coroutine( T & ); 1023 1020 }; 1024 forall( dtype T | is_coroutine(T) ) void get_coroutine( T & );1025 forall( dtype T | is_coroutine(T) ) void suspend( T & );1026 forall( dtype T | is_coroutine(T) ) void resume( T & ); 1027 \end{cfa} 1028 Th is definition ensures there is a statically-typed @main@ function that is the starting point (first stack frame) of a coroutine.1029 No return value or additional parameters are necessary for this function, because the coroutine type allows an arbitrary number of interface functions with corresponding arbitrary typed input/output values.1030 As well, any object passed to @suspend@ and @resume@is a coroutine since it must satisfy the @is_coroutine@ trait to compile.1031 The advantage of this approach is that users can easily create different types of coroutines, for example, changing the memory layout of a coroutine is trivial when implementing the @get_coroutine@ routine.1021 forall( `dtype` T | is_coroutine(T) ) void suspend( T & ); 1022 forall( `dtype` T | is_coroutine(T) ) void resume( T & ); 1023 \end{cfa} 1024 The @dtype@ property of the trait ensures the coroutine descriptor is non-copyable, so all coroutines must be passed by reference (pointer). 1025 The routine definitions ensures there is a statically-typed @main@ routine that is the starting point (first stack frame) of a coroutine, and a mechanism to get (read) the currently executing coroutine handle. 1026 The @main@ routine has no return value or additional parameters because the coroutine type allows an arbitrary number of interface routines with corresponding arbitrary typed input/output values versus fixed ones. 1027 The generic routines @suspend@ and @resume@ can be redefined, but any object passed to them is a coroutine since it must satisfy the @is_coroutine@ trait to compile. 1028 The advantage of this approach is that users can easily create different types of coroutines, \eg changing the memory layout of a coroutine is trivial when implementing the @get_coroutine@ routine, and possibly redefining @suspend@ and @resume@. 1032 1029 The \CFA keyword @coroutine@ implicitly implements the getter and forward declarations required for implementing the coroutine main: 1033 1030 \begin{cquote} … … 1039 1036 }; 1040 1037 \end{cfa} 1041 & {\Large $\Rightarrow$} & 1038 & 1039 {\Large $\Rightarrow$} 1040 & 1042 1041 \begin{tabular}{@{}ccc@{}} 1043 1042 \begin{cfa} … … 1073 1072 Like coroutines and for the same design reasons, the selected approach for user threads is to use language support by introducing a new kind of aggregate (structure) and a \CFA trait: 1074 1073 \begin{cquote} 1075 \begin{tabular}{@{}c@{\hspace{ 2\parindentlnth}}c@{}}1074 \begin{tabular}{@{}c@{\hspace{3\parindentlnth}}c@{}} 1076 1075 \begin{cfa} 1077 1076 thread myThread { … … 1083 1082 & 1084 1083 \begin{cfa} 1085 trait is_thread( dtypeT ) {1086 void main( T & this);1087 thread_desc * get_thread( T & this);1088 void ^?{}( T & `mutex` this);1084 trait is_thread( `dtype` T ) { 1085 void main( T & ); 1086 thread_desc * get_thread( T & ); 1087 void ^?{}( T & `mutex` ); 1089 1088 }; 1090 1089 \end{cfa} … … 1092 1091 \end{cquote} 1093 1092 (The qualifier @mutex@ for the destructor parameter is discussed in Section~\ref{s:Monitors}.) 1094 Like a coroutine, the statically-typed @main@ functionis the starting point (first stack frame) of a user thread.1093 Like a coroutine, the statically-typed @main@ routine is the starting point (first stack frame) of a user thread. 1095 1094 The difference is that a coroutine borrows a thread from its caller, so the first thread resuming a coroutine creates an instance of @main@; 1096 1095 whereas, a user thread receives its own thread from the runtime system, which starts in @main@ as some point after the thread constructor is run.\footnote{ 1097 The \lstinline@main@ function is already a special routine in C (where the program begins), so it is a natural extension of the semantics to use overloading to declare mains for different coroutines/threads (the normal main being the main of the initial thread).}1098 No return value or additional parameters are necessary for this function, because the task type allows an arbitrary number of interface functions with corresponding arbitrary typed input/output values.1096 The \lstinline@main@ routine is already a special routine in C, \ie where the program's initial thread begins, so it is a natural extension of this semantics to use overloading to declare \lstinline@main@s for user coroutines and threads.} 1097 No return value or additional parameters are necessary for this routine because the task type allows an arbitrary number of interface routines with corresponding arbitrary typed input/output values. 1099 1098 1100 1099 \begin{comment} % put in appendix with coroutine version ??? … … 1109 1108 1110 1109 In this example, threads of type @foo@ start execution in the @void main(foo &)@ routine, which prints @"Hello World!".@ While this paper encourages this approach to enforce strongly typed programming, users may prefer to use the routine-based thread semantics for the sake of simplicity. 1111 With the static semantics it is trivial to write a thread type that takes a functionpointer as a parameter and executes it on its stack asynchronously.1112 \begin{cfa} 1113 typedef void (*void Func)(int);1114 1115 thread FuncRunner {1116 void Funcfunc;1110 With the static semantics it is trivial to write a thread type that takes a routine pointer as a parameter and executes it on its stack asynchronously. 1111 \begin{cfa} 1112 typedef void (*voidRtn)(int); 1113 1114 thread RtnRunner { 1115 voidRtn func; 1117 1116 int arg; 1118 1117 }; 1119 1118 1120 void ?{}( FuncRunner & this, voidFunc inFunc, int arg) {1121 this.func = in Func;1119 void ?{}(RtnRunner & this, voidRtn inRtn, int arg) { 1120 this.func = inRtn; 1122 1121 this.arg = arg; 1123 1122 } 1124 1123 1125 void main( FuncRunner & this) {1126 // thread starts here and runs the function1124 void main(RtnRunner & this) { 1125 // thread starts here and runs the routine 1127 1126 this.func( this.arg ); 1128 1127 } … … 1133 1132 1134 1133 int main() { 1135 FuncRunner f = {hello, 42};1134 RtnRunner f = {hello, 42}; 1136 1135 return 0? 1137 1136 } 1138 1137 \end{cfa} 1139 A consequence of the strongly typed approach to main is that memory layout of parameters and return values to/from a thread are now explicitly specified in the \textbf{ api}.1138 A consequence of the strongly typed approach to main is that memory layout of parameters and return values to/from a thread are now explicitly specified in the \textbf{API}. 1140 1139 \end{comment} 1141 1140 … … 1186 1185 void main( Adder & adder ) with( adder ) { 1187 1186 subtotal = 0; 1188 for ( int c = 0; c < cols; c += 1 ) { 1189 subtotal += row[c]; 1190 } 1187 for ( int c = 0; c < cols; c += 1 ) { subtotal += row[c]; } 1191 1188 } 1192 1189 int main() { … … 1210 1207 1211 1208 1212 \section{ Synchronization / Mutual Exclusion}1209 \section{Mutual Exclusion / Synchronization} 1213 1210 1214 1211 Uncontrolled non-deterministic execution is meaningless. 1215 To reestablish meaningful execution requires mechanisms to reintroduce determinism (control non-determinism), called synchronization and mutual exclusion, where synchronization is a timing relationship among threads and mutual exclusion is an access-control mechanism on data shared by threads.1216 Since many deterministic challenges appear with the use of mutable shared state, some languages/libraries disallow it (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka~\cite{Akka} (Scala)).1217 In these paradigms, interaction among concurrent objects is performed by stateless message-passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms closely relate to networking concepts (\eg channels~\cite{CSP,Go}).1218 However, in call/return-based languages, these approaches force a clear distinction (\ie introduce a new programming paradigm) between non-concurrent and concurrent computation (\ie function call versus message passing).1219 This distinction means a programmers needs to learntwo sets of design patterns.1212 To reestablish meaningful execution requires mechanisms to reintroduce determinism, \ie restrict non-determinism, called mutual exclusion and synchronization, where mutual exclusion is an access-control mechanism on data shared by threads, and synchronization is a timing relationship among threads~\cite[\S~4]{Buhr05a}. 1213 Since many deterministic challenges appear with the use of mutable shared state, some languages/libraries disallow it, \eg Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka~\cite{Akka} (Scala). 1214 In these paradigms, interaction among concurrent objects is performed by stateless message-passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms closely relate to networking concepts, \eg channels~\cite{CSP,Go}. 1215 However, in call/return-based languages, these approaches force a clear distinction, \ie introduce a new programming paradigm, between regular and concurrent computation, \eg routine call versus message passing. 1216 Hence, a programmer must learn and manipulate two sets of design patterns. 1220 1217 While this distinction can be hidden away in library code, effective use of the library still has to take both paradigms into account. 1221 1218 In contrast, approaches based on statefull models more closely resemble the standard call/return programming-model, resulting in a single programming paradigm. 1222 1219 1223 At the lowest level, concurrent control is implemented as atomic operations, upon which different kinds of locks mechanism are constructed, \eg semaphores~\cite{Dijkstra68b}and path expressions~\cite{Campbell74}.1220 At the lowest level, concurrent control is implemented by atomic operations, upon which different kinds of locks mechanism are constructed, \eg semaphores~\cite{Dijkstra68b}, barriers, and path expressions~\cite{Campbell74}. 1224 1221 However, for productivity it is always desirable to use the highest-level construct that provides the necessary efficiency~\cite{Hochstein05}. 1225 A newer approach is transactional memory~\cite{Herlihy93}.1222 A newer approach for restricting non-determinism is transactional memory~\cite{Herlihy93}. 1226 1223 While this approach is pursued in hardware~\cite{Nakaike15} and system languages, like \CC~\cite{Cpp-Transactions}, the performance and feature set is still too restrictive to be the main concurrency paradigm for system languages, which is why it was rejected as the core paradigm for concurrency in \CFA. 1227 1224 1228 One of the most natural, elegant, and efficient mechanisms for synchronization and mutual exclusion for shared-memory systems is the \emph{monitor}. 1229 Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}. 1230 Many programming languages -- \eg Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java} -- provide monitors as explicit language constructs. 1231 In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. 1232 For these reasons, this project proposes monitors as the core concurrency construct, upon which even higher-level approaches can be easily constructed.. 1225 One of the most natural, elegant, and efficient mechanisms for mutual exclusion and synchronization for shared-memory systems is the \emph{monitor}. 1226 First proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}, many concurrent programming-languages provide monitors as an explicit language construct: \eg Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}. 1227 In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as mutex locks or semaphores to simulate monitors. 1228 For these reasons, \CFA selected monitors as the core high-level concurrency-construct, upon which higher-level approaches can be easily constructed. 1233 1229 1234 1230 … … 1236 1232 1237 1233 A group of instructions manipulating a specific instance of shared data that must be performed atomically is called an (individual) \newterm{critical-section}~\cite{Dijkstra65}. 1238 A generalization isa \newterm{group critical-section}~\cite{Joung00}, where multiple tasks with the same session may use the resource simultaneously, but different sessions may not use the resource simultaneously.1234 The generalization is called a \newterm{group critical-section}~\cite{Joung00}, where multiple tasks with the same session may use the resource simultaneously, but different sessions may not use the resource simultaneously. 1239 1235 The readers/writer problem~\cite{Courtois71} is an instance of a group critical-section, where readers have the same session and all writers have a unique session. 1240 \newterm{Mutual exclusion} enforces th e correction number of threads are using a critical section at the same time.1236 \newterm{Mutual exclusion} enforces that the correct kind and number of threads are using a critical section. 1241 1237 1242 1238 However, many solutions exist for mutual exclusion, which vary in terms of performance, flexibility and ease of use. 1243 1239 Methods range from low-level locks, which are fast and flexible but require significant attention for correctness, to higher-level concurrency techniques, which sacrifice some performance to improve ease of use. 1244 Ease of use comes by either guaranteeing some problems cannot occur (\eg deadlock free), or by offering a more explicit coupling between shared data and critical section.1245 For example, the \CC @std::atomic<T>@ offers an easy way to express mutual-exclusion on a restricted set of operations (\eg reading/writing large types atomically).1246 However, a significant challenge with (low-level)locks is composability because it takes careful organization for multiple locks to be used while preventing deadlock.1247 Easing composability is another feature higher-level mutual-exclusion mechanisms offer.1240 Ease of use comes by either guaranteeing some problems cannot occur, \eg deadlock free, or by offering a more explicit coupling between shared data and critical section. 1241 For example, the \CC @std::atomic<T>@ offers an easy way to express mutual-exclusion on a restricted set of operations, \eg reading/writing, for numerical types. 1242 However, a significant challenge with locks is composability because it takes careful organization for multiple locks to be used while preventing deadlock. 1243 Easing composability is another feature higher-level mutual-exclusion mechanisms can offer. 1248 1244 1249 1245 … … 1251 1247 1252 1248 Synchronization enforces relative ordering of execution, and synchronization tools provide numerous mechanisms to establish these timing relationships. 1253 Low-level synchronization primitives offer good performance and flexibility at the cost of ease of use. 1254 Higher-level mechanisms often simplify usage by adding better coupling between synchronization and data (\eg message passing), or offering a simpler solution to otherwise involved challenges, \eg barrier lock. 1255 As mentioned above, synchronization can be expressed as guaranteeing that event \textit{X} always happens before \textit{Y}. 1256 Often synchronization is used to order access to a critical section, \eg ensuring the next kind of thread to enter a critical section is a reader thread 1257 If a writer thread is scheduled for next access, but another reader thread acquires the critical section first, the reader has \newterm{barged}. 1258 Barging can result in staleness/freshness problems, where a reader barges ahead of a write and reads temporally stale data, or a writer barges ahead of another writer overwriting data with a fresh value preventing the previous value from having an opportunity to be read. 1249 Low-level synchronization primitives offer good performance and flexibility at the cost of ease of use; 1250 higher-level mechanisms often simplify usage by adding better coupling between synchronization and data, \eg message passing, or offering a simpler solution to otherwise involved challenges, \eg barrier lock. 1251 Often synchronization is used to order access to a critical section, \eg ensuring a reader thread is the next kind of thread to enter a critical section. 1252 If a writer thread is scheduled for next access, but another reader thread acquires the critical section first, that reader has \newterm{barged}. 1253 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). 1259 1254 Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs. 1260 This challenge is often split into two different approaches, barging avoidance and barging prevention. 1261 Algorithms that allow a barger but divert it until later are avoiding the barger, while algorithms that preclude a barger from entering during synchronization in the critical section prevent the barger completely. 1262 baton-pass locks~\cite{Andrews89} between threads instead of releasing the locks are said to be using barging prevention. 1255 This challenge is often split into two different approaches: barging avoidance and barging prevention. 1256 Algorithms that allow a barger, but divert it until later using current synchronization state (flags), are avoiding the barger; 1257 algorithms that preclude a barger from entering during synchronization in the critical section prevent barging completely. 1258 Techniques like baton-pass locks~\cite{Andrews89} between threads instead of unconditionally releasing locks is an example of barging prevention. 1263 1259 1264 1260 … … 1266 1262 \label{s:Monitors} 1267 1263 1268 A \textbf{monitor} is a set of routines that ensure mutual-exclusion when accessing shared state. 1269 More precisely, a monitor is a programming technique that associates mutual-exclusion to routine scopes, as opposed to mutex locks, where mutual-exclusion is defined by lock/release calls independently of any scoping of the calling routine. 1270 This strong association eases readability and maintainability, at the cost of flexibility. 1271 Note that both monitors and mutex locks, require an abstract handle to identify them. 1272 This concept is generally associated with object-oriented languages like Java~\cite{Java} or \uC~\cite{uC++book} but does not strictly require OO semantics. 1273 The only requirement is the ability to declare a handle to a shared object and a set of routines that act on it: 1274 \begin{cfa} 1275 typedef /*some monitor type*/ monitor; 1276 int f(monitor & m); 1277 1278 int main() { 1279 monitor m; // Handle m 1280 f(m); // Routine using handle 1281 } 1282 \end{cfa} 1283 1284 % ====================================================================== 1285 % ====================================================================== 1286 \subsection{Call Semantics} \label{call} 1287 % ====================================================================== 1288 % ====================================================================== 1289 The above monitor example displays some of the intrinsic characteristics. 1290 First, it is necessary to use pass-by-reference over pass-by-value for monitor routines. 1291 This semantics is important, because at their core, monitors are implicit mutual-exclusion objects (locks), and these objects cannot be copied. 1292 Therefore, monitors are non-copy-able objects (@dtype@). 1293 1294 Another aspect to consider is when a monitor acquires its mutual exclusion. 1295 For example, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual-exclusion on entry. 1296 Passthrough can occur for generic helper routines (@swap@, @sort@, \etc) or specific helper routines like the following to implement an atomic counter: 1297 1298 \begin{cfa} 1299 monitor counter_t { /*...see section $\ref{data}$...*/ }; 1300 1301 void ?{}(counter_t & nomutex this); // constructor 1302 size_t ++?(counter_t & mutex this); // increment 1303 1304 // need for mutex is platform dependent 1305 void ?{}(size_t * this, counter_t & mutex cnt); // conversion 1306 \end{cfa} 1307 This counter is used as follows: 1308 \begin{center} 1309 \begin{tabular}{c @{\hskip 0.35in} c @{\hskip 0.35in} c} 1310 \begin{cfa} 1311 // shared counter 1312 counter_t cnt1, cnt2; 1313 1314 // multiple threads access counter 1315 thread 1 : cnt1++; cnt2++; 1316 thread 2 : cnt1++; cnt2++; 1317 thread 3 : cnt1++; cnt2++; 1318 ... 1319 thread N : cnt1++; cnt2++; 1320 \end{cfa} 1321 \end{tabular} 1322 \end{center} 1323 Notice how the counter is used without any explicit synchronization and yet supports thread-safe semantics for both reading and writing, which is similar in usage to the \CC template @std::atomic@. 1324 1325 Here, the constructor (@?{}@) uses the @nomutex@ keyword to signify that it does not acquire the monitor mutual-exclusion when constructing. 1326 This semantics is because an object not yet constructed should never be shared and therefore does not require mutual exclusion. 1327 Furthermore, it allows the implementation greater freedom when it initializes the monitor locking. 1328 The prefix increment operator uses @mutex@ to protect the incrementing process from race conditions. 1329 Finally, there is a conversion operator from @counter_t@ to @size_t@. 1330 This conversion may or may not require the @mutex@ keyword depending on whether or not reading a @size_t@ is an atomic operation. 1331 1332 For maximum usability, monitors use \textbf{multi-acq} semantics, which means a single thread can acquire the same monitor multiple times without deadlock. 1333 For example, listing \ref{fig:search} uses recursion and \textbf{multi-acq} to print values inside a binary tree. 1334 \begin{figure} 1335 \begin{cfa}[caption={Recursive printing algorithm using \textbf{multi-acq}.},label={fig:search}] 1336 monitor printer { ... }; 1337 struct tree { 1338 tree * left, right; 1339 char * value; 1264 A \textbf{monitor} is a set of routines that ensure mutual exclusion when accessing shared state. 1265 More precisely, a monitor is a programming technique that binds mutual exclusion to routine scope, as opposed to locks, where mutual-exclusion is defined by acquire/release calls, independent of lexical context (analogous to block and heap storage allocation). 1266 The strong association with the call/return paradigm eases programmability, readability and maintainability, at a slight cost in flexibility and efficiency. 1267 1268 Note, like coroutines/threads, both locks and monitors require an abstract handle to reference them, because at their core, both mechanisms are manipulating non-copyable shared-state. 1269 Copying a lock is insecure because it is possible to copy an open lock and then use the open copy when the original lock is closed to simultaneously access the shared data. 1270 Copying a monitor is secure because both the lock and shared data are copies, but copying the shared data is meaningless because it no longer represents a unique entity. 1271 As for coroutines/tasks, a non-copyable (@dtype@) trait is used to capture this requirement, so all locks/monitors must be passed by reference (pointer). 1272 \begin{cfa} 1273 trait is_monitor( `dtype` T ) { 1274 monitor_desc * get_monitor( T & ); 1275 void ^?{}( T & mutex ); 1340 1276 }; 1341 void print(printer & mutex p, char * v); 1342 1343 void print(printer & mutex p, tree * t) { 1344 print(p, t->value); 1345 print(p, t->left ); 1346 print(p, t->right); 1347 } 1348 \end{cfa} 1349 \end{figure} 1350 1351 Having both @mutex@ and @nomutex@ keywords can be redundant, depending on the meaning of a routine having neither of these keywords. 1352 For example, it is reasonable that it should default to the safest option (@mutex@) when given a routine without qualifiers @void foo(counter_t & this)@, whereas assuming @nomutex@ is unsafe and may cause subtle errors. 1353 On the other hand, @nomutex@ is the ``normal'' parameter behaviour, it effectively states explicitly that ``this routine is not special''. 1354 Another alternative is making exactly one of these keywords mandatory, which provides the same semantics but without the ambiguity of supporting routines with neither keyword. 1355 Mandatory keywords would also have the added benefit of being self-documented but at the cost of extra typing. 1356 While there are several benefits to mandatory keywords, they do bring a few challenges. 1357 Mandatory keywords in \CFA would imply that the compiler must know without doubt whether or not a parameter is a monitor or not. 1277 \end{cfa} 1278 1279 1280 \subsection{Mutex Acquisition} 1281 \label{s:MutexAcquisition} 1282 1283 While correctness implicitly implies a monitor's mutual exclusion is acquired and released, there are implementation options about when and where the locking/unlocking occurs. 1284 (Much of this discussion also applies to basic locks.) 1285 For example, a monitor may need to be passed through multiple helper routines before it becomes necessary to acquire the monitor mutual-exclusion. 1286 \begin{cfa}[morekeywords=nomutex] 1287 monitor Aint { int cnt; }; $\C{// atomic integer counter}$ 1288 void ?{}( Aint & `nomutex` this ) with( this ) { cnt = 0; } $\C{// constructor}$ 1289 int ?=?( Aint & `mutex`$\(_{opt}\)$ lhs, int rhs ) with( lhs ) { cnt = rhs; } $\C{// conversions}$ 1290 void ?{}( int & this, Aint & `mutex`$\(_{opt}\)$ v ) { this = v.cnt; } 1291 int ?=?( int & lhs, Aint & `mutex`$\(_{opt}\)$ rhs ) with( rhs ) { lhs = cnt; } 1292 int ++?( Aint & `mutex`$\(_{opt}\)$ this ) with( this ) { return ++cnt; } $\C{// increment}$ 1293 \end{cfa} 1294 The @Aint@ constructor, @?{}@, uses the \lstinline[morekeywords=nomutex]@nomutex@ qualifier indicating mutual exclusion is unnecessary during construction because an object is inaccessible (private) until after it is initialized. 1295 (While a constructor may publish its address into a global variable, doing so generates a race-condition.) 1296 The conversion operators for initializing and assigning with a normal integer only need @mutex@, if reading/writing the implementation type is not atomic. 1297 Finally, the prefix increment operato, @++?@, is normally @mutex@ to protect the incrementing from race conditions, unless there is an atomic increment instruction for the implementation type. 1298 1299 The atomic counter is used without any explicit mutual-exclusion and provides thread-safe semantics, which is similar to the \CC template @std::atomic@. 1300 \begin{cfa} 1301 Aint x, y, z; 1302 ++x; ++y; ++z; $\C{// safe increment by multiple threads}$ 1303 x = 2; y = 2; z = 2; $\C{// conversions}$ 1304 int i = x, j = y, k = z; 1305 i = x; j = y; k = z; 1306 \end{cfa} 1307 1308 For maximum usability, monitors have \newterm{multi-acquire} semantics allowing a thread to acquire it multiple times without deadlock. 1309 For example, atomically printing the contents of a binary tree: 1310 \begin{cfa} 1311 monitor Tree { 1312 Tree * left, right; 1313 // value 1314 }; 1315 void print( Tree & mutex tree ) { $\C{// prefix traversal}$ 1316 // write value 1317 print( tree->left ); $\C{// multiply acquire monitor lock on each recursion}$ 1318 print( tree->right ); 1319 } 1320 \end{cfa} 1321 1322 Mandatory monitor qualifiers have the benefit of being self-documented, but requiring both @mutex@ and \lstinline[morekeywords=nomutex]@nomutex@ for all monitor parameter is redundant. 1323 Instead, one of qualifier semantics can be the default, and the other required. 1324 For example, assume the safe @mutex@ option for a monitor parameter because assuming \lstinline[morekeywords=nomutex]@nomutex@ may cause subtle errors. 1325 On the other hand, assuming \lstinline[morekeywords=nomutex]@nomutex@ is the \emph{normal} parameter behaviour, stating explicitly ``this parameter is not special''. 1326 Providing a default qualifier implies knowing whether a parameter is a monitor. 1358 1327 Since \CFA relies heavily on traits as an abstraction mechanism, the distinction between a type that is a monitor and a type that looks like a monitor can become blurred. 1359 For this reason, \CFA only has the @mutex@ keyword and uses no keyword to mean@nomutex@.1360 1361 The next semantic decision is to establish when @mutex@ may be used as a type qualifier.1362 Consider the following declarations:1363 \begin{cfa} 1364 int f1(monitor & mutex m); 1365 int f 2(const monitor & mutex m);1366 int f 3(monitor ** mutex m);1367 int f 4(monitor * mutex m []);1368 int f 5(graph(monitor *) & mutex m);1369 \end{cfa} 1370 The problem is to identify which object(s) should be acquired.1371 F urthermore, each object needs to be acquired only once.1372 In the case of simple routines like @f1@ and @f2@ it is easy to identify an exhaustive list of objects to acquire on entry.1373 Adding indirections (@f3@) still allows the compiler and programmer to identify which object is acquired.1374 However, adding in arrays (@f4@) makes it much harder. 1375 Array lengths are not necessarily known in C, and even then, making sure objects are only acquired once becomes none-trivial.1376 This problem can be extended to absurd limits like @f5@, which uses a graph of monitors.1377 To make the issue tractable, this project imposes the requirement that a routine may only acquire one monitor per parameter and it must be the type of the parameter with at most one level of indirection (ignoring potential qualifiers). 1378 Also note that while routine @f3@ can be supported, meaning that monitor @**m@ is acquired, passing an array to this routine would be type-safe and yet result in undefined behaviour because only the first element of the array is acquired.1379 However, th is ambiguity is part of the C type-systemwith respects to arrays.1380 For this reason, @mutex@ is disallowed in the context where arrays may be passed: 1381 \begin{cfa} 1382 int f1(monitor & mutex m); // Okay : recommended case 1383 int f2(monitor * mutex m); // Not Okay : Could be an array 1384 int f 3(monitor mutex m []); // Not Okay : Array of unknown length1385 int f 4(monitor ** mutex m); // Not Okay : Could be an array1386 int f 5(monitor * mutex m []); // Not Okay : Array of unknown length1387 \end{cfa} 1388 Note that not all array functions are actually distinct in the type system. 1389 However, even if the code generation could tell the difference, the extra information is still not sufficient to extend meaningfully the monitor call semantic. 1390 1391 Unlike object-oriented monitors, where calling a mutex member \emph{implicitly} acquires mutual-exclusion of the receiver object, \CFA uses an explicit mechanism to specify the object that acquires mutual-exclusion.1392 A consequence of this approach is that it extends naturally to multi-monitor calls. 1393 \begin{cfa} 1394 int f(MonitorA & mutex a, MonitorB & mutex b); 1395 1396 MonitorA a; 1397 MonitorB b; 1398 f(a,b);1399 \end{cfa} 1400 While OO monitors could be extended with a mutex qualifier for multiple-monitor calls, no example of this feature could be found. 1401 The capability to acquire multiple locks before entering a critical section is called \emph{\textbf{bulk-acq}}. 1402 In practice, writing multi-locking routines that do not lead to deadlocksis tricky.1328 For this reason, \CFA requires programmers to identify the kind of parameter with the @mutex@ keyword and uses no keyword to mean \lstinline[morekeywords=nomutex]@nomutex@. 1329 1330 The next semantic decision is establishing which parameter \emph{types} may be qualified with @mutex@. 1331 Given: 1332 \begin{cfa} 1333 monitor M { ... } 1334 int f1( M & mutex m ); 1335 int f2( M * mutex m ); 1336 int f3( M * mutex m[] ); 1337 int f4( stack( M * ) & mutex m ); 1338 \end{cfa} 1339 the issue is that some of these parameter types are composed of multiple objects. 1340 For @f1@, there is only a single parameter object. 1341 Adding indirection in @f2@ still identifies a single object. 1342 However, the matrix in @f3@ introduces multiple objects. 1343 While shown shortly, multiple acquisition is possible; 1344 however array lengths are often unknown in C. 1345 This issue is exacerbated in @f4@, where the data structure must be safely traversed to acquire all of its elements. 1346 1347 To make the issue tractable, \CFA only acquires one monitor per parameter with at most one level of indirection. 1348 However, the C type-system has an ambiguity with respects to arrays. 1349 Is the argument for @f2@ a single object or an array of objects? 1350 If it is an array, only the first element of the array is acquired, which seems unsafe; 1351 hence, @mutex@ is disallowed for array parameters. 1352 \begin{cfa} 1353 int f1( M & mutex m ); $\C{// allowed: recommended case}$ 1354 int f2( M * mutex m ); $\C{// disallowed: could be an array}$ 1355 int f3( M mutex m[$\,$] ); $\C{// disallowed: array length unknown}$ 1356 int f4( M ** mutex m ); $\C{// disallowed: could be an array}$ 1357 int f5( M * mutex m[$\,$] ); $\C{// disallowed: array length unknown}$ 1358 \end{cfa} 1359 % Note, not all array routines have distinct types: @f2@ and @f3@ have the same type, as do @f4@ and @f5@. 1360 % However, even if the code generation could tell the difference, the extra information is still not sufficient to extend meaningfully the monitor call semantic. 1361 1362 For object-oriented monitors, calling a mutex member \emph{implicitly} acquires mutual exclusion of the receiver object, @`rec`.foo(...)@. 1363 \CFA has no receiver, and hence, must use an explicit mechanism to specify which object has mutual exclusion acquired. 1364 A positive consequence of this design decision is the ability to support multi-monitor routines. 1365 \begin{cfa} 1366 int f( M & mutex x, M & mutex y ); $\C{// multiple monitor parameter of any type}$ 1367 M m1, m2; 1368 f( m1, m2 ); 1369 \end{cfa} 1370 (While object-oriented monitors can be extended with a mutex qualifier for multiple-monitor members, no prior example of this feature could be found.) 1371 In practice, writing multi-locking routines that do not deadlock is tricky. 1403 1372 Having language support for such a feature is therefore a significant asset for \CFA. 1404 In the case presented above, \CFA guarantees that the order of acquisition is consistent across calls to different routines using the same monitors as arguments. 1405 This consistent ordering means acquiring multiple monitors is safe from deadlock when using \textbf{bulk-acq}. 1406 However, users can still force the acquiring order. 1407 For example, notice which routines use @mutex@/@nomutex@ and how this affects acquiring order: 1408 \begin{cfa} 1409 void foo(A& mutex a, B& mutex b) { // acquire a & b 1410 ... 1411 } 1412 1413 void bar(A& mutex a, B& /*nomutex*/ b) { // acquire a 1414 ... foo(a, b); ... // acquire b 1415 } 1416 1417 void baz(A& /*nomutex*/ a, B& mutex b) { // acquire b 1418 ... foo(a, b); ... // acquire a 1419 } 1420 \end{cfa} 1421 The \textbf{multi-acq} monitor lock allows a monitor lock to be acquired by both @bar@ or @baz@ and acquired again in @foo@. 1422 In the calls to @bar@ and @baz@ the monitors are acquired in opposite order. 1423 1424 However, such use leads to lock acquiring order problems. 1425 In the example above, the user uses implicit ordering in the case of function @foo@ but explicit ordering in the case of @bar@ and @baz@. 1426 This subtle difference means that calling these routines concurrently may lead to deadlock and is therefore undefined behaviour. 1427 As shown~\cite{Lister77}, solving this problem requires: 1428 \begin{enumerate} 1429 \item Dynamically tracking the monitor-call order. 1430 \item Implement rollback semantics. 1431 \end{enumerate} 1432 While the first requirement is already a significant constraint on the system, implementing a general rollback semantics in a C-like language is still prohibitively complex~\cite{Dice10}. 1433 In \CFA, users simply need to be careful when acquiring multiple monitors at the same time or only use \textbf{bulk-acq} of all the monitors. 1434 While \CFA provides only a partial solution, most systems provide no solution and the \CFA partial solution handles many useful cases. 1435 1436 For example, \textbf{multi-acq} and \textbf{bulk-acq} can be used together in interesting ways: 1437 \begin{cfa} 1438 monitor bank { ... }; 1439 1440 void deposit( bank & mutex b, int deposit ); 1441 1442 void transfer( bank & mutex mybank, bank & mutex yourbank, int me2you) { 1443 deposit( mybank, -me2you ); 1444 deposit( yourbank, me2you ); 1373 1374 The capability to acquire multiple locks before entering a critical section is called \newterm{bulk acquire}. 1375 In the previous example, \CFA guarantees the order of acquisition is consistent across calls to different routines using the same monitors as arguments. 1376 This consistent ordering means acquiring multiple monitors is safe from deadlock. 1377 However, users can force the acquiring order. 1378 For example, notice the use of @mutex@/\lstinline[morekeywords=nomutex]@nomutex@ and how this affects the acquiring order: 1379 \begin{cfa} 1380 void foo( M & mutex m1, M & mutex m2 ); $\C{// acquire m1 and m2}$ 1381 void bar( M & mutex m1, M & /* nomutex */ m2 ) { $\C{// acquire m1}$ 1382 ... foo( m1, m2 ); ... $\C{// acquire m2}$ 1383 } 1384 void baz( M & /* nomutex */ m1, M & mutex m2 ) { $\C{// acquire m2}$ 1385 ... foo( m1, m2 ); ... $\C{// acquire m1}$ 1386 } 1387 \end{cfa} 1388 The multi-acquire semantics allows @bar@ or @baz@ to acquire a monitor lock and reacquire it in @foo@. 1389 In the calls to @bar@ and @baz@, the monitors are acquired in opposite order. 1390 1391 However, such use leads to lock acquiring order problems resulting in deadlock~\cite{Lister77}, where detecting it requires dynamically tracking of monitor calls, and dealing with it requires rollback semantics~\cite{Dice10}. 1392 In \CFA, safety is guaranteed by using bulk acquire of all monitors to shared objects, whereas other monitor systems provide no aid. 1393 While \CFA provides only a partial solution, the \CFA partial solution handles many useful cases. 1394 \begin{cfa} 1395 monitor Bank { ... }; 1396 void deposit( Bank & `mutex` b, int deposit ); 1397 void transfer( Bank & `mutex` mybank, Bank & `mutex` yourbank, int me2you) { 1398 deposit( mybank, `-`me2you ); $\C{// debit}$ 1399 deposit( yourbank, me2you ); $\C{// credit}$ 1445 1400 } 1446 1401 \end{cfa} 1447 1402 This example shows a trivial solution to the bank-account transfer problem~\cite{BankTransfer}. 1448 Without \textbf{multi-acq} and \textbf{bulk-acq}, the solution to this problem is much more involved andrequires careful engineering.1403 Without multi- and bulk acquire, the solution to this problem requires careful engineering. 1449 1404 1450 1405 1451 1406 \subsection{\protect\lstinline|mutex| statement} \label{mutex-stmt} 1452 1407 1453 The call semantics discussed above have one software engineering issue: only a routine can acquire the mutual-exclusion of a set of monitor. \CFA offers the @mutex@ statement to work around the need for unnecessary names, avoiding a major software engineering problem~\cite{2FTwoHardThings}. 1454 Table \ref{f:mutex-stmt} shows an example of the @mutex@ statement, which introduces a new scope in which the mutual-exclusion of a set of monitor is acquired. 1455 Beyond naming, the @mutex@ statement has no semantic difference from a routine call with @mutex@ parameters. 1456 1457 \begin{table} 1458 \begin{center} 1459 \begin{tabular}{|c|c|} 1460 function call & @mutex@ statement \\ 1461 \hline 1462 \begin{cfa}[tabsize=3] 1408 The monitor call-semantics associate all locking semantics to routines. 1409 Like Java, \CFA offers an alternative @mutex@ statement to reduce refactoring and naming. 1410 \begin{cquote} 1411 \begin{tabular}{@{}c|@{\hspace{\parindentlnth}}c@{}} 1412 routine call & @mutex@ statement \\ 1413 \begin{cfa} 1463 1414 monitor M {}; 1464 1415 void foo( M & mutex m1, M & mutex m2 ) { 1465 1416 // critical section 1466 1417 } 1467 1468 1418 void bar( M & m1, M & m2 ) { 1469 1419 foo( m1, m2 ); 1470 1420 } 1471 \end{cfa}&\begin{cfa}[tabsize=3] 1472 monitor M {}; 1421 \end{cfa} 1422 & 1423 \begin{cfa} 1424 1473 1425 void bar( M & m1, M & m2 ) { 1474 mutex( m1, m2) {1426 mutex( m1, m2 ) { // remove refactoring and naming 1475 1427 // critical section 1476 1428 } 1477 1429 } 1478 1430 1479 1480 1431 \end{cfa} 1481 1432 \end{tabular} 1482 \end{center} 1483 \caption{Regular call semantics vs. \protect\lstinline|mutex| statement} 1484 \label{f:mutex-stmt} 1485 \end{table} 1486 1487 % ====================================================================== 1488 % ====================================================================== 1489 \subsection{Data semantics} \label{data} 1490 % ====================================================================== 1491 % ====================================================================== 1492 Once the call semantics are established, the next step is to establish data semantics. 1493 Indeed, until now a monitor is used simply as a generic handle but in most cases monitors contain shared data. 1494 This data should be intrinsic to the monitor declaration to prevent any accidental use of data without its appropriate protection. 1495 For example, here is a complete version of the counter shown in section \ref{call}: 1496 \begin{cfa} 1497 monitor counter_t { 1498 int value; 1433 \end{cquote} 1434 1435 1436 \section{Scheduling} 1437 \label{s:Scheduling} 1438 1439 While monitor mutual-exclusion provides safe access to shared data, the monitor data may indicate that a thread accessing it cannot proceed. 1440 For example, Figure~\ref{f:GenericBoundedBuffer} shows a bounded buffer that may be full/empty so produce/consumer threads must block. 1441 Leaving the monitor and trying again (busy waiting) is impractical for high-level programming. 1442 Monitors eliminate busy waiting by providing internal synchronization to schedule threads needing access to the shared data, where the synchronization is blocking (threads are parked) versus spinning. 1443 Synchronization is generally achieved with internal~\cite{Hoare74} or external~\cite[\S~2.9.2]{uC++} scheduling, where \newterm{scheduling} defines which thread acquires the critical section next. 1444 \newterm{Internal scheduling} is characterized by each thread entering the monitor and making an individual decision about proceeding or blocking, while \newterm{external scheduling} is characterized by an entering thread making a decision about proceeding for itself and on behalf of other threads attempting entry. 1445 1446 Figure~\ref{f:BBInt} shows a \CFA bounded-buffer with internal scheduling, where producers/consumers enter the monitor, see the buffer is full/empty, and block on an appropriate condition lock, @full@/@empty@. 1447 The @wait@ routine atomically blocks the calling thread and implicitly releases the monitor lock(s) for all monitors in the routine's parameter list. 1448 The appropriate condition lock is signalled to unblock an opposite kind of thread after an element is inserted/removed from the buffer. 1449 Signalling is unconditional, because signalling an empty condition lock does nothing. 1450 1451 Signalling semantics cannot have the signaller and signalled thread in the monitor simultaneously, which means: 1452 \begin{enumerate} 1453 \item 1454 The signalling thread returns immediately, and the signalled thread continues. 1455 \item 1456 The signalling thread continues and the signalled thread is marked for urgent unblocking at the next scheduling point (exit/wait). 1457 \item 1458 The signalling thread blocks but is marked for urgrent unblocking at the next scheduling point and the signalled thread continues. 1459 \end{enumerate} 1460 The first approach is too restrictive, as it precludes solving a reasonable class of problems, \eg dating service. 1461 \CFA supports the next two semantics as both are useful. 1462 Finally, while it is common to store a @condition@ as a field of the monitor, in \CFA, a @condition@ variable can be created/stored independently. 1463 Furthermore, a condition variable is tied to a \emph{group} of monitors on first use (called \newterm{branding}), which means that using internal scheduling with distinct sets of monitors requires one condition variable per set of monitors. 1464 1465 \begin{figure} 1466 \centering 1467 \newbox\myboxA 1468 \begin{lrbox}{\myboxA} 1469 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1470 forall( otype T ) { // distribute forall 1471 monitor Buffer { 1472 `condition` full, empty; 1473 int front, back, count; 1474 T elements[10]; 1475 }; 1476 void ?{}( Buffer(T) & buffer ) with(buffer) { 1477 [front, back, count] = 0; 1478 } 1479 1480 void insert( Buffer(T) & mutex buffer, T elem ) 1481 with(buffer) { 1482 if ( count == 10 ) `wait( empty )`; 1483 // insert elem into buffer 1484 `signal( full )`; 1485 } 1486 T remove( Buffer(T) & mutex buffer ) with(buffer) { 1487 if ( count == 0 ) `wait( full )`; 1488 // remove elem from buffer 1489 `signal( empty )`; 1490 return elem; 1491 } 1492 } 1493 \end{cfa} 1494 \end{lrbox} 1495 1496 \newbox\myboxB 1497 \begin{lrbox}{\myboxB} 1498 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1499 forall( otype T ) { // distribute forall 1500 monitor Buffer { 1501 1502 int front, back, count; 1503 T elements[10]; 1504 }; 1505 void ?{}( Buffer(T) & buffer ) with(buffer) { 1506 [front, back, count] = 0; 1507 } 1508 T remove( Buffer(T) & mutex buffer ); // forward 1509 void insert( Buffer(T) & mutex buffer, T elem ) 1510 with(buffer) { 1511 if ( count == 10 ) `waitfor( remove, buffer )`; 1512 // insert elem into buffer 1513 1514 } 1515 T remove( Buffer(T) & mutex buffer ) with(buffer) { 1516 if ( count == 0 ) `waitfor( insert, buffer )`; 1517 // remove elem from buffer 1518 1519 return elem; 1520 } 1521 } 1522 \end{cfa} 1523 \end{lrbox} 1524 1525 \subfloat[Internal Scheduling]{\label{f:BBInt}\usebox\myboxA} 1526 %\qquad 1527 \subfloat[External Scheduling]{\label{f:BBExt}\usebox\myboxB} 1528 \caption{Generic Bounded-Buffer} 1529 \label{f:GenericBoundedBuffer} 1530 \end{figure} 1531 1532 Figure~\ref{f:BBExt} shows a \CFA bounded-buffer with external scheduling, where producers/consumers detecting a full/empty buffer block and prevent more producers/consumers from entering the monitor until the buffer has a free/empty slot. 1533 External scheduling is controlled by the @waitfor@ statement, which atomically blocks the calling thread, releases the monitor lock, and restricts the routine calls that can next acquire mutual exclusion. 1534 If the buffer is full, only calls to @remove@ can acquire the buffer, and if the buffer is empty, only calls to @insert@ can acquire the buffer. 1535 Threads making calls to routines that are currently excluded block outside (external) of the monitor on a calling queue, versus blocking on condition queues inside (internal) of the monitor. 1536 % External scheduling is more constrained and explicit, which helps programmers reduce the non-deterministic nature of concurrency. 1537 External scheduling allows users to wait for events from other threads without concern of unrelated events occurring. 1538 The mechnaism can be done in terms of control flow, \eg Ada @accept@ or \uC @_Accept@, or in terms of data, \eg Go channels. 1539 While both mechanisms have strengths and weaknesses, this project uses a control-flow mechanism to stay consistent with other language semantics. 1540 Two challenges specific to \CFA for external scheduling are loose object-definitions (see Section~\ref{s:LooseObjectDefinitions}) and multiple-monitor routines (see Section~\ref{s:Multi-MonitorScheduling}). 1541 1542 For internal scheduling, non-blocking signalling (as in the producer/consumer example) is used when the signaller is providing the cooperation for a waiting thread; 1543 the signaller enters the monitor and changes state, detects a waiting threads that can use the state, performs a non-blocking signal on the condition queue for the waiting thread, and exits the monitor to run concurrently. 1544 The waiter unblocks next, uses/takes the state, and exits the monitor. 1545 Blocking signalling is the reverse, where the waiter is providing the cooperation for the signalling thread; 1546 the signaller enters the monitor, detects a waiting thread providing the necessary state, performs a blocking signal to place it on the urgent queue and unblock the waiter. 1547 The waiter changes state and exits the monitor, and the signaller unblocks next from the urgent queue to use/take the state. 1548 1549 Figure~\ref{f:DatingService} shows a dating service demonstrating the two forms of signalling: non-blocking and blocking. 1550 The dating service matches girl and boy threads with matching compatibility codes so they can exchange phone numbers. 1551 A thread blocks until an appropriate partner arrives. 1552 The complexity is exchanging phone number in the monitor because the monitor mutual-exclusion property prevents exchanging numbers. 1553 For internal scheduling, the @exchange@ condition is necessary to block the thread finding the match, while the matcher unblocks to take the oppose number, post its phone number, and unblock the partner. 1554 For external scheduling, the implicit urgent-condition replaces the explict @exchange@-condition and @signal_block@ puts the finding thread on the urgent condition and unblocks the matcher.. 1555 1556 The dating service is an example of a monitor that cannot be written using external scheduling because it requires knowledge of calling parameters to make scheduling decisions, and parameters of waiting threads are unavailable; 1557 as well, an arriving thread may not find a partner and must wait, which requires a condition variable, and condition variables imply internal scheduling. 1558 1559 \begin{figure} 1560 \centering 1561 \newbox\myboxA 1562 \begin{lrbox}{\myboxA} 1563 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1564 enum { CCodes = 20 }; 1565 monitor DS { 1566 int GirlPhNo, BoyPhNo; 1567 condition Girls[CCodes], Boys[CCodes]; 1568 condition exchange; 1499 1569 }; 1500 1501 void ?{}(counter_t & this) { 1502 this.cnt = 0; 1503 } 1504 1505 int ?++(counter_t & mutex this) { 1506 return ++this.value; 1507 } 1508 1509 // need for mutex is platform dependent here 1510 void ?{}(int * this, counter_t & mutex cnt) { 1511 *this = (int)cnt; 1512 } 1513 \end{cfa} 1514 1515 Like threads and coroutines, monitors are defined in terms of traits with some additional language support in the form of the @monitor@ keyword. 1516 The monitor trait is: 1517 \begin{cfa} 1518 trait is_monitor(dtype T) { 1519 monitor_desc * get_monitor( T & ); 1520 void ^?{}( T & mutex ); 1570 int girl( DS & mutex ds, int phNo, int ccode ) { 1571 if ( is_empty( Boys[ccode] ) ) { 1572 wait( Girls[ccode] ); 1573 GirlPhNo = phNo; 1574 exchange.signal(); 1575 } else { 1576 GirlPhNo = phNo; 1577 signal( Boys[ccode] ); 1578 exchange.wait(); 1579 } // if 1580 return BoyPhNo; 1581 } 1582 int boy( DS & mutex ds, int phNo, int ccode ) { 1583 // as above with boy/girl interchanged 1584 } 1585 \end{cfa} 1586 \end{lrbox} 1587 1588 \newbox\myboxB 1589 \begin{lrbox}{\myboxB} 1590 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1591 1592 monitor DS { 1593 int GirlPhNo, BoyPhNo; 1594 condition Girls[CCodes], Boys[CCodes]; 1595 1521 1596 }; 1522 \end{cfa} 1523 Note that the destructor of a monitor must be a @mutex@ routine to prevent deallocation while a thread is accessing the monitor. 1524 As with any object, calls to a monitor, using @mutex@ or otherwise, is undefined behaviour after the destructor has run. 1525 1526 % ====================================================================== 1527 % ====================================================================== 1528 \section{Internal Scheduling} \label{intsched} 1529 % ====================================================================== 1530 % ====================================================================== 1531 In addition to mutual exclusion, the monitors at the core of \CFA's concurrency can also be used to achieve synchronization. 1532 With monitors, this capability is generally achieved with internal or external scheduling as in~\cite{Hoare74}. 1533 With \textbf{scheduling} loosely defined as deciding which thread acquires the critical section next, \textbf{internal scheduling} means making the decision from inside the critical section (\ie with access to the shared state), while \textbf{external scheduling} means making the decision when entering the critical section (\ie without access to the shared state). 1534 Since internal scheduling within a single monitor is mostly a solved problem, this paper concentrates on extending internal scheduling to multiple monitors. 1535 Indeed, like the \textbf{bulk-acq} semantics, internal scheduling extends to multiple monitors in a way that is natural to the user but requires additional complexity on the implementation side. 1536 1537 First, here is a simple example of internal scheduling: 1538 1539 \begin{cfa} 1540 monitor A { 1541 condition e; 1542 } 1543 1544 void foo(A& mutex a1, A& mutex a2) { 1597 int girl( DS & mutex ds, int phNo, int ccode ) { 1598 if ( is_empty( Boys[ccode] ) ) { // no compatible 1599 wait( Girls[ccode] ); // wait for boy 1600 GirlPhNo = phNo; // make phone number available 1601 1602 } else { 1603 GirlPhNo = phNo; // make phone number available 1604 signal_block( Boys[ccode] ); // restart boy 1605 1606 } // if 1607 return BoyPhNo; 1608 } 1609 int boy( DS & mutex ds, int phNo, int ccode ) { 1610 // as above with boy/girl interchanged 1611 } 1612 \end{cfa} 1613 \end{lrbox} 1614 1615 \subfloat[\lstinline@signal@]{\label{f:DatingSignal}\usebox\myboxA} 1616 \qquad 1617 \subfloat[\lstinline@signal_block@]{\label{f:DatingSignalBlock}\usebox\myboxB} 1618 \caption{Dating service. } 1619 \label{f:DatingService} 1620 \end{figure} 1621 1622 Both internal and external scheduling extend to multiple monitors in a natural way. 1623 \begin{cquote} 1624 \begin{tabular}{@{}l@{\hspace{3\parindentlnth}}l@{}} 1625 \begin{cfa} 1626 monitor M { `condition e`; ... }; 1627 void foo( M & mutex m1, M & mutex m2 ) { 1628 ... wait( `e` ); ... // wait( e, m1, m2 ) 1629 ... wait( `e, m1` ); ... 1630 ... wait( `e, m2` ); ... 1631 } 1632 \end{cfa} 1633 & 1634 \begin{cfa} 1635 void rtn$\(_1\)$( M & mutex m1, M & mutex m2 ); 1636 void rtn$\(_2\)$( M & mutex m1 ); 1637 void bar( M & mutex m1, M & mutex m2 ) { 1638 ... waitfor( `rtn` ); ... // $\LstCommentStyle{waitfor( rtn\(_1\), m1, m2 )}$ 1639 ... waitfor( `rtn, m1` ); ... // $\LstCommentStyle{waitfor( rtn\(_2\), m1 )}$ 1640 } 1641 \end{cfa} 1642 \end{tabular} 1643 \end{cquote} 1644 For @wait( e )@, the default semantics is to atomically block the signaller and release all acquired mutex types in the parameter list, \ie @wait( e, m1, m2 )@. 1645 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@. 1646 Wait statically verifies the released monitors are the acquired mutex-parameters so unconditional release is safe. 1647 Finally, a signaller, 1648 \begin{cfa} 1649 void baz( M & mutex m1, M & mutex m2 ) { 1650 ... signal( e ); ... 1651 } 1652 \end{cfa} 1653 must have acquired monitor locks that are greater than or equal to the number of locks for the waiting thread signalled from the condition queue. 1654 1655 Similarly, for @waitfor( rtn )@, the default semantics is to atomically block the acceptor and release all acquired mutex types in the parameter list, \ie @waitfor( rtn, m1, m2 )@. 1656 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn, m1 )@. 1657 Waitfor statically verifies the released monitors are the same as the acquired mutex-parameters of the given routine or routine pointer. 1658 To statically verify the released monitors match with the accepted routine's mutex parameters, the routine (pointer) prototype must be accessible. 1659 1660 Given the ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock. 1661 \begin{cfa} 1662 void foo( M & mutex m1, M & mutex m2 ) { 1663 ... wait( `e, m1` ); ... $\C{// release m1, keeping m2 acquired )}$ 1664 void bar( M & mutex m1, M & mutex m2 ) { $\C{// must acquire m1 and m2 )}$ 1665 ... signal( `e` ); ... 1666 \end{cfa} 1667 The @wait@ only releases @m1@ so the signalling thread cannot acquire both @m1@ and @m2@ to enter @bar@ to get to the @signal@. 1668 While deadlock issues can occur with multiple/nesting acquisition, this issue results from the fact that locks, and by extension monitors, are not perfectly composable. 1669 1670 Finally, an important aspect of monitor implementation is barging, \ie can calling threads barge ahead of signalled threads? 1671 If barging is allowed, synchronization between a singller and signallee is difficult, often requiring multiple unblock/block cycles (looping around a wait rechecking if a condition is met). 1672 \begin{quote} 1673 However, we decree that a signal operation be followed immediately by resumption of a waiting program, without possibility of an intervening procedure call from yet a third program. 1674 It is only in this way that a waiting program has an absolute guarantee that it can acquire the resource just released by the signalling program without any danger that a third program will interpose a monitor entry and seize the resource instead.~\cite[p.~550]{Hoare74} 1675 \end{quote} 1676 \CFA scheduling \emph{precludes} barging, which simplifies synchronization among threads in the monitor and increases correctness. 1677 For example, there are no loops in either bounded buffer solution in Figure~\ref{f:GenericBoundedBuffer}. 1678 Supporting barging prevention as well as extending internal scheduling to multiple monitors is the main source of complexity in the design and implementation of \CFA concurrency. 1679 1680 1681 \subsection{Barging Prevention} 1682 1683 Figure~\ref{f:BargingPrevention} shows \CFA code where bulk acquire adds complexity to the internal-signalling semantics. 1684 The complexity begins at the end of the inner @mutex@ statement, where the semantics of internal scheduling need to be extended for multiple monitors. 1685 The problem is that bulk acquire is used in the inner @mutex@ statement where one of the monitors is already acquired. 1686 When the signalling thread reaches the end of the inner @mutex@ statement, it should transfer ownership of @m1@ and @m2@ to the waiting threads to prevent barging into the outer @mutex@ statement by another thread. 1687 However, both the signalling and waiting thread W1 still need monitor @m1@. 1688 1689 \begin{figure} 1690 \newbox\myboxA 1691 \begin{lrbox}{\myboxA} 1692 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1693 monitor M m1, m2; 1694 condition c; 1695 mutex( m1 ) { // $\LstCommentStyle{\color{red}outer}$ 1545 1696 ... 1546 // Wait for cooperation from bar() 1547 wait(a1.e); 1697 mutex( m1, m2 ) { // $\LstCommentStyle{\color{red}inner}$ 1698 ... `signal( c )`; ... 1699 // m1, m2 acquired 1700 } // $\LstCommentStyle{\color{red}release m2}$ 1701 // m1 acquired 1702 } // release m1 1703 \end{cfa} 1704 \end{lrbox} 1705 1706 \newbox\myboxB 1707 \begin{lrbox}{\myboxB} 1708 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1709 1710 1711 mutex( m1 ) { 1548 1712 ... 1549 } 1550 1551 void bar(A& mutex a1, A& mutex a2) { 1552 // Provide cooperation for foo() 1553 ... 1554 // Unblock foo 1555 signal(a1.e); 1556 } 1557 \end{cfa} 1558 There are two details to note here. 1559 First, @signal@ is a delayed operation; it only unblocks the waiting thread when it reaches the end of the critical section. 1560 This semantics is needed to respect mutual-exclusion, \ie the signaller and signalled thread cannot be in the monitor simultaneously. 1561 The alternative is to return immediately after the call to @signal@, which is significantly more restrictive. 1562 Second, in \CFA, while it is common to store a @condition@ as a field of the monitor, a @condition@ variable can be stored/created independently of a monitor. 1563 Here routine @foo@ waits for the @signal@ from @bar@ before making further progress, ensuring a basic ordering. 1564 1565 An important aspect of the implementation is that \CFA does not allow barging, which means that once function @bar@ releases the monitor, @foo@ is guaranteed to be the next thread to acquire the monitor (unless some other thread waited on the same condition). 1566 This guarantee offers the benefit of not having to loop around waits to recheck that a condition is met. 1567 The main reason \CFA offers this guarantee is that users can easily introduce barging if it becomes a necessity but adding barging prevention or barging avoidance is more involved without language support. 1568 Supporting barging prevention as well as extending internal scheduling to multiple monitors is the main source of complexity in the design and implementation of \CFA concurrency. 1569 1570 % ====================================================================== 1571 % ====================================================================== 1572 \subsection{Internal Scheduling - Multi-Monitor} 1573 % ====================================================================== 1574 % ====================================================================== 1575 It is easy to understand the problem of multi-monitor scheduling using a series of pseudo-code examples. 1576 Note that for simplicity in the following snippets of pseudo-code, waiting and signalling is done using an implicit condition variable, like Java built-in monitors. 1577 Indeed, @wait@ statements always use the implicit condition variable as parameters and explicitly name the monitors (A and B) associated with the condition. 1578 Note that in \CFA, condition variables are tied to a \emph{group} of monitors on first use (called branding), which means that using internal scheduling with distinct sets of monitors requires one condition variable per set of monitors. 1579 The example below shows the simple case of having two threads (one for each column) and a single monitor A. 1580 1581 \begin{multicols}{2} 1582 thread 1 1583 \begin{cfa} 1584 acquire A 1585 wait A 1586 release A 1587 \end{cfa} 1588 1589 \columnbreak 1590 1591 thread 2 1592 \begin{cfa} 1593 acquire A 1594 signal A 1595 release A 1596 \end{cfa} 1597 \end{multicols} 1598 One thread acquires before waiting (atomically blocking and releasing A) and the other acquires before signalling. 1599 It is important to note here that both @wait@ and @signal@ must be called with the proper monitor(s) already acquired. 1600 This semantic is a logical requirement for barging prevention. 1601 1602 A direct extension of the previous example is a \textbf{bulk-acq} version: 1603 \begin{multicols}{2} 1604 \begin{cfa} 1605 acquire A & B 1606 wait A & B 1607 release A & B 1608 \end{cfa} 1609 \columnbreak 1610 \begin{cfa} 1611 acquire A & B 1612 signal A & B 1613 release A & B 1614 \end{cfa} 1615 \end{multicols} 1616 \noindent This version uses \textbf{bulk-acq} (denoted using the {\sf\&} symbol), but the presence of multiple monitors does not add a particularly new meaning. 1617 Synchronization happens between the two threads in exactly the same way and order. 1618 The only difference is that mutual exclusion covers a group of monitors. 1619 On the implementation side, handling multiple monitors does add a degree of complexity as the next few examples demonstrate. 1620 1621 While deadlock issues can occur when nesting monitors, these issues are only a symptom of the fact that locks, and by extension monitors, are not perfectly composable. 1622 For monitors, a well-known deadlock problem is the Nested Monitor Problem~\cite{Lister77}, which occurs when a @wait@ is made by a thread that holds more than one monitor. 1623 For example, the following cfa-code runs into the nested-monitor problem: 1624 \begin{multicols}{2} 1625 \begin{cfa} 1626 acquire A 1627 acquire B 1628 wait B 1629 release B 1630 release A 1631 \end{cfa} 1632 1633 \columnbreak 1634 1635 \begin{cfa} 1636 acquire A 1637 acquire B 1638 signal B 1639 release B 1640 release A 1641 \end{cfa} 1642 \end{multicols} 1643 \noindent The @wait@ only releases monitor @B@ so the signalling thread cannot acquire monitor @A@ to get to the @signal@. 1644 Attempting release of all acquired monitors at the @wait@ introduces a different set of problems, such as releasing monitor @C@, which has nothing to do with the @signal@. 1645 1646 However, for monitors as for locks, it is possible to write a program using nesting without encountering any problems if nesting is done correctly. 1647 For example, the next cfa-code snippet acquires monitors {\sf A} then {\sf B} before waiting, while only acquiring {\sf B} when signalling, effectively avoiding the Nested Monitor Problem~\cite{Lister77}. 1648 1649 \begin{multicols}{2} 1650 \begin{cfa} 1651 acquire A 1652 acquire B 1653 wait B 1654 release B 1655 release A 1656 \end{cfa} 1657 1658 \columnbreak 1659 1660 \begin{cfa} 1661 1662 acquire B 1663 signal B 1664 release B 1665 1666 \end{cfa} 1667 \end{multicols} 1668 1669 \noindent However, this simple refactoring may not be possible, forcing more complex restructuring. 1670 1671 % ====================================================================== 1672 % ====================================================================== 1673 \subsection{Internal Scheduling - In Depth} 1674 % ====================================================================== 1675 % ====================================================================== 1676 1677 A larger example is presented to show complex issues for \textbf{bulk-acq} and its implementation options are analyzed. 1678 Figure~\ref{f:int-bulk-cfa} shows an example where \textbf{bulk-acq} adds a significant layer of complexity to the internal signalling semantics, and listing \ref{f:int-bulk-cfa} shows the corresponding \CFA code to implement the cfa-code in listing \ref{f:int-bulk-cfa}. 1679 For the purpose of translating the given cfa-code into \CFA-code, any method of introducing a monitor is acceptable, \eg @mutex@ parameters, global variables, pointer parameters, or using locals with the @mutex@ statement. 1680 1681 \begin{figure} 1682 \begin{multicols}{2} 1683 Waiting thread 1684 \begin{cfa}[numbers=left] 1685 acquire A 1686 // Code Section 1 1687 acquire A & B 1688 // Code Section 2 1689 wait A & B 1690 // Code Section 3 1691 release A & B 1692 // Code Section 4 1693 release A 1694 \end{cfa} 1695 \columnbreak 1696 Signalling thread 1697 \begin{cfa}[numbers=left, firstnumber=10,escapechar=|] 1698 acquire A 1699 // Code Section 5 1700 acquire A & B 1701 // Code Section 6 1702 |\label{line:signal1}|signal A & B 1703 // Code Section 7 1704 |\label{line:releaseFirst}|release A & B 1705 // Code Section 8 1706 |\label{line:lastRelease}|release A 1707 \end{cfa} 1708 \end{multicols} 1709 \begin{cfa}[caption={Internal scheduling with \textbf{bulk-acq}},label={f:int-bulk-cfa}] 1710 \end{cfa} 1711 \begin{center} 1712 \begin{cfa}[xleftmargin=.4\textwidth] 1713 monitor A a; 1714 monitor B b; 1715 condition c; 1716 \end{cfa} 1717 \end{center} 1718 \begin{multicols}{2} 1719 Waiting thread 1720 \begin{cfa} 1721 mutex(a) { 1722 // Code Section 1 1723 mutex(a, b) { 1724 // Code Section 2 1725 wait(c); 1726 // Code Section 3 1727 } 1728 // Code Section 4 1729 } 1730 \end{cfa} 1731 \columnbreak 1732 Signalling thread 1733 \begin{cfa} 1734 mutex(a) { 1735 // Code Section 5 1736 mutex(a, b) { 1737 // Code Section 6 1738 signal(c); 1739 // Code Section 7 1740 } 1741 // Code Section 8 1742 } 1743 \end{cfa} 1744 \end{multicols} 1745 \begin{cfa}[caption={Equivalent \CFA code for listing \ref{f:int-bulk-cfa}},label={f:int-bulk-cfa}] 1746 \end{cfa} 1747 \begin{multicols}{2} 1748 Waiter 1749 \begin{cfa}[numbers=left] 1750 acquire A 1751 acquire A & B 1752 wait A & B 1753 release A & B 1754 release A 1755 \end{cfa} 1756 1757 \columnbreak 1758 1759 Signaller 1760 \begin{cfa}[numbers=left, firstnumber=6,escapechar=|] 1761 acquire A 1762 acquire A & B 1763 signal A & B 1764 release A & B 1765 |\label{line:secret}|// Secretly keep B here 1766 release A 1767 // Wakeup waiter and transfer A & B 1768 \end{cfa} 1769 \end{multicols} 1770 \begin{cfa}[caption={Figure~\ref{f:int-bulk-cfa}, with delayed signalling comments},label={f:int-secret}] 1771 \end{cfa} 1713 mutex( m1, m2 ) { 1714 ... `wait( c )`; // block and release m1, m2 1715 // m1, m2 acquired 1716 } // $\LstCommentStyle{\color{red}release m2}$ 1717 // m1 acquired 1718 } // release m1 1719 \end{cfa} 1720 \end{lrbox} 1721 1722 \newbox\myboxC 1723 \begin{lrbox}{\myboxC} 1724 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1725 1726 1727 mutex( m2 ) { 1728 ... `wait( c )`; ... 1729 // m2 acquired 1730 } // $\LstCommentStyle{\color{red}release m2}$ 1731 1732 1733 1734 1735 \end{cfa} 1736 \end{lrbox} 1737 1738 \begin{cquote} 1739 \subfloat[Signalling Thread]{\label{f:SignallingThread}\usebox\myboxA} 1740 \hspace{2\parindentlnth} 1741 \subfloat[Waiting Thread (W1)]{\label{f:WaitingThread}\usebox\myboxB} 1742 \hspace{2\parindentlnth} 1743 \subfloat[Waiting Thread (W2)]{\label{f:OtherWaitingThread}\usebox\myboxC} 1744 \end{cquote} 1745 \caption{Barging Prevention} 1746 \label{f:BargingPrevention} 1772 1747 \end{figure} 1773 1748 1774 The complexity begins at code sections 4 and 8 in listing \ref{f:int-bulk-cfa}, which are where the existing semantics of internal scheduling needs to be extended for multiple monitors. 1775 The root of the problem is that \textbf{bulk-acq} is used in a context where one of the monitors is already acquired, which is why it is important to define the behaviour of the previous cfa-code. 1776 When the signaller thread reaches the location where it should ``release @A & B@'' (listing \ref{f:int-bulk-cfa} line \ref{line:releaseFirst}), it must actually transfer ownership of monitor @B@ to the waiting thread. 1777 This ownership transfer is required in order to prevent barging into @B@ by another thread, since both the signalling and signalled threads still need monitor @A@. 1778 There are three options: 1779 1780 \subsubsection{Delaying Signals} 1781 The obvious solution to the problem of multi-monitor scheduling is to keep ownership of all locks until the last lock is ready to be transferred. 1782 It can be argued that that moment is when the last lock is no longer needed, because this semantics fits most closely to the behaviour of single-monitor scheduling. 1783 This solution has the main benefit of transferring ownership of groups of monitors, which simplifies the semantics from multiple objects to a single group of objects, effectively making the existing single-monitor semantic viable by simply changing monitors to monitor groups. 1784 This solution releases the monitors once every monitor in a group can be released. 1785 However, since some monitors are never released (\eg the monitor of a thread), this interpretation means a group might never be released. 1786 A more interesting interpretation is to transfer the group until all its monitors are released, which means the group is not passed further and a thread can retain its locks. 1787 1788 However, listing \ref{f:int-secret} shows this solution can become much more complicated depending on what is executed while secretly holding B at line \ref{line:secret}, while avoiding the need to transfer ownership of a subset of the condition monitors. 1749 One scheduling solution is for the signaller to keep ownership of all locks until the last lock is ready to be transferred, because this semantics fits most closely to the behaviour of single-monitor scheduling. 1750 However, Figure~\ref{f:OtherWaitingThread} shows this solution is complex depending on other waiters, resulting is choices when the signaller finishes the inner mutex-statement. 1751 The singaller can retain @m2@ until completion of the outer mutex statement and pass the locks to waiter W1, or it can pass @m2@ to waiter W2 after completing the inner mutex-statement, while continuing to hold @m1@. 1752 In the latter case, waiter W2 must eventually pass @m2@ to waiter W1, which is complex because W1 may have waited before W2, so W2 is unaware of it. 1753 Furthermore, there is an execution sequence where the signaller always finds waiter W2, and hence, waiter W1 starves. 1754 1755 While a number of approaches were examined~\cite[\S~4.3]{Delisle18}, the solution chosen for \CFA is a novel techique called \newterm{partial signalling}. 1756 Signalled threads are moved to an urgent queue and the waiter at the front defines the set of monitors necessary for it to unblock. 1757 Partial signalling transfers ownership of monitors to the front waiter. 1758 When the signaller thread exits or waits in the monitor the front waiter is unblocked if all its monitors are released. 1759 This solution has the benefit that complexity is encapsulated into only two actions: passing monitors to the next owner when they should be released and conditionally waking threads if all conditions are met. 1760 1761 \begin{comment} 1789 1762 Figure~\ref{f:dependency} shows a slightly different example where a third thread is waiting on monitor @A@, using a different condition variable. 1790 1763 Because the third thread is signalled when secretly holding @B@, the goal becomes unreachable. … … 1800 1773 In both cases, the threads need to be able to distinguish, on a per monitor basis, which ones need to be released and which ones need to be transferred, which means knowing when to release a group becomes complex and inefficient (see next section) and therefore effectively precludes this approach. 1801 1774 1775 1802 1776 \subsubsection{Dependency graphs} 1803 1804 1777 1805 1778 \begin{figure} … … 1878 1851 The extra challenge is that this dependency graph is effectively post-mortem, but the runtime system needs to be able to build and solve these graphs as the dependencies unfold. 1879 1852 Resolving dependency graphs being a complex and expensive endeavour, this solution is not the preferred one. 1880 1881 \subsubsection{Partial Signalling} \label{partial-sig} 1882 Finally, the solution that is chosen for \CFA is to use partial signalling. 1883 Again using listing \ref{f:int-bulk-cfa}, the partial signalling solution transfers ownership of monitor @B@ at lines \ref{line:signal1} to the waiter but does not wake the waiting thread since it is still using monitor @A@. 1884 Only when it reaches line \ref{line:lastRelease} does it actually wake up the waiting thread. 1885 This solution has the benefit that complexity is encapsulated into only two actions: passing monitors to the next owner when they should be released and conditionally waking threads if all conditions are met. 1886 This solution has a much simpler implementation than a dependency graph solving algorithms, which is why it was chosen. 1887 Furthermore, after being fully implemented, this solution does not appear to have any significant downsides. 1888 1889 Using partial signalling, listing \ref{f:dependency} can be solved easily: 1890 \begin{itemize} 1891 \item When thread $\gamma$ reaches line \ref{line:release-ab} it transfers monitor @B@ to thread $\alpha$ and continues to hold monitor @A@. 1892 \item When thread $\gamma$ reaches line \ref{line:release-a} it transfers monitor @A@ to thread $\beta$ and wakes it up. 1893 \item When thread $\beta$ reaches line \ref{line:release-aa} it transfers monitor @A@ to thread $\alpha$ and wakes it up. 1894 \end{itemize} 1895 1896 % ====================================================================== 1897 % ====================================================================== 1898 \subsection{Signalling: Now or Later} 1899 % ====================================================================== 1900 % ====================================================================== 1901 \begin{table} 1902 \begin{tabular}{|c|c|} 1903 @signal@ & @signal_block@ \\ 1904 \hline 1905 \begin{cfa}[tabsize=3] 1906 monitor DatingService { 1907 // compatibility codes 1908 enum{ CCodes = 20 }; 1909 1910 int girlPhoneNo 1911 int boyPhoneNo; 1912 }; 1913 1914 condition girls[CCodes]; 1915 condition boys [CCodes]; 1916 condition exchange; 1917 1918 int girl(int phoneNo, int cfa) { 1919 // no compatible boy ? 1920 if(empty(boys[cfa])) { 1921 wait(girls[cfa]); // wait for boy 1922 girlPhoneNo = phoneNo; // make phone number available 1923 signal(exchange); // wake boy from chair 1924 } else { 1925 girlPhoneNo = phoneNo; // make phone number available 1926 signal(boys[cfa]); // wake boy 1927 wait(exchange); // sit in chair 1928 } 1929 return boyPhoneNo; 1930 } 1931 int boy(int phoneNo, int cfa) { 1932 // same as above 1933 // with boy/girl interchanged 1934 } 1935 \end{cfa}&\begin{cfa}[tabsize=3] 1936 monitor DatingService { 1937 1938 enum{ CCodes = 20 }; // compatibility codes 1939 1940 int girlPhoneNo; 1941 int boyPhoneNo; 1942 }; 1943 1944 condition girls[CCodes]; 1945 condition boys [CCodes]; 1946 // exchange is not needed 1947 1948 int girl(int phoneNo, int cfa) { 1949 // no compatible boy ? 1950 if(empty(boys[cfa])) { 1951 wait(girls[cfa]); // wait for boy 1952 girlPhoneNo = phoneNo; // make phone number available 1953 signal(exchange); // wake boy from chair 1954 } else { 1955 girlPhoneNo = phoneNo; // make phone number available 1956 signal_block(boys[cfa]); // wake boy 1957 1958 // second handshake unnecessary 1959 1960 } 1961 return boyPhoneNo; 1962 } 1963 1964 int boy(int phoneNo, int cfa) { 1965 // same as above 1966 // with boy/girl interchanged 1967 } 1968 \end{cfa} 1969 \end{tabular} 1970 \caption{Dating service example using \protect\lstinline|signal| and \protect\lstinline|signal_block|. } 1971 \label{tbl:datingservice} 1972 \end{table} 1973 An important note is that, until now, signalling a monitor was a delayed operation. 1974 The ownership of the monitor is transferred only when the monitor would have otherwise been released, not at the point of the @signal@ statement. 1975 However, in some cases, it may be more convenient for users to immediately transfer ownership to the thread that is waiting for cooperation, which is achieved using the @signal_block@ routine. 1976 1977 The example in table \ref{tbl:datingservice} highlights the difference in behaviour. 1978 As mentioned, @signal@ only transfers ownership once the current critical section exits; this behaviour requires additional synchronization when a two-way handshake is needed. 1979 To avoid this explicit synchronization, the @condition@ type offers the @signal_block@ routine, which handles the two-way handshake as shown in the example. 1980 This feature removes the need for a second condition variables and simplifies programming. 1981 Like every other monitor semantic, @signal_block@ uses barging prevention, which means mutual-exclusion is baton-passed both on the front end and the back end of the call to @signal_block@, meaning no other thread can acquire the monitor either before or after the call. 1982 1983 % ====================================================================== 1984 % ====================================================================== 1853 \end{comment} 1854 1855 1856 \begin{comment} 1985 1857 \section{External scheduling} \label{extsched} 1986 % ====================================================================== 1987 % ====================================================================== 1988 An alternative to internal scheduling is external scheduling (see Table~\ref{tbl:sched}). 1858 1989 1859 \begin{table} 1990 1860 \begin{tabular}{|c|c|c|} … … 2050 1920 \label{tbl:sched} 2051 1921 \end{table} 2052 This method is more constrained and explicit, which helps users reduce the non-deterministic nature of concurrency.2053 Indeed, as the following examples demonstrate, external scheduling allows users to wait for events from other threads without the concern of unrelated events occurring.2054 External scheduling can generally be done either in terms of control flow (\eg Ada with @accept@, \uC with @_Accept@) or in terms of data (\eg Go with channels).2055 Of course, both of these paradigms have their own strengths and weaknesses, but for this project, control-flow semantics was chosen to stay consistent with the rest of the languages semantics.2056 Two challenges specific to \CFA arise when trying to add external scheduling with loose object definitions and multiple-monitor routines.2057 The previous example shows a simple use @_Accept@ versus @wait@/@signal@ and its advantages.2058 Note that while other languages often use @accept@/@select@ as the core external scheduling keyword, \CFA uses @waitfor@ to prevent name collisions with existing socket \textbf{api}s.2059 1922 2060 1923 For the @P@ member above using internal scheduling, the call to @wait@ only guarantees that @V@ is the last routine to access the monitor, allowing a third routine, say @isInUse()@, acquire mutual exclusion several times while routine @P@ is waiting. 2061 1924 On the other hand, external scheduling guarantees that while routine @P@ is waiting, no other routine than @V@ can acquire the monitor. 2062 2063 % ====================================================================== 2064 % ====================================================================== 1925 \end{comment} 1926 1927 2065 1928 \subsection{Loose Object Definitions} 2066 % ====================================================================== 2067 % ====================================================================== 2068 In \uC, a monitor class declaration includes an exhaustive list of monitor operations. 2069 Since \CFA is not object oriented, monitors become both more difficult to implement and less clear for a user: 2070 2071 \begin{cfa} 2072 monitor A {}; 2073 2074 void f(A & mutex a); 2075 void g(A & mutex a) { 2076 waitfor(f); // Obvious which f() to wait for 2077 } 2078 2079 void f(A & mutex a, int); // New different F added in scope 2080 void h(A & mutex a) { 2081 waitfor(f); // Less obvious which f() to wait for 2082 } 2083 \end{cfa} 2084 2085 Furthermore, external scheduling is an example where implementation constraints become visible from the interface. 2086 Here is the cfa-code for the entering phase of a monitor: 2087 \begin{center} 2088 \begin{tabular}{l} 2089 \begin{cfa} 2090 if monitor is free 2091 enter 2092 elif already own the monitor 2093 continue 2094 elif monitor accepts me 2095 enter 2096 else 2097 block 2098 \end{cfa} 2099 \end{tabular} 2100 \end{center} 1929 \label{s:LooseObjectDefinitions} 1930 1931 In an object-oriented programming-language, a class includes an exhaustive list of operations. 1932 However, new members can be added via static inheritance or dynaic members, \eg JavaScript~\cite{JavaScript}. 1933 Similarly, monitor routines can be added at any time in \CFA, making it less clear for programmers and more difficult to implement. 1934 \begin{cfa} 1935 monitor M {}; 1936 void `f`( M & mutex m ); 1937 void g( M & mutex m ) { waitfor( `f` ); } $\C{// clear which f}$ 1938 void `f`( M & mutex m, int ); $\C{// different f}$ 1939 void h( M & mutex m ) { waitfor( `f` ); } $\C{// unclear which f}$ 1940 \end{cfa} 1941 Hence, the cfa-code for the entering a monitor looks like: 1942 \begin{cfa} 1943 if ( $\textrm{\textit{monitor is free}}$ ) $\LstCommentStyle{// \color{red}enter}$ 1944 else if ( $\textrm{\textit{already own monitor}}$ ) $\LstCommentStyle{// \color{red}continue}$ 1945 else if ( $\textrm{\textit{monitor accepts me}}$ ) $\LstCommentStyle{// \color{red}enter}$ 1946 else $\LstCommentStyle{// \color{red}block}$ 1947 \end{cfa} 2101 1948 For the first two conditions, it is easy to implement a check that can evaluate the condition in a few instructions. 2102 However, a fast check for @monitor accepts me@is much harder to implement depending on the constraints put on the monitors.2103 Indeed, monitors are often expressed as an entry queue and some acceptor queue as in Figure~\ref{fig:ClassicalMonitor}.1949 However, a fast check for \emph{monitor accepts me} is much harder to implement depending on the constraints put on the monitors. 1950 Figure~\ref{fig:ClassicalMonitor} shows monitors are often expressed as an entry (calling) queue, some acceptor queues, and an urgent stack/queue. 2104 1951 2105 1952 \begin{figure} 2106 1953 \centering 2107 \subfloat[Classical Monitor] {1954 \subfloat[Classical monitor] { 2108 1955 \label{fig:ClassicalMonitor} 2109 {\resizebox{0.45\textwidth}{!}{\input{monitor }}}1956 {\resizebox{0.45\textwidth}{!}{\input{monitor.pstex_t}}} 2110 1957 }% subfloat 2111 \q quad2112 \subfloat[ \textbf{bulk-acq} Monitor] {1958 \quad 1959 \subfloat[Bulk acquire monitor] { 2113 1960 \label{fig:BulkMonitor} 2114 {\resizebox{0.45\textwidth}{!}{\input{ext_monitor }}}1961 {\resizebox{0.45\textwidth}{!}{\input{ext_monitor.pstex_t}}} 2115 1962 }% subfloat 2116 \caption{External Scheduling Monitor} 1963 \caption{Monitor Implementation} 1964 \label{f:MonitorImplementation} 2117 1965 \end{figure} 2118 1966 2119 There are other alternatives to these pictures, but in the case of the left picture, implementing a fast accept check is relatively easy. 2120 Restricted to a fixed number of mutex members, N, the accept check reduces to updating a bitmask when the acceptor queue changes, a check that executes in a single instruction even with a fairly large number (\eg 128) of mutex members. 2121 This approach requires a unique dense ordering of routines with an upper-bound and that ordering must be consistent across translation units. 2122 For OO languages these constraints are common, since objects only offer adding member routines consistently across translation units via inheritance. 2123 However, in \CFA users can extend objects with mutex routines that are only visible in certain translation unit. 2124 This means that establishing a program-wide dense-ordering among mutex routines can only be done in the program linking phase, and still could have issues when using dynamically shared objects. 2125 2126 The alternative is to alter the implementation as in Figure~\ref{fig:BulkMonitor}. 2127 Here, the mutex routine called is associated with a thread on the entry queue while a list of acceptable routines is kept separate. 2128 Generating a mask dynamically means that the storage for the mask information can vary between calls to @waitfor@, allowing for more flexibility and extensions. 2129 Storing an array of accepted function pointers replaces the single instruction bitmask comparison with dereferencing a pointer followed by a linear search. 2130 Furthermore, supporting nested external scheduling (\eg listing \ref{f:nest-ext}) may now require additional searches for the @waitfor@ statement to check if a routine is already queued. 2131 1967 For a fixed (small) number of mutex routines (\eg 128), the accept check reduces to a bitmask of allowed callers, which can be checked with a single instruction. 1968 This approach requires a unique dense ordering of routines with a small upper-bound and the ordering must be consistent across translation units. 1969 For object-oriented languages these constraints are common, but \CFA mutex routines can be added in any scope and are only visible in certain translation unit, precluding program-wide dense-ordering among mutex routines. 1970 1971 Figure~\ref{fig:BulkMonitor} shows the \CFA monitor implementation. 1972 The mutex routine called is associated with each thread on the entry queue, while a list of acceptable routines is kept separately. 1973 The accepted list is a variable-sized array of accepted routine pointers, so the single instruction bitmask comparison is replaced by dereferencing a pointer followed by a linear search. 1974 1975 \begin{comment} 2132 1976 \begin{figure} 2133 1977 \begin{cfa}[caption={Example of nested external scheduling},label={f:nest-ext}] … … 2145 1989 \end{figure} 2146 1990 2147 Note that in the right picture, tasks need to always keep track of the monitors associated with mutex routines, and the routine mask needs to have both a functionpointer and a set of monitors, as is discussed in the next section.1991 Note that in the right picture, tasks need to always keep track of the monitors associated with mutex routines, and the routine mask needs to have both a routine pointer and a set of monitors, as is discussed in the next section. 2148 1992 These details are omitted from the picture for the sake of simplicity. 2149 1993 … … 2153 1997 In the end, the most flexible approach has been chosen since it allows users to write programs that would otherwise be hard to write. 2154 1998 This decision is based on the assumption that writing fast but inflexible locks is closer to a solved problem than writing locks that are as flexible as external scheduling in \CFA. 2155 2156 % ====================================================================== 2157 % ====================================================================== 1999 \end{comment} 2000 2001 2158 2002 \subsection{Multi-Monitor Scheduling} 2159 % ====================================================================== 2160 % ====================================================================== 2003 \label{s:Multi-MonitorScheduling} 2161 2004 2162 2005 External scheduling, like internal scheduling, becomes significantly more complex when introducing multi-monitor syntax. 2163 Even in the simplest possible case, somenew semantics needs to be established:2006 Even in the simplest possible case, new semantics needs to be established: 2164 2007 \begin{cfa} 2165 2008 monitor M {}; 2166 2167 void f(M & mutex a); 2168 2169 void g(M & mutex b, M & mutex c) { 2170 waitfor(f); // two monitors M => unknown which to pass to f(M & mutex) 2171 } 2172 \end{cfa} 2173 The obvious solution is to specify the correct monitor as follows: 2174 2009 void f( M & mutex m1 ); 2010 void g( M & mutex m1, M & mutex m2 ) { 2011 waitfor( f ); $\C{// pass m1 or m2 to f?}$ 2012 } 2013 \end{cfa} 2014 The solution is for the programmer to disambiguate: 2015 \begin{cfa} 2016 waitfor( f, m2 ); $\C{// wait for call to f with argument m2}$ 2017 \end{cfa} 2018 Routine @g@ has acquired both locks, so when routine @f@ is called, the lock for monitor @m2@ is passed from @g@ to @f@ (while @g@ still holds lock @m1@). 2019 This behaviour can be extended to the multi-monitor @waitfor@ statement. 2175 2020 \begin{cfa} 2176 2021 monitor M {}; 2177 2178 void f(M & mutex a); 2179 2180 void g(M & mutex a, M & mutex b) { 2181 // wait for call to f with argument b 2182 waitfor(f, b); 2183 } 2184 \end{cfa} 2185 This syntax is unambiguous. 2186 Both locks are acquired and kept by @g@. 2187 When routine @f@ is called, the lock for monitor @b@ is temporarily transferred from @g@ to @f@ (while @g@ still holds lock @a@). 2188 This behaviour can be extended to the multi-monitor @waitfor@ statement as follows. 2189 2190 \begin{cfa} 2191 monitor M {}; 2192 2193 void f(M & mutex a, M & mutex b); 2194 2195 void g(M & mutex a, M & mutex b) { 2196 // wait for call to f with arguments a and b 2197 waitfor(f, a, b); 2198 } 2199 \end{cfa} 2200 2201 Note that the set of monitors passed to the @waitfor@ statement must be entirely contained in the set of monitors already acquired in the routine. @waitfor@ used in any other context is undefined behaviour. 2022 void f( M & mutex m1, M & mutex m2 ); 2023 void g( M & mutex m1, M & mutex m2 ) { 2024 waitfor( f, m1, m2 ); $\C{// wait for call to f with arguments m1 and m2}$ 2025 } 2026 \end{cfa} 2027 Again, the set of monitors passed to the @waitfor@ statement must be entirely contained in the set of monitors already acquired by accepting routine. 2202 2028 2203 2029 An important behaviour to note is when a set of monitors only match partially: 2204 2205 2030 \begin{cfa} 2206 2031 mutex struct A {}; 2207 2208 2032 mutex struct B {}; 2209 2210 void g(A & mutex a, B & mutex b) { 2211 waitfor(f, a, b); 2212 } 2213 2033 void g( A & mutex m1, B & mutex m2 ) { 2034 waitfor( f, m1, m2 ); 2035 } 2214 2036 A a1, a2; 2215 2037 B b; 2216 2217 2038 void foo() { 2218 g(a1, b); // block on accept 2219 } 2220 2039 g( a1, b ); // block on accept 2040 } 2221 2041 void bar() { 2222 f( a2, b); // fulfill cooperation2042 f( a2, b ); // fulfill cooperation 2223 2043 } 2224 2044 \end{cfa} … … 2227 2047 It is also important to note that in the case of external scheduling the order of parameters is irrelevant; @waitfor(f,a,b)@ and @waitfor(f,b,a)@ are indistinguishable waiting condition. 2228 2048 2229 % ====================================================================== 2230 % ====================================================================== 2049 2231 2050 \subsection{\protect\lstinline|waitfor| Semantics} 2232 % ====================================================================== 2233 % ====================================================================== 2234 2235 Syntactically, the @waitfor@ statement takes a function identifier and a set of monitors. 2236 While the set of monitors can be any list of expressions, the function name is more restricted because the compiler validates at compile time the validity of the function type and the parameters used with the @waitfor@ statement. 2237 It checks that the set of monitors passed in matches the requirements for a function call. 2051 2052 Syntactically, the @waitfor@ statement takes a routine identifier and a set of monitors. 2053 While the set of monitors can be any list of expressions, the routine name is more restricted because the compiler validates at compile time the validity of the routine type and the parameters used with the @waitfor@ statement. 2054 It checks that the set of monitors passed in matches the requirements for a routine call. 2238 2055 Figure~\ref{f:waitfor} shows various usages of the waitfor statement and which are acceptable. 2239 The choice of the functiontype is made ignoring any non-@mutex@ parameter.2056 The choice of the routine type is made ignoring any non-@mutex@ parameter. 2240 2057 One limitation of the current implementation is that it does not handle overloading, but overloading is possible. 2241 2058 \begin{figure} … … 2263 2080 waitfor(f2, a1, a2); // Incorrect : Mutex arguments don't match 2264 2081 waitfor(f1, 1); // Incorrect : 1 not a mutex argument 2265 waitfor(f9, a1); // Incorrect : f9 functiondoes not exist2082 waitfor(f9, a1); // Incorrect : f9 routine does not exist 2266 2083 waitfor(*fp, a1 ); // Incorrect : fp not an identifier 2267 2084 waitfor(f4, a1); // Incorrect : f4 ambiguous … … 2273 2090 2274 2091 Finally, for added flexibility, \CFA supports constructing a complex @waitfor@ statement using the @or@, @timeout@ and @else@. 2275 Indeed, multiple @waitfor@ clauses can be chained together using @or@; this chain forms a single statement that uses baton pass to any function that fits one of the function+monitor set passed in.2276 To enable users to tell which accepted functionexecuted, @waitfor@s are followed by a statement (including the null statement @;@) or a compound statement, which is executed after the clause is triggered.2277 A @waitfor@ chain can also be followed by a @timeout@, to signify an upper bound on the wait, or an @else@, to signify that the call should be non-blocking, which checks for a matching functioncall already arrived and otherwise continues.2092 Indeed, multiple @waitfor@ clauses can be chained together using @or@; this chain forms a single statement that uses baton pass to any routine that fits one of the routine+monitor set passed in. 2093 To enable users to tell which accepted routine executed, @waitfor@s are followed by a statement (including the null statement @;@) or a compound statement, which is executed after the clause is triggered. 2094 A @waitfor@ chain can also be followed by a @timeout@, to signify an upper bound on the wait, or an @else@, to signify that the call should be non-blocking, which checks for a matching routine call already arrived and otherwise continues. 2278 2095 Any and all of these clauses can be preceded by a @when@ condition to dynamically toggle the accept clauses on or off based on some current state. 2279 2096 Figure~\ref{f:waitfor2} demonstrates several complex masks and some incorrect ones. … … 2330 2147 \end{figure} 2331 2148 2332 % ====================================================================== 2333 % ====================================================================== 2149 2334 2150 \subsection{Waiting For The Destructor} 2335 % ====================================================================== 2336 % ====================================================================== 2151 2337 2152 An interesting use for the @waitfor@ statement is destructor semantics. 2338 2153 Indeed, the @waitfor@ statement can accept any @mutex@ routine, which includes the destructor (see section \ref{data}). … … 2361 2176 2362 2177 2363 % ###### # ###### # # # ####### # ### ##### # #2364 % # # # # # # # # # # # # # # # ## ##2365 % # # # # # # # # # # # # # # # # # #2366 % ###### # # ###### # # # # ##### # # ##### # # #2367 % # ####### # # ####### # # # # # # # #2368 % # # # # # # # # # # # # # # # #2369 % # # # # # # # ####### ####### ####### ####### ### ##### # #2370 2178 \section{Parallelism} 2179 2371 2180 Historically, computer performance was about processor speeds and instruction counts. 2372 2181 However, with heat dissipation being a direct consequence of speed increase, parallelism has become the new source for increased performance~\cite{Sutter05, Sutter05b}. … … 2378 2187 While there are many variations of the presented paradigms, most of these variations do not actually change the guarantees or the semantics, they simply move costs in order to achieve better performance for certain workloads. 2379 2188 2189 2380 2190 \section{Paradigms} 2191 2192 2381 2193 \subsection{User-Level Threads} 2194 2382 2195 A direct improvement on the \textbf{kthread} approach is to use \textbf{uthread}. 2383 2196 These threads offer most of the same features that the operating system already provides but can be used on a much larger scale. … … 2388 2201 Examples of languages that support \textbf{uthread} are Erlang~\cite{Erlang} and \uC~\cite{uC++book}. 2389 2202 2203 2390 2204 \subsection{Fibers : User-Level Threads Without Preemption} \label{fibers} 2205 2391 2206 A popular variant of \textbf{uthread} is what is often referred to as \textbf{fiber}. 2392 2207 However, \textbf{fiber} do not present meaningful semantic differences with \textbf{uthread}. … … 2397 2212 An example of a language that uses fibers is Go~\cite{Go} 2398 2213 2214 2399 2215 \subsection{Jobs and Thread Pools} 2216 2400 2217 An approach on the opposite end of the spectrum is to base parallelism on \textbf{pool}. 2401 2218 Indeed, \textbf{pool} offer limited flexibility but at the benefit of a simpler user interface. … … 2408 2225 The gold standard of this implementation is Intel's TBB library~\cite{TBB}. 2409 2226 2227 2410 2228 \subsection{Paradigm Performance} 2229 2411 2230 While the choice between the three paradigms listed above may have significant performance implications, it is difficult to pin down the performance implications of choosing a model at the language level. 2412 2231 Indeed, in many situations one of these paradigms may show better performance but it all strongly depends on the workload. … … 2416 2235 Finally, if the units of uninterrupted work are large, enough the paradigm choice is largely amortized by the actual work done. 2417 2236 2237 2418 2238 \section{The \protect\CFA\ Kernel : Processors, Clusters and Threads}\label{kernel} 2239 2419 2240 A \textbf{cfacluster} is a group of \textbf{kthread} executed in isolation. \textbf{uthread} are scheduled on the \textbf{kthread} of a given \textbf{cfacluster}, allowing organization between \textbf{uthread} and \textbf{kthread}. 2420 2241 It is important that \textbf{kthread} belonging to a same \textbf{cfacluster} have homogeneous settings, otherwise migrating a \textbf{uthread} from one \textbf{kthread} to the other can cause issues. … … 2424 2245 Currently \CFA only supports one \textbf{cfacluster}, the initial one. 2425 2246 2247 2426 2248 \subsection{Future Work: Machine Setup}\label{machine} 2249 2427 2250 While this was not done in the context of this paper, another important aspect of clusters is affinity. 2428 2251 While many common desktop and laptop PCs have homogeneous CPUs, other devices often have more heterogeneous setups. … … 2430 2253 OS support for CPU affinity is now common~\cite{affinityLinux, affinityWindows, affinityFreebsd, affinityNetbsd, affinityMacosx}, which means it is both possible and desirable for \CFA to offer an abstraction mechanism for portable CPU affinity. 2431 2254 2255 2432 2256 \subsection{Paradigms}\label{cfaparadigms} 2257 2433 2258 Given these building blocks, it is possible to reproduce all three of the popular paradigms. 2434 2259 Indeed, \textbf{uthread} is the default paradigm in \CFA. … … 2438 2263 2439 2264 2440 2441 2265 \section{Behind the Scenes} 2266 2442 2267 There are several challenges specific to \CFA when implementing concurrency. 2443 These challenges are a direct result of \textbf{bulk-acq}and loose object definitions.2268 These challenges are a direct result of bulk acquire and loose object definitions. 2444 2269 These two constraints are the root cause of most design decisions in the implementation. 2445 2270 Furthermore, to avoid contention from dynamically allocating memory in a concurrent environment, the internal-scheduling design is (almost) entirely free of mallocs. … … 2449 2274 The main memory concern for concurrency is queues. 2450 2275 All blocking operations are made by parking threads onto queues and all queues are designed with intrusive nodes, where each node has pre-allocated link fields for chaining, to avoid the need for memory allocation. 2451 Since several concurrency operations can use an unbound amount of memory (depending on \textbf{bulk-acq}), statically defining information in the intrusive fields of threads is insufficient.The only way to use a variable amount of memory without requiring memory allocation is to pre-allocate large buffers of memory eagerly and store the information in these buffers.2276 Since several concurrency operations can use an unbound amount of memory (depending on bulk acquire), statically defining information in the intrusive fields of threads is insufficient.The only way to use a variable amount of memory without requiring memory allocation is to pre-allocate large buffers of memory eagerly and store the information in these buffers. 2452 2277 Conveniently, the call stack fits that description and is easy to use, which is why it is used heavily in the implementation of internal scheduling, particularly variable-length arrays. 2453 2278 Since stack allocation is based on scopes, the first step of the implementation is to identify the scopes that are available to store the information, and which of these can have a variable-length array. 2454 2279 The threads and the condition both have a fixed amount of memory, while @mutex@ routines and blocking calls allow for an unbound amount, within the stack size. 2455 2280 2456 Note that since the major contributions of this paper are extending monitor semantics to \textbf{bulk-acq} and loose object definitions, any challenges that are not resulting of these characteristics of \CFA are considered as solved problems and therefore not discussed. 2457 2458 % ====================================================================== 2459 % ====================================================================== 2281 Note that since the major contributions of this paper are extending monitor semantics to bulk acquire and loose object definitions, any challenges that are not resulting of these characteristics of \CFA are considered as solved problems and therefore not discussed. 2282 2283 2460 2284 \section{Mutex Routines} 2461 % ======================================================================2462 % ======================================================================2463 2285 2464 2286 The first step towards the monitor implementation is simple @mutex@ routines. … … 2495 2317 \end{figure} 2496 2318 2319 2497 2320 \subsection{Details: Interaction with polymorphism} 2321 2498 2322 Depending on the choice of semantics for when monitor locks are acquired, interaction between monitors and \CFA's concept of polymorphism can be more complex to support. 2499 2323 However, it is shown that entry-point locking solves most of the issues. … … 2564 2388 void foo(T * mutex t); 2565 2389 2566 // Correct: this functiononly works on monitors (any monitor)2390 // Correct: this routine only works on monitors (any monitor) 2567 2391 forall(dtype T | is_monitor(T)) 2568 2392 void bar(T * mutex t)); … … 2571 2395 Both entry point and \textbf{callsite-locking} are feasible implementations. 2572 2396 The current \CFA implementation uses entry-point locking because it requires less work when using \textbf{raii}, effectively transferring the burden of implementation to object construction/destruction. 2573 It is harder to use \textbf{raii} for call-site locking, as it does not necessarily have an existing scope that matches exactly the scope of the mutual exclusion, \ie the functionbody.2397 It is harder to use \textbf{raii} for call-site locking, as it does not necessarily have an existing scope that matches exactly the scope of the mutual exclusion, \ie the routine body. 2574 2398 For example, the monitor call can appear in the middle of an expression. 2575 2399 Furthermore, entry-point locking requires less code generation since any useful routine is called multiple times but there is only one entry point for many call sites. 2576 2400 2577 % ====================================================================== 2578 % ====================================================================== 2401 2579 2402 \section{Threading} \label{impl:thread} 2580 % ======================================================================2581 % ======================================================================2582 2403 2583 2404 Figure \ref{fig:system1} shows a high-level picture if the \CFA runtime system in regards to concurrency. … … 2592 2413 \end{figure} 2593 2414 2415 2594 2416 \subsection{Processors} 2417 2595 2418 Parallelism in \CFA is built around using processors to specify how much parallelism is desired. \CFA processors are object wrappers around kernel threads, specifically @pthread@s in the current implementation of \CFA. 2596 2419 Indeed, any parallelism must go through operating-system libraries. … … 2600 2423 Processors internally use coroutines to take advantage of the existing context-switching semantics. 2601 2424 2425 2602 2426 \subsection{Stack Management} 2427 2603 2428 One of the challenges of this system is to reduce the footprint as much as possible. 2604 2429 Specifically, all @pthread@s created also have a stack created with them, which should be used as much as possible. … … 2607 2432 In order to respect C user expectations, the stack of the initial kernel thread, the main stack of the program, is used by the main user thread rather than the main processor, which can grow very large. 2608 2433 2434 2609 2435 \subsection{Context Switching} 2436 2610 2437 As mentioned in section \ref{coroutine}, coroutines are a stepping stone for implementing threading, because they share the same mechanism for context-switching between different stacks. 2611 To improve performance and simplicity, context-switching is implemented using the following assumption: all context-switches happen inside a specific functioncall.2438 To improve performance and simplicity, context-switching is implemented using the following assumption: all context-switches happen inside a specific routine call. 2612 2439 This assumption means that the context-switch only has to copy the callee-saved registers onto the stack and then switch the stack registers with the ones of the target coroutine/thread. 2613 Note that the instruction pointer can be left untouched since the context-switch is always inside the same function.2440 Note that the instruction pointer can be left untouched since the context-switch is always inside the same routine 2614 2441 Threads, however, do not context-switch between each other directly. 2615 2442 They context-switch to the scheduler. … … 2621 2448 This option is not currently present in \CFA, but the changes required to add it are strictly additive. 2622 2449 2450 2623 2451 \subsection{Preemption} \label{preemption} 2452 2624 2453 Finally, an important aspect for any complete threading system is preemption. 2625 2454 As mentioned in section \ref{basics}, preemption introduces an extra degree of uncertainty, which enables users to have multiple threads interleave transparently, rather than having to cooperate among threads for proper scheduling and CPU distribution. … … 2648 2477 As a result, a signal handler can start on one kernel thread and terminate on a second kernel thread (but the same user thread). 2649 2478 It is important to note that signal handlers save and restore signal masks because user-thread migration can cause a signal mask to migrate from one kernel thread to another. 2650 This behaviour is only a problem if all kernel threads, among which a user thread can migrate, differ in terms of signal masks\footnote{Sadly, official POSIX documentation is silent on what distinguishes ``async-signal-safe'' functions from other functions.}.2479 This behaviour is only a problem if all kernel threads, among which a user thread can migrate, differ in terms of signal masks\footnote{Sadly, official POSIX documentation is silent on what distinguishes ``async-signal-safe'' routines from other routines}. 2651 2480 However, since the kernel thread handling preemption requires a different signal mask, executing user threads on the kernel-alarm thread can cause deadlocks. 2652 2481 For this reason, the alarm thread is in a tight loop around a system call to @sigwaitinfo@, requiring very little CPU time for preemption. … … 2655 2484 Indeed, @sigwait@ can differentiate signals sent from @pthread_sigqueue@ from signals sent from alarms or the kernel. 2656 2485 2486 2657 2487 \subsection{Scheduler} 2658 2488 Finally, an aspect that was not mentioned yet is the scheduling algorithm. … … 2660 2490 Further discussion on scheduling is present in section \ref{futur:sched}. 2661 2491 2662 % ====================================================================== 2663 % ====================================================================== 2492 2664 2493 \section{Internal Scheduling} \label{impl:intsched} 2665 % ====================================================================== 2666 % ====================================================================== 2494 2667 2495 The following figure is the traditional illustration of a monitor (repeated from page~\pageref{fig:ClassicalMonitor} for convenience): 2668 2496 2669 2497 \begin{figure} 2670 2498 \begin{center} 2671 {\resizebox{0.4\textwidth}{!}{\input{monitor }}}2499 {\resizebox{0.4\textwidth}{!}{\input{monitor.pstex_t}}} 2672 2500 \end{center} 2673 2501 \caption{Traditional illustration of a monitor} … … 2678 2506 2679 2507 For \CFA, this picture does not have support for blocking multiple monitors on a single condition. 2680 To support \textbf{bulk-acq}two changes to this picture are required.2508 To support bulk acquire two changes to this picture are required. 2681 2509 First, it is no longer helpful to attach the condition to \emph{a single} monitor. 2682 2510 Secondly, the thread waiting on the condition has to be separated across multiple monitors, seen in figure \ref{fig:monitor_cfa}. … … 2727 2555 \end{figure} 2728 2556 2729 The solution discussed in \ref{ intsched} can be seen in the exit routine of listing \ref{f:entry2}.2557 The solution discussed in \ref{s:InternalScheduling} can be seen in the exit routine of listing \ref{f:entry2}. 2730 2558 Basically, the solution boils down to having a separate data structure for the condition queue and the AS-stack, and unconditionally transferring ownership of the monitors but only unblocking the thread when the last monitor has transferred ownership. 2731 2559 This solution is deadlock safe as well as preventing any potential barging. … … 2963 2791 } 2964 2792 \end{cfa} 2965 This functionis called by the kernel to fetch the default preemption rate, where 0 signifies an infinite time-slice, \ie no preemption.2793 This routine is called by the kernel to fetch the default preemption rate, where 0 signifies an infinite time-slice, \ie no preemption. 2966 2794 However, once clusters are fully implemented, it will be possible to create fibers and \textbf{uthread} in the same system, as in listing \ref{f:fiber-uthread} 2967 2795 \begin{figure} … … 3148 2976 For monitors, the simplest approach is to measure how long it takes to enter and leave a monitor routine. 3149 2977 Figure~\ref{f:mutex} shows the code for \CFA. 3150 To put the results in context, the cost of entering a non-inline functionand the cost of acquiring and releasing a @pthread_mutex@ lock is also measured.2978 To put the results in context, the cost of entering a non-inline routine and the cost of acquiring and releasing a @pthread_mutex@ lock is also measured. 3151 2979 The results can be shown in table \ref{tab:mutex}. 3152 2980 … … 3399 3227 Therefore, there is still significant work to improve performance. 3400 3228 Many of the data structures and algorithms may change in the future to more efficient versions. 3401 For example, the number of monitors in a single \textbf{bulk-acq}is only bound by the stack size, this is probably unnecessarily generous.3229 For example, the number of monitors in a single bulk acquire is only bound by the stack size, this is probably unnecessarily generous. 3402 3230 It may be possible that limiting the number helps increase performance. 3403 3231 However, it is not obvious that the benefit would be significant. -
TabularUnified doc/papers/concurrency/figures/ext_monitor.fig ¶
r0182bfa r28f3a19 8 8 -2 9 9 1200 2 10 5 1 0 1 -1 -1 0 0 -1 0.000 0 1 0 0 3150.000 3450.000 3150 3150 2850 3450 3150375011 5 1 0 1 -1 -1 0 0 -1 0.000 0 1 0 0 3150.000 4350.000 3150 4050 2850 4350 3150465012 6 5850 1950 6150225013 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6000 2100 105 105 6000 2100 6105220514 4 1 -1 0 0 0 10 0.0000 2 105 90 60002160 d\00110 5 1 0 1 -1 -1 0 0 -1 0.000 0 1 0 0 1575.000 3450.000 1575 3150 1275 3450 1575 3750 11 5 1 0 1 -1 -1 0 0 -1 0.000 0 1 0 0 1575.000 4350.000 1575 4050 1275 4350 1575 4650 12 6 4275 1950 4575 2250 13 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4425 2100 105 105 4425 2100 4530 2205 14 4 1 -1 0 0 0 10 0.0000 2 105 90 4425 2160 d\001 15 15 -6 16 6 5100 2100 5400 240017 1 3 0 1 -1 -1 1 0 4 0.000 1 0.0000 5250 2250 105 105 5250 2250 5355 225018 4 1 -1 0 0 0 10 0.0000 2 105 120 5250 2295 X\00116 6 4275 1650 4575 1950 17 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4425 1800 105 105 4425 1800 4530 1905 18 4 1 -1 0 0 0 10 0.0000 2 105 90 4425 1860 b\001 19 19 -6 20 6 5100 1800 5400 2100 21 1 3 0 1 -1 -1 1 0 4 0.000 1 0.0000 5250 1950 105 105 5250 1950 5355 1950 22 4 1 -1 0 0 0 10 0.0000 2 105 120 5250 2010 Y\001 20 6 1495 5445 5700 5655 21 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 1575 5550 80 80 1575 5550 1655 5630 22 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 2925 5550 105 105 2925 5550 3030 5655 23 1 3 0 1 -1 -1 0 0 4 0.000 1 0.0000 4425 5550 105 105 4425 5550 4530 5655 24 4 0 -1 0 0 0 12 0.0000 2 135 1035 3150 5625 blocked task\001 25 4 0 -1 0 0 0 12 0.0000 2 135 870 1725 5625 active task\001 26 4 0 -1 0 0 0 12 0.0000 2 135 1050 4650 5625 routine mask\001 23 27 -6 24 6 5850 1650 6150 1950 25 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6000 1800 105 105 6000 1800 6105 1905 26 4 1 -1 0 0 0 10 0.0000 2 105 90 6000 1860 b\001 28 6 3525 1800 3825 2400 29 1 3 0 1 -1 -1 1 0 4 0.000 1 0.0000 3675 1950 105 105 3675 1950 3780 1950 30 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 31 3525 1800 3825 1800 3825 2400 3525 2400 3525 1800 32 4 1 4 0 0 0 10 0.0000 2 105 120 3675 2010 Y\001 27 33 -6 28 6 3070 5445 7275 5655 29 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3150 5550 80 80 3150 5550 3230 5630 30 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4500 5550 105 105 4500 5550 4605 5655 31 1 3 0 1 -1 -1 0 0 4 0.000 1 0.0000 6000 5550 105 105 6000 5550 6105 5655 32 4 0 -1 0 0 0 12 0.0000 2 135 1035 4725 5625 blocked task\001 33 4 0 -1 0 0 0 12 0.0000 2 135 870 3300 5625 active task\001 34 4 0 -1 0 0 0 12 0.0000 2 135 1050 6225 5625 routine mask\001 34 6 3525 2100 3825 2400 35 1 3 0 1 -1 -1 1 0 4 0.000 1 0.0000 3675 2250 105 105 3675 2250 3780 2250 36 4 1 4 0 0 0 10 0.0000 2 105 120 3675 2295 X\001 35 37 -6 36 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3300 3600 105 105 3300 3600 3405370537 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3600 3600 105 105 3600 3600 3705370538 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6600 3900 105 105 6600 3900 6705400539 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6900 3900 105 105 6900 3900 7005400540 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6000 2700 105 105 6000 2700 6105280541 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6000 2400 105 105 6000 2400 6105250542 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5100 4575 80 80 5100 4575 5180465538 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 1725 3600 105 105 1725 3600 1830 3705 39 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 2025 3600 105 105 2025 3600 2130 3705 40 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5025 3900 105 105 5025 3900 5130 4005 41 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5325 3900 105 105 5325 3900 5430 4005 42 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4425 2700 105 105 4425 2700 4530 2805 43 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4425 2400 105 105 4425 2400 4530 2505 44 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3525 4575 80 80 3525 4575 3605 4655 43 45 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 44 4050 2925 5475 2925 5475 3225 4050 3225 4050292546 2475 2925 3900 2925 3900 3225 2475 3225 2475 2925 45 47 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 4 46 3150 3750 3750 3750 3750 4050 3150405048 1575 3750 2175 3750 2175 4050 1575 4050 47 49 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 3 48 3150 3450 3750 3450 3900367550 1575 3450 2175 3450 2325 3675 49 51 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 50 3750 3150 3600337552 2175 3150 2025 3375 51 53 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 3 52 3150 4350 3750 4350 3900457554 1575 4350 2175 4350 2325 4575 53 55 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 54 3750 4050 3600427556 2175 4050 2025 4275 55 57 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 4 56 3150 4650 3750 4650 3750 4950 4950495058 1575 4650 2175 4650 2175 4950 3375 4950 57 59 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 58 6450 3750 6300397560 4875 3750 4725 3975 59 61 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 60 4950 4950 5175510062 3375 4950 3600 5100 61 63 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 9 62 5250 4950 6450 4950 6450 4050 7050 4050 7050 3750 6450375063 6450 2850 6150 2850 6150165064 3675 4950 4875 4950 4875 4050 5475 4050 5475 3750 4875 3750 65 4875 2850 4575 2850 4575 1650 64 66 2 2 1 1 -1 -1 0 0 -1 4.000 0 0 0 0 0 5 65 5850 4200 5850 3300 4350 3300 4350 4200 5850420066 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1267 4275 4200 4275 3300 2775 3300 2775 4200 4275 4200 68 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 67 69 1 1 1.00 60.00 120.00 68 7 1 1.00 60.00 120.00 69 5250 3150 5250 2400 70 3675 3075 3675 2400 71 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 72 4125 2850 4575 3000 70 73 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 71 3150 3150 3750 3150 3750 2850 5700 2850 5700 1650 72 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 73 5700 2850 6150 3000 74 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 75 5100 1800 5400 1800 5400 2400 5100 2400 5100 1800 76 4 1 -1 0 0 0 10 0.0000 2 75 75 6000 2745 a\001 77 4 1 -1 0 0 0 10 0.0000 2 75 75 6000 2445 c\001 78 4 1 -1 0 0 0 12 0.0000 2 135 315 5100 5325 exit\001 79 4 1 -1 0 0 0 12 0.0000 2 135 135 3300 3075 A\001 80 4 1 -1 0 0 0 12 0.0000 2 135 795 3300 4875 condition\001 81 4 1 -1 0 0 0 12 0.0000 2 135 135 3300 5100 B\001 82 4 0 -1 0 0 0 12 0.0000 2 135 420 6600 3675 stack\001 83 4 0 -1 0 0 0 12 0.0000 2 180 750 6600 3225 acceptor/\001 84 4 0 -1 0 0 0 12 0.0000 2 180 750 6600 3450 signalled\001 85 4 1 -1 0 0 0 12 0.0000 2 135 795 3300 2850 condition\001 86 4 1 -1 0 0 0 12 0.0000 2 165 420 6000 1350 entry\001 87 4 1 -1 0 0 0 12 0.0000 2 135 495 6000 1575 queue\001 88 4 0 -1 0 0 0 12 0.0000 2 135 525 6300 2400 arrival\001 89 4 0 -1 0 0 0 12 0.0000 2 135 630 6300 2175 order of\001 90 4 1 -1 0 0 0 12 0.0000 2 135 525 5100 3675 shared\001 91 4 1 -1 0 0 0 12 0.0000 2 135 735 5100 3975 variables\001 92 4 0 0 50 -1 0 11 0.0000 2 165 855 4275 3150 Acceptables\001 93 4 0 0 50 -1 0 11 0.0000 2 120 165 5775 2700 W\001 94 4 0 0 50 -1 0 11 0.0000 2 120 135 5775 2400 X\001 95 4 0 0 50 -1 0 11 0.0000 2 120 105 5775 2100 Z\001 96 4 0 0 50 -1 0 11 0.0000 2 120 135 5775 1800 Y\001 74 1575 3150 2175 3150 2175 2850 4125 2850 4125 1650 75 4 1 -1 0 0 0 10 0.0000 2 75 75 4425 2745 a\001 76 4 1 -1 0 0 0 10 0.0000 2 75 75 4425 2445 c\001 77 4 1 -1 0 0 0 12 0.0000 2 135 315 3525 5325 exit\001 78 4 1 -1 0 0 0 12 0.0000 2 135 135 1725 3075 A\001 79 4 1 -1 0 0 0 12 0.0000 2 135 795 1725 4875 condition\001 80 4 1 -1 0 0 0 12 0.0000 2 135 135 1725 5100 B\001 81 4 0 -1 0 0 0 12 0.0000 2 135 420 5025 3675 stack\001 82 4 0 -1 0 0 0 12 0.0000 2 180 750 5025 3225 acceptor/\001 83 4 0 -1 0 0 0 12 0.0000 2 180 750 5025 3450 signalled\001 84 4 1 -1 0 0 0 12 0.0000 2 135 795 1725 2850 condition\001 85 4 1 -1 0 0 0 12 0.0000 2 165 420 4425 1350 entry\001 86 4 1 -1 0 0 0 12 0.0000 2 135 495 4425 1575 queue\001 87 4 0 -1 0 0 0 12 0.0000 2 135 525 4725 2400 arrival\001 88 4 0 -1 0 0 0 12 0.0000 2 135 630 4725 2175 order of\001 89 4 1 -1 0 0 0 12 0.0000 2 135 525 3525 3675 shared\001 90 4 1 -1 0 0 0 12 0.0000 2 135 735 3525 3975 variables\001 91 4 0 4 50 -1 0 11 0.0000 2 120 135 4150 1875 Y\001 92 4 0 4 50 -1 0 11 0.0000 2 120 105 4150 2175 Z\001 93 4 0 4 50 -1 0 11 0.0000 2 120 135 4150 2475 X\001 94 4 0 4 50 -1 0 11 0.0000 2 120 165 4150 2775 W\001 95 4 0 -1 0 0 3 12 0.0000 2 150 540 5025 4275 urgent\001 96 4 1 0 50 -1 0 11 0.0000 2 165 600 3150 3150 accepted\001 -
TabularUnified doc/papers/concurrency/figures/monitor.fig ¶
r0182bfa r28f3a19 72 72 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 4 73 73 3600 1500 3600 2100 4200 2100 4200 900 74 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 475 2700 1500 2700 2100 3300 2100 3300 150076 74 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 9 77 75 3600 4200 4800 4200 4800 3300 5400 3300 5400 3000 4800 3000 … … 79 77 2 2 1 1 -1 -1 0 0 -1 4.000 0 0 0 0 0 5 80 78 4200 3450 4200 2550 2700 2550 2700 3450 4200 3450 79 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 4 80 2700 1500 2700 2100 3300 2100 3300 1500 81 81 4 1 -1 0 0 0 10 0.0000 2 75 75 4350 1995 a\001 82 82 4 1 -1 0 0 0 10 0.0000 2 75 75 4350 1695 c\001 … … 89 89 4 0 -1 0 0 0 12 0.0000 2 180 750 4950 2700 signalled\001 90 90 4 1 -1 0 0 0 12 0.0000 2 135 795 1650 2100 condition\001 91 4 1 -10 0 0 12 0.0000 2 135 135 2550 1425 X\00192 4 1 -10 0 0 12 0.0000 2 135 135 3450 1425 Y\00191 4 1 4 0 0 0 12 0.0000 2 135 135 2550 1425 X\001 92 4 1 4 0 0 0 12 0.0000 2 135 135 3450 1425 Y\001 93 93 4 1 -1 0 0 0 12 0.0000 2 165 420 4350 600 entry\001 94 94 4 1 -1 0 0 0 12 0.0000 2 135 495 4350 825 queue\001 … … 100 100 4 1 -1 0 0 0 10 0.0000 2 75 75 3450 1995 c\001 101 101 4 1 -1 0 0 0 12 0.0000 2 135 570 3000 1200 queues\001 102 4 0 -1 0 0 3 12 0.0000 2 150 540 4950 3525 urgent\001 -
TabularUnified doc/papers/general/Makefile ¶
r0182bfa r28f3a19 59 59 dvips ${Build}/$< -o $@ 60 60 61 ${BASE}.dvi : Makefile ${B uild} ${BASE}.out.ps WileyNJD-AMA.bst ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \62 ../../bibliography/pl.bib 61 ${BASE}.dvi : Makefile ${BASE}.out.ps WileyNJD-AMA.bst ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 62 ../../bibliography/pl.bib | ${Build} 63 63 # Must have *.aux file containing citations for bibtex 64 64 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi … … 75 75 mkdir -p ${Build} 76 76 77 ${BASE}.out.ps : ${Build}77 ${BASE}.out.ps : | ${Build} 78 78 ln -fs ${Build}/Paper.out.ps . 79 79 … … 84 84 gnuplot -e Build="'${Build}/'" evaluation/timing.gp 85 85 86 %.tex : %.fig ${Build}86 %.tex : %.fig | ${Build} 87 87 fig2dev -L eepic $< > ${Build}/$@ 88 88 89 %.ps : %.fig ${Build}89 %.ps : %.fig | ${Build} 90 90 fig2dev -L ps $< > ${Build}/$@ 91 91 92 %.pstex : %.fig ${Build}92 %.pstex : %.fig | ${Build} 93 93 fig2dev -L pstex $< > ${Build}/$@ 94 94 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t -
TabularUnified doc/papers/general/Paper.tex ¶
r0182bfa r28f3a19 201 201 202 202 \abstract[Summary]{ 203 The C programming language is a foundational technology for modern computing with millions of lines of code implementing everything from commercial operating-systems to hobby projects.203 The C programming language is a foundational technology for modern computing with millions of lines of code implementing everything from hobby projects to commercial operating-systems. 204 204 This installation base and the programmers producing it represent a massive software-engineering investment spanning decades and likely to continue for decades more. 205 205 Nevertheless, C, first standardized almost forty years ago, lacks many features that make programming in more modern languages safer and more productive. … … 224 224 \section{Introduction} 225 225 226 The C programming language is a foundational technology for modern computing with millions of lines of code implementing everything from commercial operating-systems to hobby projects.226 The C programming language is a foundational technology for modern computing with millions of lines of code implementing everything from hobby projects to commercial operating-systems. 227 227 This installation base and the programmers producing it represent a massive software-engineering investment spanning decades and likely to continue for decades more. 228 228 The TIOBE~\cite{TIOBE} ranks the top 5 most \emph{popular} programming languages as: Java 15\%, \Textbf{C 12\%}, \Textbf{\CC 5.5\%}, Python 5\%, \Csharp 4.5\% = 42\%, where the next 50 languages are less than 4\% each with a long tail. -
TabularUnified doc/proposals/ctordtor/Makefile ¶
r0182bfa r28f3a19 1 ## Define the appropriateconfiguration variables.1 ## Define the configuration variables. 2 2 3 MACROS = ../../LaTeXmacros 4 BIB = ../../bibliography 3 Build = build 4 Figures = figures 5 Macros = ../../LaTeXmacros 6 Bib = ../../bibliography 5 7 6 TeXLIB = .:$ (MACROS):$(MACROS)/listings:$(MACROS)/enumitem:$(BIB)/:7 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error 8 TeXLIB = .:${Macros}:${MACROS}/listings:${MACROS}/enumitem:${Bib}/: 9 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build} 8 10 BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex 11 12 MAKEFLAGS = --no-print-directory # --silent 13 VPATH = ${Build} ${Figures} 9 14 10 15 ## Define the text source files. … … 29 34 30 35 DOCUMENT = ctor.pdf 36 BASE = ${basename ${DOCUMENT}} 31 37 32 38 # Directives # 39 40 .PHONY : all clean # not file names 33 41 34 42 all : ${DOCUMENT} 35 43 36 44 clean : 37 rm -f *.bbl *.aux *.dvi *.idx *.ilg *.ind *.brf *.out *.log *.toc *.blg *.pstex_t *.cf \ 38 ${FIGURES} ${PICTURES} ${PROGRAMS} ${GRAPHS} ${basename ${DOCUMENT}}.ps ${DOCUMENT} 45 @rm -frv ${DOCUMENT} ${BASE}.ps ${Build} 39 46 40 47 # File Dependencies # 41 48 42 ${DOCUMENT} : ${ basename ${DOCUMENT}}.ps49 ${DOCUMENT} : ${BASE}.ps 43 50 ps2pdf $< 44 51 45 ${ basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi46 dvips $ < -o $@52 ${BASE}.ps : ${BASE}.dvi 53 dvips ${Build}/$< -o $@ 47 54 48 ${ basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex\49 $ (MACROS)/common.tex $(MACROS)/indexstyle $(BIB)/cfa.bib55 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 56 ${Macros}/common.tex ${Macros}/indexstyle ${Bib}/pl.bib | ${Build} 50 57 # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run. 51 if [ ! -r ${basename $@}.ind ] ; then touch${basename $@}.ind ; fi58 #if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi 52 59 # Must have *.aux file containing citations for bibtex 53 60 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi 54 -${BibTeX} ${ basename $@}55 # Some citations reference others so run stepsagain to resolve these citations61 -${BibTeX} ${Build}/${basename $@} 62 # Some citations reference others so run again to resolve these citations 56 63 ${LaTeX} ${basename $@}.tex 57 -${BibTeX} ${ basename $@}64 -${BibTeX} ${Build}/${basename $@} 58 65 # Make index from *.aux entries and input index at end of document 59 makeindex -s $(MACROS)/indexstyle ${basename $@}.idx 66 #makeindex -s ${Macros}/indexstyle ${Build}/${basename $@}.idx 67 # Run again to finish citations 60 68 ${LaTeX} ${basename $@}.tex 61 69 # Run again to get index title into table of contents … … 67 75 ## Define the default recipes. 68 76 69 %.tex : %.fig 70 fig2dev -L eepic $< > $@77 ${Build}: 78 mkdir -p ${Build} 71 79 72 %. ps : %.fig73 fig2dev -L ps $< >$@80 %.tex : %.fig | ${Build} 81 fig2dev -L eepic $< > ${Build}/$@ 74 82 75 %.pstex : %.fig 76 fig2dev -L pstex $< > $@ 77 fig2dev -L pstex_t -p $@ $< > $@_t 83 %.ps : %.fig | ${Build} 84 fig2dev -L ps $< > ${Build}/$@ 85 86 %.pstex : %.fig | ${Build} 87 fig2dev -L pstex $< > ${Build}/$@ 88 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t 78 89 79 90 # Local Variables: # -
TabularUnified doc/proposals/ctordtor/ctor.tex ¶
r0182bfa r28f3a19 1 % inline code ©...© (copyright symbol) emacs: C-q M-)2 % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.3 % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_4 % green highlighting ¢...¢ (cent symbol) emacs: C-q M-"5 % LaTex escape §...§ (section symbol) emacs: C-q M-'6 % keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^7 % math escape $...$ (dollar symbol)8 9 1 \documentclass[twoside,11pt]{article} 10 2 … … 15 7 \usepackage{textcomp} 16 8 \usepackage[latin1]{inputenc} 9 17 10 \usepackage{fullpage,times,comment} 18 11 \usepackage{epic,eepic} 19 \usepackage{upquote} 12 \usepackage{upquote} % switch curled `'" to straight 20 13 \usepackage{calc} 21 14 \usepackage{xspace} 22 15 \usepackage{graphicx} 23 \usepackage{varioref} 24 \usepackage{listings} 25 \usepackage[flushmargin]{footmisc} 16 \usepackage{varioref} % extended references 17 \usepackage{listings} % format program code 18 \usepackage[flushmargin]{footmisc} % support label/reference in footnote 26 19 \usepackage{latexsym} % \Box glyph 27 20 \usepackage{mathptmx} % better math font with "times" … … 34 27 \renewcommand{\UrlFont}{\small\sf} 35 28 36 \setlength{\topmargin}{-0.45in} 29 \setlength{\topmargin}{-0.45in} % move running title into header 37 30 \setlength{\headsep}{0.25in} 38 31 … … 43 36 44 37 \interfootnotelinepenalty=10000 38 39 \CFAStyle % use default CFA format-style 40 % inline code ©...© (copyright symbol) emacs: C-q M-) 41 % red highlighting ®...® (registered trademark symbol) emacs: C-q M-. 42 % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_ 43 % green highlighting ¢...¢ (cent symbol) emacs: C-q M-" 44 % LaTex escape §...§ (section symbol) emacs: C-q M-' 45 % keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^ 46 % math escape $...$ (dollar symbol) 47 45 48 46 49 \title{ … … 83 86 \thispagestyle{plain} 84 87 \pagenumbering{arabic} 85 86 88 87 89 -
TabularUnified doc/proposals/tuples/Makefile ¶
r0182bfa r28f3a19 1 ## Define the appropriateconfiguration variables.1 ## Define the configuration variables. 2 2 3 MACROS = ../../LaTeXmacros 4 BIB = ../../bibliography 3 Build = build 4 Figures = figures 5 Macros = ../../LaTeXmacros 6 Bib = ../../bibliography 5 7 6 TeXLIB = .:$ (MACROS):$(MACROS)/listings:$(MACROS)/enumitem:$(BIB)/:7 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error 8 TeXLIB = .:${Macros}:${MACROS}/listings:${MACROS}/enumitem:${Bib}/: 9 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build} 8 10 BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex 11 12 MAKEFLAGS = --no-print-directory --silent # 13 VPATH = ${Build} ${Figures} 9 14 10 15 ## Define the text source files. … … 29 34 30 35 DOCUMENT = tuples.pdf 36 BASE = ${basename ${DOCUMENT}} 31 37 32 38 # Directives # 39 40 .PHONY : all clean # not file names 33 41 34 42 all : ${DOCUMENT} 35 43 36 44 clean : 37 rm -f *.bbl *.aux *.dvi *.idx *.ilg *.ind *.brf *.out *.log *.toc *.blg *.pstex_t *.cf \ 38 ${FIGURES} ${PICTURES} ${PROGRAMS} ${GRAPHS} ${basename ${DOCUMENT}}.ps ${DOCUMENT} 45 @rm -frv ${DOCUMENT} ${BASE}.ps ${Build} 39 46 40 47 # File Dependencies # 41 48 42 ${DOCUMENT} : ${ basename ${DOCUMENT}}.ps49 ${DOCUMENT} : ${BASE}.ps 43 50 ps2pdf $< 44 51 45 ${ basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi46 dvips $ < -o $@52 ${BASE}.ps : ${BASE}.dvi 53 dvips ${Build}/$< -o $@ 47 54 48 ${ basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex\49 $ (MACROS)/common.tex $(MACROS)/indexstyle $(BIB)/cfa.bib55 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 56 ${Macros}/common.tex ${Macros}/indexstyle ${Bib}/pl.bib | ${Build} 50 57 # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run. 51 if [ ! -r ${basename $@}.ind ] ; then touch${basename $@}.ind ; fi58 #if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi 52 59 # Must have *.aux file containing citations for bibtex 53 60 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi 54 -${BibTeX} ${ basename $@}55 # Some citations reference others so run stepsagain to resolve these citations61 -${BibTeX} ${Build}/${basename $@} 62 # Some citations reference others so run again to resolve these citations 56 63 ${LaTeX} ${basename $@}.tex 57 -${BibTeX} ${ basename $@}64 -${BibTeX} ${Build}/${basename $@} 58 65 # Make index from *.aux entries and input index at end of document 59 makeindex -s $(MACROS)/indexstyle ${basename $@}.idx 66 #makeindex -s ${Macros}/indexstyle ${Build}/${basename $@}.idx 67 # Run again to finish citations 60 68 ${LaTeX} ${basename $@}.tex 61 69 # Run again to get index title into table of contents … … 67 75 ## Define the default recipes. 68 76 69 %.tex : %.fig 70 fig2dev -L eepic $< > $@77 ${Build}: 78 mkdir -p ${Build} 71 79 72 %. ps : %.fig73 fig2dev -L ps $< >$@80 %.tex : %.fig | ${Build} 81 fig2dev -L eepic $< > ${Build}/$@ 74 82 75 %.pstex : %.fig 76 fig2dev -L pstex $< > $@ 77 fig2dev -L pstex_t -p $@ $< > $@_t 83 %.ps : %.fig | ${Build} 84 fig2dev -L ps $< > ${Build}/$@ 85 86 %.pstex : %.fig | ${Build} 87 fig2dev -L pstex $< > ${Build}/$@ 88 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t 78 89 79 90 # Local Variables: # -
TabularUnified doc/proposals/tuples/tuples.tex ¶
r0182bfa r28f3a19 1 % inline code ©...© (copyright symbol) emacs: C-q M-)2 % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.3 % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_4 % green highlighting ¢...¢ (cent symbol) emacs: C-q M-"5 % LaTex escape §...§ (section symbol) emacs: C-q M-'6 % keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^7 % math escape $...$ (dollar symbol)8 9 1 \documentclass[twoside,11pt]{article} 10 2 … … 15 7 \usepackage{textcomp} 16 8 \usepackage[latin1]{inputenc} 9 17 10 \usepackage{fullpage,times,comment} 18 11 \usepackage{epic,eepic} 19 \usepackage{upquote} 12 \usepackage{upquote} % switch curled `'" to straight 20 13 \usepackage{calc} 21 14 \usepackage{xspace} 22 15 \usepackage{graphicx} 23 \usepackage{varioref} 24 \usepackage{listings} 25 \usepackage[flushmargin]{footmisc} 16 \usepackage{varioref} % extended references 17 \usepackage{listings} % format program code 18 \usepackage[flushmargin]{footmisc} % support label/reference in footnote 26 19 \usepackage{latexsym} % \Box glyph 27 20 \usepackage{mathptmx} % better math font with "times" … … 34 27 \renewcommand{\UrlFont}{\small\sf} 35 28 36 \setlength{\topmargin}{-0.45in} 29 \setlength{\topmargin}{-0.45in} % move running title into header 37 30 \setlength{\headsep}{0.25in} 38 31 … … 42 35 43 36 \interfootnotelinepenalty=10000 37 38 \CFAStyle % use default CFA format-style 39 % inline code ©...© (copyright symbol) emacs: C-q M-) 40 % red highlighting ®...® (registered trademark symbol) emacs: C-q M-. 41 % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_ 42 % green highlighting ¢...¢ (cent symbol) emacs: C-q M-" 43 % LaTex escape §...§ (section symbol) emacs: C-q M-' 44 % keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^ 45 % math escape $...$ (dollar symbol) 46 44 47 45 48 \title{ -
TabularUnified doc/proposals/user_conversions.md ¶
r0182bfa r28f3a19 5 5 There is also a set of _explicit_ conversions that are only allowed through a 6 6 cast expression. 7 Based on Glen's notes on conversions [1], I propose that safe and unsafe 8 conversions be expressed as constructor variants, though I make explicit 9 (cast) conversions a constructor variant as well rather than a dedicated 10 operator. 7 I propose that safe, unsafe, and explicit (cast) conversions be expressed as 8 constructor variants. 11 9 Throughout this article, I will use the following operator names for 12 10 constructors and conversion functions from `From` to `To`: 13 11 14 void ?{} ( To*, To ); // copy constructor 15 void ?{} ( To*, From ); // explicit constructor 16 void ?{explicit} ( To*, From ); // explicit cast conversion 17 void ?{safe} ( To*, From ); // implicit safe conversion 18 void ?{unsafe} ( To*, From ); // implicit unsafe conversion 19 20 [1] http://plg.uwaterloo.ca/~cforall/Conversions/index.html 21 22 Glen's design made no distinction between constructors and unsafe implicit 12 void ?{} ( To&, To ); // copy constructor 13 void ?{} ( To&, From ); // explicit constructor 14 void ?{explicit} ( To&, From ); // explicit cast conversion 15 void ?{safe} ( To&, From ); // implicit safe conversion 16 void ?{unsafe} ( To&, From ); // implicit unsafe conversion 17 18 It has been suggested that all constructors would define unsafe implicit 23 19 conversions; this is elegant, but interacts poorly with tuples. 24 20 Essentially, without making this distinction, a constructor like the following … … 26 22 multiplying the space of possible interpretations of all functions: 27 23 28 void ?{}( Coord *this, int x, int y );24 void ?{}( Coord& this, int x, int y ); 29 25 30 26 That said, it would certainly be possible to make a multiple-argument implicit … … 32 28 used infrequently: 33 29 34 void ?{unsafe}( Coord *this, int x, int y );30 void ?{unsafe}( Coord& this, int x, int y ); 35 31 36 32 An alternate possibility would be to only count two-arg constructors 37 `void ?{} ( To *, From )` as unsafe conversions; under this semantics, safe and33 `void ?{} ( To&, From )` as unsafe conversions; under this semantics, safe and 38 34 explicit conversions should also have a compiler-enforced restriction to 39 35 ensure that they are two-arg functions (this restriction may be valuable … … 43 39 is convertable to `To`. 44 40 If user-defined conversions are not added to the language, 45 `void ?{} ( To *, From )` may be a suitable representation, relying on41 `void ?{} ( To&, From )` may be a suitable representation, relying on 46 42 conversions on the argument types to account for transitivity. 47 On the other hand, `To*` should perhaps match its target type exactly, so 48 another assertion syntax specific to conversions may be required, e.g. 49 `From -> To`. 43 Since `To&` should be an exact match on `To`, this should put all the implicit 44 conversions on the RHS. 45 On the other hand, under some models (like [1]), implicit conversions are not 46 allowed in assertion parameters, so another assertion syntax specific to 47 conversions may be required, e.g. `From -> To`. 48 It has also been suggested that, for programmer control, no implicit 49 conversions (except, possibly, for polymorphic specialization) should be 50 allowed in resolution of cast operators. 51 52 [1] ../working/assertion_resolution.md 50 53 51 54 ### Constructor Idiom ### … … 53 56 that we can use the full range of Cforall features for conversions, including 54 57 polymorphism. 55 Glen [1] defines a _constructor idiom_ that can be used to create chains of 56 safe conversions without duplicating code; given a type `Safe` which members 57 of another type `From` can be directly converted to, the constructor idiom 58 allows us to write a conversion for any type `To` which `Safe` converts to: 59 60 forall(otype To | { void ?{safe}( To*, Safe ) }) 61 void ?{safe}( To *this, From that ) { 58 In an earlier version of this proposal, Glen Ditchfield defines a 59 _constructor idiom_ that can be used to create chains of safe conversions 60 without duplicating code; given a type `Safe` which members of another type 61 `From` can be directly converted to, the constructor idiom allows us to write 62 a conversion for any type `To` which `Safe` converts to: 63 64 forall(otype To | { void ?{safe}( To&, Safe ) }) 65 void ?{safe}( To& this, From that ) { 62 66 Safe tmp = /* some expression involving that */; 63 *this = tmp; // usesassertion parameter67 this{ tmp }; // initialize from assertion parameter 64 68 } 65 69 … … 67 71 unsafe conversions. 68 72 73 Glen's original suggestion said the copy constructor for `To` should also be 74 accepted as a resolution for `void ?{safe}( To&, Safe )` (`Safe` == `To`), 75 allowing this same code to be used for the single-step conversion as well. 76 This proposal does come at the cost of an extra copy initialization of the 77 target value, though. 78 79 Contrariwise, if a monomorphic conversion from `From` to `Safe` is written, 80 e.g: 81 82 void ?{safe}( Safe& this, From that ) { 83 this{ /* some parameters involving that */ }; 84 } 85 86 Then the code for a transitive conversion from `From` to any `To` type 87 convertable from `Safe` is written: 88 89 forall(otype To | { void ?{safe}( To&, Safe ) }) 90 void ?{safe}( To& this, From that ) { 91 Safe tmp = that; // uses monomorphic conversion 92 this{ tmp }; // initialize from assertion parameter 93 } 94 95 Given the entirely-boilerplate nature of this code, but negative performance 96 implications of the unmodified constructor idiom, it might be fruitful to have 97 transitive and single step conversion operators, and let CFA build the 98 transitive conversions; some possible names: 99 100 void ?{safe} (To&, From); void ?{final safe} (To&, From); // single-step 101 void ?{safe*} (To&, From); void ?{safe} (To&, From); // transitive 102 69 103 What selective non-use of the constructor idiom gives us is the ability to 70 104 define a conversion that may only be the *last* conversion in a chain of such. 71 Constructing a conversion graph able to unambiguously represent the full 72 hierarchy of implicit conversions in C is provably impossible using only 73 single-step conversions with no additional information (see Appendix A), but 74 this mechanism is sufficiently powerful (see [1], though the design there has 75 some minor bugs; the general idea is to use the constructor idiom to define 76 two chains of conversions, one among the signed integral types, another among 77 the unsigned, and to use monomorphic conversions to allow conversions between 78 signed and unsigned integer types). 105 One use for this is to solve the problem that `explicit` conversions were 106 added to C++ for, that of conversions to `bool` chaining to become conversions 107 to any arithmetic type. 108 Another use is to unambiguously represent the full hierarchy of implicit 109 conversions in C by making sign conversions non-transitive, allowing the 110 compiler to resolve e.g. `int -> unsigned long` as 111 `int -> long -> unsigned long` over `int -> unsigned int -> unsigned long`. 112 See [2] for more details. 113 114 [2] ../working/glen_conversions/index.html#usual 79 115 80 116 ### Appendix A: Partial and Total Orders ### … … 153 189 convert from `int` to `unsigned long`, so we just put in a direct conversion 154 190 and make the compiler smart enough to figure out the costs" - this is the 155 approach taken by the existing compi pler, but given that in a user-defined191 approach taken by the existing compiler, but given that in a user-defined 156 192 conversion proposal the users can build an arbitrary graph of conversions, 157 193 this case still needs to be handled. … … 160 196 exists a chain of conversions from `a` to `b` (see Appendix A for description 161 197 of preorders and related constructs). 162 This preorder corresponds roughlyto a more usual type-theoretic concept of198 This preorder roughly corresponds to a more usual type-theoretic concept of 163 199 subtyping ("if I can convert `a` to `b`, `a` is a more specific type than 164 200 `b`"); however, since this graph is arbitrary, it may contain cycles, so if … … 192 228 and so is considered to be the nearer type. 193 229 By transitivity, then, the conversion from `X` to `Y2` should be cheaper than 194 the conversion from `X` to `W`, but in this case the ` X` and `W` are230 the conversion from `X` to `W`, but in this case the `Y2` and `W` are 195 231 incomparable by the conversion preorder, so the tie is broken by the shorter 196 232 path from `X` to `W` in favour of `W`, contradicting the transitivity property -
TabularUnified doc/refrat/Makefile ¶
r0182bfa r28f3a19 53 53 dvips ${Build}/$< -o $@ 54 54 55 ${BASE}.dvi : Makefile ${ Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \56 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib 55 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 56 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib | ${Build} 57 57 # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run. 58 58 if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi … … 78 78 mkdir -p ${Build} 79 79 80 %.tex : %.fig ${Build}80 %.tex : %.fig | ${Build} 81 81 fig2dev -L eepic $< > ${Build}/$@ 82 82 83 %.ps : %.fig ${Build}83 %.ps : %.fig | ${Build} 84 84 fig2dev -L ps $< > ${Build}/$@ 85 85 86 %.pstex : %.fig ${Build}86 %.pstex : %.fig | ${Build} 87 87 fig2dev -L pstex $< > ${Build}/$@ 88 88 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t -
TabularUnified doc/theses/aaron_moss/comp_II/Makefile ¶
r0182bfa r28f3a19 32 32 33 33 DOCUMENT = comp_II.pdf 34 BASE = ${basename ${DOCUMENT}} 34 35 35 36 # Directives # … … 40 41 41 42 clean : 42 @rm -frv ${DOCUMENT} ${ basename ${DOCUMENT}}.ps ${Build}43 @rm -frv ${DOCUMENT} ${BASE}.ps ${Build} 43 44 44 45 # File Dependencies # 45 46 46 ${DOCUMENT} : ${ basename ${DOCUMENT}}.ps47 ${DOCUMENT} : ${BASE}.ps 47 48 ps2pdf $< 48 49 49 ${ basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi50 ${BASE}.ps : ${BASE}.dvi 50 51 dvips ${Build}/$< -o $@ 51 52 52 ${ basename ${DOCUMENT}}.dvi : Makefile ${Build}${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \53 ${Macros}/common.tex ${Macros}/indexstyle ../../../bibliography/pl.bib 53 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 54 ${Macros}/common.tex ${Macros}/indexstyle ../../../bibliography/pl.bib | ${Build} 54 55 # Must have *.aux file containing citations for bibtex 55 56 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi … … 66 67 mkdir -p ${Build} 67 68 68 %.tex : %.fig 69 %.tex : %.fig ${Build} 69 70 fig2dev -L eepic $< > ${Build}/$@ 70 71 71 %.ps : %.fig 72 %.ps : %.fig | ${Build} 72 73 fig2dev -L ps $< > ${Build}/$@ 73 74 74 %.pstex : %.fig 75 %.pstex : %.fig | ${Build} 75 76 fig2dev -L pstex $< > ${Build}/$@ 76 77 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t -
TabularUnified doc/theses/thierry_delisle/.gitignore ¶
r0182bfa r28f3a19 25 25 *.pdf 26 26 *.png 27 *.ps 27 28 figures/*.tex 28 29 -
TabularUnified doc/theses/thierry_delisle/Makefile ¶
r0182bfa r28f3a19 51 51 52 52 DOCUMENT = thesis.pdf 53 BASE = ${basename ${DOCUMENT}} 53 54 54 55 # Directives # … … 59 60 60 61 clean : 61 @rm -frv ${DOCUMENT} ${ basename ${DOCUMENT}}.ps ${Build}62 @rm -frv ${DOCUMENT} ${BASE}.ps ${Build} 62 63 63 64 # File Dependencies # 64 65 65 ${DOCUMENT} : ${ basename ${DOCUMENT}}.ps66 ${DOCUMENT} : ${BASE}.ps 66 67 ps2pdf $< 67 68 68 ${ basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi69 ${BASE}.ps : ${BASE}.dvi 69 70 dvips ${Build}/$< -o $@ 70 71 71 ${ basename ${DOCUMENT}}.dvi : Makefile ${Build}${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \72 ${Macros}/common.tex ${Macros}/indexstyle annex/local.bib ../../bibliography/pl.bib 72 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 73 ${Macros}/common.tex ${Macros}/indexstyle annex/local.bib ../../bibliography/pl.bib | ${Build} 73 74 # Must have *.aux file containing citations for bibtex 74 75 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi … … 88 89 mkdir -p ${Build} 89 90 90 %.tex : %.fig 91 %.tex : %.fig ${Build} 91 92 fig2dev -L eepic $< > ${Build}/$@ 92 93 93 %.ps : %.fig 94 %.ps : %.fig | ${Build} 94 95 fig2dev -L ps $< > ${Build}/$@ 95 96 96 %.pstex : %.fig 97 %.pstex : %.fig | ${Build} 97 98 fig2dev -L pstex $< > ${Build}/$@ 98 99 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t … … 101 102 # Tools to generate png files 102 103 # to create a png we create a pdf and convert it to png 103 %.png : build/%.pstex figures/%.tex 104 %.png : build/%.pstex figures/%.tex ${Build} 104 105 echo ${basename $@} 105 106 ${LaTeX} figures/${basename $@}.tex … … 109 110 110 111 # creating a pdf of a figure requires generating some latex that just includes the figure 111 figures/%.tex: build/%.pstex 112 figures/%.tex: build/%.pstex ${Build} 112 113 echo -n "\documentclass[preview]{standalone}\n" \ 113 114 "\usepackage[T1]{fontenc}\n" \ -
TabularUnified doc/user/Makefile ¶
r0182bfa r28f3a19 57 57 dvips ${Build}/$< -o $@ 58 58 59 ${BASE}.dvi : Makefile ${ Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \60 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib 59 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 60 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib | ${Build} 61 61 # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run. 62 62 if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi … … 79 79 mkdir -p ${Build} 80 80 81 %.tex : %.fig ${Build}81 %.tex : %.fig | ${Build} 82 82 fig2dev -L eepic $< > ${Build}/$@ 83 83 84 %.ps : %.fig ${Build}84 %.ps : %.fig | ${Build} 85 85 fig2dev -L ps $< > ${Build}/$@ 86 86 87 %.pstex : %.fig ${Build}87 %.pstex : %.fig | ${Build} 88 88 fig2dev -L pstex $< > ${Build}/$@ 89 89 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t -
TabularUnified src/CodeGen/CodeGenerator.cc ¶
r0182bfa r28f3a19 133 133 output << "__attribute__ (("; 134 134 for ( list< Attribute * >::iterator attr( attributes.begin() );; ) { 135 output << (*attr)-> get_name();136 if ( ! (*attr)-> get_parameters().empty() ) {135 output << (*attr)->name; 136 if ( ! (*attr)->parameters.empty() ) { 137 137 output << "("; 138 genCommaList( (*attr)-> get_parameters().begin(), (*attr)->get_parameters().end() );138 genCommaList( (*attr)->parameters.begin(), (*attr)->parameters.end() ); 139 139 output << ")"; 140 140 } // if … … 172 172 // *** Declarations 173 173 void CodeGenerator::postvisit( FunctionDecl * functionDecl ) { 174 // deleted decls should never be used, so don't print them 175 if ( functionDecl->isDeleted && genC ) return; 174 176 extension( functionDecl ); 175 177 genAttributes( functionDecl->get_attributes() ); … … 185 187 functionDecl->get_statements()->accept( *visitor ); 186 188 } // if 189 if ( functionDecl->isDeleted ) { 190 output << " = void"; 191 } 187 192 } 188 193 189 194 void CodeGenerator::postvisit( ObjectDecl * objectDecl ) { 195 // deleted decls should never be used, so don't print them 196 if ( objectDecl->isDeleted && genC ) return; 190 197 if (objectDecl->get_name().empty() && genC ) { 191 198 // only generate an anonymous name when generating C code, otherwise it clutters the output too much … … 206 213 objectDecl->get_init()->accept( *visitor ); 207 214 } // if 215 if ( objectDecl->isDeleted ) { 216 output << " = void"; 217 } 208 218 209 219 if ( objectDecl->get_bitfieldWidth() ) { … … 827 837 expr->expr->accept( *visitor ); 828 838 } 839 840 void CodeGenerator::postvisit( DefaultArgExpr * arg ) { 841 assertf( ! genC, "Default argument expressions should not reach code generation." ); 842 arg->expr->accept( *visitor ); 843 } 844 845 void CodeGenerator::postvisit( GenericExpr * expr ) { 846 assertf( ! genC, "C11 _Generic expressions should not reach code generation." ); 847 output << "_Generic("; 848 expr->control->accept( *visitor ); 849 output << ", "; 850 unsigned int numAssocs = expr->associations.size(); 851 unsigned int i = 0; 852 for ( GenericExpr::Association & assoc : expr->associations ) { 853 if (assoc.isDefault) { 854 output << "default: "; 855 } else { 856 output << genType( assoc.type, "", pretty, genC ) << ": "; 857 } 858 assoc.expr->accept( *visitor ); 859 if ( i+1 != numAssocs ) { 860 output << ", "; 861 } 862 i++; 863 } 864 output << ")"; 865 } 866 829 867 830 868 // *** Statements -
TabularUnified src/CodeGen/CodeGenerator.h ¶
r0182bfa r28f3a19 94 94 void postvisit( ConstructorExpr * ); 95 95 void postvisit( DeletedExpr * ); 96 void postvisit( DefaultArgExpr * ); 97 void postvisit( GenericExpr * ); 96 98 97 99 //*** Statements -
TabularUnified src/Common/Debug.h ¶
r0182bfa r28f3a19 28 28 namespace Debug { 29 29 /// debug codegen a translation unit 30 static inline void codeGen( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label, __attribute__((unused)) LinkageSpec::Spec linkageFilter = LinkageSpec:: Compiler) {30 static inline void codeGen( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label, __attribute__((unused)) LinkageSpec::Spec linkageFilter = LinkageSpec::Builtin ) { 31 31 #ifdef DEBUG 32 32 std::list< Declaration * > decls; -
TabularUnified src/Common/PassVisitor.h ¶
r0182bfa r28f3a19 125 125 virtual void visit( InitExpr * initExpr ) override final; 126 126 virtual void visit( DeletedExpr * delExpr ) override final; 127 virtual void visit( DefaultArgExpr * argExpr ) override final; 128 virtual void visit( GenericExpr * genExpr ) override final; 127 129 128 130 virtual void visit( VoidType * basicType ) override final; … … 225 227 virtual Expression * mutate( InitExpr * initExpr ) override final; 226 228 virtual Expression * mutate( DeletedExpr * delExpr ) override final; 229 virtual Expression * mutate( DefaultArgExpr * argExpr ) override final; 230 virtual Expression * mutate( GenericExpr * genExpr ) override final; 227 231 228 232 virtual Type * mutate( VoidType * basicType ) override final; … … 258 262 259 263 private: 264 bool inFunction = false; 265 260 266 template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); 261 267 template<typename pass_t> friend void mutateAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); … … 313 319 void indexerAddUnionFwd ( UnionDecl * node ) { indexer_impl_addUnionFwd ( pass, 0, node ); } 314 320 void indexerAddTrait ( TraitDecl * node ) { indexer_impl_addTrait ( pass, 0, node ); } 315 void indexerAddWith ( std::list< Expression * > & exprs, BaseSyntaxNode * withStmt ) { indexer_impl_addWith 321 void indexerAddWith ( std::list< Expression * > & exprs, BaseSyntaxNode * withStmt ) { indexer_impl_addWith( pass, 0, exprs, withStmt ); } 316 322 317 323 -
TabularUnified src/Common/PassVisitor.impl.h ¶
r0182bfa r28f3a19 404 404 indexerAddId( func ); 405 405 maybeAccept_impl( node->type, *this ); 406 // function body needs to have the same scope as parameters - CompoundStmt will not enter 407 // a new scope if inFunction is true 408 ValueGuard< bool > oldInFunction( inFunction ); 409 inFunction = true; 406 410 maybeAccept_impl( node->statements, *this ); 407 411 maybeAccept_impl( node->attributes, *this ); … … 434 438 indexerAddId( func ); 435 439 maybeMutate_impl( node->type, *this ); 440 // function body needs to have the same scope as parameters - CompoundStmt will not enter 441 // a new scope if inFunction is true 442 ValueGuard< bool > oldInFunction( inFunction ); 443 inFunction = true; 436 444 maybeMutate_impl( node->statements, *this ); 437 445 maybeMutate_impl( node->attributes, *this ); … … 712 720 VISIT_START( node ); 713 721 { 714 auto guard1 = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 722 // do not enter a new scope if inFunction is true - needs to check old state before the assignment 723 ValueGuard< bool > oldInFunction( inFunction ); 724 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeLeave(); } ); 715 725 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 726 inFunction = false; 716 727 visitStatementList( node->kids ); 717 728 } … … 723 734 MUTATE_START( node ); 724 735 { 725 auto guard1 = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 736 // do not enter a new scope if inFunction is true - needs to check old state before the assignment 737 ValueGuard< bool > oldInFunction( inFunction ); 738 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeLeave(); } ); 726 739 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 740 inFunction = false; 727 741 mutateStatementList( node->kids ); 728 742 } … … 828 842 VISIT_START( node ); 829 843 830 visitExpression( node->condition ); 831 node->body = visitStatement( node->body ); 844 { 845 // while statements introduce a level of scope (for the initialization) 846 auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 847 maybeAccept_impl( node->initialization, *this ); 848 visitExpression ( node->condition ); 849 node->body = visitStatement( node->body ); 850 } 832 851 833 852 VISIT_END( node ); … … 838 857 MUTATE_START( node ); 839 858 840 node->condition = mutateExpression( node->condition ); 841 node->body = mutateStatement ( node->body ); 859 { 860 // while statements introduce a level of scope (for the initialization) 861 auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 862 maybeMutate_impl( node->initialization, *this ); 863 node->condition = mutateExpression( node->condition ); 864 node->body = mutateStatement ( node->body ); 865 } 866 842 867 843 868 MUTATE_END( Statement, node ); … … 2074 2099 2075 2100 //-------------------------------------------------------------------------- 2101 // DefaultArgExpr 2102 template< typename pass_type > 2103 void PassVisitor< pass_type >::visit( DefaultArgExpr * node ) { 2104 VISIT_START( node ); 2105 2106 indexerScopedAccept( node->result, *this ); 2107 maybeAccept_impl( node->expr, *this ); 2108 2109 VISIT_END( node ); 2110 } 2111 2112 template< typename pass_type > 2113 Expression * PassVisitor< pass_type >::mutate( DefaultArgExpr * node ) { 2114 MUTATE_START( node ); 2115 2116 indexerScopedMutate( node->env, *this ); 2117 indexerScopedMutate( node->result, *this ); 2118 maybeMutate_impl( node->expr, *this ); 2119 2120 MUTATE_END( Expression, node ); 2121 } 2122 2123 //-------------------------------------------------------------------------- 2124 // GenericExpr 2125 template< typename pass_type > 2126 void PassVisitor< pass_type >::visit( GenericExpr * node ) { 2127 VISIT_START( node ); 2128 2129 indexerScopedAccept( node->result, *this ); 2130 maybeAccept_impl( node->control, *this ); 2131 for ( GenericExpr::Association & assoc : node->associations ) { 2132 indexerScopedAccept( assoc.type, *this ); 2133 maybeAccept_impl( assoc.expr, *this ); 2134 } 2135 2136 VISIT_END( node ); 2137 } 2138 2139 template< typename pass_type > 2140 Expression * PassVisitor< pass_type >::mutate( GenericExpr * node ) { 2141 MUTATE_START( node ); 2142 2143 indexerScopedMutate( node->env, *this ); 2144 indexerScopedMutate( node->result, *this ); 2145 maybeMutate_impl( node->control, *this ); 2146 for ( GenericExpr::Association & assoc : node->associations ) { 2147 indexerScopedMutate( assoc.type, *this ); 2148 maybeMutate_impl( assoc.expr, *this ); 2149 } 2150 2151 MUTATE_END( Expression, node ); 2152 } 2153 2154 //-------------------------------------------------------------------------- 2076 2155 // VoidType 2077 2156 template< typename pass_type > -
TabularUnified src/Common/SemanticError.cc ¶
r0182bfa r28f3a19 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 16 15:01:20201813 // Update Count : 912 // Last Modified On : Thu Jun 7 08:05:26 2018 13 // Update Count : 10 14 14 // 15 15 … … 97 97 void SemanticError( CodeLocation location, std::string error ) { 98 98 SemanticErrorThrow = true; 99 throw SemanticErrorException( location, error);99 throw SemanticErrorException( location, error ); 100 100 } 101 101 -
TabularUnified src/Concurrency/Keywords.cc ¶
r0182bfa r28f3a19 192 192 void postvisit( StructDecl * decl ); 193 193 194 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl* );194 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first ); 195 195 void validate( DeclarationWithType * ); 196 196 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); … … 431 431 void MutexKeyword::postvisit(FunctionDecl* decl) { 432 432 433 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl ); 434 if( mutexArgs.empty() ) return; 435 436 if( CodeGen::isConstructor(decl->name) ) SemanticError( decl, "constructors cannot have mutex parameters" ); 437 433 bool first = false; 434 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first ); 438 435 bool isDtor = CodeGen::isDestructor( decl->name ); 439 436 437 // Is this function relevant to monitors 438 if( mutexArgs.empty() ) { 439 // If this is the destructor for a monitor it must be mutex 440 if(isDtor) { 441 Type* ty = decl->get_functionType()->get_parameters().front()->get_type(); 442 443 // If it's a copy, it's not a mutex 444 ReferenceType* rty = dynamic_cast< ReferenceType * >( ty ); 445 if( ! rty ) return; 446 447 // If we are not pointing directly to a type, it's not a mutex 448 Type* base = rty->get_base(); 449 if( dynamic_cast< ReferenceType * >( base ) ) return; 450 if( dynamic_cast< PointerType * >( base ) ) return; 451 452 // Check if its a struct 453 StructInstType * baseStruct = dynamic_cast< StructInstType * >( base ); 454 if( !baseStruct ) return; 455 456 // Check if its a monitor 457 if(baseStruct->baseStruct->is_monitor() || baseStruct->baseStruct->is_thread()) 458 SemanticError( decl, "destructors for structures declared as \"monitor\" must use mutex parameters\n" ); 459 } 460 return; 461 } 462 463 // Monitors can't be constructed with mutual exclusion 464 if( CodeGen::isConstructor(decl->name) && !first ) SemanticError( decl, "constructors cannot have mutex parameters" ); 465 466 // It makes no sense to have multiple mutex parameters for the destructor 440 467 if( isDtor && mutexArgs.size() != 1 ) SemanticError( decl, "destructors can only have 1 mutex argument" ); 441 468 469 // Make sure all the mutex arguments are monitors 442 470 for(auto arg : mutexArgs) { 443 471 validate( arg ); 444 472 } 445 473 474 // Check if we need to instrument the body 446 475 CompoundStmt* body = decl->get_statements(); 447 476 if( ! body ) return; 448 477 478 // Do we have the required headers 449 479 if( !monitor_decl || !guard_decl || !dtor_guard_decl ) 450 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor>" ); 451 480 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor>\n" ); 481 482 // Instrument the body 452 483 if( isDtor ) { 453 484 addDtorStatments( decl, body, mutexArgs ); … … 474 505 } 475 506 476 std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl ) {507 std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl, bool & first ) { 477 508 std::list<DeclarationWithType*> mutexArgs; 478 509 510 bool once = true; 479 511 for( auto arg : decl->get_functionType()->get_parameters()) { 480 512 //Find mutex arguments 481 513 Type* ty = arg->get_type(); 482 514 if( ! ty->get_mutex() ) continue; 515 516 if(once) {first = true;} 517 once = false; 483 518 484 519 //Append it to the list -
TabularUnified src/ControlStruct/ForExprMutator.cc ¶
r0182bfa r28f3a19 45 45 return hoist( forStmt, forStmt->initialization ); 46 46 } 47 Statement *ForExprMutator::postmutate( WhileStmt *whileStmt ) { 48 return hoist( whileStmt, whileStmt->initialization ); 49 } 47 50 } // namespace ControlStruct 48 51 -
TabularUnified src/ControlStruct/ForExprMutator.h ¶
r0182bfa r28f3a19 18 18 class IfStmt; 19 19 class ForStmt; 20 class WhileStmt; 20 21 class Statement; 21 22 … … 25 26 Statement *postmutate( IfStmt * ); 26 27 Statement *postmutate( ForStmt * ); 28 Statement *postmutate( WhileStmt * ); 27 29 }; 28 30 } // namespace ControlStruct -
TabularUnified src/ControlStruct/Mutate.cc ¶
r0182bfa r28f3a19 27 27 #include "SynTree/Visitor.h" // for acceptAll 28 28 29 using namespace std; 29 namespace ControlStruct { 30 void fixLabels( std::list< Declaration * > & translationUnit ) { 31 PassVisitor<LabelFixer> lfix; 32 acceptAll( translationUnit, lfix ); 33 } 30 34 31 namespace ControlStruct { 32 void mutate( std::list< Declaration * > translationUnit ) { 33 // hoist initialization out of for statements 35 void hoistControlDecls( std::list< Declaration * > & translationUnit ) { 34 36 PassVisitor<ForExprMutator> formut; 35 36 // normalizes label definitions and generates multi-level exit labels37 PassVisitor<LabelFixer> lfix;38 39 37 mutateAll( translationUnit, formut ); 40 acceptAll( translationUnit, lfix );41 38 } 42 39 } // namespace CodeGen -
TabularUnified src/ControlStruct/Mutate.h ¶
r0182bfa r28f3a19 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Mutate.h -- 7 // Mutate.h -- 8 8 // 9 9 // Author : Rodolfo G. Esteves … … 20 20 class Declaration; 21 21 22 /// Desugars Cforall control structures 22 23 namespace ControlStruct { 23 /// Desugars Cforall control structures 24 void mutate( std::list< Declaration* > translationUnit ); 24 /// normalizes label definitions and generates multi-level exit labels 25 void fixLabels( std::list< Declaration * > & translationUnit ); 26 27 /// hoist initialization out of for statements 28 void hoistControlDecls( std::list< Declaration * > & translationUnit ); 25 29 } // namespace ControlStruct 26 30 -
TabularUnified src/GenPoly/Lvalue.cc ¶
r0182bfa r28f3a19 145 145 146 146 namespace { 147 // true for intrinsic function calls that return a reference147 // true for intrinsic function calls that return an lvalue in C 148 148 bool isIntrinsicReference( Expression * expr ) { 149 // known intrinsic-reference prelude functions 150 static std::set<std::string> lvalueFunctions = { "*?", "?[?]" }; 149 151 if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * >( expr ) ) { 150 152 std::string fname = InitTweak::getFunctionName( untyped ); 151 // known intrinsic-reference prelude functions 152 return fname == "*?" || fname == "?[?]"; 153 return lvalueFunctions.count(fname); 153 154 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) { 154 155 if ( DeclarationWithType * func = InitTweak::getFunction( appExpr ) ) { 155 // use type of return variable rather than expr result type, since it may have been changed to a pointer type 156 FunctionType * ftype = GenPoly::getFunctionType( func->get_type() ); 157 Type * ret = ftype->returnVals.empty() ? nullptr : ftype->returnVals.front()->get_type(); 158 return func->linkage == LinkageSpec::Intrinsic && dynamic_cast<ReferenceType *>( ret ); 156 return func->linkage == LinkageSpec::Intrinsic && lvalueFunctions.count(func->name); 159 157 } 160 158 } … … 210 208 // TODO: it's likely that the second condition should be ... && ! isIntrinsicReference( arg ), but this requires investigation. 211 209 212 if ( function-> get_linkage()!= LinkageSpec::Intrinsic && isIntrinsicReference( arg ) ) {210 if ( function->linkage != LinkageSpec::Intrinsic && isIntrinsicReference( arg ) ) { 213 211 // needed for definition of prelude functions, etc. 214 212 // if argument is dereference or array subscript, the result isn't REALLY a reference, but non-intrinsic functions expect a reference: take address … … 226 224 arg = new AddressExpr( arg ); 227 225 // } else if ( function->get_linkage() == LinkageSpec::Intrinsic && InitTweak::getPointerBase( arg->result ) ) { 228 } else if ( function-> get_linkage()== LinkageSpec::Intrinsic && arg->result->referenceDepth() != 0 ) {226 } else if ( function->linkage == LinkageSpec::Intrinsic && arg->result->referenceDepth() != 0 ) { 229 227 // argument is a 'real' reference, but function expects a C lvalue: add a dereference to the reference-typed argument 230 228 PRINT( -
TabularUnified src/Parser/DeclarationNode.cc ¶
r0182bfa r28f3a19 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue May 22 08:39:29201813 // Update Count : 107 412 // Last Modified On : Thu Jun 7 12:08:55 2018 13 // Update Count : 1079 14 14 // 15 15 … … 173 173 } 174 174 175 DeclarationNode * DeclarationNode::newFunction( string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {175 DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) { 176 176 DeclarationNode * newnode = new DeclarationNode; 177 177 newnode->name = name; … … 244 244 } // DeclarationNode::newForall 245 245 246 DeclarationNode * DeclarationNode::newFromTypedef( string * name ) {246 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) { 247 247 DeclarationNode * newnode = new DeclarationNode; 248 248 newnode->type = new TypeData( TypeData::SymbolicInst ); … … 267 267 } // DeclarationNode::newAggregate 268 268 269 DeclarationNode * DeclarationNode::newEnum( string * name, DeclarationNode * constants, bool body ) {269 DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body ) { 270 270 assert( name ); 271 271 DeclarationNode * newnode = new DeclarationNode; … … 277 277 } // DeclarationNode::newEnum 278 278 279 DeclarationNode * DeclarationNode::newEnumConstant( string * name, ExpressionNode * constant ) {279 DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) { 280 280 DeclarationNode * newnode = new DeclarationNode; 281 281 newnode->name = name; … … 284 284 } // DeclarationNode::newEnumConstant 285 285 286 DeclarationNode * DeclarationNode::newName( string * name ) {286 DeclarationNode * DeclarationNode::newName( const string * name ) { 287 287 DeclarationNode * newnode = new DeclarationNode; 288 288 newnode->name = name; … … 290 290 } // DeclarationNode::newName 291 291 292 DeclarationNode * DeclarationNode::newFromTypeGen( string * name, ExpressionNode * params ) {292 DeclarationNode * DeclarationNode::newFromTypeGen( const string * name, ExpressionNode * params ) { 293 293 DeclarationNode * newnode = new DeclarationNode; 294 294 newnode->type = new TypeData( TypeData::SymbolicInst ); … … 299 299 } // DeclarationNode::newFromTypeGen 300 300 301 DeclarationNode * DeclarationNode::newTypeParam( TypeClass tc, string * name ) {301 DeclarationNode * DeclarationNode::newTypeParam( TypeClass tc, const string * name ) { 302 302 DeclarationNode * newnode = new DeclarationNode; 303 303 newnode->type = nullptr; … … 330 330 } // DeclarationNode::newTraitUse 331 331 332 DeclarationNode * DeclarationNode::newTypeDecl( string * name, DeclarationNode * typeParams ) {332 DeclarationNode * DeclarationNode::newTypeDecl( const string * name, DeclarationNode * typeParams ) { 333 333 DeclarationNode * newnode = new DeclarationNode; 334 334 newnode->name = name; … … 405 405 } // DeclarationNode::newBuiltinType 406 406 407 DeclarationNode * DeclarationNode::newAttr( string * name, ExpressionNode * expr ) {407 DeclarationNode * DeclarationNode::newAttr( const string * name, ExpressionNode * expr ) { 408 408 DeclarationNode * newnode = new DeclarationNode; 409 409 newnode->type = nullptr; … … 414 414 } 415 415 416 DeclarationNode * DeclarationNode::newAttr( string * name, DeclarationNode * type ) {416 DeclarationNode * DeclarationNode::newAttr( const string * name, DeclarationNode * type ) { 417 417 DeclarationNode * newnode = new DeclarationNode; 418 418 newnode->type = nullptr; … … 423 423 } 424 424 425 DeclarationNode * DeclarationNode::newAttribute( string * name, ExpressionNode * expr ) {425 DeclarationNode * DeclarationNode::newAttribute( const string * name, ExpressionNode * expr ) { 426 426 DeclarationNode * newnode = new DeclarationNode; 427 427 newnode->type = nullptr; … … 544 544 type->aggregate.params->appendList( q->type->forall ); // augment forall qualifier 545 545 } else { // not polymorphic 546 type->aggregate.params = q->type->forall; // make polymorphic type 547 // change implicit typedef from TYPEDEFname to TYPEGENname 548 typedefTable.changeKind( *type->aggregate.name, TYPEGENname ); 546 type->aggregate.params = q->type->forall; // set forall qualifier 549 547 } // if 550 548 } else { // not polymorphic … … 1065 1063 SemanticError( this, "invalid function specifier for " ); 1066 1064 } // if 1067 return buildDecl( type, name ? *name : string( "" ), storageClasses, maybeBuild< Expression >( bitfieldWidth ), funcSpecs, linkage, asmName, maybeBuild< Initializer >(initializer), attributes )->set_extension( extension ); 1065 bool isDelete = initializer && initializer->get_isDelete(); 1066 Declaration * decl = buildDecl( type, name ? *name : string( "" ), storageClasses, maybeBuild< Expression >( bitfieldWidth ), funcSpecs, linkage, asmName, isDelete ? nullptr : maybeBuild< Initializer >(initializer), attributes )->set_extension( extension ); 1067 if ( isDelete ) { 1068 DeclarationWithType * dwt = strict_dynamic_cast<DeclarationWithType *>( decl ); 1069 dwt->isDeleted = true; 1070 } 1071 return decl; 1068 1072 } // if 1069 1073 -
TabularUnified src/Parser/ExpressionNode.cc ¶
r0182bfa r28f3a19 10 10 // Created On : Sat May 16 13:17:07 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Mar 22 11:57:39201813 // Update Count : 80 112 // Last Modified On : Mon Jun 4 21:24:45 2018 13 // Update Count : 802 14 14 // 15 15 … … 314 314 315 315 Expression * build_constantStr( string & str ) { 316 assert( str.length() > 0 ); 316 317 string units; // units 317 318 sepString( str, units, '"' ); // separate constant from units -
TabularUnified src/Parser/InitializerNode.cc ¶
r0182bfa r28f3a19 27 27 28 28 InitializerNode::InitializerNode( ExpressionNode * _expr, bool aggrp, ExpressionNode * des ) 29 : expr( _expr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ) {29 : expr( _expr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ), isDelete( false ) { 30 30 if ( aggrp ) 31 31 kids = dynamic_cast< InitializerNode * >( get_next() ); … … 36 36 37 37 InitializerNode::InitializerNode( InitializerNode * init, bool aggrp, ExpressionNode * des ) 38 : expr( nullptr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ) {38 : expr( nullptr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ), isDelete( false ) { 39 39 if ( init ) 40 40 set_last( init ); … … 46 46 set_next( nullptr ); 47 47 } // InitializerNode::InitializerNode 48 49 InitializerNode::InitializerNode( bool isDelete ) : expr( nullptr ), aggregate( false ), designator( nullptr ), kids( nullptr ), maybeConstructed( false ), isDelete( isDelete ) {} 48 50 49 51 InitializerNode::~InitializerNode() { … … 84 86 85 87 Initializer * InitializerNode::build() const { 88 assertf( ! isDelete, "Should not build delete stmt InitializerNode" ); 86 89 if ( aggregate ) { 87 90 // steal designators from children -
TabularUnified src/Parser/ParseNode.h ¶
r0182bfa r28f3a19 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 30 09:19:17201813 // Update Count : 8 3112 // Last Modified On : Wed Jun 6 16:17:18 2018 13 // Update Count : 843 14 14 // 15 15 … … 77 77 78 78 ParseNode * next = nullptr; 79 std::string * name = nullptr;79 const std::string * name = nullptr; 80 80 CodeLocation location = yylloc; 81 81 }; // ParseNode … … 87 87 InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr ); 88 88 InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr ); 89 InitializerNode( bool isDelete ); 89 90 ~InitializerNode(); 90 91 virtual InitializerNode * clone() const { assert( false ); return nullptr; } … … 97 98 InitializerNode * set_maybeConstructed( bool value ) { maybeConstructed = value; return this; } 98 99 bool get_maybeConstructed() const { return maybeConstructed; } 100 101 bool get_isDelete() const { return isDelete; } 99 102 100 103 InitializerNode * next_init() const { return kids; } … … 110 113 InitializerNode * kids; 111 114 bool maybeConstructed; 115 bool isDelete; 112 116 }; // InitializerNode 113 117 … … 167 171 }; 168 172 169 Expression * build_constantInteger( std::string & str );170 Expression * build_constantFloat( std::string & str );171 Expression * build_constantChar( std::string & str );172 Expression * build_constantStr( std::string & str );173 Expression * build_constantInteger( std::string & str ); // these 4 routines modify the string 174 Expression * build_constantFloat( std::string & str ); 175 Expression * build_constantChar( std::string & str ); 176 Expression * build_constantStr( std::string & str ); 173 177 Expression * build_field_name_FLOATING_FRACTIONconstant( const std::string & str ); 174 178 Expression * build_field_name_FLOATING_DECIMALconstant( const std::string & str ); … … 226 230 static DeclarationNode * newBuiltinType( BuiltinType ); 227 231 static DeclarationNode * newForall( DeclarationNode * ); 228 static DeclarationNode * newFromTypedef( std::string * );229 static DeclarationNode * newFunction( std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );232 static DeclarationNode * newFromTypedef( const std::string * ); 233 static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ); 230 234 static DeclarationNode * newAggregate( Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ); 231 static DeclarationNode * newEnum( std::string * name, DeclarationNode * constants, bool body );232 static DeclarationNode * newEnumConstant( std::string * name, ExpressionNode * constant );233 static DeclarationNode * newName( std::string * );234 static DeclarationNode * newFromTypeGen( std::string *, ExpressionNode * params );235 static DeclarationNode * newTypeParam( TypeClass, std::string * );235 static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body ); 236 static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant ); 237 static DeclarationNode * newName( const std::string * ); 238 static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params ); 239 static DeclarationNode * newTypeParam( TypeClass, const std::string * ); 236 240 static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts ); 237 241 static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params ); 238 static DeclarationNode * newTypeDecl( std::string * name, DeclarationNode * typeParams );242 static DeclarationNode * newTypeDecl( const std::string * name, DeclarationNode * typeParams ); 239 243 static DeclarationNode * newPointer( DeclarationNode * qualifiers, OperKinds kind ); 240 244 static DeclarationNode * newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic ); … … 243 247 static DeclarationNode * newTuple( DeclarationNode * members ); 244 248 static DeclarationNode * newTypeof( ExpressionNode * expr ); 245 static DeclarationNode * newAttr( std::string *, ExpressionNode * expr ); // @ attributes246 static DeclarationNode * newAttr( std::string *, DeclarationNode * type ); // @ attributes247 static DeclarationNode * newAttribute( std::string *, ExpressionNode * expr = nullptr ); // gcc attributes249 static DeclarationNode * newAttr( const std::string *, ExpressionNode * expr ); // @ attributes 250 static DeclarationNode * newAttr( const std::string *, DeclarationNode * type ); // @ attributes 251 static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes 248 252 static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement 249 253 static DeclarationNode * newStaticAssert( ExpressionNode * condition, Expression * message ); … … 399 403 }; 400 404 405 Expression * build_if_control( IfCtl * ctl, std::list< Statement * > & init ); 401 406 Statement * build_if( IfCtl * ctl, StatementNode * then_stmt, StatementNode * else_stmt ); 402 407 Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ); 403 408 Statement * build_case( ExpressionNode * ctl ); 404 409 Statement * build_default(); 405 Statement * build_while( ExpressionNode * ctl, StatementNode * stmt, bool kind = false ); 410 Statement * build_while( IfCtl * ctl, StatementNode * stmt ); 411 Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt ); 406 412 Statement * build_for( ForCtl * forctl, StatementNode * stmt ); 407 413 Statement * build_branch( BranchStmt::Type kind ); -
TabularUnified src/Parser/StatementNode.cc ¶
r0182bfa r28f3a19 10 10 // Created On : Sat May 16 14:59:41 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 30 09:21:16201813 // Update Count : 3 5412 // Last Modified On : Tue Jun 5 08:58:34 2018 13 // Update Count : 362 14 14 // 15 15 … … 69 69 caseStmt->get_statements().splice( caseStmt->get_statements().end(), stmts ); 70 70 return this; 71 } 71 } // StatementNode::append_last_case 72 72 73 73 Statement * build_expr( ExpressionNode * ctl ) { 74 74 Expression * e = maybeMoveBuild< Expression >( ctl ); 75 75 76 if ( e ) 77 return new ExprStmt( e ); 78 else 79 return new NullStmt(); 80 } 81 82 Statement * build_if( IfCtl * ctl, StatementNode * then_stmt, StatementNode * else_stmt ) { 83 Statement * thenb, * elseb = 0; 84 std::list< Statement * > branches; 85 buildMoveList< Statement, StatementNode >( then_stmt, branches ); 86 assert( branches.size() == 1 ); 87 thenb = branches.front(); 88 89 if ( else_stmt ) { 90 std::list< Statement * > branches; 91 buildMoveList< Statement, StatementNode >( else_stmt, branches ); 92 assert( branches.size() == 1 ); 93 elseb = branches.front(); 94 } // if 95 96 std::list< Statement * > init; 76 if ( e ) return new ExprStmt( e ); 77 else return new NullStmt(); 78 } // build_expr 79 80 Expression * build_if_control( IfCtl * ctl, std::list< Statement * > & init ) { 97 81 if ( ctl->init != 0 ) { 98 82 buildMoveList( ctl->init, init ); … … 102 86 if ( ctl->condition ) { 103 87 // compare the provided condition against 0 104 cond = 88 cond = notZeroExpr( maybeMoveBuild< Expression >(ctl->condition) ); 105 89 } else { 106 90 for ( Statement * stmt : init ) { … … 113 97 } 114 98 delete ctl; 99 return cond; 100 } // build_if_control 101 102 Statement * build_if( IfCtl * ctl, StatementNode * then_stmt, StatementNode * else_stmt ) { 103 Statement * thenb, * elseb = nullptr; 104 std::list< Statement * > branches; 105 buildMoveList< Statement, StatementNode >( then_stmt, branches ); 106 assert( branches.size() == 1 ); 107 thenb = branches.front(); 108 109 if ( else_stmt ) { 110 std::list< Statement * > branches; 111 buildMoveList< Statement, StatementNode >( else_stmt, branches ); 112 assert( branches.size() == 1 ); 113 elseb = branches.front(); 114 } // if 115 116 std::list< Statement * > init; 117 Expression * cond = build_if_control( ctl, init ); 115 118 return new IfStmt( cond, thenb, elseb, init ); 116 } 119 } // build_if 117 120 118 121 Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) { … … 130 133 // branches.size() == 0 for switch (...) {}, i.e., no declaration or statements 131 134 return new SwitchStmt( maybeMoveBuild< Expression >(ctl), branches ); 132 } 135 } // build_switch 136 133 137 Statement * build_case( ExpressionNode * ctl ) { 134 138 std::list< Statement * > branches; 135 139 return new CaseStmt( maybeMoveBuild< Expression >(ctl), branches ); 136 } 140 } // build_case 141 137 142 Statement * build_default() { 138 143 std::list< Statement * > branches; 139 144 return new CaseStmt( nullptr, branches, true ); 140 } 141 142 Statement * build_while( ExpressionNode * ctl, StatementNode * stmt, bool kind ) { 143 std::list< Statement * > branches; 144 buildMoveList< Statement, StatementNode >( stmt, branches ); 145 assert( branches.size() == 1 ); 146 return new WhileStmt( notZeroExpr( maybeMoveBuild< Expression >(ctl) ), branches.front(), kind ); 147 } 145 } // build_default 146 147 Statement * build_while( IfCtl * ctl, StatementNode * stmt ) { 148 std::list< Statement * > branches; 149 buildMoveList< Statement, StatementNode >( stmt, branches ); 150 assert( branches.size() == 1 ); 151 152 std::list< Statement * > init; 153 Expression * cond = build_if_control( ctl, init ); 154 return new WhileStmt( cond, branches.front(), init, false ); 155 } // build_while 156 157 Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt ) { 158 std::list< Statement * > branches; 159 buildMoveList< Statement, StatementNode >( stmt, branches ); 160 assert( branches.size() == 1 ); 161 162 std::list< Statement * > init; 163 return new WhileStmt( notZeroExpr( maybeMoveBuild< Expression >(ctl) ), branches.front(), init, true ); 164 } // build_do_while 148 165 149 166 Statement * build_for( ForCtl * forctl, StatementNode * stmt ) { … … 167 184 delete forctl; 168 185 return new ForStmt( init, cond, incr, branches.front() ); 169 } 186 } // build_for 170 187 171 188 Statement * build_branch( BranchStmt::Type kind ) { 172 189 Statement * ret = new BranchStmt( "", kind ); 173 190 return ret; 174 } 191 } // build_branch 192 175 193 Statement * build_branch( std::string * identifier, BranchStmt::Type kind ) { 176 194 Statement * ret = new BranchStmt( * identifier, kind ); 177 195 delete identifier; // allocated by lexer 178 196 return ret; 179 } 197 } // build_branch 198 180 199 Statement * build_computedgoto( ExpressionNode * ctl ) { 181 200 return new BranchStmt( maybeMoveBuild< Expression >(ctl), BranchStmt::Goto ); 182 } 201 } // build_computedgoto 183 202 184 203 Statement * build_return( ExpressionNode * ctl ) { … … 186 205 buildMoveList( ctl, exps ); 187 206 return new ReturnStmt( exps.size() > 0 ? exps.back() : nullptr ); 188 } 207 } // build_return 189 208 190 209 Statement * build_throw( ExpressionNode * ctl ) { … … 193 212 assertf( exps.size() < 2, "This means we are leaking memory"); 194 213 return new ThrowStmt( ThrowStmt::Terminate, !exps.empty() ? exps.back() : nullptr ); 195 } 214 } // build_throw 196 215 197 216 Statement * build_resume( ExpressionNode * ctl ) { … … 200 219 assertf( exps.size() < 2, "This means we are leaking memory"); 201 220 return new ThrowStmt( ThrowStmt::Resume, !exps.empty() ? exps.back() : nullptr ); 202 } 221 } // build_resume 203 222 204 223 Statement * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) { … … 206 225 (void)target; 207 226 assertf( false, "resume at (non-local throw) is not yet supported," ); 208 } 227 } // build_resume_at 209 228 210 229 Statement * build_try( StatementNode * try_stmt, StatementNode * catch_stmt, StatementNode * finally_stmt ) { … … 214 233 FinallyStmt * finallyBlock = dynamic_cast< FinallyStmt * >(maybeMoveBuild< Statement >(finally_stmt) ); 215 234 return new TryStmt( tryBlock, branches, finallyBlock ); 216 } 235 } // build_try 236 217 237 Statement * build_catch( CatchStmt::Kind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) { 218 238 std::list< Statement * > branches; … … 220 240 assert( branches.size() == 1 ); 221 241 return new CatchStmt( kind, maybeMoveBuild< Declaration >(decl), maybeMoveBuild< Expression >(cond), branches.front() ); 222 } 242 } // build_catch 243 223 244 Statement * build_finally( StatementNode * stmt ) { 224 245 std::list< Statement * > branches; … … 226 247 assert( branches.size() == 1 ); 227 248 return new FinallyStmt( dynamic_cast< CompoundStmt * >( branches.front() ) ); 228 } 249 } // build_finally 229 250 230 251 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) { … … 247 268 248 269 return node; 249 } 270 } // build_waitfor 250 271 251 272 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when, WaitForStmt * node ) { … … 266 287 267 288 return node; 268 } 289 } // build_waitfor 269 290 270 291 WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when ) { … … 275 296 node->timeout.statement = maybeMoveBuild<Statement >( stmt ); 276 297 node->timeout.condition = notZeroExpr( maybeMoveBuild<Expression>( when ) ); 277 } 278 else { 298 } else { 279 299 node->orelse.statement = maybeMoveBuild<Statement >( stmt ); 280 300 node->orelse.condition = notZeroExpr( maybeMoveBuild<Expression>( when ) ); 281 } 301 } // if 282 302 283 303 return node; 284 } 304 } // build_waitfor_timeout 285 305 286 306 WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when, StatementNode * else_stmt, ExpressionNode * else_when ) { … … 295 315 296 316 return node; 297 } 317 } // build_waitfor_timeout 298 318 299 319 WithStmt * build_with( ExpressionNode * exprs, StatementNode * stmt ) { … … 302 322 Statement * s = maybeMoveBuild<Statement>( stmt ); 303 323 return new WithStmt( e, s ); 304 } 324 } // build_with 305 325 306 326 Statement * build_compound( StatementNode * first ) { … … 308 328 buildMoveList( first, cs->get_kids() ); 309 329 return cs; 310 } 330 } // build_compound 311 331 312 332 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) { … … 318 338 buildMoveList( clobber, clob ); 319 339 return new AsmStmt( voltile, instruction, out, in, clob, gotolabels ? gotolabels->labels : noLabels ); 320 } 340 } // build_asm 321 341 322 342 Statement * build_directive( string * directive ) { 323 343 return new DirectiveStmt( *directive ); 324 } 344 } // build_directive 325 345 326 346 // Local Variables: // -
TabularUnified src/Parser/TypeData.cc ¶
r0182bfa r28f3a19 10 10 // Created On : Sat May 16 15:12:51 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Apr 26 13:46:07201813 // Update Count : 60 312 // Last Modified On : Wed Jun 6 17:40:33 2018 13 // Update Count : 604 14 14 // 15 15 … … 65 65 case Aggregate: 66 66 // aggregate = new Aggregate_t; 67 aggregate.kind = DeclarationNode::NoAggregate; 67 68 aggregate.name = nullptr; 68 69 aggregate.params = nullptr; … … 70 71 aggregate.fields = nullptr; 71 72 aggregate.body = false; 73 aggregate.tagged = false; 74 aggregate.parent = nullptr; 72 75 break; 73 76 case AggregateInst: … … 198 201 break; 199 202 case Aggregate: 203 newtype->aggregate.kind = aggregate.kind; 200 204 newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr; 201 205 newtype->aggregate.params = maybeClone( aggregate.params ); 202 206 newtype->aggregate.actuals = maybeClone( aggregate.actuals ); 203 207 newtype->aggregate.fields = maybeClone( aggregate.fields ); 204 newtype->aggregate.kind = aggregate.kind;205 208 newtype->aggregate.body = aggregate.body; 206 209 newtype->aggregate.tagged = aggregate.tagged; … … 575 578 576 579 case DeclarationNode::Int128: 577 ret = td->signedness == 1? BasicType::UnsignedInt128 : BasicType::SignedInt128;580 ret = td->signedness == DeclarationNode::Unsigned ? BasicType::UnsignedInt128 : BasicType::SignedInt128; 578 581 if ( td->length != DeclarationNode::NoLength ) { 579 582 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); … … 599 602 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); 600 603 } // if 601 if ( td->basictype == DeclarationNode::Float&& td->length == DeclarationNode::Long ) {604 if ( td->basictype != DeclarationNode::Double && td->length == DeclarationNode::Long ) { 602 605 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); 603 606 } // if … … 605 608 const_cast<TypeData *>(td)->basictype = DeclarationNode::LongDouble; 606 609 } // if 610 611 if ( td->basictype == DeclarationNode::Float80 || td->basictype == DeclarationNode::Float128 ) { 612 // if ( td->complextype != DeclarationNode::NoComplexType ) { 613 // genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype ); 614 // } 615 if ( td->basictype == DeclarationNode::Float80 ) ret = BasicType::Float80; 616 else ret = BasicType::Float128; 617 break; 618 } 607 619 608 620 ret = floattype[ td->complextype ][ td->basictype - DeclarationNode::Float ]; -
TabularUnified src/Parser/TypedefTable.cc ¶
r0182bfa r28f3a19 10 10 // Created On : Sat May 16 15:20:13 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue May 22 08:40:01201813 // Update Count : 12112 // Last Modified On : Fri Jun 22 06:14:39 2018 13 // Update Count : 206 14 14 // 15 15 … … 17 17 #include "TypedefTable.h" 18 18 #include <cassert> // for assert 19 #include <iostream> 19 20 20 21 #if 0 21 #include <iostream> 22 #define debugPrint( x ) cerr << x 22 #define debugPrint( code ) code 23 23 #else 24 #define debugPrint( x)24 #define debugPrint( code ) 25 25 #endif 26 26 27 27 using namespace std; // string, iostream 28 28 29 debugPrint( 30 static const char *kindName( int kind ) { 31 switch ( kind ) { 32 case IDENTIFIER: return "identifier"; 33 case TYPEDEFname: return "typedef"; 34 case TYPEGENname: return "typegen"; 35 default: 36 cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl; 37 abort(); 38 } // switch 39 } // kindName 40 ) 41 29 42 TypedefTable::~TypedefTable() { 30 43 if ( ! SemanticErrorThrow && kindTable.currentScope() != 0 ) { 31 // std::cerr << "scope failure " << kindTable.currentScope() << endl; 44 cerr << "Error: cfa-cpp internal error, scope failure " << kindTable.currentScope() << endl; 45 abort(); 32 46 } // if 33 47 } // TypedefTable::~TypedefTable … … 44 58 } // TypedefTable::isKind 45 59 46 void TypedefTable::changeKind( const string & identifier, int kind ) {47 KindTable::iterator posn = kindTable.find( identifier );48 if ( posn != kindTable.end() ) posn->second = kind; // exists => update49 } // TypedefTable::changeKind50 51 60 // SKULLDUGGERY: Generate a typedef for the aggregate name so the aggregate does not have to be qualified by 52 61 // "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the 53 62 // name is explicitly used. 54 void TypedefTable::makeTypedef( const string & name ) { 63 void TypedefTable::makeTypedef( const string & name, int kind ) { 64 // Check for existence is necessary to handle: 65 // struct Fred {}; 66 // void Fred(); 67 // void fred() { 68 // struct Fred act; // do not add as type in this scope 69 // Fred(); 70 // } 55 71 if ( ! typedefTable.exists( name ) ) { 56 typedefTable.addToEnclosingScope( name, TYPEDEFname);72 typedefTable.addToEnclosingScope( name, kind, "MTD" ); 57 73 } // if 58 74 } // TypedefTable::makeTypedef 59 75 60 void TypedefTable::addToEnclosingScope( const std::string & identifier, int kind ) { 61 assert( kindTable.currentScope() >= 1 ); 62 auto scope = kindTable.currentScope() - 1; 63 debugPrint( "Adding " << identifier << " as kind " << kind << " scope " << scope << endl ); 76 void TypedefTable::addToScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) { 77 auto scope = kindTable.currentScope(); 78 debugPrint( cerr << "Adding current at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << endl ); 79 auto ret = kindTable.insertAt( scope, identifier, kind ); 80 //if ( ! ret.second ) ret.first->second = kind; // exists => update 81 assert( ret.first->second == kind ); // exists 82 } // TypedefTable::addToScope 83 84 void TypedefTable::addToEnclosingScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) { 85 assert( kindTable.currentScope() >= 1 + level ); 86 auto scope = kindTable.currentScope() - 1 - level; 87 debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << " level " << level << endl ); 64 88 auto ret = kindTable.insertAt( scope, identifier, kind ); 65 89 if ( ! ret.second ) ret.first->second = kind; // exists => update … … 68 92 void TypedefTable::enterScope() { 69 93 kindTable.beginScope(); 70 debugPrint( "Entering scope " << kindTable.currentScope() << endl);94 debugPrint( cerr << "Entering scope " << kindTable.currentScope() << endl; print() ); 71 95 } // TypedefTable::enterScope 72 96 73 97 void TypedefTable::leaveScope() { 74 debugPrint( "Leaving scope " << kindTable.currentScope() << endl);98 debugPrint( cerr << "Leaving scope " << kindTable.currentScope() << endl; print() ); 75 99 kindTable.endScope(); 76 100 } // TypedefTable::leaveScope 77 101 78 // void TypedefTable::print( void ) const { 79 // for ( KindTable::const_iterator i = table.begin(); i != table.end(); i++) { 80 // debugPrint( (*i ).first << ": " ); 81 // list< Entry > declList = (*i).second; 82 // for ( list< Entry >::const_iterator j = declList.begin(); j != declList.end(); j++ ) { 83 // debugPrint( "(" << (*j).scope << " " << (*j).kind << ") " ); 84 // } 85 // debugPrint( endl ); 86 // } // for 87 // } 102 void TypedefTable::print( void ) const { 103 KindTable::size_type scope = kindTable.currentScope(); 104 debugPrint( cerr << "[" << scope << "]" ); 105 for ( KindTable::const_iterator i = kindTable.begin(); i != kindTable.end(); i++ ) { 106 while ( i.get_level() != scope ) { 107 --scope; 108 debugPrint( cerr << endl << "[" << scope << "]" ); 109 } // while 110 debugPrint( cerr << " " << (*i).first << ":" << kindName( (*i).second ) ); 111 } // for 112 while ( scope > 0 ) { 113 --scope; 114 debugPrint( cerr << endl << "[" << scope << "]" ); 115 } // while 116 debugPrint( cerr << endl ); 117 } // TypedefTable::print 88 118 89 119 // Local Variables: // -
TabularUnified src/Parser/TypedefTable.h ¶
r0182bfa r28f3a19 10 10 // Created On : Sat May 16 15:24:36 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue May 22 08:39:29201813 // Update Count : 7712 // Last Modified On : Fri Jun 22 05:29:58 2018 13 // Update Count : 86 14 14 // 15 15 … … 25 25 typedef ScopedMap< std::string, int > KindTable; 26 26 KindTable kindTable; 27 unsigned int level = 0; 27 28 public: 28 29 ~TypedefTable(); … … 30 31 bool exists( const std::string & identifier ); 31 32 int isKind( const std::string & identifier ) const; 32 void changeKind( const std::string & identifier, int kind);33 void makeTypedef( const std::string & name);34 void addToEnclosingScope( const std::string & identifier, int kind );33 void makeTypedef( const std::string & name, int kind = TYPEDEFname ); 34 void addToScope( const std::string & identifier, int kind, const char * ); 35 void addToEnclosingScope( const std::string & identifier, int kind, const char * ); 35 36 36 37 void enterScope(); 37 38 void leaveScope(); 39 40 void up() { level += 1; } 41 void down() { level -= 1; } 42 43 void print( void ) const; 38 44 }; // TypedefTable 39 45 -
TabularUnified src/Parser/lex.ll ¶
r0182bfa r28f3a19 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Thu May 3 13:42:40201813 * Update Count : 6 7612 * Last Modified On : Wed Jun 20 09:08:28 2018 13 * Update Count : 682 14 14 */ 15 15 … … 25 25 //**************************** Includes and Defines **************************** 26 26 27 // trigger before each matching rule's action 28 #define YY_USER_ACTION \ 29 yylloc.first_line = yylineno; \ 30 yylloc.first_column = column; \ 31 column += yyleng; \ 32 yylloc.last_column = column; \ 33 yylloc.last_line = yylineno; \ 34 yylloc.filename = yyfilename ? yyfilename : ""; 27 35 unsigned int column = 0; // position of the end of the last token parsed 28 #define YY_USER_ACTION yylloc.first_line = yylineno; yylloc.first_column = column; column += yyleng; yylloc.last_column = column; yylloc.last_line = yylineno; yylloc.filename = yyfilename ? yyfilename : ""; // trigger before each matching rule's action29 36 30 37 #include <string> … … 49 56 #define NUMERIC_RETURN(x) rm_underscore(); RETURN_VAL( x ) // numeric constant 50 57 #define KEYWORD_RETURN(x) RETURN_CHAR( x ) // keyword 51 #define QKEYWORD_RETURN(x) typedefTable.isKind( yytext ); RETURN_VAL(x);// quasi-keyword58 #define QKEYWORD_RETURN(x) RETURN_VAL(x); // quasi-keyword 52 59 #define IDENTIFIER_RETURN() RETURN_VAL( typedefTable.isKind( yytext ) ) 53 60 #define ATTRIBUTE_RETURN() RETURN_VAL( ATTR_IDENTIFIER ) … … 232 239 finally { KEYWORD_RETURN(FINALLY); } // CFA 233 240 float { KEYWORD_RETURN(FLOAT); } 241 _Float32 { KEYWORD_RETURN(FLOAT); } // GCC 242 _Float32x { KEYWORD_RETURN(FLOAT); } // GCC 243 _Float64 { KEYWORD_RETURN(DOUBLE); } // GCC 244 _Float64x { KEYWORD_RETURN(DOUBLE); } // GCC 234 245 __float80 { KEYWORD_RETURN(FLOAT80); } // GCC 235 246 float80 { KEYWORD_RETURN(FLOAT80); } // GCC 247 _Float128 { KEYWORD_RETURN(FLOAT128); } // GCC 248 _Float128x { KEYWORD_RETURN(FLOAT128); } // GCC 236 249 __float128 { KEYWORD_RETURN(FLOAT128); } // GCC 237 250 float128 { KEYWORD_RETURN(FLOAT128); } // GCC … … 446 459 447 460 %% 461 448 462 // ----end of lexer---- 449 463 450 464 void yyerror( const char * errmsg ) { 465 SemanticErrorThrow = true; 451 466 cout << (yyfilename ? yyfilename : "*unknown file*") << ':' << yylineno << ':' << column - yyleng + 1 452 467 << ": " << ErrorHelpers::error_str() << errmsg << " at token \"" << (yytext[0] == '\0' ? "EOF" : yytext) << '"' << endl; -
TabularUnified src/Parser/parser.yy ¶
r0182bfa r28f3a19 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu May 24 18:11:59201813 // Update Count : 3 36912 // Last Modified On : Fri Jun 22 13:59:11 2018 13 // Update Count : 3586 14 14 // 15 15 … … 136 136 } // build_postfix_name 137 137 138 bool forall = false, xxx = false ;// aggregate have one or more forall qualifiers ?138 bool forall = false, xxx = false, yyy = false; // aggregate have one or more forall qualifiers ? 139 139 140 140 // https://www.gnu.org/software/bison/manual/bison.html#Location-Type … … 175 175 bool flag; 176 176 CatchStmt::Kind catch_kind; 177 GenericExpr * genexpr; 177 178 } 178 179 … … 259 260 %type<flag> asm_volatile_opt 260 261 %type<en> handler_predicate_opt 262 %type<genexpr> generic_association generic_assoc_list 261 263 262 264 // statements 263 265 %type<sn> statement labeled_statement compound_statement 264 266 %type<sn> statement_decl statement_decl_list statement_list_nodecl 265 %type<sn> selection_statement 267 %type<sn> selection_statement if_statement 266 268 %type<sn> switch_clause_list_opt switch_clause_list 267 269 %type<en> case_value … … 302 304 %type<en> enumerator_value_opt 303 305 304 %type<decl> exception_declaration external_definition external_definition_list external_definition_list_opt 306 %type<decl> external_definition external_definition_list external_definition_list_opt 307 308 %type<decl> exception_declaration 305 309 306 310 %type<decl> field_declaration field_declaration_list_opt field_declarator_opt field_declaring_list … … 324 328 %type<decl> cfa_identifier_parameter_declarator_tuple cfa_identifier_parameter_ptr 325 329 326 %type<decl> cfa_parameter_declaration cfa_parameter_list cfa_parameter_ type_list_opt330 %type<decl> cfa_parameter_declaration cfa_parameter_list cfa_parameter_ellipsis_list_opt 327 331 328 332 %type<decl> cfa_typedef_declaration cfa_variable_declaration cfa_variable_specifier … … 330 334 %type<decl> c_declaration static_assert 331 335 %type<decl> KR_function_declarator KR_function_no_ptr KR_function_ptr KR_function_array 332 %type<decl> KR_ declaration_list KR_declaration_list_opt336 %type<decl> KR_parameter_list KR_parameter_list_opt 333 337 334 338 %type<decl> parameter_declaration parameter_list parameter_type_list_opt … … 402 406 //************************* Namespace Management ******************************** 403 407 404 // The grammar in the ANSI C standard is not strictly context-free, since it relies upon the distinct terminal symbols 405 // "identifier", "TYPEDEFname", and "TYPEGENname" that are lexically identical. While it is possible to write a purely 406 // context-free grammar, such a grammar would obscure the relationship between syntactic and semantic constructs. 407 // Hence, this grammar uses the ANSI style. 408 // 409 // Cforall compounds this problem by introducing type names local to the scope of a declaration (for instance, those 410 // introduced through "forall" qualifiers), and by introducing "type generators" -- parameterized types. This latter 411 // type name creates a third class of identifiers that must be distinguished by the scanner. 412 // 413 // Since the scanner cannot distinguish among the different classes of identifiers without some context information, it 414 // accesses a data structure (TypedefTable) to allow classification of an identifier that it has just read. Semantic 415 // actions during the parser update this data structure when the class of identifiers change. 416 // 417 // Because the Cforall language is block-scoped, an identifier can change its class in a local scope; it must revert to 418 // its original class at the end of the block. Since type names can be local to a particular declaration, each 419 // declaration is itself a scope. This requires distinguishing between type names that are local to the current 420 // declaration scope and those that persist past the end of the declaration (i.e., names defined in "typedef" or "otype" 421 // declarations). 422 // 423 // The non-terminals "push" and "pop" denote the opening and closing of scopes. Every push must have a matching pop, 424 // although it is regrettable the matching pairs do not always occur within the same rule. These non-terminals may 425 // appear in more contexts than strictly necessary from a semantic point of view. 408 // The C grammar is not context free because it relies on the distinct terminal symbols "identifier" and "TYPEDEFname", 409 // which are lexically identical. 410 // 411 // typedef int foo; // identifier foo must now be scanned as TYPEDEFname 412 // foo f; // to allow it to appear in this context 413 // 414 // While it may be possible to write a purely context-free grammar, such a grammar would obscure the relationship 415 // between syntactic and semantic constructs. Cforall compounds this problem by introducing type names local to the 416 // scope of a declaration (for instance, those introduced through "forall" qualifiers), and by introducing "type 417 // generators" -- parameterized types. This latter type name creates a third class of identifiers, "TYPEGENname", which 418 // must be distinguished by the lexical scanner. 419 // 420 // Since the scanner cannot distinguish among the different classes of identifiers without some context information, 421 // there is a type table (typedefTable), which holds type names and identifiers that override type names, for each named 422 // scope. During parsing, semantic actions update the type table by adding new identifiers in the current scope. For 423 // each context that introduces a name scope, a new level is created in the type table and that level is popped on 424 // exiting the scope. Since type names can be local to a particular declaration, each declaration is itself a scope. 425 // This requires distinguishing between type names that are local to the current declaration scope and those that 426 // persist past the end of the declaration (i.e., names defined in "typedef" or "otype" declarations). 427 // 428 // The non-terminals "push" and "pop" denote the opening and closing of named scopes. Every push has a matching pop in 429 // the production rule. There are multiple lists of declarations, where each declaration is a named scope, so pop/push 430 // around the list separator. 431 // 432 // int f( forall(T) T (*f1) T , forall( S ) S (*f2)( S ) ); 433 // push pop push pop 426 434 427 435 push: … … 497 505 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $5 ) ), $2 ) ); } 498 506 | type_name '.' no_attr_identifier // CFA, nested type 499 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 507 // { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 508 { $$ = nullptr; } 500 509 | type_name '.' '[' field_list ']' // CFA, nested type / tuple field selector 501 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 510 // { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 511 { $$ = nullptr; } 502 512 | GENERIC '(' assignment_expression ',' generic_assoc_list ')' // C11 503 { SemanticError( yylloc, "_Generic is currently unimplemented." ); $$ = nullptr; } 513 { 514 // add the missing control expression to the GenericExpr and return it 515 $5->control = maybeMoveBuild<Expression>( $3 ); 516 $$ = new ExpressionNode( $5 ); 517 } 504 518 ; 505 519 506 520 generic_assoc_list: // C11 507 |generic_association521 generic_association 508 522 | generic_assoc_list ',' generic_association 523 { 524 // steal the association node from the singleton and delete the wrapper 525 $1->associations.splice($1->associations.end(), $3->associations); 526 delete $3; 527 $$ = $1; 528 } 509 529 ; 510 530 511 531 generic_association: // C11 512 532 type_no_function ':' assignment_expression 533 { 534 // create a GenericExpr wrapper with one association pair 535 $$ = new GenericExpr( nullptr, { { maybeMoveBuildType($1), maybeMoveBuild<Expression>($3) } } ); 536 } 513 537 | DEFAULT ':' assignment_expression 538 { $$ = new GenericExpr( nullptr, { { maybeMoveBuild<Expression>($3) } } ); } 514 539 ; 515 540 … … 623 648 // semantics checks, e.g., ++3, 3--, *3, &&3 624 649 | constant 625 { $$ = $1; }626 650 | string_literal 627 651 { $$ = new ExpressionNode( $1 ); } … … 835 859 // '[' ']' 836 860 // { $$ = new ExpressionNode( build_tuple() ); } 837 // '[' push assignment_expression pop ']'861 // | '[' push assignment_expression pop ']' 838 862 // { $$ = new ExpressionNode( build_tuple( $3 ) ); } 839 '[' push ',' tuple_expression_list pop']'840 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $ 4) ) ); }841 | '[' push assignment_expression ',' tuple_expression_list pop']'842 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)$3->set_last( $ 5) ) ); }863 '[' ',' tuple_expression_list ']' 864 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); } 865 | '[' push assignment_expression pop ',' tuple_expression_list ']' 866 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)$3->set_last( $6 ) ) ); } 843 867 ; 844 868 … … 892 916 '{' '}' 893 917 { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); } 894 | '{' 895 // Two scopes are necessary because the block itself has a scope, but every declaration within the block also 896 // requires its own scope. 897 push push 918 | '{' push 898 919 local_label_declaration_opt // GCC, local labels 899 920 statement_decl_list // C99, intermix declarations and statements 900 921 pop '}' 901 { $$ = new StatementNode( build_compound( $ 5) ); }922 { $$ = new StatementNode( build_compound( $4 ) ); } 902 923 ; 903 924 904 925 statement_decl_list: // C99 905 926 statement_decl 906 | statement_decl_list pushstatement_decl907 { if ( $1 != 0 ) { $1->set_last( $ 3); $$ = $1; } }927 | statement_decl_list statement_decl 928 { if ( $1 != 0 ) { $1->set_last( $2 ); $$ = $1; } } 908 929 ; 909 930 … … 923 944 $$ = new StatementNode( $2 ); 924 945 } 925 | statement pop946 | statement 926 947 ; 927 948 … … 938 959 939 960 selection_statement: 940 IF '(' push if_control_expression ')' statement %prec THEN 941 // explicitly deal with the shift/reduce conflict on if/else 942 { $$ = new StatementNode( build_if( $4, $6, nullptr ) ); } 943 | IF '(' push if_control_expression ')' statement ELSE statement 944 { $$ = new StatementNode( build_if( $4, $6, $8 ) ); } 961 // pop causes a S/R conflict without separating the IF statement into a non-terminal even after resolving 962 // the inherent S/R conflict with THEN/ELSE. 963 push if_statement pop 964 { $$ = $2; } 945 965 | SWITCH '(' comma_expression ')' case_clause 946 966 { $$ = new StatementNode( build_switch( true, $3, $5 ) ); } 947 | SWITCH '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt '}' // CFA967 | SWITCH '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA 948 968 { 949 969 StatementNode *sw = new StatementNode( build_switch( true, $3, $8 ) ); … … 957 977 | CHOOSE '(' comma_expression ')' case_clause // CFA 958 978 { $$ = new StatementNode( build_switch( false, $3, $5 ) ); } 959 | CHOOSE '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt '}' // CFA979 | CHOOSE '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop '}' // CFA 960 980 { 961 981 StatementNode *sw = new StatementNode( build_switch( false, $3, $8 ) ); … … 964 984 ; 965 985 986 if_statement: 987 IF '(' if_control_expression ')' statement %prec THEN 988 // explicitly deal with the shift/reduce conflict on if/else 989 { $$ = new StatementNode( build_if( $3, $5, nullptr ) ); } 990 | IF '(' if_control_expression ')' statement ELSE statement 991 { $$ = new StatementNode( build_if( $3, $5, $7 ) ); } 992 ; 993 966 994 if_control_expression: 967 comma_expression pop995 comma_expression 968 996 { $$ = new IfCtl( nullptr, $1 ); } 969 | c_declaration pop// no semi-colon997 | c_declaration // no semi-colon 970 998 { $$ = new IfCtl( $1, nullptr ); } 971 | cfa_declaration pop// no semi-colon999 | cfa_declaration // no semi-colon 972 1000 { $$ = new IfCtl( $1, nullptr ); } 973 1001 | declaration comma_expression // semi-colon separated … … 1026 1054 1027 1055 iteration_statement: 1028 WHILE '(' comma_expression ')' statement1029 { $$ = new StatementNode( build_while( $ 3, $5) ); }1056 WHILE '(' push if_control_expression ')' statement pop 1057 { $$ = new StatementNode( build_while( $4, $6 ) ); } 1030 1058 | DO statement WHILE '(' comma_expression ')' ';' 1031 { $$ = new StatementNode( build_ while( $5, $2, true) ); }1032 | FOR '(' push for_control_expression ')' statement 1059 { $$ = new StatementNode( build_do_while( $5, $2 ) ); } 1060 | FOR '(' push for_control_expression ')' statement pop 1033 1061 { $$ = new StatementNode( build_for( $4, $6 ) ); } 1034 1062 ; 1035 1063 1036 1064 for_control_expression: 1037 comma_expression_opt pop';' comma_expression_opt ';' comma_expression_opt1038 { $$ = new ForCtl( $1, $ 4, $6); }1065 comma_expression_opt ';' comma_expression_opt ';' comma_expression_opt 1066 { $$ = new ForCtl( $1, $3, $5 ); } 1039 1067 | declaration comma_expression_opt ';' comma_expression_opt // C99 1040 1068 { $$ = new ForCtl( $1, $2, $4 ); } … … 1158 1186 1159 1187 handler_clause: 1160 handler_key '(' push pushexception_declaration pop handler_predicate_opt ')' compound_statement pop1161 { $$ = new StatementNode( build_catch( $1, $ 5, $7, $9) ); }1162 | handler_clause handler_key '(' push pushexception_declaration pop handler_predicate_opt ')' compound_statement pop1163 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, $ 6, $8, $10) ) ); }1188 handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement pop 1189 { $$ = new StatementNode( build_catch( $1, $4, $6, $8 ) ); } 1190 | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement pop 1191 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, $5, $7, $9 ) ) ); } 1164 1192 ; 1165 1193 … … 1265 1293 1266 1294 declaration_list_opt: // used at beginning of switch statement 1267 pop// empty1295 // empty 1268 1296 { $$ = nullptr; } 1269 1297 | declaration_list … … 1272 1300 declaration_list: 1273 1301 declaration 1274 | declaration_list pushdeclaration1275 { $$ = $1->appendList( $ 3); }1276 ; 1277 1278 KR_ declaration_list_opt:// used to declare parameter types in K&R style functions1302 | declaration_list declaration 1303 { $$ = $1->appendList( $2 ); } 1304 ; 1305 1306 KR_parameter_list_opt: // used to declare parameter types in K&R style functions 1279 1307 // empty 1280 1308 { $$ = nullptr; } 1281 | KR_ declaration_list1282 ; 1283 1284 KR_ declaration_list:1309 | KR_parameter_list 1310 ; 1311 1312 KR_parameter_list: 1285 1313 push c_declaration pop ';' 1286 1314 { $$ = $2; } 1287 | KR_ declaration_list push c_declaration pop ';'1315 | KR_parameter_list push c_declaration pop ';' 1288 1316 { $$ = $1->appendList( $3 ); } 1289 1317 ; … … 1305 1333 1306 1334 declaration: // old & new style declarations 1307 c_declaration pop';'1308 | cfa_declaration pop ';'// CFA1309 | static_assert 1335 c_declaration ';' 1336 | cfa_declaration ';' // CFA 1337 | static_assert // C11 1310 1338 ; 1311 1339 … … 1313 1341 STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11 1314 1342 { $$ = DeclarationNode::newStaticAssert( $3, $5 ); } 1343 | STATICASSERT '(' constant_expression ')' ';' // CFA 1344 { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( *new string( "\"\"" ) ) ); } 1315 1345 1316 1346 // C declaration syntax is notoriously confusing and error prone. Cforall provides its own type, variable and function … … 1357 1387 cfa_function_declaration: // CFA 1358 1388 cfa_function_specifier 1359 { $$ = $1; }1360 1389 | type_qualifier_list cfa_function_specifier 1361 1390 { $$ = $2->addQualifiers( $1 ); } … … 1364 1393 | declaration_qualifier_list type_qualifier_list cfa_function_specifier 1365 1394 { $$ = $3->addQualifiers( $1 )->addQualifiers( $2 ); } 1366 | cfa_function_declaration ',' identifier_or_type_name '(' cfa_parameter_type_list_opt')'1395 | cfa_function_declaration ',' identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' 1367 1396 { 1368 1397 // Append the return type at the start (left-hand-side) to each identifier in the list. 1369 1398 DeclarationNode * ret = new DeclarationNode; 1370 1399 ret->type = maybeClone( $1->type->base ); 1371 $$ = $1->appendList( DeclarationNode::newFunction( $3, ret, $ 5, nullptr ) );1400 $$ = $1->appendList( DeclarationNode::newFunction( $3, ret, $6, nullptr ) ); 1372 1401 } 1373 1402 ; 1374 1403 1375 1404 cfa_function_specifier: // CFA 1376 // '[' ']' identifier_or_type_name '(' push cfa_parameter_ type_list_opt pop ')' // S/R conflict1405 // '[' ']' identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' // S/R conflict 1377 1406 // { 1378 1407 // $$ = DeclarationNode::newFunction( $3, DeclarationNode::newTuple( 0 ), $6, 0, true ); 1379 1408 // } 1380 // '[' ']' identifier '(' push cfa_parameter_ type_list_opt pop ')'1409 // '[' ']' identifier '(' push cfa_parameter_ellipsis_list_opt pop ')' 1381 1410 // { 1382 1411 // typedefTable.setNextIdentifier( *$5 ); 1383 1412 // $$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, 0, true ); 1384 1413 // } 1385 // | '[' ']' TYPEDEFname '(' push cfa_parameter_ type_list_opt pop ')'1414 // | '[' ']' TYPEDEFname '(' push cfa_parameter_ellipsis_list_opt pop ')' 1386 1415 // { 1387 1416 // typedefTable.setNextIdentifier( *$5 ); … … 1391 1420 // identifier_or_type_name must be broken apart because of the sequence: 1392 1421 // 1393 // '[' ']' identifier_or_type_name '(' cfa_parameter_ type_list_opt ')'1422 // '[' ']' identifier_or_type_name '(' cfa_parameter_ellipsis_list_opt ')' 1394 1423 // '[' ']' type_specifier 1395 1424 // 1396 1425 // type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be 1397 1426 // flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name. 1398 cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ type_list_opt pop ')'1427 cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' 1399 1428 // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator). 1400 1429 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); } 1401 | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ type_list_opt pop ')'1430 | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' 1402 1431 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); } 1403 1432 ; … … 1414 1443 TYPEDEF cfa_variable_specifier 1415 1444 { 1416 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname );1445 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, "1" ); 1417 1446 $$ = $2->addTypedef(); 1418 1447 } 1419 1448 | TYPEDEF cfa_function_specifier 1420 1449 { 1421 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname );1450 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, "2" ); 1422 1451 $$ = $2->addTypedef(); 1423 1452 } 1424 1453 | cfa_typedef_declaration pop ',' push no_attr_identifier 1425 1454 { 1426 typedefTable.addToEnclosingScope( *$5, TYPEDEFname );1455 typedefTable.addToEnclosingScope( *$5, TYPEDEFname, "3" ); 1427 1456 $$ = $1->appendList( $1->cloneType( $5 ) ); 1428 1457 } … … 1435 1464 TYPEDEF type_specifier declarator 1436 1465 { 1437 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname );1466 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "4" ); 1438 1467 $$ = $3->addType( $2 )->addTypedef(); 1439 1468 } 1440 1469 | typedef_declaration pop ',' push declarator 1441 1470 { 1442 typedefTable.addToEnclosingScope( *$5->name, TYPEDEFname );1471 typedefTable.addToEnclosingScope( *$5->name, TYPEDEFname, "5" ); 1443 1472 $$ = $1->appendList( $1->cloneBaseType( $5 )->addTypedef() ); 1444 1473 } 1445 1474 | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 ) 1446 1475 { 1447 typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname );1476 typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname, "6" ); 1448 1477 $$ = $4->addType( $3 )->addQualifiers( $1 )->addTypedef(); 1449 1478 } 1450 1479 | type_specifier TYPEDEF declarator 1451 1480 { 1452 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname );1481 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "7" ); 1453 1482 $$ = $3->addType( $1 )->addTypedef(); 1454 1483 } 1455 1484 | type_specifier TYPEDEF type_qualifier_list declarator 1456 1485 { 1457 typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname );1486 typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname, "8" ); 1458 1487 $$ = $4->addQualifiers( $1 )->addTypedef()->addType( $1 ); 1459 1488 } … … 1582 1611 1583 1612 forall: 1584 FORALL '(' push type_parameter_list pop')' // CFA1585 { $$ = DeclarationNode::newForall( $ 4); }1613 FORALL '(' type_parameter_list ')' // CFA 1614 { $$ = DeclarationNode::newForall( $3 ); } 1586 1615 ; 1587 1616 … … 1765 1794 { $$ = DeclarationNode::newFromTypedef( $1 ); } 1766 1795 | '.' TYPEDEFname 1767 { $$ = DeclarationNode::newFromTypedef( $2 ); } // FIX ME1796 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 1768 1797 | type_name '.' TYPEDEFname 1769 { $$ = DeclarationNode::newFromTypedef( $3 ); } // FIX ME1798 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 1770 1799 | typegen_name 1771 1800 | '.' typegen_name 1772 { $$ = $2; } // FIX ME1801 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 1773 1802 | type_name '.' typegen_name 1774 { $$ = $3; } // FIX ME1803 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 1775 1804 ; 1776 1805 … … 1794 1823 ; 1795 1824 1825 fred: 1826 // empty 1827 { yyy = false; } 1828 ; 1829 1796 1830 aggregate_type: // struct, union 1797 1831 aggregate_key attribute_list_opt '{' field_declaration_list_opt '}' 1798 1832 { $$ = DeclarationNode::newAggregate( $1, new string( DeclarationNode::anonymous.newName() ), nullptr, $4, true )->addQualifiers( $2 ); } 1799 | aggregate_key attribute_list_opt no_attr_identifier _or_type_name1800 { 1801 typedefTable.makeTypedef( *$3 );// create typedef1802 if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update1833 | aggregate_key attribute_list_opt no_attr_identifier fred 1834 { 1835 typedefTable.makeTypedef( *$3, forall ? TYPEGENname : TYPEDEFname ); // create typedef 1836 //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update 1803 1837 forall = false; // reset 1804 1838 } 1805 1839 '{' field_declaration_list_opt '}' 1806 { $$ = DeclarationNode::newAggregate( $1, $3, nullptr, $6, true )->addQualifiers( $2 ); } 1840 { $$ = DeclarationNode::newAggregate( $1, $3, nullptr, $7, true )->addQualifiers( $2 ); } 1841 | aggregate_key attribute_list_opt type_name fred 1842 { 1843 typedefTable.makeTypedef( *$3->type->symbolic.name, forall ? TYPEGENname : TYPEDEFname ); // create typedef 1844 //if ( forall ) typedefTable.changeKind( *$3->type->symbolic.name, TYPEGENname ); // possibly update 1845 forall = false; // reset 1846 } 1847 '{' field_declaration_list_opt '}' 1848 { $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, nullptr, $7, true )->addQualifiers( $2 ); } 1807 1849 | aggregate_key attribute_list_opt '(' type_list ')' '{' field_declaration_list_opt '}' // CFA 1808 1850 { $$ = DeclarationNode::newAggregate( $1, new string( DeclarationNode::anonymous.newName() ), $4, $7, false )->addQualifiers( $2 ); } … … 1811 1853 1812 1854 aggregate_type_nobody: // struct, union - {...} 1813 aggregate_key attribute_list_opt no_attr_identifier 1814 { 1815 typedefTable.makeTypedef( *$3 );1816 if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update1855 aggregate_key attribute_list_opt no_attr_identifier fred 1856 { 1857 typedefTable.makeTypedef( *$3, forall ? TYPEGENname : TYPEDEFname ); 1858 //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update 1817 1859 forall = false; // reset 1818 1860 $$ = DeclarationNode::newAggregate( $1, $3, nullptr, nullptr, false )->addQualifiers( $2 ); 1819 1861 } 1820 | aggregate_key attribute_list_opt TYPEDEFname 1821 { 1822 typedefTable.makeTypedef( *$3 ); 1823 $$ = DeclarationNode::newAggregate( $1, $3, nullptr, nullptr, false )->addQualifiers( $2 ); 1824 } 1825 | aggregate_key attribute_list_opt typegen_name // CFA 1862 | aggregate_key attribute_list_opt type_name fred 1826 1863 { 1827 1864 // Create new generic declaration with same name as previous forward declaration, where the IDENTIFIER is … … 1837 1874 aggregate_key: 1838 1875 STRUCT 1839 { $$ = DeclarationNode::Struct; }1876 { yyy = true; $$ = DeclarationNode::Struct; } 1840 1877 | UNION 1841 { $$ = DeclarationNode::Union; }1878 { yyy = true; $$ = DeclarationNode::Union; } 1842 1879 | EXCEPTION 1843 { $$ = DeclarationNode::Exception; }1880 { yyy = true; $$ = DeclarationNode::Exception; } 1844 1881 | COROUTINE 1845 { $$ = DeclarationNode::Coroutine; }1882 { yyy = true; $$ = DeclarationNode::Coroutine; } 1846 1883 | MONITOR 1847 { $$ = DeclarationNode::Monitor; }1884 { yyy = true; $$ = DeclarationNode::Monitor; } 1848 1885 | THREAD 1849 { $$ = DeclarationNode::Thread; }1886 { yyy = true; $$ = DeclarationNode::Thread; } 1850 1887 ; 1851 1888 … … 1858 1895 1859 1896 field_declaration: 1860 cfa_field_declaring_list ';' // CFA, new style field declaration 1897 type_specifier field_declaring_list ';' 1898 { $$ = distAttr( $1, $2 ); } 1899 | EXTENSION type_specifier field_declaring_list ';' // GCC 1900 { distExt( $3 ); $$ = distAttr( $2, $3 ); } // mark all fields in list 1901 | typedef_declaration ';' // CFA 1902 { SemanticError( yylloc, "Typedef in aggregate is currently unimplemented." ); $$ = nullptr; } 1903 | cfa_field_declaring_list ';' // CFA, new style field declaration 1861 1904 | EXTENSION cfa_field_declaring_list ';' // GCC 1862 { 1863 distExt( $2 ); // mark all fields in list 1864 $$ = $2; 1865 } 1866 | type_specifier field_declaring_list ';' 1867 { 1868 $$ = distAttr( $1, $2 ); } 1869 | EXTENSION type_specifier field_declaring_list ';' // GCC 1870 { 1871 distExt( $3 ); // mark all fields in list 1872 $$ = distAttr( $2, $3 ); 1873 } 1874 | static_assert 1905 { distExt( $2 ); $$ = $2; } // mark all fields in list 1906 | cfa_typedef_declaration ';' // CFA 1907 { SemanticError( yylloc, "Typedef in aggregate is currently unimplemented." ); $$ = nullptr; } 1908 | static_assert // C11 1875 1909 ; 1876 1910 … … 1911 1945 { $$ = nullptr; } 1912 1946 | bit_subrange_size 1913 { $$ = $1; }1914 1947 ; 1915 1948 … … 1922 1955 ENUM attribute_list_opt '{' enumerator_list comma_opt '}' 1923 1956 { $$ = DeclarationNode::newEnum( new string( DeclarationNode::anonymous.newName() ), $4, true )->addQualifiers( $2 ); } 1924 | ENUM attribute_list_opt no_attr_identifier _or_type_name1957 | ENUM attribute_list_opt no_attr_identifier 1925 1958 { typedefTable.makeTypedef( *$3 ); } 1926 1959 '{' enumerator_list comma_opt '}' 1927 1960 { $$ = DeclarationNode::newEnum( $3, $6, true )->addQualifiers( $2 ); } 1961 | ENUM attribute_list_opt type_name 1962 '{' enumerator_list comma_opt '}' 1963 { $$ = DeclarationNode::newEnum( $3->type->symbolic.name, $5, true )->addQualifiers( $2 ); } 1928 1964 | enum_type_nobody 1929 1965 ; 1930 1966 1931 1967 enum_type_nobody: // enum - {...} 1932 ENUM attribute_list_opt no_attr_identifier _or_type_name1968 ENUM attribute_list_opt no_attr_identifier 1933 1969 { 1934 1970 typedefTable.makeTypedef( *$3 ); 1935 1971 $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 ); 1972 } 1973 | ENUM attribute_list_opt type_name 1974 { 1975 typedefTable.makeTypedef( *$3->type->symbolic.name ); 1976 $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 ); 1936 1977 } 1937 1978 ; … … 1951 1992 ; 1952 1993 1953 cfa_parameter_ type_list_opt: // CFA, abstract + real1994 cfa_parameter_ellipsis_list_opt: // CFA, abstract + real 1954 1995 // empty 1955 1996 { $$ = DeclarationNode::newBasicType( DeclarationNode::Void ); } … … 2084 2125 { $$ = $2; } 2085 2126 | '=' VOID 2086 { $$ = n ullptr; }2127 { $$ = new InitializerNode( true ); } 2087 2128 | ATassign initializer 2088 2129 { $$ = $2->set_maybeConstructed( false ); } … … 2161 2202 type_parameter_list: // CFA 2162 2203 type_parameter 2163 { $$ = $1; }2164 2204 | type_parameter_list ',' type_parameter 2165 2205 { $$ = $1->appendList( $3 ); } … … 2175 2215 type_parameter: // CFA 2176 2216 type_class no_attr_identifier_or_type_name 2177 { typedefTable.addTo EnclosingScope( *$2, TYPEDEFname); }2217 { typedefTable.addToScope( *$2, TYPEDEFname, "9" ); } 2178 2218 type_initializer_opt assertion_list_opt 2179 2219 { $$ = DeclarationNode::newTypeParam( $1, $2 )->addTypeInitializer( $4 )->addAssertions( $5 ); } … … 2209 2249 '|' no_attr_identifier_or_type_name '(' type_list ')' 2210 2250 { $$ = DeclarationNode::newTraitUse( $2, $4 ); } 2211 | '|' '{' push trait_declaration_list '}'2251 | '|' '{' push trait_declaration_list pop '}' 2212 2252 { $$ = $4; } 2213 | '|' '(' push type_parameter_list pop ')' '{' push trait_declaration_list'}' '(' type_list ')'2214 { SemanticError( yylloc, "Generic data-type assertion is currently unimplemented." ); $$ = nullptr; }2253 // | '|' '(' push type_parameter_list pop ')' '{' push trait_declaration_list pop '}' '(' type_list ')' 2254 // { SemanticError( yylloc, "Generic data-type assertion is currently unimplemented." ); $$ = nullptr; } 2215 2255 ; 2216 2256 … … 2244 2284 no_attr_identifier_or_type_name 2245 2285 { 2246 typedefTable.addToEnclosingScope( *$1, TYPEDEFname );2286 typedefTable.addToEnclosingScope( *$1, TYPEDEFname, "10" ); 2247 2287 $$ = DeclarationNode::newTypeDecl( $1, 0 ); 2248 2288 } 2249 | no_attr_identifier_or_type_name '(' push type_parameter_list pop')'2250 { 2251 typedefTable.addToEnclosingScope( *$1, TYPEGENname );2252 $$ = DeclarationNode::newTypeDecl( $1, $ 4);2289 | no_attr_identifier_or_type_name '(' type_parameter_list ')' 2290 { 2291 typedefTable.addToEnclosingScope( *$1, TYPEGENname, "11" ); 2292 $$ = DeclarationNode::newTypeDecl( $1, $3 ); 2253 2293 } 2254 2294 ; 2255 2295 2256 2296 trait_specifier: // CFA 2257 TRAIT no_attr_identifier_or_type_name '(' push type_parameter_list pop')' '{' '}'2258 { $$ = DeclarationNode::newTrait( $2, $ 5, 0 ); }2259 | TRAIT no_attr_identifier_or_type_name '(' push type_parameter_list pop ')' '{' push trait_declaration_list'}'2260 { $$ = DeclarationNode::newTrait( $2, $ 5, $10); }2297 TRAIT no_attr_identifier_or_type_name '(' type_parameter_list ')' '{' '}' 2298 { $$ = DeclarationNode::newTrait( $2, $4, 0 ); } 2299 | TRAIT no_attr_identifier_or_type_name '(' type_parameter_list ')' '{' push trait_declaration_list pop '}' 2300 { $$ = DeclarationNode::newTrait( $2, $4, $8 ); } 2261 2301 ; 2262 2302 2263 2303 trait_declaration_list: // CFA 2264 2304 trait_declaration 2265 | trait_declaration_list p ush trait_declaration2266 { $$ = $1->appendList( $ 3); }2305 | trait_declaration_list pop push trait_declaration 2306 { $$ = $1->appendList( $4 ); } 2267 2307 ; 2268 2308 2269 2309 trait_declaration: // CFA 2270 cfa_trait_declaring_list pop';'2271 | trait_declaring_list pop';'2310 cfa_trait_declaring_list ';' 2311 | trait_declaring_list ';' 2272 2312 ; 2273 2313 … … 2289 2329 2290 2330 translation_unit: 2291 // empty 2292 {} // empty input file 2331 // empty, input file 2293 2332 | external_definition_list 2294 2333 { parseTree = parseTree ? parseTree->appendList( $1 ) : $1; } … … 2296 2335 2297 2336 external_definition_list: 2298 external_definition 2337 push external_definition pop 2338 { $$ = $2; } 2299 2339 | external_definition_list 2300 2340 { forall = xxx; } 2301 push external_definition 2341 push external_definition pop 2302 2342 { $$ = $1 ? $1->appendList( $4 ) : $4; } 2303 2343 ; … … 2309 2349 ; 2310 2350 2351 up: 2352 { typedefTable.up(); } 2353 ; 2354 2355 down: 2356 { typedefTable.down(); } 2357 ; 2358 2311 2359 external_definition: 2312 2360 declaration 2313 2361 | external_function_definition 2362 | EXTENSION external_definition // GCC, multiple __extension__ allowed, meaning unknown 2363 { 2364 distExt( $2 ); // mark all fields in list 2365 $$ = $2; 2366 } 2314 2367 | ASM '(' string_literal ')' ';' // GCC, global assembler statement 2315 2368 { … … 2321 2374 linkage = LinkageSpec::linkageUpdate( yylloc, linkage, $2 ); 2322 2375 } 2323 '{' external_definition_list_opt'}'2376 '{' up external_definition_list_opt down '}' 2324 2377 { 2325 2378 linkage = linkageStack.top(); 2326 2379 linkageStack.pop(); 2327 $$ = $5; 2328 } 2329 | EXTENSION external_definition // GCC, multiple __extension__ allowed, meaning unknown 2330 { 2331 distExt( $2 ); // mark all fields in list 2332 $$ = $2; 2380 $$ = $6; 2333 2381 } 2334 2382 | type_qualifier_list 2335 { if ( $1->type->forall ) xxx = forall = true; } // remember generic type 2336 push '{' external_definition_list '}' // CFA, namespace 2383 { 2384 if ( $1->type->qualifiers.val ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); } 2385 if ( $1->type->forall ) xxx = forall = true; // remember generic type 2386 } 2387 '{' up external_definition_list_opt down '}' // CFA, namespace 2337 2388 { 2338 2389 for ( DeclarationNode * iter = $5; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) { … … 2346 2397 } 2347 2398 | declaration_qualifier_list 2348 { if ( $1->type->forall ) xxx = forall = true; } // remember generic type 2349 push '{' external_definition_list '}' // CFA, namespace 2399 { 2400 if ( $1->type->qualifiers.val ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); } 2401 if ( $1->type->forall ) xxx = forall = true; // remember generic type 2402 } 2403 '{' up external_definition_list_opt down '}' // CFA, namespace 2350 2404 { 2351 2405 for ( DeclarationNode * iter = $5; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) { … … 2360 2414 | declaration_qualifier_list type_qualifier_list 2361 2415 { 2362 // forall must be in the type_qualifier_list2363 if ( $2->type->forall ) xxx = forall = true; // remember generic type2364 } 2365 push '{' external_definition_list '}'// CFA, namespace2416 if ( ($1->type && $1->type->qualifiers.val) || $2->type->qualifiers.val ) { SemanticError( yylloc, "CV qualifiers cannot be distributed; only storage-class and forall qualifiers." ); } 2417 if ( ($1->type && $1->type->forall) || $2->type->forall ) xxx = forall = true; // remember generic type 2418 } 2419 '{' up external_definition_list_opt down '}' // CFA, namespace 2366 2420 { 2367 2421 for ( DeclarationNode * iter = $6; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) { … … 2387 2441 | function_declarator compound_statement 2388 2442 { $$ = $1->addFunctionBody( $2 ); } 2389 | KR_function_declarator KR_ declaration_list_opt compound_statement2443 | KR_function_declarator KR_parameter_list_opt compound_statement 2390 2444 { $$ = $1->addOldDeclList( $2 )->addFunctionBody( $3 ); } 2391 2445 ; … … 2427 2481 2428 2482 // Old-style K&R function definition, OBSOLESCENT (see 4) 2429 | declaration_specifier KR_function_declarator KR_ declaration_list_opt with_clause_opt compound_statement2483 | declaration_specifier KR_function_declarator KR_parameter_list_opt with_clause_opt compound_statement 2430 2484 { 2431 2485 rebindForall( $1, $2 ); … … 2433 2487 } 2434 2488 // handles default int return type, OBSOLESCENT (see 1) 2435 | type_qualifier_list KR_function_declarator KR_ declaration_list_opt with_clause_opt compound_statement2489 | type_qualifier_list KR_function_declarator KR_parameter_list_opt with_clause_opt compound_statement 2436 2490 { $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 ); } 2437 2491 // handles default int return type, OBSOLESCENT (see 1) 2438 | declaration_qualifier_list KR_function_declarator KR_ declaration_list_opt with_clause_opt compound_statement2492 | declaration_qualifier_list KR_function_declarator KR_parameter_list_opt with_clause_opt compound_statement 2439 2493 { $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 ); } 2440 2494 // handles default int return type, OBSOLESCENT (see 1) 2441 | declaration_qualifier_list type_qualifier_list KR_function_declarator KR_ declaration_list_opt with_clause_opt compound_statement2495 | declaration_qualifier_list type_qualifier_list KR_function_declarator KR_parameter_list_opt with_clause_opt compound_statement 2442 2496 { $$ = $3->addOldDeclList( $4 )->addFunctionBody( $6, $5 )->addQualifiers( $2 )->addQualifiers( $1 ); } 2443 2497 ; … … 2684 2738 typedef 2685 2739 // hide type name in enclosing scope by variable name 2686 { typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER ); }2740 { typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" ); } 2687 2741 | '(' paren_type ')' 2688 2742 { $$ = $2; } … … 2974 3028 '[' ']' 2975 3029 { $$ = DeclarationNode::newArray( 0, 0, false ); } 2976 // multi_array_dimension handles the '[' '*' ']' case3030 // multi_array_dimension handles the '[' '*' ']' case 2977 3031 | '[' push type_qualifier_list '*' pop ']' // remaining C99 2978 3032 { $$ = DeclarationNode::newVarArray( $3 ); } 2979 3033 | '[' push type_qualifier_list pop ']' 2980 3034 { $$ = DeclarationNode::newArray( 0, $3, false ); } 2981 // multi_array_dimension handles the '[' assignment_expression ']' case3035 // multi_array_dimension handles the '[' assignment_expression ']' case 2982 3036 | '[' push type_qualifier_list assignment_expression pop ']' 2983 3037 { $$ = DeclarationNode::newArray( $4, $3, false ); } … … 3115 3169 // 3116 3170 // cfa_abstract_tuple identifier_or_type_name 3117 // '[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_ type_list_opt ')'3171 // '[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_ellipsis_list_opt ')' 3118 3172 // 3119 3173 // since a function return type can be syntactically identical to a tuple type: … … 3174 3228 '[' push cfa_abstract_parameter_list pop ']' 3175 3229 { $$ = DeclarationNode::newTuple( $3 ); } 3230 | '[' push type_specifier_nobody ELLIPSIS pop ']' 3231 { SemanticError( yylloc, "Tuple array currently unimplemented." ); $$ = nullptr; } 3232 | '[' push type_specifier_nobody ELLIPSIS constant_expression pop ']' 3233 { SemanticError( yylloc, "Tuple array currently unimplemented." ); $$ = nullptr; } 3176 3234 ; 3177 3235 3178 3236 cfa_abstract_function: // CFA 3179 // '[' ']' '(' cfa_parameter_ type_list_opt ')'3237 // '[' ']' '(' cfa_parameter_ellipsis_list_opt ')' 3180 3238 // { $$ = DeclarationNode::newFunction( nullptr, DeclarationNode::newTuple( nullptr ), $4, nullptr ); } 3181 cfa_abstract_tuple '(' push cfa_parameter_ type_list_opt pop ')'3239 cfa_abstract_tuple '(' push cfa_parameter_ellipsis_list_opt pop ')' 3182 3240 { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); } 3183 | cfa_function_return '(' push cfa_parameter_ type_list_opt pop ')'3241 | cfa_function_return '(' push cfa_parameter_ellipsis_list_opt pop ')' 3184 3242 { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); } 3185 3243 ; … … 3212 3270 3213 3271 %% 3272 3214 3273 // ----end of grammar---- 3215 3274 -
TabularUnified src/ResolvExpr/Alternative.cc ¶
r0182bfa r28f3a19 30 30 31 31 namespace ResolvExpr { 32 Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( 0) {}32 Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( nullptr ) {} 33 33 34 34 Alternative::Alternative( Expression *expr, const TypeEnvironment &env, const Cost& cost ) -
TabularUnified src/ResolvExpr/AlternativeFinder.cc ¶
r0182bfa r28f3a19 98 98 void postvisit( InitExpr * initExpr ); 99 99 void postvisit( DeletedExpr * delExpr ); 100 void postvisit( GenericExpr * genExpr ); 100 101 101 102 /// Adds alternatives for anonymous members … … 175 176 selected[ mangleName ] = current; 176 177 } else if ( candidate->cost == mapPlace->second.candidate->cost ) { 177 PRINT( 178 std::cerr << "marking ambiguous" << std::endl; 179 ) 180 mapPlace->second.isAmbiguous = true; 178 // if one of the candidates contains a deleted identifier, can pick the other, since 179 // deleted expressions should not be ambiguous if there is another option that is at least as good 180 if ( findDeletedExpr( candidate->expr ) ) { 181 // do nothing 182 PRINT( std::cerr << "candidate is deleted" << std::endl; ) 183 } else if ( findDeletedExpr( mapPlace->second.candidate->expr ) ) { 184 PRINT( std::cerr << "current is deleted" << std::endl; ) 185 selected[ mangleName ] = current; 186 } else { 187 PRINT( 188 std::cerr << "marking ambiguous" << std::endl; 189 ) 190 mapPlace->second.isAmbiguous = true; 191 } 181 192 } else { 182 193 PRINT( … … 298 309 // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value 299 310 Expression* aggrExpr = alt.expr->clone(); 300 alt.env.apply( aggrExpr-> get_result());301 Type * aggrType = aggrExpr-> get_result();311 alt.env.apply( aggrExpr->result ); 312 Type * aggrType = aggrExpr->result; 302 313 if ( dynamic_cast< ReferenceType * >( aggrType ) ) { 303 314 aggrType = aggrType->stripReferences(); … … 305 316 } 306 317 307 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr-> get_result()) ) {318 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->result ) ) { 308 319 addAggMembers( structInst, aggrExpr, alt.cost+Cost::safe, alt.env, "" ); 309 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr-> get_result()) ) {320 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->result ) ) { 310 321 addAggMembers( unionInst, aggrExpr, alt.cost+Cost::safe, alt.env, "" ); 311 322 } // if … … 317 328 aggInst->lookup( name, members ); 318 329 319 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) { 320 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) { 321 alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) ); 322 renameTypes( alternatives.back().expr ); 323 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression. 330 for ( Declaration * decl : members ) { 331 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( decl ) ) { 332 // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so 333 // can't construct in place and use vector::back 334 Alternative newAlt( new MemberExpr( dwt, expr->clone() ), env, newCost ); 335 renameTypes( newAlt.expr ); 336 addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression. 337 alternatives.push_back( std::move(newAlt) ); 324 338 } else { 325 339 assert( false ); … … 331 345 if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) { 332 346 // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning 333 // xxx - this should be improved by memoizing the value of constant exprs 334 // during parsing and reusing that information here. 335 std::stringstream ss( constantExpr->get_constant()->get_value() ); 336 int val = 0; 347 auto val = constantExpr->intValue(); 337 348 std::string tmp; 338 if ( ss >> val && ! (ss >> tmp) ) { 339 if ( val >= 0 && (unsigned int)val < tupleType->size() ) { 340 alternatives.push_back( Alternative( new TupleIndexExpr( expr, val ), env, newCost ) ); 341 } // if 349 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 350 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) ); 342 351 } // if 343 } else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) {344 // xxx - temporary hack until 0/1 are int constants345 if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) {346 std::stringstream ss( nameExpr->get_name() );347 int val;348 ss >> val;349 alternatives.push_back( Alternative( new TupleIndexExpr( expr, val ), env, newCost ) );350 }351 352 } // if 352 353 } … … 435 436 return Cost::infinity; 436 437 } 438 } 439 if ( DefaultArgExpr * def = dynamic_cast< DefaultArgExpr * >( *actualExpr ) ) { 440 // default arguments should be free - don't include conversion cost. 441 // Unwrap them here because they are not relevant to the rest of the system. 442 *actualExpr = def->expr; 443 ++formal; 444 continue; 437 445 } 438 446 Type * formalType = (*formal)->get_type(); … … 604 612 ConstantExpr* getDefaultValue( Initializer* init ) { 605 613 if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) { 606 if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->get_value() ) ) { 607 return dynamic_cast<ConstantExpr*>( ce->get_arg() ); 614 if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->value ) ) { 615 return dynamic_cast<ConstantExpr*>( ce->arg ); 616 } else { 617 return dynamic_cast<ConstantExpr*>( si->value ); 608 618 } 609 619 } … … 866 876 indexer ) ) { 867 877 results.emplace_back( 868 i, cnstExpr, move(env), move(need), move(have),878 i, new DefaultArgExpr( cnstExpr ), move(env), move(need), move(have), 869 879 move(openVars), nextArg, nTuples ); 870 880 } … … 1058 1068 funcFinder.findWithAdjustment( untypedExpr->function ); 1059 1069 // if there are no function alternatives, then proceeding is a waste of time. 1070 // xxx - findWithAdjustment throws, so this check and others like it shouldn't be necessary. 1060 1071 if ( funcFinder.alternatives.empty() ) return; 1061 1072 … … 1085 1096 argExpansions.emplace_back(); 1086 1097 auto& argE = argExpansions.back(); 1087 argE.reserve( arg.alternatives.size() );1098 // argE.reserve( arg.alternatives.size() ); 1088 1099 1089 1100 for ( const Alternative& actual : arg ) { … … 1108 1119 std::back_inserter( candidates ) ); 1109 1120 } 1110 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr-> get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)1111 if ( const EqvClass *eqvClass = func->env.lookup( typeInst-> get_name()) ) {1121 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->result->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer) 1122 if ( const EqvClass *eqvClass = func->env.lookup( typeInst->name ) ) { 1112 1123 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass->type ) ) { 1113 1124 Alternative newFunc( *func ); … … 1364 1375 Cost cost = Cost::zero; 1365 1376 Expression * newExpr = data.combine( cost ); 1366 alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) ); 1377 1378 // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so 1379 // can't construct in place and use vector::back 1380 Alternative newAlt( newExpr, env, Cost::zero, cost ); 1367 1381 PRINT( 1368 1382 std::cerr << "decl is "; … … 1373 1387 std::cerr << std::endl; 1374 1388 ) 1375 renameTypes( alternatives.back().expr ); 1376 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression. 1389 renameTypes( newAlt.expr ); 1390 addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression. 1391 alternatives.push_back( std::move(newAlt) ); 1377 1392 } // for 1378 1393 } … … 1741 1756 assertf( false, "AlternativeFinder should never see a DeletedExpr." ); 1742 1757 } 1758 1759 void AlternativeFinder::Finder::postvisit( GenericExpr * ) { 1760 assertf( false, "_Generic is not yet supported." ); 1761 } 1743 1762 } // namespace ResolvExpr 1744 1763 -
TabularUnified src/ResolvExpr/CommonType.cc ¶
r0182bfa r28f3a19 24 24 #include "SynTree/Type.h" // for BasicType, BasicType::Kind::... 25 25 #include "SynTree/Visitor.h" // for Visitor 26 #include "Unify.h" // for unifyExact, bindVar,WidenMode26 #include "Unify.h" // for unifyExact, WidenMode 27 27 #include "typeops.h" // for isFtype 28 28 … … 176 176 } 177 177 178 static const BasicType::Kind combinedType[ BasicType::NUMBER_OF_BASIC_TYPES][ BasicType::NUMBER_OF_BASIC_TYPES ] =178 static const BasicType::Kind combinedType[][ BasicType::NUMBER_OF_BASIC_TYPES ] = 179 179 { 180 /* Bool Char SignedChar UnsignedChar ShortSignedInt ShortUnsignedInt SignedInt UnsignedInt LongSignedInt LongUnsignedInt LongLongSignedInt LongLongUnsignedInt Float Double LongDouble FloatComplex DoubleComplex LongDoubleComplex FloatImaginary DoubleImaginary LongDoubleImaginary SignedInt128 UnsignedInt128 */ 181 /* Bool */ { BasicType::Bool, BasicType::Char, BasicType::SignedChar, BasicType::UnsignedChar, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 182 /* Char */ { BasicType::Char, BasicType::Char, BasicType::UnsignedChar, BasicType::UnsignedChar, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 183 /* SignedChar */ { BasicType::SignedChar, BasicType::UnsignedChar, BasicType::SignedChar, BasicType::UnsignedChar, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 184 /* UnsignedChar */ { BasicType::UnsignedChar, BasicType::UnsignedChar, BasicType::UnsignedChar, BasicType::UnsignedChar, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 185 /* ShortSignedInt */ { BasicType::ShortSignedInt, BasicType::ShortSignedInt, BasicType::ShortSignedInt, BasicType::ShortSignedInt, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 186 /* ShortUnsignedInt */ { BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 187 /* SignedInt */ { BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 188 /* UnsignedInt */ { BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 189 /* LongSignedInt */ { BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 190 /* LongUnsignedInt */ { BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 191 /* LongLongSignedInt */ { BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 192 /* LongLongUnsignedInt */ { BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 193 /* Float */ { BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::Float, BasicType::Float, }, 194 /* Double */ { BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::LongDouble, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::Double, BasicType::Double, }, 195 /* LongDouble */ { BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDouble, BasicType::LongDouble, }, 196 /* FloatComplex */ { BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::FloatComplex, }, 197 /* DoubleComplex */ { BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, }, 198 /* LongDoubleComplex */ { BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, }, 199 /* FloatImaginary */ { BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatImaginary, BasicType::DoubleImaginary, BasicType::LongDoubleImaginary, BasicType::FloatImaginary, BasicType::FloatImaginary, }, 200 /* DoubleImaginary */ { BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleImaginary, BasicType::DoubleImaginary, BasicType::LongDoubleImaginary, BasicType::DoubleImaginary, BasicType::DoubleImaginary, }, 201 /* LongDoubleImaginary */ { BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary }, 202 /* SignedInt128 */ { BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, }, 203 /* UnsignedInt128 */ { BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::UnsignedInt128, BasicType::UnsignedInt128, }, 180 /* Bool Char SignedChar UnsignedChar ShortSignedInt ShortUnsignedInt SignedInt UnsignedInt LongSignedInt LongUnsignedInt LongLongSignedInt LongLongUnsignedInt Float Double LongDouble FloatComplex DoubleComplex LongDoubleComplex FloatImaginary DoubleImaginary LongDoubleImaginary SignedInt128 UnsignedInt128 Float80 Float128 */ 181 /* Bool */ { BasicType::Bool, BasicType::Char, BasicType::SignedChar, BasicType::UnsignedChar, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 182 /* Char */ { BasicType::Char, BasicType::Char, BasicType::UnsignedChar, BasicType::UnsignedChar, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 183 /* SignedChar */ { BasicType::SignedChar, BasicType::UnsignedChar, BasicType::SignedChar, BasicType::UnsignedChar, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 184 /* UnsignedChar */ { BasicType::UnsignedChar, BasicType::UnsignedChar, BasicType::UnsignedChar, BasicType::UnsignedChar, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 185 /* ShortSignedInt */ { BasicType::ShortSignedInt, BasicType::ShortSignedInt, BasicType::ShortSignedInt, BasicType::ShortSignedInt, BasicType::ShortSignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 186 /* ShortUnsignedInt */ { BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::ShortUnsignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 187 /* SignedInt */ { BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::SignedInt, BasicType::UnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 188 /* UnsignedInt */ { BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 189 /* LongSignedInt */ { BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongSignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 190 /* LongUnsignedInt */ { BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 191 /* LongLongSignedInt */ { BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongSignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 192 /* LongLongUnsignedInt */ { BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 }, 193 /* Float */ { BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::Float, BasicType::Float, BasicType::Float80, BasicType::Float128 }, 194 /* Double */ { BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::Double, BasicType::LongDouble, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::Double, BasicType::Double, BasicType::Float80, BasicType::Float128 }, 195 /* LongDouble */ { BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDouble, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDouble, BasicType::LongDouble, BasicType::BasicType::LongDouble, BasicType::Float128 }, 196 /* FloatComplex */ { BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, }, 197 /* DoubleComplex */ { BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex }, 198 /* LongDoubleComplex */ { BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, }, 199 /* FloatImaginary */ { BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatImaginary, BasicType::DoubleImaginary, BasicType::LongDoubleImaginary, BasicType::FloatImaginary, BasicType::FloatImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, }, 200 /* DoubleImaginary */ { BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::DoubleImaginary, BasicType::DoubleImaginary, BasicType::LongDoubleImaginary, BasicType::DoubleImaginary, BasicType::DoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, }, 201 /* LongDoubleImaginary */ { BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, }, 202 /* SignedInt128 */ { BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::SignedInt128, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::SignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128, }, 203 /* UnsignedInt128 */ { BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::UnsignedInt128, BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128, }, 204 /* Float80 */ { BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::LongDouble, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::Float80, BasicType::Float80, BasicType::Float80, BasicType::Float128 }, 205 /* Float128 */ { BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::Float128, BasicType::Float128, BasicType::Float128, BasicType::Float128 }, 204 206 }; 207 static_assert( 208 sizeof(combinedType)/sizeof(combinedType[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES, 209 "Each basic type kind should have a corresponding row in the combined type matrix" 210 ); 205 211 206 212 CommonType::CommonType( Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) … … 232 238 AssertionSet need, have; 233 239 WidenMode widen( widenFirst, widenSecond ); 234 if ( entry != openVars.end() && ! bindVar(var, voidPointer->get_base(), entry->second, env, need, have, openVars, widen, indexer ) ) return;240 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return; 235 241 } 236 242 } -
TabularUnified src/ResolvExpr/ConversionCost.cc ¶
r0182bfa r28f3a19 229 229 */ 230 230 231 static const int costMatrix[ BasicType::NUMBER_OF_BASIC_TYPES ][ BasicType::NUMBER_OF_BASIC_TYPES ] = { 232 /* Src \ Dest: Bool Char SChar UChar Short UShort Int UInt Long ULong LLong ULLong Float Double LDbl FCplex DCplex LDCplex FImag DImag LDImag I128, U128 */ 233 /* Bool */ { 0, 1, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 12, 13, 14, 12, 13, 14, -1, -1, -1, 10, 11, }, 234 /* Char */ { -1, 0, -1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 11, 12, 13, 11, 12, 13, -1, -1, -1, 9, 10, }, 235 /* SChar */ { -1, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 11, 12, 13, 11, 12, 13, -1, -1, -1, 9, 10, }, 236 /* UChar */ { -1, -1, -1, 0, 1, 2, 3, 4, 4, 5, 6, 7, 10, 11, 12, 10, 11, 12, -1, -1, -1, 8, 9, }, 237 /* Short */ { -1, -1, -1, -1, 0, 1, 2, 3, 3, 4, 5, 6, 9, 10, 11, 9, 10, 11, -1, -1, -1, 7, 8, }, 238 /* UShort */{ -1, -1, -1, -1, -1, 0, 1, 2, 2, 3, 4, 5, 8, 9, 10, 8, 9, 10, -1, -1, -1, 6, 7, }, 239 /* Int */ { -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 3, 4, 7, 8, 9, 7, 8, 9, -1, -1, -1, 5, 6, }, 240 /* UInt */ { -1, -1, -1, -1, -1, -1, -1, 0, -1, 1, 2, 3, 6, 7, 8, 6, 7, 8, -1, -1, -1, 4, 5, }, 241 /* Long */ { -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 6, 7, 8, 6, 7, 8, -1, -1, -1, 4, 5, }, 242 /* ULong */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 5, 6, 7, 5, 6, 7, -1, -1, -1, 3, 4, }, 243 /* LLong */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 4, 5, 6, 4, 5, 6, -1, -1, -1, 2, 3, }, 244 /* ULLong */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 4, 5, 3, 4, 5, -1, -1, -1, 1, 2, }, 245 246 /* Float */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 1, 2, 3, -1, -1, -1, -1, -1, }, 247 /* Double */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, 1, 2, -1, -1, -1, -1, -1, }, 248 /* LDbl */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, -1, -1, -1, -1, -1, }, 249 /* FCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, -1, -1, -1, -1, }, 250 /* DCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, -1, -1, -1, -1, }, 251 /* LDCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, }, 252 /* FImag */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 3, 0, 1, 2, -1, -1, }, 253 /* DImag */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, -1, 0, 1, -1, -1, }, 254 /* LDImag */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0, -1, -1, }, 255 256 /* I128 */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 3, 4, 3, 4, 5, -1, -1, -1, 0, 1, }, 257 /* U128 */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 3, 2, 3, 4, -1, -1, -1, -1, 0, }, 231 static const int costMatrix[][ BasicType::NUMBER_OF_BASIC_TYPES ] = { 232 /* Src \ Dest: Bool Char SChar UChar Short UShort Int UInt Long ULong LLong ULLong Float Double LDbl FCplex DCplex LDCplex FImag DImag LDImag I128, U128, F80, F128 */ 233 /* Bool */ { 0, 1, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 12, 13, 14, 12, 13, 14, -1, -1, -1, 10, 11, 14, 15}, 234 /* Char */ { -1, 0, -1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 11, 12, 13, 11, 12, 13, -1, -1, -1, 9, 10, 13, 14}, 235 /* SChar */ { -1, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 11, 12, 13, 11, 12, 13, -1, -1, -1, 9, 10, 13, 14}, 236 /* UChar */ { -1, -1, -1, 0, 1, 2, 3, 4, 4, 5, 6, 7, 10, 11, 12, 10, 11, 12, -1, -1, -1, 8, 9, 12, 13}, 237 /* Short */ { -1, -1, -1, -1, 0, 1, 2, 3, 3, 4, 5, 6, 9, 10, 11, 9, 10, 11, -1, -1, -1, 7, 8, 11, 12}, 238 /* UShort */{ -1, -1, -1, -1, -1, 0, 1, 2, 2, 3, 4, 5, 8, 9, 10, 8, 9, 10, -1, -1, -1, 6, 7, 10, 11}, 239 /* Int */ { -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 3, 4, 7, 8, 9, 7, 8, 9, -1, -1, -1, 5, 6, 9, 10}, 240 /* UInt */ { -1, -1, -1, -1, -1, -1, -1, 0, -1, 1, 2, 3, 6, 7, 8, 6, 7, 8, -1, -1, -1, 4, 5, 8, 9}, 241 /* Long */ { -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 6, 7, 8, 6, 7, 8, -1, -1, -1, 4, 5, 8, 9}, 242 /* ULong */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 5, 6, 7, 5, 6, 7, -1, -1, -1, 3, 4, 7, 8}, 243 /* LLong */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 4, 5, 6, 4, 5, 6, -1, -1, -1, 2, 3, 6, 7}, 244 /* ULLong */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 4, 5, 3, 4, 5, -1, -1, -1, 1, 2, 5, 6}, 245 246 /* Float */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 1, 2, 3, -1, -1, -1, -1, -1, 2, 3}, 247 /* Double */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, 1, 2, -1, -1, -1, -1, -1, 1, 2}, 248 /* LDbl */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1}, 249 /* FCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, -1, -1, -1, -1, -1, -1}, 250 /* DCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, -1, -1, -1, -1, -1, -1}, 251 /* LDCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1}, 252 /* FImag */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 3, 0, 1, 2, -1, -1, -1, -1}, 253 /* DImag */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, -1, 0, 1, -1, -1, -1, -1}, 254 /* LDImag */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0, -1, -1, -1, -1}, 255 256 /* I128 */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 3, 4, 3, 4, 5, -1, -1, -1, 0, 1, 4, 4}, 257 /* U128 */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 3, 2, 3, 4, -1, -1, -1, -1, 0, 3, 3}, 258 259 /* F80 */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 0, 1}, 260 /* F128 */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 0}, 258 261 }; 262 static_assert( 263 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES, 264 "Each basic type kind should have a corresponding row in the cost matrix" 265 ); 266 259 267 260 268 void ConversionCost::postvisit( VoidType * ) { -
TabularUnified src/ResolvExpr/ExplodedActual.h ¶
r0182bfa r28f3a19 31 31 32 32 ExplodedActual() : env(), cost(Cost::zero), exprs() {} 33 34 33 ExplodedActual( const Alternative& actual, const SymTab::Indexer& indexer ); 34 ExplodedActual(ExplodedActual&&) = default; 35 ExplodedActual& operator= (ExplodedActual&&) = default; 35 36 }; 36 37 } -
TabularUnified src/ResolvExpr/Resolver.cc ¶
r0182bfa r28f3a19 211 211 if ( findDeletedExpr( choice.expr ) ) { 212 212 trace( choice.expr ); 213 SemanticError( choice.expr, "Unique best alternative includes deleted identifier in " );213 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " ); 214 214 } 215 215 alt = std::move( choice ); … … 246 246 247 247 auto untyped = new CastExpr{ expr }; // cast to void 248 untyped->location = expr->location; 248 249 249 250 // set up and resolve expression cast to void … … 271 272 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) { 272 273 assert( untyped && type ); 274 // transfer location to generated cast for error purposes 275 CodeLocation location = untyped->location; 273 276 untyped = new CastExpr( untyped, type ); 277 untyped->location = location; 274 278 findSingleExpression( untyped, indexer ); 275 279 removeExtraneousCast( untyped, indexer ); … … 574 578 575 579 // Make sure we don't widen any existing bindings 576 for ( auto & i : resultEnv ) { 577 i.allowWidening = false; 578 } 579 580 resultEnv.forbidWidening(); 581 580 582 // Find any unbound type variables 581 583 resultEnv.extractOpenVars( openVars ); -
TabularUnified src/ResolvExpr/Resolver.h ¶
r0182bfa r28f3a19 36 36 void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ); 37 37 void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ); 38 /// Searches expr and returns the first DeletedExpr found, otherwise nullptr 39 DeletedExpr * findDeletedExpr( Expression * expr ); 38 40 } // namespace ResolvExpr 39 41 -
TabularUnified src/ResolvExpr/TypeEnvironment.cc ¶
r0182bfa r28f3a19 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:19:47 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sun May 17 12:23:36 201513 // Update Count : 311 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 18 11:58:00 2018 13 // Update Count : 4 14 14 // 15 15 … … 24 24 #include "SynTree/Type.h" // for Type, FunctionType, Type::Fora... 25 25 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 26 #include "Tuples/Tuples.h" // for isTtype 26 27 #include "TypeEnvironment.h" 28 #include "typeops.h" // for occurs 29 #include "Unify.h" // for unifyInexact 27 30 28 31 namespace ResolvExpr { … … 46 49 47 50 void EqvClass::initialize( const EqvClass &src, EqvClass &dest ) { 51 initialize( src, dest, src.type ); 52 } 53 54 void EqvClass::initialize( const EqvClass &src, EqvClass &dest, const Type *ty ) { 48 55 dest.vars = src.vars; 49 dest.type = maybeClone( src.type);56 dest.type = maybeClone( ty ); 50 57 dest.allowWidening = src.allowWidening; 51 58 dest.data = src.data; 52 59 } 53 60 54 EqvClass::EqvClass() : type( 0), allowWidening( true ) {61 EqvClass::EqvClass() : type( nullptr ), allowWidening( true ) { 55 62 } 56 63 57 64 EqvClass::EqvClass( const EqvClass &other ) { 58 65 initialize( other, *this ); 66 } 67 68 EqvClass::EqvClass( const EqvClass &other, const Type *ty ) { 69 initialize( other, *this, ty ); 70 } 71 72 EqvClass::EqvClass( EqvClass &&other ) 73 : vars{std::move(other.vars)}, type{other.type}, 74 allowWidening{std::move(other.allowWidening)}, data{std::move(other.data)} { 75 other.type = nullptr; 59 76 } 60 77 … … 64 81 return *this; 65 82 } 83 84 EqvClass &EqvClass::operator=( EqvClass &&other ) { 85 if ( this == &other ) return *this; 86 87 vars = std::move(other.vars); 88 type = other.type; 89 allowWidening = std::move(other.allowWidening); 90 data = std::move(other.data); 91 92 return *this; 93 } 94 95 void EqvClass::set_type( Type* ty ) { type = ty; } 66 96 67 97 void EqvClass::print( std::ostream &os, Indenter indent ) const { … … 81 111 const EqvClass* TypeEnvironment::lookup( const std::string &var ) const { 82 112 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) { 83 if ( i->vars.find( var ) != i->vars.end() ) { 84 /// std::cout << var << " is in class "; 85 /// i->print( std::cout ); 86 return &*i; 87 } 88 /// std::cout << var << " is not in class "; 89 /// i->print( std::cout ); 113 if ( i->vars.find( var ) != i->vars.end() ) return &*i; 90 114 } // for 91 115 return nullptr; … … 105 129 } 106 130 107 void TypeEnvironment::add( const EqvClass &eqvClass ) {108 filterOverlappingClasses( env, eqvClass );109 env.push_back( eqvClass );110 }111 112 131 void TypeEnvironment::add( EqvClass &&eqvClass ) { 113 132 filterOverlappingClasses( env, eqvClass ); … … 120 139 newClass.vars.insert( (*i)->get_name() ); 121 140 newClass.data = TypeDecl::Data{ (*i) }; 122 env.push_back( newClass);141 env.push_back( std::move(newClass) ); 123 142 } // for 124 143 } … … 134 153 // transition to TypeSubstitution 135 154 newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false }; 136 add( newClass);155 add( std::move(newClass) ); 137 156 } 138 157 } … … 141 160 for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) { 142 161 for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) { 143 /// std::cerr << "adding " << *theVar;144 162 if ( theClass->type ) { 145 /// std::cerr << " bound to ";146 /// theClass->type->print( std::cerr );147 /// std::cerr << std::endl;148 163 sub.add( *theVar, theClass->type ); 149 164 } else if ( theVar != theClass->vars.begin() ) { 150 165 TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype ); 151 /// std::cerr << " bound to variable " << *theClass->vars.begin() << std::endl;152 166 sub.add( *theVar, newTypeInst ); 153 167 } // if 154 168 } // for 155 169 } // for 156 /// std::cerr << "input env is:" << std::endl;157 /// print( std::cerr, 8 );158 /// std::cerr << "sub is:" << std::endl;159 /// sub.print( std::cerr, 8 );160 170 sub.normalize(); 161 171 } 162 172 163 173 void TypeEnvironment::print( std::ostream &os, Indenter indent ) const { 164 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i) {165 i->print( os, indent );174 for ( const EqvClass & theClass : env ) { 175 theClass.print( os, indent ); 166 176 } // for 167 177 } … … 169 179 std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) { 170 180 for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) { 171 if ( i->vars.find( var ) == i->vars.end() ) { 172 return i; 173 } // if 181 if ( i->vars.count( var ) ) return i; 174 182 } // for 175 183 return env.end(); … … 178 186 void TypeEnvironment::simpleCombine( const TypeEnvironment &second ) { 179 187 env.insert( env.end(), second.env.begin(), second.env.end() ); 180 }181 182 void TypeEnvironment::combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) ) {183 TypeEnvironment secondCopy( second );184 for ( std::list< EqvClass >::iterator firstClass = env.begin(); firstClass != env.end(); ++firstClass ) {185 EqvClass &newClass = *firstClass;186 std::set< std::string > newVars;187 for ( std::set< std::string >::const_iterator var = firstClass->vars.begin(); var != firstClass->vars.end(); ++var ) {188 std::list< EqvClass >::iterator secondClass = secondCopy.internal_lookup( *var );189 if ( secondClass != secondCopy.env.end() ) {190 newVars.insert( secondClass->vars.begin(), secondClass->vars.end() );191 if ( secondClass->type ) {192 if ( newClass.type ) {193 newClass.type = combineFunc( newClass.type, secondClass->type );194 newClass.allowWidening = newClass.allowWidening && secondClass->allowWidening;195 } else {196 newClass.type = secondClass->type->clone();197 newClass.allowWidening = secondClass->allowWidening;198 } // if199 } // if200 secondCopy.env.erase( secondClass );201 } // if202 } // for203 newClass.vars.insert( newVars.begin(), newVars.end() );204 } // for205 for ( std::list< EqvClass >::iterator secondClass = secondCopy.env.begin(); secondClass != secondCopy.env.end(); ++secondClass ) {206 env.push_back( *secondClass );207 } // for208 188 } 209 189 … … 227 207 } 228 208 209 bool isFtype( Type *type ) { 210 if ( dynamic_cast< FunctionType* >( type ) ) { 211 return true; 212 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) { 213 return typeInst->get_isFtype(); 214 } // if 215 return false; 216 } 217 218 bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) { 219 switch ( data.kind ) { 220 case TypeDecl::Dtype: 221 // to bind to an object type variable, the type must not be a function type. 222 // if the type variable is specified to be a complete type then the incoming 223 // type must also be complete 224 // xxx - should this also check that type is not a tuple type and that it's not a ttype? 225 return ! isFtype( type ) && (! data.isComplete || type->isComplete() ); 226 case TypeDecl::Ftype: 227 return isFtype( type ); 228 case TypeDecl::Ttype: 229 // ttype unifies with any tuple type 230 return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type ); 231 } // switch 232 return false; 233 } 234 235 bool TypeEnvironment::bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 236 237 // remove references from other, so that type variables can only bind to value types 238 bindTo = bindTo->stripReferences(); 239 OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() ); 240 assert( tyvar != openVars.end() ); 241 if ( ! tyVarCompatible( tyvar->second, bindTo ) ) { 242 return false; 243 } // if 244 if ( occurs( bindTo, typeInst->get_name(), *this ) ) { 245 return false; 246 } // if 247 auto curClass = internal_lookup( typeInst->get_name() ); 248 if ( curClass != env.end() ) { 249 if ( curClass->type ) { 250 Type *common = 0; 251 // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to 252 Type *newType = curClass->type->clone(); 253 newType->get_qualifiers() = typeInst->get_qualifiers(); 254 if ( unifyInexact( newType, bindTo, *this, need, have, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) { 255 if ( common ) { 256 common->get_qualifiers() = Type::Qualifiers{}; 257 curClass->set_type( common ); 258 } // if 259 } else return false; 260 } else { 261 Type* newType = bindTo->clone(); 262 newType->get_qualifiers() = Type::Qualifiers{}; 263 curClass->set_type( newType ); 264 curClass->allowWidening = widenMode.widenFirst && widenMode.widenSecond; 265 } // if 266 } else { 267 EqvClass newClass; 268 newClass.vars.insert( typeInst->get_name() ); 269 newClass.type = bindTo->clone(); 270 newClass.type->get_qualifiers() = Type::Qualifiers(); 271 newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond; 272 newClass.data = data; 273 env.push_back( std::move(newClass) ); 274 } // if 275 return true; 276 } 277 278 bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 279 280 auto class1 = internal_lookup( var1->get_name() ); 281 auto class2 = internal_lookup( var2->get_name() ); 282 283 // exit early if variables already bound together 284 if ( class1 != env.end() && class1 == class2 ) { 285 class1->allowWidening &= widenMode; 286 return true; 287 } 288 289 bool widen1 = false, widen2 = false; 290 const Type *type1 = nullptr, *type2 = nullptr; 291 292 // check for existing bindings, perform occurs check 293 if ( class1 != env.end() ) { 294 if ( class1->type ) { 295 if ( occurs( class1->type, var2->get_name(), *this ) ) return false; 296 type1 = class1->type; 297 } // if 298 widen1 = widenMode.widenFirst && class1->allowWidening; 299 } // if 300 if ( class2 != env.end() ) { 301 if ( class2->type ) { 302 if ( occurs( class2->type, var1->get_name(), *this ) ) return false; 303 type2 = class2->type; 304 } // if 305 widen2 = widenMode.widenSecond && class2->allowWidening; 306 } // if 307 308 if ( type1 && type2 ) { 309 // both classes bound, merge if bound types can be unified 310 Type *newType1 = type1->clone(), *newType2 = type2->clone(); 311 WidenMode newWidenMode{ widen1, widen2 }; 312 Type *common = 0; 313 if ( unifyInexact( newType1, newType2, *this, need, have, openVars, newWidenMode, indexer, common ) ) { 314 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 315 class1->allowWidening = widen1 && widen2; 316 if ( common ) { 317 common->get_qualifiers() = Type::Qualifiers{}; 318 class1->set_type( common ); 319 } 320 env.erase( class2 ); 321 } else return false; 322 } else if ( class1 != env.end() && class2 != env.end() ) { 323 // both classes exist, at least one unbound, merge unconditionally 324 if ( type1 ) { 325 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 326 class1->allowWidening = widen1; 327 env.erase( class2 ); 328 } else { 329 class2->vars.insert( class1->vars.begin(), class1->vars.end() ); 330 class2->allowWidening = widen2; 331 env.erase( class1 ); 332 } // if 333 } else if ( class1 != env.end() ) { 334 // var2 unbound, add to class1 335 class1->vars.insert( var2->get_name() ); 336 class1->allowWidening = widen1; 337 } else if ( class2 != env.end() ) { 338 // var1 unbound, add to class2 339 class2->vars.insert( var1->get_name() ); 340 class2->allowWidening = widen2; 341 } else { 342 // neither var bound, create new class 343 EqvClass newClass; 344 newClass.vars.insert( var1->get_name() ); 345 newClass.vars.insert( var2->get_name() ); 346 newClass.allowWidening = widen1 && widen2; 347 newClass.data = data; 348 env.push_back( std::move(newClass) ); 349 } // if 350 return true; 351 } 352 353 void TypeEnvironment::forbidWidening() { 354 for ( EqvClass& c : env ) c.allowWidening = false; 355 } 356 229 357 std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) { 230 358 env.print( out ); -
TabularUnified src/ResolvExpr/TypeEnvironment.h ¶
r0182bfa r28f3a19 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:24:58 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:35:45 201713 // Update Count : 311 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 18 11:58:00 2018 13 // Update Count : 4 14 14 // 15 15 … … 21 21 #include <set> // for set 22 22 #include <string> // for string 23 #include <utility> // for move, swap 24 25 #include "WidenMode.h" // for WidenMode 23 26 24 27 #include "SynTree/Declaration.h" // for TypeDecl::Data, DeclarationWit... … … 77 80 78 81 void initialize( const EqvClass &src, EqvClass &dest ); 82 void initialize( const EqvClass &src, EqvClass &dest, const Type *ty ); 79 83 EqvClass(); 80 84 EqvClass( const EqvClass &other ); 85 EqvClass( const EqvClass &other, const Type *ty ); 86 EqvClass( EqvClass &&other ); 81 87 EqvClass &operator=( const EqvClass &other ); 88 EqvClass &operator=( EqvClass &&other ); 82 89 void print( std::ostream &os, Indenter indent = {} ) const; 90 91 /// Takes ownership of `ty`, freeing old `type` 92 void set_type(Type* ty); 83 93 }; 84 94 … … 86 96 public: 87 97 const EqvClass* lookup( const std::string &var ) const; 88 void add( const EqvClass &eqvClass );98 private: 89 99 void add( EqvClass &&eqvClass ); 100 public: 90 101 void add( const Type::ForallList &tyDecls ); 91 102 void add( const TypeSubstitution & sub ); … … 95 106 bool isEmpty() const { return env.empty(); } 96 107 void print( std::ostream &os, Indenter indent = {} ) const; 97 void combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) );108 // void combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) ); 98 109 void simpleCombine( const TypeEnvironment &second ); 99 110 void extractOpenVars( OpenVarSet &openVars ) const; … … 104 115 void addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ); 105 116 106 typedef std::list< EqvClass >::iterator iterator; 107 iterator begin() { return env.begin(); } 108 iterator end() { return env.end(); } 109 typedef std::list< EqvClass >::const_iterator const_iterator; 110 const_iterator begin() const { return env.begin(); } 111 const_iterator end() const { return env.end(); } 117 /// Binds the type class represented by `typeInst` to the type `bindTo`; will add 118 /// the class if needed. Returns false on failure. 119 bool bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ); 120 121 /// Binds the type classes represented by `var1` and `var2` together; will add 122 /// one or both classes if needed. Returns false on failure. 123 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ); 124 125 /// Disallows widening for all bindings in the environment 126 void forbidWidening(); 127 128 using iterator = std::list< EqvClass >::const_iterator; 129 iterator begin() const { return env.begin(); } 130 iterator end() const { return env.end(); } 131 112 132 private: 113 133 std::list< EqvClass > env; 134 114 135 std::list< EqvClass >::iterator internal_lookup( const std::string &var ); 115 136 }; -
TabularUnified src/ResolvExpr/Unify.cc ¶
r0182bfa r28f3a19 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:27:10 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Mar 16 16:22:54 201713 // Update Count : 4 211 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 18 11:58:00 2018 13 // Update Count : 43 14 14 // 15 15 … … 122 122 } 123 123 124 bool isFtype( Type *type ) {125 if ( dynamic_cast< FunctionType* >( type ) ) {126 return true;127 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {128 return typeInst->get_isFtype();129 } // if130 return false;131 }132 133 bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) {134 switch ( data.kind ) {135 case TypeDecl::Dtype:136 // to bind to an object type variable, the type must not be a function type.137 // if the type variable is specified to be a complete type then the incoming138 // type must also be complete139 // xxx - should this also check that type is not a tuple type and that it's not a ttype?140 return ! isFtype( type ) && (! data.isComplete || type->isComplete() );141 case TypeDecl::Ftype:142 return isFtype( type );143 case TypeDecl::Ttype:144 // ttype unifies with any tuple type145 return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type );146 } // switch147 return false;148 }149 150 bool bindVar( TypeInstType *typeInst, Type *other, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {151 // remove references from other, so that type variables can only bind to value types152 other = other->stripReferences();153 OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );154 assert( tyvar != openVars.end() );155 if ( ! tyVarCompatible( tyvar->second, other ) ) {156 return false;157 } // if158 if ( occurs( other, typeInst->get_name(), env ) ) {159 return false;160 } // if161 if ( const EqvClass *curClass = env.lookup( typeInst->get_name() ) ) {162 if ( curClass->type ) {163 Type *common = 0;164 // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to165 Type* newType = curClass->type->clone();166 newType->get_qualifiers() = typeInst->get_qualifiers();167 if ( unifyInexact( newType, other, env, needAssertions, haveAssertions, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) {168 if ( common ) {169 common->get_qualifiers() = Type::Qualifiers();170 EqvClass newClass = *curClass;171 newClass.type = common;172 env.add( std::move(newClass) );173 } // if174 return true;175 } else {176 return false;177 } // if178 } else {179 EqvClass newClass = *curClass;180 newClass.type = other->clone();181 newClass.type->get_qualifiers() = Type::Qualifiers();182 newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;183 env.add( std::move(newClass) );184 } // if185 } else {186 EqvClass newClass;187 newClass.vars.insert( typeInst->get_name() );188 newClass.type = other->clone();189 newClass.type->get_qualifiers() = Type::Qualifiers();190 newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;191 newClass.data = data;192 env.add( newClass );193 } // if194 return true;195 }196 197 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {198 bool result = true;199 const EqvClass *class1 = env.lookup( var1->get_name() );200 const EqvClass *class2 = env.lookup( var2->get_name() );201 bool widen1 = false, widen2 = false;202 Type *type1 = nullptr, *type2 = nullptr;203 204 if ( class1 ) {205 if ( class1->type ) {206 if ( occurs( class1->type, var2->get_name(), env ) ) {207 return false;208 } // if209 type1 = class1->type->clone();210 } // if211 widen1 = widenMode.widenFirst && class1->allowWidening;212 } // if213 if ( class2 ) {214 if ( class2->type ) {215 if ( occurs( class2->type, var1->get_name(), env ) ) {216 return false;217 } // if218 type2 = class2->type->clone();219 } // if220 widen2 = widenMode.widenSecond && class2->allowWidening;221 } // if222 223 if ( type1 && type2 ) {224 // std::cerr << "has type1 && type2" << std::endl;225 WidenMode newWidenMode ( widen1, widen2 );226 Type *common = 0;227 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, newWidenMode, indexer, common ) ) {228 EqvClass newClass1 = *class1;229 newClass1.vars.insert( class2->vars.begin(), class2->vars.end() );230 newClass1.allowWidening = widen1 && widen2;231 if ( common ) {232 common->get_qualifiers() = Type::Qualifiers();233 newClass1.type = common;234 } // if235 env.add( std::move(newClass1) );236 } else {237 result = false;238 } // if239 } else if ( class1 && class2 ) {240 if ( type1 ) {241 EqvClass newClass1 = *class1;242 newClass1.vars.insert( class2->vars.begin(), class2->vars.end() );243 newClass1.allowWidening = widen1;244 env.add( std::move(newClass1) );245 } else {246 EqvClass newClass2 = *class2;247 newClass2.vars.insert( class1->vars.begin(), class1->vars.end() );248 newClass2.allowWidening = widen2;249 env.add( std::move(newClass2) );250 } // if251 } else if ( class1 ) {252 EqvClass newClass1 = *class1;253 newClass1.vars.insert( var2->get_name() );254 newClass1.allowWidening = widen1;255 env.add( std::move(newClass1) );256 } else if ( class2 ) {257 EqvClass newClass2 = *class2;258 newClass2.vars.insert( var1->get_name() );259 newClass2.allowWidening = widen2;260 env.add( std::move(newClass2) );261 } else {262 EqvClass newClass;263 newClass.vars.insert( var1->get_name() );264 newClass.vars.insert( var2->get_name() );265 newClass.allowWidening = widen1 && widen2;266 newClass.data = data;267 env.add( newClass );268 } // if269 return result;270 }271 272 124 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 273 125 OpenVarSet closedVars; … … 307 159 308 160 if ( isopen1 && isopen2 && entry1->second == entry2->second ) { 309 result = bindVarToVar( var1, var2, entry1->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );161 result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer ); 310 162 } else if ( isopen1 ) { 311 result = bindVar( var1, type2, entry1->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );163 result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer ); 312 164 } else if ( isopen2 ) { // TODO: swap widenMode values in call, since type positions are flipped? 313 result = bindVar( var2, type1, entry2->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );165 result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widenMode, indexer ); 314 166 } else { 315 167 PassVisitor<Unify> comparator( type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer ); -
TabularUnified src/ResolvExpr/Unify.h ¶
r0182bfa r28f3a19 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 13:09:04 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Jul 21 23:09:34 201713 // Update Count : 311 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 18 11:58:00 2018 13 // Update Count : 4 14 14 // 15 15 … … 21 21 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data 22 22 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet 23 #include "WidenMode.h" // for WidenMode 23 24 24 25 class Type; … … 29 30 30 31 namespace ResolvExpr { 31 struct WidenMode {32 WidenMode( bool widenFirst, bool widenSecond ): widenFirst( widenFirst ), widenSecond( widenSecond ) {}33 WidenMode &operator|=( const WidenMode &other ) { widenFirst |= other.widenFirst; widenSecond |= other.widenSecond; return *this; }34 WidenMode &operator&=( const WidenMode &other ) { widenFirst &= other.widenFirst; widenSecond &= other.widenSecond; return *this; }35 WidenMode operator|( const WidenMode &other ) { WidenMode newWM( *this ); newWM |= other; return newWM; }36 WidenMode operator&( const WidenMode &other ) { WidenMode newWM( *this ); newWM &= other; return newWM; }37 operator bool() { return widenFirst && widenSecond; }38 39 bool widenFirst : 1, widenSecond : 1;40 };41 42 bool bindVar( TypeInstType *typeInst, Type *other, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );43 32 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ); 44 33 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ); 45 34 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ); 35 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer, Type *&common ); 46 36 47 37 template< typename Iterator1, typename Iterator2 > -
TabularUnified src/SymTab/Indexer.cc ¶
r0182bfa r28f3a19 106 106 if ( ! CodeGen::isCtorDtorAssign( id ) ) return; 107 107 108 // helpful data structure 108 // helpful data structure to organize properties for a type 109 109 struct ValueType { 110 struct DeclBall { 110 struct DeclBall { // properties for this particular decl 111 111 IdData decl; 112 bool isUserDefinedFunc; // properties for this particular decl 113 bool isDefaultCtor; 114 bool isDtor; 112 bool isUserDefinedFunc; 115 113 bool isCopyFunc; 116 114 }; 117 115 // properties for this type 118 bool existsUserDefinedFunc = false; // any user-defined function found119 bool existsUserDefinedCtor = false; // any user-defined constructor found120 bool existsUserDefinedDtor = false; // any user-defined destructor found121 116 bool existsUserDefinedCopyFunc = false; // user-defined copy ctor found 122 bool existsUserDefinedDefaultCtor = false; // user-defined default ctorfound117 BaseSyntaxNode * deleteStmt = nullptr; // non-null if a user-defined function is found 123 118 std::list< DeclBall > decls; 124 119 … … 127 122 ValueType & operator+=( IdData data ) { 128 123 DeclarationWithType * function = data.id; 129 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->get_linkage() ); 130 bool isDefaultCtor = InitTweak::isDefaultConstructor( function ); 131 bool isDtor = InitTweak::isDestructor( function ); 132 bool isCopyFunc = InitTweak::isCopyFunction( function, function->get_name() ); 133 decls.push_back( DeclBall{ data, isUserDefinedFunc, isDefaultCtor, isDtor, isCopyFunc } ); 134 existsUserDefinedFunc = existsUserDefinedFunc || isUserDefinedFunc; 135 existsUserDefinedCtor = existsUserDefinedCtor || (isUserDefinedFunc && CodeGen::isConstructor( function->get_name() ) ); 136 existsUserDefinedDtor = existsUserDefinedDtor || (isUserDefinedFunc && isDtor); 124 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage ); 125 bool isCopyFunc = InitTweak::isCopyFunction( function, function->name ); 126 decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } ); 137 127 existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc); 138 existsUserDefinedDefaultCtor = existsUserDefinedDefaultCtor || (isUserDefinedFunc && isDefaultCtor); 128 if ( isUserDefinedFunc && ! deleteStmt ) { 129 // any user-defined function can act as an implicit delete statement for generated constructors. 130 // a delete stmt should not act as an implicit delete statement. 131 deleteStmt = data.id; 132 } 139 133 return *this; 140 134 } … … 148 142 for ( auto decl : copy ) { 149 143 if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) { 150 std::list< DeclarationWithType * > & params = function-> get_functionType()->get_parameters();144 std::list< DeclarationWithType * > & params = function->type->parameters; 151 145 assert( ! params.empty() ); 152 146 // use base type of pointer, so that qualifiers on the pointer type aren't considered. … … 160 154 161 155 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine 162 // the set of ctor/dtor/assign that are seen by the requester. In particular, if the user defines 163 // a default ctor, then the generated default ctor should never be seen, likewise for copy ctor 164 // and dtor. If the user defines any ctor/dtor, then no generated field ctors should be seen. 165 // If the user defines any ctor then the generated default ctor should not be seen (intrinsic default 166 // ctor must be overridden exactly). 156 // the set of ctor/dtor/assign that can be used by the requester. In particular, if the user defines 157 // a default ctor, then the generated default ctor is unavailable, likewise for copy ctor 158 // and dtor. If the user defines any ctor/dtor, then no generated field ctors are available. 159 // If the user defines any ctor then the generated default ctor is unavailable (intrinsic default 160 // ctor must be overridden exactly). If the user defines anything that looks like a copy constructor, 161 // then the generated copy constructor is unavailable, and likewise for the assignment operator. 167 162 for ( std::pair< const std::string, ValueType > & pair : funcMap ) { 168 163 ValueType & val = pair.second; 169 164 for ( ValueType::DeclBall ball : val.decls ) { 170 bool noUserDefinedFunc = ! val.existsUserDefinedFunc; 171 bool isUserDefinedFunc = ball.isUserDefinedFunc; 172 bool isAcceptableDefaultCtor = (! val.existsUserDefinedCtor || (! val.existsUserDefinedDefaultCtor && ball.decl.id->get_linkage() == LinkageSpec::Intrinsic)) && ball.isDefaultCtor; // allow default constructors only when no user-defined constructors exist, except in the case of intrinsics, which require exact overrides 173 bool isAcceptableCopyFunc = ! val.existsUserDefinedCopyFunc && ball.isCopyFunc; // handles copy ctor and assignment operator 174 bool isAcceptableDtor = ! val.existsUserDefinedDtor && ball.isDtor; 175 if ( noUserDefinedFunc || isUserDefinedFunc || isAcceptableDefaultCtor || isAcceptableCopyFunc || isAcceptableDtor ) { 176 // decl conforms to the rules described above, so it should be seen by the requester 177 out.push_back( ball.decl ); 165 bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic; 166 bool isCopyFunc = ball.isCopyFunc; 167 bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc; 168 169 // only implicitly delete non-user defined functions that are not intrinsic, and are 170 // not copy functions (assignment or copy constructor). If a user-defined copy function exists, 171 // do not pass along the non-user-defined copy functions since signatures do not have to match, 172 // and the generated functions will often be cheaper. 173 if ( isNotUserDefinedFunc ) { 174 if ( isCopyFunc ) { 175 // Skip over non-user-defined copy functions when there is a user-defined copy function. 176 // Since their signatures do not have to be exact, deleting them is the wrong choice. 177 if ( existsUserDefinedCopyFunc ) continue; 178 } else { 179 // delete non-user-defined non-copy functions if applicable. 180 // deleteStmt will be non-null only if a user-defined function is found. 181 ball.decl.deleteStmt = val.deleteStmt; 182 } 178 183 } 184 out.push_back( ball.decl ); 179 185 } 180 186 } … … 471 477 void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) { 472 478 // default handling of conflicts is to raise an error 473 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr );479 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr ); 474 480 } 475 481 -
TabularUnified src/SymTab/Mangler.cc ¶
r0182bfa r28f3a19 171 171 "w", // SignedInt128 172 172 "Uw", // UnsignedInt128 173 "x", // Float80 174 "y", // Float128 173 175 }; 176 static_assert( 177 sizeof(btLetter)/sizeof(btLetter[0]) == BasicType::NUMBER_OF_BASIC_TYPES, 178 "Each basic type kind should have a corresponding mangler letter" 179 ); 174 180 175 181 printQualifiers( basicType ); 182 assert( basicType->get_kind() < sizeof(btLetter)/sizeof(btLetter[0]) ); 176 183 mangleName << btLetter[ basicType->get_kind() ]; 177 184 } … … 218 225 GuardValue( inFunctionType ); 219 226 inFunctionType = true; 220 std::list< Type* > returnTypes = getTypes( functionType-> get_returnVals());227 std::list< Type* > returnTypes = getTypes( functionType->returnVals ); 221 228 acceptAll( returnTypes, *visitor ); 222 229 mangleName << "_"; 223 std::list< Type* > paramTypes = getTypes( functionType-> get_parameters());230 std::list< Type* > paramTypes = getTypes( functionType->parameters ); 224 231 acceptAll( paramTypes, *visitor ); 225 232 mangleName << "_"; … … 229 236 printQualifiers( refType ); 230 237 231 mangleName << ( refType-> get_name().length() + prefix.length() ) << prefix << refType->get_name();238 mangleName << ( refType->name.length() + prefix.length() ) << prefix << refType->name; 232 239 233 240 if ( mangleGenericParams ) { 234 std::list< Expression* >& params = refType-> get_parameters();241 std::list< Expression* >& params = refType->parameters; 235 242 if ( ! params.empty() ) { 236 243 mangleName << "_"; 237 244 for ( std::list< Expression* >::const_iterator param = params.begin(); param != params.end(); ++param ) { 238 245 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); 239 assertf(paramType, "Aggregate parameters should be type expressions: %s", to String(*param).c_str());240 maybeAccept( paramType-> get_type(), *visitor );246 assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(*param)); 247 maybeAccept( paramType->type, *visitor ); 241 248 } 242 249 mangleName << "_"; -
TabularUnified src/SymTab/Validate.cc ¶
r0182bfa r28f3a19 49 49 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign 50 50 #include "Common/GC.h" // for new_static_root, register_static_root 51 #include "ControlStruct/Mutate.h" // for ForExprMutator 51 52 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd 52 53 #include "Common/ScopedMap.h" // for ScopedMap … … 77 78 class SwitchStmt; 78 79 79 80 80 #define debugPrint( x ) if ( doDebug ) { std::cout << x; } 81 81 … … 275 275 Concurrency::applyKeywords( translationUnit ); 276 276 acceptAll( translationUnit, fpd ); // must happen before autogenerateRoutines, after Concurrency::applyKeywords because uniqueIds must be set on declaration before resolution 277 ControlStruct::hoistControlDecls( translationUnit ); // hoist initialization out of for statements; must happen before autogenerateRoutines 277 278 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay 278 279 Concurrency::implementMutexFuncs( translationUnit ); -
TabularUnified src/SynTree/BasicType.cc ¶
r0182bfa r28f3a19 55 55 case DoubleImaginary: 56 56 case LongDoubleImaginary: 57 case Float80: 58 case Float128: 57 59 return false; 58 60 case NUMBER_OF_BASIC_TYPES: -
TabularUnified src/SynTree/Declaration.cc ¶
r0182bfa r28f3a19 92 92 } 93 93 94 94 95 // Local Variables: // 95 96 // tab-width: 4 // -
TabularUnified src/SynTree/Declaration.h ¶
r0182bfa r28f3a19 83 83 Expression *asmName; 84 84 std::list< Attribute * > attributes; 85 bool isDeleted = false; 85 86 86 87 DeclarationWithType( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage, const std::list< Attribute * > & attributes, Type::FuncSpecifiers fs ); -
TabularUnified src/SynTree/Expression.cc ¶
r0182bfa r28f3a19 640 640 641 641 642 DefaultArgExpr::DefaultArgExpr( Expression * expr ) : expr( expr ) { 643 assert( expr->result ); 644 result = expr->result->clone(); 645 } 646 DefaultArgExpr::DefaultArgExpr( const DefaultArgExpr & other ) : Expression( other ), expr( maybeClone( other.expr ) ) {} 647 648 void DefaultArgExpr::print( std::ostream & os, Indenter indent ) const { 649 os << "Default Argument Expression" << std::endl << indent+1; 650 expr->print( os, indent+1 ); 651 } 652 653 GenericExpr::Association::Association( Type * type, Expression * expr ) : type( type ), expr( expr ), isDefault( false ) {} 654 GenericExpr::Association::Association( Expression * expr ) : type( nullptr ), expr( expr ), isDefault( true ) {} 655 GenericExpr::Association::Association( const Association & other ) : type( maybeClone( other.type ) ), expr( maybeClone( other.expr ) ), isDefault( other.isDefault ) {} 656 657 GenericExpr::GenericExpr( Expression * control, const std::list<Association> & assoc ) : Expression(), control( control ), associations( assoc ) {} 658 GenericExpr::GenericExpr( const GenericExpr & other ) : Expression(other), control( maybeClone( other.control ) ), associations( other.associations ) {} 659 GenericExpr::~GenericExpr() {} 660 661 void GenericExpr::print( std::ostream & os, Indenter indent ) const { 662 os << "C11 _Generic Expression" << std::endl << indent+1; 663 control->print( os, indent+1 ); 664 os << std::endl << indent+1 << "... with associations: " << std::endl; 665 for ( const Association & assoc : associations ) { 666 os << indent+1; 667 if (assoc.isDefault) { 668 os << "... default: "; 669 assoc.expr->print( os, indent+1 ); 670 } else { 671 os << "... type: "; 672 assoc.type->print( os, indent+1 ); 673 os << std::endl << indent+1 << "... expression: "; 674 assoc.expr->print( os, indent+1 ); 675 os << std::endl; 676 } 677 os << std::endl; 678 } 679 } 680 642 681 // Local Variables: // 643 682 // tab-width: 4 // -
TabularUnified src/SynTree/Expression.h ¶
r0182bfa r28f3a19 833 833 }; 834 834 835 /// expression wrapping the use of a default argument - should never make it past the resolver. 836 class DefaultArgExpr : public Expression { 837 public: 838 Expression * expr; 839 840 DefaultArgExpr( Expression * expr ); 841 DefaultArgExpr( const DefaultArgExpr & other ); 842 843 virtual DefaultArgExpr * clone() const { return new DefaultArgExpr( * this ); } 844 virtual void accept( Visitor & v ) { v.visit( this ); } 845 virtual Expression * acceptMutator( Mutator & m ) { return m.mutate( this ); } 846 virtual void print( std::ostream & os, Indenter indent = {} ) const; 847 }; 848 849 /// C11 _Generic expression 850 class GenericExpr : public Expression { 851 public: 852 struct Association { 853 Type * type = nullptr; 854 Expression * expr = nullptr; 855 bool isDefault = false; 856 857 Association( Type * type, Expression * expr ); 858 Association( Expression * expr ); 859 Association( const Association & other ); 860 Association & operator=( const Association & other ) = delete; // at the moment this isn't used, and I don't want to implement it 861 }; 862 863 Expression * control; 864 std::list<Association> associations; 865 866 GenericExpr( Expression * control, const std::list<Association> & assoc ); 867 GenericExpr( const GenericExpr & other ); 868 ~GenericExpr(); 869 870 virtual GenericExpr * clone() const { return new GenericExpr( * this ); } 871 virtual void accept( Visitor & v ) { v.visit( this ); } 872 virtual Expression * acceptMutator( Mutator & m ) { return m.mutate( this ); } 873 virtual void print( std::ostream & os, Indenter indent = {} ) const; 874 }; 875 835 876 // Local Variables: // 836 877 // tab-width: 4 // -
TabularUnified src/SynTree/Mutator.h ¶
r0182bfa r28f3a19 93 93 virtual Expression * mutate( InitExpr * initExpr ) = 0; 94 94 virtual Expression * mutate( DeletedExpr * delExpr ) = 0; 95 virtual Expression * mutate( DefaultArgExpr * argExpr ) = 0; 96 virtual Expression * mutate( GenericExpr * genExpr ) = 0; 95 97 96 98 virtual Type * mutate( VoidType * basicType ) = 0; -
TabularUnified src/SynTree/ReferenceToType.cc ¶
r0182bfa r28f3a19 46 46 47 47 namespace { 48 void doLookup( const std::list< Declaration * > &members, const std::string &name, std::list< Declaration* > &foundDecls ) {49 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i) {50 if ( (*i)->get_name()== name ) {51 foundDecls.push_back( *i);48 void doLookup( const std::list< Declaration * > & members, const std::string & name, std::list< Declaration* > & foundDecls ) { 49 for ( Declaration * decl : members ) { 50 if ( decl->name == name ) { 51 foundDecls.push_back( decl ); 52 52 } // if 53 53 } // for … … 56 56 57 57 StructInstType::StructInstType( const Type::Qualifiers & tq, StructDecl * baseStruct, const std::list< Attribute * > & attributes ) : 58 Parent( tq, baseStruct-> get_name(), attributes ), baseStruct( baseStruct ) {}58 Parent( tq, baseStruct->name, attributes ), baseStruct( baseStruct ) {} 59 59 60 60 std::string StructInstType::typeString() const { return "struct"; } … … 80 80 void StructInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const { 81 81 assert( baseStruct ); 82 doLookup( baseStruct-> get_members(), name, foundDecls );82 doLookup( baseStruct->members, name, foundDecls ); 83 83 } 84 84 … … 99 99 100 100 UnionInstType::UnionInstType( const Type::Qualifiers & tq, UnionDecl * baseUnion, const std::list< Attribute * > & attributes ) : 101 Parent( tq, baseUnion-> get_name(), attributes ), baseUnion( baseUnion ) {}101 Parent( tq, baseUnion->name, attributes ), baseUnion( baseUnion ) {} 102 102 103 103 std::string UnionInstType::typeString() const { return "union"; } … … 123 123 void UnionInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const { 124 124 assert( baseUnion ); 125 doLookup( baseUnion-> get_members(), name, foundDecls );125 doLookup( baseUnion->members, name, foundDecls ); 126 126 } 127 127 -
TabularUnified src/SynTree/Statement.cc ¶
r0182bfa r28f3a19 208 208 } 209 209 210 WhileStmt::WhileStmt( Expression *condition, Statement *body, bool isDoWhile ):211 Statement(), condition( condition), body( body), i sDoWhile( isDoWhile) {210 WhileStmt::WhileStmt( Expression *condition, Statement *body, std::list< Statement * > & initialization, bool isDoWhile ): 211 Statement(), condition( condition), body( body), initialization( initialization ), isDoWhile( isDoWhile) { 212 212 } 213 213 -
TabularUnified src/SynTree/Statement.h ¶
r0182bfa r28f3a19 213 213 Expression *condition; 214 214 Statement *body; 215 std::list<Statement *> initialization; 215 216 bool isDoWhile; 216 217 217 218 WhileStmt( Expression *condition, 218 Statement *body, bool isDoWhile = false );219 Statement *body, std::list<Statement *> & initialization, bool isDoWhile = false ); 219 220 WhileStmt( const WhileStmt &other ); 220 221 -
TabularUnified src/SynTree/SynTree.h ¶
r0182bfa r28f3a19 101 101 class InitExpr; 102 102 class DeletedExpr; 103 class DefaultArgExpr; 104 class GenericExpr; 103 105 104 106 class Type; -
TabularUnified src/SynTree/Type.cc ¶
r0182bfa r28f3a19 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Sep 25 15:16:32 201713 // Update Count : 3 812 // Last Modified On : Fri Jun 22 10:17:19 2018 13 // Update Count : 39 14 14 // 15 15 #include "Type.h" … … 24 24 using namespace std; 25 25 26 const char *BasicType::typeNames[ BasicType::NUMBER_OF_BASIC_TYPES] = {26 const char *BasicType::typeNames[] = { 27 27 "_Bool", 28 28 "char", … … 48 48 "__int128", 49 49 "unsigned __int128", 50 "__float80", 51 "__float128" 50 52 }; 53 static_assert( 54 sizeof(BasicType::typeNames)/sizeof(BasicType::typeNames[0]) == BasicType::NUMBER_OF_BASIC_TYPES, 55 "Each basic type name should have a corresponding kind enum value" 56 ); 51 57 52 58 Type::Type( const Qualifiers &tq, const std::list< Attribute * > & attributes ) : tq( tq ), attributes( attributes ) {} … … 58 64 59 65 // These must remain in the same order as the corresponding bit fields. 60 const char * Type::FuncSpecifiersNames[] = { "inline", " fortran", "_Noreturn" };66 const char * Type::FuncSpecifiersNames[] = { "inline", "_Noreturn", "fortran" }; 61 67 const char * Type::StorageClassesNames[] = { "extern", "static", "auto", "register", "_Thread_local" }; 62 68 const char * Type::QualifiersNames[] = { "const", "restrict", "volatile", "lvalue", "mutex", "_Atomic" }; -
TabularUnified src/SynTree/Type.h ¶
r0182bfa r28f3a19 230 230 SignedInt128, 231 231 UnsignedInt128, 232 Float80, 233 Float128, 232 234 NUMBER_OF_BASIC_TYPES 233 235 } kind; -
TabularUnified src/SynTree/Visitor.h ¶
r0182bfa r28f3a19 95 95 virtual void visit( InitExpr * initExpr ) = 0; 96 96 virtual void visit( DeletedExpr * delExpr ) = 0; 97 virtual void visit( DefaultArgExpr * argExpr ) = 0; 98 virtual void visit( GenericExpr * genExpr ) = 0; 97 99 98 100 virtual void visit( VoidType * basicType ) = 0; -
TabularUnified src/benchmark/Makefile.am ¶
r0182bfa r28f3a19 92 92 93 93 ## ========================================================================================================= 94 loop$(EXEEXT): 95 @@BACKEND_CC@ loop.c -DBENCH_N=5000000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 96 97 function$(EXEEXT): 98 @@BACKEND_CC@ function.c -DBENCH_N=5000000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 99 100 fetch_add$(EXEEXT): 101 @@BACKEND_CC@ fetch_add.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 102 103 ## ========================================================================================================= 94 104 ctxswitch$(EXEEXT): \ 105 loop.run \ 106 function.run \ 107 fetch_add.run \ 95 108 ctxswitch-pthread.run \ 96 109 ctxswitch-cfa_coroutine.run \ 97 110 ctxswitch-cfa_thread.run \ 111 ctxswitch-cfa_thread2.run \ 98 112 ctxswitch-upp_coroutine.run \ 99 113 ctxswitch-upp_thread.run \ 114 -ctxswitch-kos_fibre.run \ 115 -ctxswitch-kos_fibre2.run \ 100 116 ctxswitch-goroutine.run \ 101 117 ctxswitch-java_thread.run 102 118 119 ctxswitch-pthread$(EXEEXT): 120 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 121 103 122 ctxswitch-cfa_coroutine$(EXEEXT): 104 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}123 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 105 124 106 125 ctxswitch-cfa_thread$(EXEEXT): 107 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 126 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 127 128 ctxswitch-cfa_thread2$(EXEEXT): 129 @${CC} ctxswitch/cfa_thrd2.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 108 130 109 131 ctxswitch-upp_coroutine$(EXEEXT): 110 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags}132 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 111 133 112 134 ctxswitch-upp_thread$(EXEEXT): 113 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 114 115 ctxswitch-pthread$(EXEEXT): 116 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 135 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 136 137 ctxswitch-kos_fibre$(EXEEXT): 138 @${CXX} ctxswitch/kos_fibre.cpp -DBENCH_N=50000000 -I. -I/home/tdelisle/software/KOS/src/ -g -O2 -lfibre -lpthread -lrt 139 140 ctxswitch-kos_fibre2$(EXEEXT): 141 @${CXX} ctxswitch/kos_fibre2.cpp -DBENCH_N=50000000 -I. -I/home/tdelisle/software/KOS/src/ -g -O2 -lfibre -lpthread -lrt 117 142 118 143 ctxswitch-goroutine$(EXEEXT): … … 127 152 ## ========================================================================================================= 128 153 mutex$(EXEEXT) :\ 129 mutex-function.run \ 130 mutex-fetch_add.run \ 154 loop.run \ 155 function.run \ 156 fetch_add.run \ 131 157 mutex-pthread_lock.run \ 132 158 mutex-upp.run \ … … 135 161 mutex-cfa4.run \ 136 162 mutex-java_thread.run 137 138 mutex-function$(EXEEXT):139 @@BACKEND_CC@ mutex/function.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags}140 141 mutex-fetch_add$(EXEEXT):142 @@BACKEND_CC@ mutex/fetch_add.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags}143 163 144 164 mutex-pthread_lock$(EXEEXT): … … 277 297 278 298 compile-io$(EXEEXT): 279 @${CC} -quiet -fsyntax-only -w ../tests/io .c@CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}299 @${CC} -quiet -fsyntax-only -w ../tests/io1.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 280 300 281 301 compile-monitor$(EXEEXT): 282 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c 302 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 283 303 284 304 compile-operators$(EXEEXT): … … 289 309 290 310 compile-typeof$(EXEEXT): 291 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c 292 311 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 312 -
TabularUnified src/benchmark/Makefile.in ¶
r0182bfa r28f3a19 505 505 @echo "}" 506 506 507 loop$(EXEEXT): 508 @@BACKEND_CC@ loop.c -DBENCH_N=5000000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 509 510 function$(EXEEXT): 511 @@BACKEND_CC@ function.c -DBENCH_N=5000000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 512 513 fetch_add$(EXEEXT): 514 @@BACKEND_CC@ fetch_add.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 515 507 516 ctxswitch$(EXEEXT): \ 517 loop.run \ 518 function.run \ 519 fetch_add.run \ 508 520 ctxswitch-pthread.run \ 509 521 ctxswitch-cfa_coroutine.run \ 510 522 ctxswitch-cfa_thread.run \ 523 ctxswitch-cfa_thread2.run \ 511 524 ctxswitch-upp_coroutine.run \ 512 525 ctxswitch-upp_thread.run \ 526 -ctxswitch-kos_fibre.run \ 527 -ctxswitch-kos_fibre2.run \ 513 528 ctxswitch-goroutine.run \ 514 529 ctxswitch-java_thread.run 515 530 531 ctxswitch-pthread$(EXEEXT): 532 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 533 516 534 ctxswitch-cfa_coroutine$(EXEEXT): 517 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}535 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 518 536 519 537 ctxswitch-cfa_thread$(EXEEXT): 520 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 538 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 539 540 ctxswitch-cfa_thread2$(EXEEXT): 541 @${CC} ctxswitch/cfa_thrd2.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 521 542 522 543 ctxswitch-upp_coroutine$(EXEEXT): 523 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags}544 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 524 545 525 546 ctxswitch-upp_thread$(EXEEXT): 526 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 527 528 ctxswitch-pthread$(EXEEXT): 529 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 547 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 548 549 ctxswitch-kos_fibre$(EXEEXT): 550 @${CXX} ctxswitch/kos_fibre.cpp -DBENCH_N=50000000 -I. -I/home/tdelisle/software/KOS/src/ -g -O2 -lfibre -lpthread -lrt 551 552 ctxswitch-kos_fibre2$(EXEEXT): 553 @${CXX} ctxswitch/kos_fibre2.cpp -DBENCH_N=50000000 -I. -I/home/tdelisle/software/KOS/src/ -g -O2 -lfibre -lpthread -lrt 530 554 531 555 ctxswitch-goroutine$(EXEEXT): … … 539 563 540 564 mutex$(EXEEXT) :\ 541 mutex-function.run \ 542 mutex-fetch_add.run \ 565 loop.run \ 566 function.run \ 567 fetch_add.run \ 543 568 mutex-pthread_lock.run \ 544 569 mutex-upp.run \ … … 547 572 mutex-cfa4.run \ 548 573 mutex-java_thread.run 549 550 mutex-function$(EXEEXT):551 @@BACKEND_CC@ mutex/function.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags}552 553 mutex-fetch_add$(EXEEXT):554 @@BACKEND_CC@ mutex/fetch_add.c -DBENCH_N=500000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags}555 574 556 575 mutex-pthread_lock$(EXEEXT): … … 682 701 683 702 compile-io$(EXEEXT): 684 @${CC} -quiet -fsyntax-only -w ../tests/io .c@CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}703 @${CC} -quiet -fsyntax-only -w ../tests/io1.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 685 704 686 705 compile-monitor$(EXEEXT): 687 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c 706 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 688 707 689 708 compile-operators$(EXEEXT): … … 694 713 695 714 compile-typeof$(EXEEXT): 696 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c 715 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 697 716 698 717 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
TabularUnified src/benchmark/function.c ¶
r0182bfa r28f3a19 4 4 5 5 void __attribute__((noinline)) do_call() { 6 asm volatile ("");6 asm volatile("" ::: "memory"); 7 7 } 8 8 -
TabularUnified src/libcfa/Makefile.am ¶
r0182bfa r28f3a19 51 51 # not all platforms support concurrency, add option do disable it 52 52 if BUILD_CONCURRENCY 53 headers += concurrency/coroutine concurrency/thread concurrency/kernel concurrency/monitor 53 headers += concurrency/coroutine concurrency/thread concurrency/kernel concurrency/monitor concurrency/mutex 54 54 endif 55 55 -
TabularUnified src/libcfa/Makefile.in ¶
r0182bfa r28f3a19 97 97 98 98 # not all platforms support concurrency, add option do disable it 99 @BUILD_CONCURRENCY_TRUE@am__append_3 = concurrency/coroutine concurrency/thread concurrency/kernel concurrency/monitor 99 @BUILD_CONCURRENCY_TRUE@am__append_3 = concurrency/coroutine concurrency/thread concurrency/kernel concurrency/monitor concurrency/mutex 100 100 101 101 # not all platforms support concurrency, add option do disable it … … 153 153 containers/pair.c containers/result.c containers/vector.c \ 154 154 concurrency/coroutine.c concurrency/thread.c \ 155 concurrency/kernel.c concurrency/monitor.c assert.c \156 exception.c virtual.c concurrency/CtxSwitch-@MACHINE_TYPE@.S\157 concurrency/ alarm.c concurrency/invoke.c \158 concurrency/ preemption.c155 concurrency/kernel.c concurrency/monitor.c concurrency/mutex.c \ 156 assert.c exception.c virtual.c \ 157 concurrency/CtxSwitch-@MACHINE_TYPE@.S concurrency/alarm.c \ 158 concurrency/invoke.c concurrency/preemption.c 159 159 am__dirstamp = $(am__leading_dot)dirstamp 160 160 @BUILD_CONCURRENCY_TRUE@am__objects_1 = concurrency/libcfa_d_a-coroutine.$(OBJEXT) \ 161 161 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_d_a-thread.$(OBJEXT) \ 162 162 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_d_a-kernel.$(OBJEXT) \ 163 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_d_a-monitor.$(OBJEXT) 163 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_d_a-monitor.$(OBJEXT) \ 164 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_d_a-mutex.$(OBJEXT) 164 165 am__objects_2 = libcfa_d_a-fstream.$(OBJEXT) \ 165 166 libcfa_d_a-iostream.$(OBJEXT) libcfa_d_a-iterator.$(OBJEXT) \ … … 188 189 containers/result.c containers/vector.c \ 189 190 concurrency/coroutine.c concurrency/thread.c \ 190 concurrency/kernel.c concurrency/monitor.c assert.c \191 exception.c virtual.c concurrency/CtxSwitch-@MACHINE_TYPE@.S\192 concurrency/ alarm.c concurrency/invoke.c \193 concurrency/ preemption.c191 concurrency/kernel.c concurrency/monitor.c concurrency/mutex.c \ 192 assert.c exception.c virtual.c \ 193 concurrency/CtxSwitch-@MACHINE_TYPE@.S concurrency/alarm.c \ 194 concurrency/invoke.c concurrency/preemption.c 194 195 @BUILD_CONCURRENCY_TRUE@am__objects_5 = concurrency/libcfa_a-coroutine.$(OBJEXT) \ 195 196 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-thread.$(OBJEXT) \ 196 197 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-kernel.$(OBJEXT) \ 197 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-monitor.$(OBJEXT) 198 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-monitor.$(OBJEXT) \ 199 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-mutex.$(OBJEXT) 198 200 am__objects_6 = libcfa_a-fstream.$(OBJEXT) libcfa_a-iostream.$(OBJEXT) \ 199 201 libcfa_a-iterator.$(OBJEXT) libcfa_a-limits.$(OBJEXT) \ … … 264 266 containers/result containers/vector concurrency/coroutine \ 265 267 concurrency/thread concurrency/kernel concurrency/monitor \ 266 ${shell find stdhdr -type f -printf "%p "} math gmp time_t.h\267 clock bits/align.h bits/containers.h bits/defs.h bits/debug.h \268 bits/ locks.h concurrency/invoke.h268 concurrency/mutex ${shell find stdhdr -type f -printf "%p "} \ 269 math gmp time_t.h clock bits/align.h bits/containers.h \ 270 bits/defs.h bits/debug.h bits/locks.h concurrency/invoke.h 269 271 HEADERS = $(nobase_cfa_include_HEADERS) 270 272 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) … … 548 550 concurrency/libcfa_d_a-monitor.$(OBJEXT): concurrency/$(am__dirstamp) \ 549 551 concurrency/$(DEPDIR)/$(am__dirstamp) 552 concurrency/libcfa_d_a-mutex.$(OBJEXT): concurrency/$(am__dirstamp) \ 553 concurrency/$(DEPDIR)/$(am__dirstamp) 550 554 concurrency/CtxSwitch-@MACHINE_TYPE@.$(OBJEXT): \ 551 555 concurrency/$(am__dirstamp) \ … … 580 584 concurrency/$(DEPDIR)/$(am__dirstamp) 581 585 concurrency/libcfa_a-monitor.$(OBJEXT): concurrency/$(am__dirstamp) \ 586 concurrency/$(DEPDIR)/$(am__dirstamp) 587 concurrency/libcfa_a-mutex.$(OBJEXT): concurrency/$(am__dirstamp) \ 582 588 concurrency/$(DEPDIR)/$(am__dirstamp) 583 589 concurrency/libcfa_a-alarm.$(OBJEXT): concurrency/$(am__dirstamp) \ … … 635 641 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_a-kernel.Po@am__quote@ 636 642 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_a-monitor.Po@am__quote@ 643 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_a-mutex.Po@am__quote@ 637 644 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_a-preemption.Po@am__quote@ 638 645 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_a-thread.Po@am__quote@ … … 642 649 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_d_a-kernel.Po@am__quote@ 643 650 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_d_a-monitor.Po@am__quote@ 651 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_d_a-mutex.Po@am__quote@ 644 652 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_d_a-preemption.Po@am__quote@ 645 653 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_d_a-thread.Po@am__quote@ … … 930 938 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -c -o concurrency/libcfa_d_a-monitor.obj `if test -f 'concurrency/monitor.c'; then $(CYGPATH_W) 'concurrency/monitor.c'; else $(CYGPATH_W) '$(srcdir)/concurrency/monitor.c'; fi` 931 939 940 concurrency/libcfa_d_a-mutex.o: concurrency/mutex.c 941 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -MT concurrency/libcfa_d_a-mutex.o -MD -MP -MF concurrency/$(DEPDIR)/libcfa_d_a-mutex.Tpo -c -o concurrency/libcfa_d_a-mutex.o `test -f 'concurrency/mutex.c' || echo '$(srcdir)/'`concurrency/mutex.c 942 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) concurrency/$(DEPDIR)/libcfa_d_a-mutex.Tpo concurrency/$(DEPDIR)/libcfa_d_a-mutex.Po 943 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='concurrency/mutex.c' object='concurrency/libcfa_d_a-mutex.o' libtool=no @AMDEPBACKSLASH@ 944 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 945 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -c -o concurrency/libcfa_d_a-mutex.o `test -f 'concurrency/mutex.c' || echo '$(srcdir)/'`concurrency/mutex.c 946 947 concurrency/libcfa_d_a-mutex.obj: concurrency/mutex.c 948 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -MT concurrency/libcfa_d_a-mutex.obj -MD -MP -MF concurrency/$(DEPDIR)/libcfa_d_a-mutex.Tpo -c -o concurrency/libcfa_d_a-mutex.obj `if test -f 'concurrency/mutex.c'; then $(CYGPATH_W) 'concurrency/mutex.c'; else $(CYGPATH_W) '$(srcdir)/concurrency/mutex.c'; fi` 949 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) concurrency/$(DEPDIR)/libcfa_d_a-mutex.Tpo concurrency/$(DEPDIR)/libcfa_d_a-mutex.Po 950 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='concurrency/mutex.c' object='concurrency/libcfa_d_a-mutex.obj' libtool=no @AMDEPBACKSLASH@ 951 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 952 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -c -o concurrency/libcfa_d_a-mutex.obj `if test -f 'concurrency/mutex.c'; then $(CYGPATH_W) 'concurrency/mutex.c'; else $(CYGPATH_W) '$(srcdir)/concurrency/mutex.c'; fi` 953 932 954 libcfa_d_a-assert.o: assert.c 933 955 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_d_a_CFLAGS) $(CFLAGS) -MT libcfa_d_a-assert.o -MD -MP -MF $(DEPDIR)/libcfa_d_a-assert.Tpo -c -o libcfa_d_a-assert.o `test -f 'assert.c' || echo '$(srcdir)/'`assert.c … … 1237 1259 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 1238 1260 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_a_CFLAGS) $(CFLAGS) -c -o concurrency/libcfa_a-monitor.obj `if test -f 'concurrency/monitor.c'; then $(CYGPATH_W) 'concurrency/monitor.c'; else $(CYGPATH_W) '$(srcdir)/concurrency/monitor.c'; fi` 1261 1262 concurrency/libcfa_a-mutex.o: concurrency/mutex.c 1263 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_a_CFLAGS) $(CFLAGS) -MT concurrency/libcfa_a-mutex.o -MD -MP -MF concurrency/$(DEPDIR)/libcfa_a-mutex.Tpo -c -o concurrency/libcfa_a-mutex.o `test -f 'concurrency/mutex.c' || echo '$(srcdir)/'`concurrency/mutex.c 1264 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) concurrency/$(DEPDIR)/libcfa_a-mutex.Tpo concurrency/$(DEPDIR)/libcfa_a-mutex.Po 1265 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='concurrency/mutex.c' object='concurrency/libcfa_a-mutex.o' libtool=no @AMDEPBACKSLASH@ 1266 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 1267 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_a_CFLAGS) $(CFLAGS) -c -o concurrency/libcfa_a-mutex.o `test -f 'concurrency/mutex.c' || echo '$(srcdir)/'`concurrency/mutex.c 1268 1269 concurrency/libcfa_a-mutex.obj: concurrency/mutex.c 1270 @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_a_CFLAGS) $(CFLAGS) -MT concurrency/libcfa_a-mutex.obj -MD -MP -MF concurrency/$(DEPDIR)/libcfa_a-mutex.Tpo -c -o concurrency/libcfa_a-mutex.obj `if test -f 'concurrency/mutex.c'; then $(CYGPATH_W) 'concurrency/mutex.c'; else $(CYGPATH_W) '$(srcdir)/concurrency/mutex.c'; fi` 1271 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) concurrency/$(DEPDIR)/libcfa_a-mutex.Tpo concurrency/$(DEPDIR)/libcfa_a-mutex.Po 1272 @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='concurrency/mutex.c' object='concurrency/libcfa_a-mutex.obj' libtool=no @AMDEPBACKSLASH@ 1273 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 1274 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcfa_a_CFLAGS) $(CFLAGS) -c -o concurrency/libcfa_a-mutex.obj `if test -f 'concurrency/mutex.c'; then $(CYGPATH_W) 'concurrency/mutex.c'; else $(CYGPATH_W) '$(srcdir)/concurrency/mutex.c'; fi` 1239 1275 1240 1276 libcfa_a-assert.o: assert.c -
TabularUnified src/libcfa/bits/containers.h ¶
r0182bfa r28f3a19 183 183 verify( *tail == NULL ); 184 184 return val; 185 } 186 187 forall(dtype T | is_node(T)) 188 static inline bool ?!=?( __queue(T) & this, zero_t zero ) { 189 return this.head != 0; 185 190 } 186 191 #endif … … 261 266 __get( node ).prev = NULL; 262 267 } 268 269 forall(dtype T | sized(T)) 270 static inline bool ?!=?( __dllist(T) & this, zero_t zero ) { 271 return this.head != 0; 272 } 263 273 #undef next 264 274 #undef prev -
TabularUnified src/libcfa/bits/locks.h ¶
r0182bfa r28f3a19 18 18 #include "bits/debug.h" 19 19 #include "bits/defs.h" 20 #include <assert.h> 21 22 #ifdef __cforall 23 extern "C" { 24 #include <pthread.h> 25 } 26 #endif 20 27 21 28 // pause to prevent excess processor bus usage … … 112 119 __atomic_clear( &this.lock, __ATOMIC_RELEASE ); 113 120 } 121 122 123 #ifdef __CFA_WITH_VERIFY__ 124 extern bool __cfaabi_dbg_in_kernel(); 125 #endif 126 127 struct __bin_sem_t { 128 bool signaled; 129 pthread_mutex_t lock; 130 pthread_cond_t cond; 131 }; 132 133 static inline void ?{}(__bin_sem_t & this) with( this ) { 134 signaled = false; 135 pthread_mutex_init(&lock, NULL); 136 pthread_cond_init (&cond, NULL); 137 } 138 139 static inline void ^?{}(__bin_sem_t & this) with( this ) { 140 pthread_mutex_destroy(&lock); 141 pthread_cond_destroy (&cond); 142 } 143 144 static inline void wait(__bin_sem_t & this) with( this ) { 145 verify(__cfaabi_dbg_in_kernel()); 146 pthread_mutex_lock(&lock); 147 if(!signaled) { // this must be a loop, not if! 148 pthread_cond_wait(&cond, &lock); 149 } 150 signaled = false; 151 pthread_mutex_unlock(&lock); 152 } 153 154 static inline void post(__bin_sem_t & this) with( this ) { 155 verify(__cfaabi_dbg_in_kernel()); 156 157 pthread_mutex_lock(&lock); 158 bool needs_signal = !signaled; 159 signaled = true; 160 pthread_mutex_unlock(&lock); 161 162 if (needs_signal) 163 pthread_cond_signal(&cond); 164 } 114 165 #endif -
TabularUnified src/libcfa/concurrency/invoke.h ¶
r0182bfa r28f3a19 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 30 22:33:59201813 // Update Count : 3 012 // Last Modified On : Sat May 19 08:23:21 2018 13 // Update Count : 31 14 14 // 15 15 … … 18 18 #include "bits/locks.h" 19 19 20 #define TL_GET( member ) kernelTLS.member21 #define TL_SET( member, value ) kernelTLS.member = value;22 23 20 #ifdef __cforall 24 21 extern "C" { … … 28 25 #ifndef _INVOKE_H_ 29 26 #define _INVOKE_H_ 27 28 #ifdef __ARM_ARCH 29 // function prototypes are only really used by these macros on ARM 30 void disable_global_interrupts(); 31 void enable_global_interrupts(); 32 33 #define TL_GET( member ) ( { __typeof__( kernelTLS.member ) target; \ 34 disable_global_interrupts(); \ 35 target = kernelTLS.member; \ 36 enable_global_interrupts(); \ 37 target; } ) 38 #define TL_SET( member, value ) disable_global_interrupts(); \ 39 kernelTLS.member = value; \ 40 enable_global_interrupts(); 41 #else 42 #define TL_GET( member ) kernelTLS.member 43 #define TL_SET( member, value ) kernelTLS.member = value; 44 #endif 30 45 31 46 #ifdef __cforall -
TabularUnified src/libcfa/concurrency/kernel ¶
r0182bfa r28f3a19 23 23 extern "C" { 24 24 #include <pthread.h> 25 #include <semaphore.h> 25 26 } 26 27 … … 43 44 extern struct cluster * mainCluster; 44 45 45 enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule }; 46 enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule, Callback }; 47 48 typedef void (*__finish_callback_fptr_t)(void); 46 49 47 50 //TODO use union, many of these fields are mutually exclusive (i.e. MULTI vs NOMULTI) 48 51 struct FinishAction { 49 52 FinishOpCode action_code; 53 /* 54 // Union of possible actions 55 union { 56 // Option 1 : locks and threads 57 struct { 58 // 1 thread or N thread 59 union { 60 thread_desc * thrd; 61 struct { 62 thread_desc ** thrds; 63 unsigned short thrd_count; 64 }; 65 }; 66 // 1 lock or N lock 67 union { 68 __spinlock_t * lock; 69 struct { 70 __spinlock_t ** locks; 71 unsigned short lock_count; 72 }; 73 }; 74 }; 75 // Option 2 : action pointer 76 __finish_callback_fptr_t callback; 77 }; 78 /*/ 50 79 thread_desc * thrd; 80 thread_desc ** thrds; 81 unsigned short thrd_count; 51 82 __spinlock_t * lock; 52 83 __spinlock_t ** locks; 53 84 unsigned short lock_count; 54 thread_desc ** thrds;55 unsigned short thrd_count;85 __finish_callback_fptr_t callback; 86 //*/ 56 87 }; 57 88 static inline void ?{}(FinishAction & this) { … … 82 113 pthread_t kernel_thread; 83 114 115 // RunThread data 116 // Action to do after a thread is ran 117 struct FinishAction finish; 118 119 // Preemption data 120 // Node which is added in the discrete event simulaiton 121 struct alarm_node_t * preemption_alarm; 122 123 // If true, a preemption was triggered in an unsafe region, the processor must preempt as soon as possible 124 bool pending_preemption; 125 126 // Idle lock 127 __bin_sem_t idleLock; 128 84 129 // Termination 85 130 // Set to true to notify the processor should terminate … … 89 134 semaphore terminated; 90 135 91 // RunThread data92 // Action to do after a thread is ran93 struct FinishAction finish;94 95 // Preemption data96 // Node which is added in the discrete event simulaiton97 struct alarm_node_t * preemption_alarm;98 99 // If true, a preemption was triggered in an unsafe region, the processor must preempt as soon as possible100 bool pending_preemption;101 102 // Idle lock103 104 136 // Link lists fields 105 struct {137 struct __dbg_node_proc { 106 138 struct processor * next; 107 139 struct processor * prev; … … 150 182 151 183 // Link lists fields 152 struct {184 struct __dbg_node_cltr { 153 185 cluster * next; 154 186 cluster * prev; -
TabularUnified src/libcfa/concurrency/kernel.c ¶
r0182bfa r28f3a19 16 16 //C Includes 17 17 #include <stddef.h> 18 #include <errno.h> 19 #include <string.h> 18 20 extern "C" { 19 21 #include <stdio.h> … … 49 51 thread_desc * mainThread; 50 52 51 struct { __dllist_t(cluster ) list; __spinlock_t lock; } global_clusters; 53 extern "C" { 54 struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters; 55 } 52 56 53 57 //----------------------------------------------------------------------------- … … 143 147 runner.proc = &this; 144 148 149 idleLock{}; 150 145 151 start( &this ); 146 152 } 147 153 148 154 void ^?{}(processor & this) with( this ){ 149 if( ! do_terminate) {155 if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) { 150 156 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this); 151 terminate(&this); 152 verify(this.do_terminate); 153 verify( kernelTLS.this_processor != &this); 157 158 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED); 159 wake( &this ); 160 154 161 P( terminated ); 155 162 verify( kernelTLS.this_processor != &this); 156 pthread_join( kernel_thread, NULL ); 157 } 163 } 164 165 pthread_join( kernel_thread, NULL ); 158 166 } 159 167 … … 194 202 195 203 thread_desc * readyThread = NULL; 196 for( unsigned int spin_count = 0; ! this->do_terminate; spin_count++ )204 for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ ) 197 205 { 198 206 readyThread = nextThread( this->cltr ); … … 213 221 else 214 222 { 215 spin(this, &spin_count); 223 // spin(this, &spin_count); 224 halt(this); 216 225 } 217 226 } … … 257 266 // its final actions must be executed from the kernel 258 267 void finishRunning(processor * this) with( this->finish ) { 259 if( action_code == Release ) { 260 verify( ! kernelTLS.preemption_state.enabled ); 268 verify( ! kernelTLS.preemption_state.enabled ); 269 choose( action_code ) { 270 case No_Action: 271 break; 272 case Release: 261 273 unlock( *lock ); 262 } 263 else if( action_code == Schedule ) { 274 case Schedule: 264 275 ScheduleThread( thrd ); 265 } 266 else if( action_code == Release_Schedule ) { 267 verify( ! kernelTLS.preemption_state.enabled ); 276 case Release_Schedule: 268 277 unlock( *lock ); 269 278 ScheduleThread( thrd ); 270 } 271 else if( action_code == Release_Multi ) { 272 verify( ! kernelTLS.preemption_state.enabled ); 279 case Release_Multi: 273 280 for(int i = 0; i < lock_count; i++) { 274 281 unlock( *locks[i] ); 275 282 } 276 } 277 else if( action_code == Release_Multi_Schedule ) { 283 case Release_Multi_Schedule: 278 284 for(int i = 0; i < lock_count; i++) { 279 285 unlock( *locks[i] ); … … 282 288 ScheduleThread( thrds[i] ); 283 289 } 284 } 285 else { 286 assert(action_code == No_Action); 287 } 288 } 289 290 // Handles spinning logic 291 // TODO : find some strategy to put cores to sleep after some time 292 void spin(processor * this, unsigned int * spin_count) { 293 (*spin_count)++; 290 case Callback: 291 callback(); 292 default: 293 abort("KERNEL ERROR: Unexpected action to run after thread"); 294 } 294 295 } 295 296 … … 396 397 with( *thrd->curr_cluster ) { 397 398 lock ( ready_queue_lock __cfaabi_dbg_ctx2 ); 399 bool was_empty = !(ready_queue != 0); 398 400 append( ready_queue, thrd ); 399 401 unlock( ready_queue_lock ); 402 403 if(was_empty) { 404 lock (proc_list_lock __cfaabi_dbg_ctx2); 405 if(idles) { 406 wake_fast(idles.head); 407 } 408 unlock (proc_list_lock); 409 } 410 else if( struct processor * idle = idles.head ) { 411 wake_fast(idle); 412 } 413 400 414 } 401 415 … … 497 511 } 498 512 513 void BlockInternal(__finish_callback_fptr_t callback) { 514 disable_interrupts(); 515 with( *kernelTLS.this_processor ) { 516 finish.action_code = Callback; 517 finish.callback = callback; 518 } 519 520 verify( ! kernelTLS.preemption_state.enabled ); 521 returnToKernel(); 522 verify( ! kernelTLS.preemption_state.enabled ); 523 524 enable_interrupts( __cfaabi_dbg_ctx ); 525 } 526 499 527 // KERNEL ONLY 500 528 void LeaveThread(__spinlock_t * lock, thread_desc * thrd) { … … 518 546 __cfaabi_dbg_print_safe("Kernel : Starting\n"); 519 547 520 global_clusters.list{ __get };521 global_clusters.lock{};548 __cfa_dbg_global_clusters.list{ __get }; 549 __cfa_dbg_global_clusters.lock{}; 522 550 523 551 // Initialize the main cluster … … 600 628 // When its coroutine terminates, it return control to the mainThread 601 629 // which is currently here 602 mainProcessor->do_terminate = true;630 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 603 631 returnToKernel(); 632 mainThread->self_cor.state = Halted; 604 633 605 634 // THE SYSTEM IS NOW COMPLETELY STOPPED … … 617 646 ^(mainThread){}; 618 647 619 ^( global_clusters.list){};620 ^( global_clusters.lock){};648 ^(__cfa_dbg_global_clusters.list){}; 649 ^(__cfa_dbg_global_clusters.lock){}; 621 650 622 651 __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n"); … … 627 656 //============================================================================================= 628 657 629 // void halt(processor * this) with( this ) { 630 // pthread_mutex_lock( &idle.lock ); 631 632 633 634 // // SKULLDUGGERY: Even if spurious wake-up is a thing 635 // // spuriously waking up a kernel thread is not a big deal 636 // // if it is very rare. 637 // pthread_cond_wait( &idle.cond, &idle.lock); 638 // pthread_mutex_unlock( &idle.lock ); 639 // } 640 641 // void wake(processor * this) with( this ) { 642 // pthread_mutex_lock (&idle.lock); 643 // pthread_cond_signal (&idle.cond); 644 // pthread_mutex_unlock(&idle.lock); 645 // } 658 void halt(processor * this) with( *this ) { 659 // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 660 661 with( *cltr ) { 662 lock (proc_list_lock __cfaabi_dbg_ctx2); 663 remove (procs, *this); 664 push_front(idles, *this); 665 unlock (proc_list_lock); 666 } 667 668 __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this); 669 670 wait( idleLock ); 671 672 __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this); 673 674 with( *cltr ) { 675 lock (proc_list_lock __cfaabi_dbg_ctx2); 676 remove (idles, *this); 677 push_front(procs, *this); 678 unlock (proc_list_lock); 679 } 680 } 646 681 647 682 //============================================================================================= … … 758 793 // Global Queues 759 794 void doregister( cluster & cltr ) { 760 lock ( global_clusters.lock __cfaabi_dbg_ctx2);761 push_front( global_clusters.list, cltr );762 unlock ( global_clusters.lock );795 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2); 796 push_front( __cfa_dbg_global_clusters.list, cltr ); 797 unlock ( __cfa_dbg_global_clusters.lock ); 763 798 } 764 799 765 800 void unregister( cluster & cltr ) { 766 lock ( global_clusters.lock __cfaabi_dbg_ctx2);767 remove( global_clusters.list, cltr );768 unlock( global_clusters.lock );801 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2); 802 remove( __cfa_dbg_global_clusters.list, cltr ); 803 unlock( __cfa_dbg_global_clusters.lock ); 769 804 } 770 805 -
TabularUnified src/libcfa/concurrency/kernel_private.h ¶
r0182bfa r28f3a19 48 48 void BlockInternal(__spinlock_t * locks [], unsigned short count); 49 49 void BlockInternal(__spinlock_t * locks [], unsigned short count, thread_desc * thrds [], unsigned short thrd_count); 50 void BlockInternal(__finish_callback_fptr_t callback); 50 51 void LeaveThread(__spinlock_t * lock, thread_desc * thrd); 51 52 … … 56 57 void runThread(processor * this, thread_desc * dst); 57 58 void finishRunning(processor * this); 58 void terminate(processor * this); 59 void spin(processor * this, unsigned int * spin_count); 59 void halt(processor * this); 60 61 static inline void wake_fast(processor * this) { 62 __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this); 63 post( this->idleLock ); 64 } 65 66 static inline void wake(processor * this) { 67 disable_interrupts(); 68 wake_fast(this); 69 enable_interrupts( __cfaabi_dbg_ctx ); 70 } 60 71 61 72 struct event_kernel_t { … … 65 76 66 77 extern event_kernel_t * event_kernel; 67 68 //extern thread_local coroutine_desc * volatile this_coroutine;69 //extern thread_local thread_desc * volatile this_thread;70 //extern thread_local processor * volatile this_processor;71 72 // extern volatile thread_local bool preemption_in_progress;73 // extern volatile thread_local bool preemption_enabled;74 // extern volatile thread_local unsigned short disable_preempt_count;75 78 76 79 struct __cfa_kernel_preemption_state_t { -
TabularUnified src/libcfa/concurrency/monitor.c ¶
r0182bfa r28f3a19 297 297 this.count = count; 298 298 299 // Sort monitors based on address -> TODO use a sort specialized for small numbers299 // Sort monitors based on address 300 300 __libcfa_small_sort(this.m, count); 301 301 -
TabularUnified src/libcfa/concurrency/preemption.c ¶
r0182bfa r28f3a19 10 10 // Created On : Mon Jun 5 14:20:42 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 9 13:52:39 201813 // Update Count : 3 612 // Last Modified On : Tue Jun 5 17:35:49 2018 13 // Update Count : 37 14 14 // 15 15 … … 116 116 // If there are still alarms pending, reset the timer 117 117 if( alarms->head ) { 118 __cfaabi_dbg_print_buffer_decl( " KERNEL: @% lu(%lu) resetting alarm to %lu.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);118 __cfaabi_dbg_print_buffer_decl( " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv); 119 119 Duration delta = alarms->head->alarm - currtime; 120 120 Duration caped = max(delta, 50`us); … … 161 161 void disable_interrupts() { 162 162 with( kernelTLS.preemption_state ) { 163 #if GCC_VERSION > 50000 163 164 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); 165 #endif 164 166 165 167 // Set enabled flag to false … … 190 192 // Check if we need to prempt the thread because an interrupt was missed 191 193 if( prev == 1 ) { 194 #if GCC_VERSION > 50000 192 195 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); 196 #endif 193 197 194 198 // Set enabled flag to true … … 217 221 verifyf( prev != 0u, "Incremented from %u\n", prev ); // If this triggers someone is enabled already enabled interrupts 218 222 if( prev == 1 ) { 223 #if GCC_VERSION > 50000 219 224 static_assert(__atomic_always_lock_free(sizeof(kernelTLS.preemption_state.enabled), &kernelTLS.preemption_state.enabled), "Must be lock-free"); 225 #endif 220 226 // Set enabled flag to true 221 227 // should be atomic to avoid preemption in the middle of the operation. … … 254 260 static void preempt( processor * this ) { 255 261 sigval_t value = { PREEMPT_NORMAL }; 256 pthread_sigqueue( this->kernel_thread, SIGUSR1, value );257 }258 259 // kill wrapper : signal a processor260 void terminate(processor * this) {261 this->do_terminate = true;262 sigval_t value = { PREEMPT_TERMINATE };263 262 pthread_sigqueue( this->kernel_thread, SIGUSR1, value ); 264 263 } … … 362 361 choose(sfp->si_value.sival_int) { 363 362 case PREEMPT_NORMAL : ;// Normal case, nothing to do here 364 case PREEMPT_TERMINATE: verify( kernelTLS.this_processor->do_terminate);363 case PREEMPT_TERMINATE: verify( __atomic_load_n( &kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ) ); 365 364 default: 366 365 abort( "internal error, signal value is %d", sfp->si_value.sival_int ); … … 376 375 377 376 // Clear sighandler mask before context switching. 377 #if GCC_VERSION > 50000 378 378 static_assert( sizeof( sigset_t ) == sizeof( cxt->uc_sigmask ), "Expected cxt->uc_sigmask to be of sigset_t" ); 379 #endif 379 380 if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), NULL ) == -1 ) { 380 381 abort( "internal error, sigprocmask" ); … … 479 480 } 480 481 482 #ifdef __CFA_WITH_VERIFY__ 483 bool __cfaabi_dbg_in_kernel() { 484 return !kernelTLS.preemption_state.enabled; 485 } 486 #endif 487 481 488 // Local Variables: // 482 489 // mode: c // -
TabularUnified src/libcfa/fstream ¶
r0182bfa r28f3a19 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Dec 7 15:17:26 201713 // Update Count : 13 012 // Last Modified On : Tue Jun 5 10:20:25 2018 13 // Update Count : 131 14 14 // 15 15 … … 54 54 void open( ofstream &, const char * name ); 55 55 void close( ofstream & ); 56 ofstream & write( ofstream &, const char * data, unsigned long int size );56 ofstream & write( ofstream &, const char * data, size_t size ); 57 57 int fmt( ofstream &, const char fmt[], ... ); 58 58 … … 74 74 void open( ifstream & is, const char * name ); 75 75 void close( ifstream & is ); 76 ifstream & read( ifstream & is, char * data, unsigned long int size );76 ifstream & read( ifstream & is, char * data, size_t size ); 77 77 ifstream & ungetc( ifstream & is, char c ); 78 78 int fmt( ifstream &, const char fmt[], ... ); -
TabularUnified src/libcfa/fstream.c ¶
r0182bfa r28f3a19 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Dec 9 09:31:23 201713 // Update Count : 2 7512 // Last Modified On : Tue Jun 5 17:02:56 2018 13 // Update Count : 281 14 14 // 15 15 … … 116 116 } // close 117 117 118 ofstream & write( ofstream & os, const char * data, unsigned long int size ) {118 ofstream & write( ofstream & os, const char * data, size_t size ) { 119 119 if ( fail( os ) ) { 120 120 fprintf( stderr, "attempt write I/O on failed stream\n" ); … … 198 198 } // close 199 199 200 ifstream & read( ifstream & is, char * data, unsigned long int size ) {200 ifstream & read( ifstream & is, char * data, size_t size ) { 201 201 if ( fail( is ) ) { 202 202 fprintf( stderr, "attempt read I/O on failed stream\n" ); -
TabularUnified src/libcfa/iostream ¶
r0182bfa r28f3a19 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Apr 28 13:08:24201813 // Update Count : 15 212 // Last Modified On : Sat Jun 2 08:07:55 2018 13 // Update Count : 153 14 14 // 15 15 … … 56 56 // implement writable for intrinsic types 57 57 58 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, _Bool ); 58 forall( dtype ostype | ostream( ostype ) ) { 59 ostype & ?|?( ostype &, _Bool ); 59 60 60 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, char );61 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, signed char );62 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, unsigned char );61 ostype & ?|?( ostype &, char ); 62 ostype & ?|?( ostype &, signed char ); 63 ostype & ?|?( ostype &, unsigned char ); 63 64 64 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, short int );65 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, unsigned short int );66 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, int );67 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, unsigned int );68 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, long int );69 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, long long int );70 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, unsigned long int );71 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, unsigned long long int );65 ostype & ?|?( ostype &, short int ); 66 ostype & ?|?( ostype &, unsigned short int ); 67 ostype & ?|?( ostype &, int ); 68 ostype & ?|?( ostype &, unsigned int ); 69 ostype & ?|?( ostype &, long int ); 70 ostype & ?|?( ostype &, long long int ); 71 ostype & ?|?( ostype &, unsigned long int ); 72 ostype & ?|?( ostype &, unsigned long long int ); 72 73 73 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, float ); // FIX ME: should not be required74 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, double );75 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, long double );74 ostype & ?|?( ostype &, float ); // FIX ME: should not be required 75 ostype & ?|?( ostype &, double ); 76 ostype & ?|?( ostype &, long double ); 76 77 77 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, float _Complex );78 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, double _Complex );79 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, long double _Complex );78 ostype & ?|?( ostype &, float _Complex ); 79 ostype & ?|?( ostype &, double _Complex ); 80 ostype & ?|?( ostype &, long double _Complex ); 80 81 81 forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, const char * );82 //forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, const char16_t * );82 ostype & ?|?( ostype &, const char * ); 83 // ostype & ?|?( ostype &, const char16_t * ); 83 84 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous 84 //forall( dtype ostype | ostream( ostype ) )ostype & ?|?( ostype &, const char32_t * );85 // ostype & ?|?( ostype &, const char32_t * ); 85 86 #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) 86 //forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, const wchar_t * ); 87 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, const void * ); 87 // ostype & ?|?( ostype &, const wchar_t * ); 88 ostype & ?|?( ostype &, const void * ); 89 90 // manipulators 91 ostype & ?|?( ostype &, ostype & (*)( ostype & ) ); 92 ostype & endl( ostype & ); 93 ostype & sep( ostype & ); 94 ostype & sepTuple( ostype & ); 95 ostype & sepOn( ostype & ); 96 ostype & sepOff( ostype & ); 97 ostype & sepDisable( ostype & ); 98 ostype & sepEnable( ostype & ); 99 } // distribution 88 100 89 101 // tuples 90 102 forall( dtype ostype, otype T, ttype Params | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) 91 103 ostype & ?|?( ostype & os, T arg, Params rest ); 92 93 // manipulators94 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, ostype & (*)( ostype & ) );95 forall( dtype ostype | ostream( ostype ) ) ostype & endl( ostype & );96 forall( dtype ostype | ostream( ostype ) ) ostype & sep( ostype & );97 forall( dtype ostype | ostream( ostype ) ) ostype & sepTuple( ostype & );98 forall( dtype ostype | ostream( ostype ) ) ostype & sepOn( ostype & );99 forall( dtype ostype | ostream( ostype ) ) ostype & sepOff( ostype & );100 forall( dtype ostype | ostream( ostype ) ) ostype & sepDisable( ostype & );101 forall( dtype ostype | ostream( ostype ) ) ostype & sepEnable( ostype & );102 104 103 105 // writes the range [begin, end) to the given stream … … 124 126 }; // readable 125 127 126 forall( dtype istype | istream( istype ) ) istype & ?|?( istype &, _Bool & ); 128 forall( dtype istype | istream( istype ) ) { 129 istype & ?|?( istype &, _Bool & ); 127 130 128 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, char & );129 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, signed char & );130 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, unsigned char & );131 istype & ?|?( istype &, char & ); 132 istype & ?|?( istype &, signed char & ); 133 istype & ?|?( istype &, unsigned char & ); 131 134 132 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, short int & );133 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, unsigned short int & );134 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, int & );135 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, unsigned int & );136 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, long int & );137 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, long long int & );138 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, unsigned long int & );139 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, unsigned long long int & );135 istype & ?|?( istype &, short int & ); 136 istype & ?|?( istype &, unsigned short int & ); 137 istype & ?|?( istype &, int & ); 138 istype & ?|?( istype &, unsigned int & ); 139 istype & ?|?( istype &, long int & ); 140 istype & ?|?( istype &, long long int & ); 141 istype & ?|?( istype &, unsigned long int & ); 142 istype & ?|?( istype &, unsigned long long int & ); 140 143 141 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, float & );142 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, double & );143 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, long double & );144 istype & ?|?( istype &, float & ); 145 istype & ?|?( istype &, double & ); 146 istype & ?|?( istype &, long double & ); 144 147 145 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, float _Complex & );146 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, double _Complex & );147 forall( dtype istype | istream( istype ) )istype & ?|?( istype &, long double _Complex & );148 istype & ?|?( istype &, float _Complex & ); 149 istype & ?|?( istype &, double _Complex & ); 150 istype & ?|?( istype &, long double _Complex & ); 148 151 149 // manipulators 150 forall( dtype istype | istream( istype ) ) istype & ?|?( istype &, istype & (*)( istype & ) ); 151 forall( dtype istype | istream( istype ) ) istype & endl( istype & is ); 152 // manipulators 153 istype & ?|?( istype &, istype & (*)( istype & ) ); 154 istype & endl( istype & is ); 155 } // distribution 152 156 153 157 struct _Istream_cstrUC { char * s; }; -
TabularUnified src/libcfa/iostream.c ¶
r0182bfa r28f3a19 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Apr 28 13:08:25201813 // Update Count : 4 6912 // Last Modified On : Sat Jun 2 08:24:56 2018 13 // Update Count : 471 14 14 // 15 15 … … 26 26 } 27 27 28 forall( dtype ostype | ostream( ostype ) ) 29 ostype & ?|?( ostype & os, _Bool b ) { 30 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 31 fmt( os, "%s", b ? "true" : "false" ); 32 return os; 33 } // ?|? 34 35 forall( dtype ostype | ostream( ostype ) ) 36 ostype & ?|?( ostype & os, char ch ) { 37 fmt( os, "%c", ch ); 38 if ( ch == '\n' ) setNL( os, true ); 39 sepOff( os ); 40 return os; 41 } // ?|? 42 43 forall( dtype ostype | ostream( ostype ) ) 44 ostype & ?|?( ostype & os, signed char c ) { 45 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 46 fmt( os, "%hhd", c ); 47 return os; 48 } // ?|? 49 50 forall( dtype ostype | ostream( ostype ) ) 51 ostype & ?|?( ostype & os, unsigned char c ) { 52 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 53 fmt( os, "%hhu", c ); 54 return os; 55 } // ?|? 56 57 forall( dtype ostype | ostream( ostype ) ) 58 ostype & ?|?( ostype & os, short int si ) { 59 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 60 fmt( os, "%hd", si ); 61 return os; 62 } // ?|? 63 64 forall( dtype ostype | ostream( ostype ) ) 65 ostype & ?|?( ostype & os, unsigned short int usi ) { 66 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 67 fmt( os, "%hu", usi ); 68 return os; 69 } // ?|? 70 71 forall( dtype ostype | ostream( ostype ) ) 72 ostype & ?|?( ostype & os, int i ) { 73 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 74 fmt( os, "%d", i ); 75 return os; 76 } // ?|? 77 78 forall( dtype ostype | ostream( ostype ) ) 79 ostype & ?|?( ostype & os, unsigned int ui ) { 80 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 81 fmt( os, "%u", ui ); 82 return os; 83 } // ?|? 84 85 forall( dtype ostype | ostream( ostype ) ) 86 ostype & ?|?( ostype & os, long int li ) { 87 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 88 fmt( os, "%ld", li ); 89 return os; 90 } // ?|? 91 92 forall( dtype ostype | ostream( ostype ) ) 93 ostype & ?|?( ostype & os, unsigned long int uli ) { 94 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 95 fmt( os, "%lu", uli ); 96 return os; 97 } // ?|? 98 99 forall( dtype ostype | ostream( ostype ) ) 100 ostype & ?|?( ostype & os, long long int lli ) { 101 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 102 fmt( os, "%lld", lli ); 103 return os; 104 } // ?|? 105 106 forall( dtype ostype | ostream( ostype ) ) 107 ostype & ?|?( ostype & os, unsigned long long int ulli ) { 108 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 109 fmt( os, "%llu", ulli ); 110 return os; 111 } // ?|? 112 113 forall( dtype ostype | ostream( ostype ) ) 114 ostype & ?|?( ostype & os, float f ) { 115 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 116 fmt( os, "%g", f ); 117 return os; 118 } // ?|? 119 120 forall( dtype ostype | ostream( ostype ) ) 121 ostype & ?|?( ostype & os, double d ) { 122 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 123 fmt( os, "%.*lg", DBL_DIG, d ); 124 return os; 125 } // ?|? 126 127 forall( dtype ostype | ostream( ostype ) ) 128 ostype & ?|?( ostype & os, long double ld ) { 129 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 130 fmt( os, "%.*Lg", LDBL_DIG, ld ); 131 return os; 132 } // ?|? 133 134 forall( dtype ostype | ostream( ostype ) ) 135 ostype & ?|?( ostype & os, float _Complex fc ) { 136 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 137 fmt( os, "%g%+gi", crealf( fc ), cimagf( fc ) ); 138 return os; 139 } // ?|? 140 141 forall( dtype ostype | ostream( ostype ) ) 142 ostype & ?|?( ostype & os, double _Complex dc ) { 143 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 144 fmt( os, "%.*lg%+.*lgi", DBL_DIG, creal( dc ), DBL_DIG, cimag( dc ) ); 145 return os; 146 } // ?|? 147 148 forall( dtype ostype | ostream( ostype ) ) 149 ostype & ?|?( ostype & os, long double _Complex ldc ) { 150 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 151 fmt( os, "%.*Lg%+.*Lgi", LDBL_DIG, creall( ldc ), LDBL_DIG, cimagl( ldc ) ); 152 return os; 153 } // ?|? 154 155 forall( dtype ostype | ostream( ostype ) ) 156 ostype & ?|?( ostype & os, const char * str ) { 157 enum { Open = 1, Close, OpenClose }; 158 static const unsigned char mask[256] @= { 159 // opening delimiters, no space after 160 ['('] : Open, ['['] : Open, ['{'] : Open, 161 ['='] : Open, ['$'] : Open, [(unsigned char)'£'] : Open, [(unsigned char)'¥'] : Open, 162 [(unsigned char)'¡'] : Open, [(unsigned char)'¿'] : Open, [(unsigned char)'«'] : Open, 163 // closing delimiters, no space before 164 [','] : Close, ['.'] : Close, [';'] : Close, ['!'] : Close, ['?'] : Close, 165 ['%'] : Close, [(unsigned char)'¢'] : Close, [(unsigned char)'»'] : Close, 166 [')'] : Close, [']'] : Close, ['}'] : Close, 167 // opening-closing delimiters, no space before or after 168 ['\''] : OpenClose, ['`'] : OpenClose, ['"'] : OpenClose, [':'] : OpenClose, 169 [' '] : OpenClose, ['\f'] : OpenClose, ['\n'] : OpenClose, ['\r'] : OpenClose, ['\t'] : OpenClose, ['\v'] : OpenClose, // isspace 170 }; // mask 171 172 if ( str[0] == '\0' ) { sepOff( os ); return os; } // null string => no separator 173 174 // first character IS NOT spacing or closing punctuation => add left separator 175 unsigned char ch = str[0]; // must make unsigned 176 if ( sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) { 177 fmt( os, "%s", sepGetCur( os ) ); 178 } // if 179 180 // if string starts line, must reset to determine open state because separator is off 181 sepReset( os ); // reset separator 182 183 // last character IS spacing or opening punctuation => turn off separator for next item 184 size_t len = strlen( str ); 185 ch = str[len - 1]; // must make unsigned 186 if ( sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) { 28 forall( dtype ostype | ostream( ostype ) ) { 29 ostype & ?|?( ostype & os, _Bool b ) { 30 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 31 fmt( os, "%s", b ? "true" : "false" ); 32 return os; 33 } // ?|? 34 35 ostype & ?|?( ostype & os, char ch ) { 36 fmt( os, "%c", ch ); 37 if ( ch == '\n' ) setNL( os, true ); 38 sepOff( os ); 39 return os; 40 } // ?|? 41 42 ostype & ?|?( ostype & os, signed char c ) { 43 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 44 fmt( os, "%hhd", c ); 45 return os; 46 } // ?|? 47 48 ostype & ?|?( ostype & os, unsigned char c ) { 49 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 50 fmt( os, "%hhu", c ); 51 return os; 52 } // ?|? 53 54 ostype & ?|?( ostype & os, short int si ) { 55 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 56 fmt( os, "%hd", si ); 57 return os; 58 } // ?|? 59 60 ostype & ?|?( ostype & os, unsigned short int usi ) { 61 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 62 fmt( os, "%hu", usi ); 63 return os; 64 } // ?|? 65 66 ostype & ?|?( ostype & os, int i ) { 67 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 68 fmt( os, "%d", i ); 69 return os; 70 } // ?|? 71 72 ostype & ?|?( ostype & os, unsigned int ui ) { 73 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 74 fmt( os, "%u", ui ); 75 return os; 76 } // ?|? 77 78 ostype & ?|?( ostype & os, long int li ) { 79 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 80 fmt( os, "%ld", li ); 81 return os; 82 } // ?|? 83 84 ostype & ?|?( ostype & os, unsigned long int uli ) { 85 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 86 fmt( os, "%lu", uli ); 87 return os; 88 } // ?|? 89 90 ostype & ?|?( ostype & os, long long int lli ) { 91 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 92 fmt( os, "%lld", lli ); 93 return os; 94 } // ?|? 95 96 ostype & ?|?( ostype & os, unsigned long long int ulli ) { 97 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 98 fmt( os, "%llu", ulli ); 99 return os; 100 } // ?|? 101 102 ostype & ?|?( ostype & os, float f ) { 103 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 104 fmt( os, "%g", f ); 105 return os; 106 } // ?|? 107 108 ostype & ?|?( ostype & os, double d ) { 109 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 110 fmt( os, "%.*lg", DBL_DIG, d ); 111 return os; 112 } // ?|? 113 114 ostype & ?|?( ostype & os, long double ld ) { 115 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 116 fmt( os, "%.*Lg", LDBL_DIG, ld ); 117 return os; 118 } // ?|? 119 120 ostype & ?|?( ostype & os, float _Complex fc ) { 121 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 122 fmt( os, "%g%+gi", crealf( fc ), cimagf( fc ) ); 123 return os; 124 } // ?|? 125 126 ostype & ?|?( ostype & os, double _Complex dc ) { 127 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 128 fmt( os, "%.*lg%+.*lgi", DBL_DIG, creal( dc ), DBL_DIG, cimag( dc ) ); 129 return os; 130 } // ?|? 131 132 ostype & ?|?( ostype & os, long double _Complex ldc ) { 133 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 134 fmt( os, "%.*Lg%+.*Lgi", LDBL_DIG, creall( ldc ), LDBL_DIG, cimagl( ldc ) ); 135 return os; 136 } // ?|? 137 138 ostype & ?|?( ostype & os, const char * str ) { 139 enum { Open = 1, Close, OpenClose }; 140 static const unsigned char mask[256] @= { 141 // opening delimiters, no space after 142 ['('] : Open, ['['] : Open, ['{'] : Open, 143 ['='] : Open, ['$'] : Open, [(unsigned char)'£'] : Open, [(unsigned char)'¥'] : Open, 144 [(unsigned char)'¡'] : Open, [(unsigned char)'¿'] : Open, [(unsigned char)'«'] : Open, 145 // closing delimiters, no space before 146 [','] : Close, ['.'] : Close, [';'] : Close, ['!'] : Close, ['?'] : Close, 147 ['%'] : Close, [(unsigned char)'¢'] : Close, [(unsigned char)'»'] : Close, 148 [')'] : Close, [']'] : Close, ['}'] : Close, 149 // opening-closing delimiters, no space before or after 150 ['\''] : OpenClose, ['`'] : OpenClose, ['"'] : OpenClose, [':'] : OpenClose, 151 [' '] : OpenClose, ['\f'] : OpenClose, ['\n'] : OpenClose, ['\r'] : OpenClose, ['\t'] : OpenClose, ['\v'] : OpenClose, // isspace 152 }; // mask 153 154 if ( str[0] == '\0' ) { sepOff( os ); return os; } // null string => no separator 155 156 // first character IS NOT spacing or closing punctuation => add left separator 157 unsigned char ch = str[0]; // must make unsigned 158 if ( sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) { 159 fmt( os, "%s", sepGetCur( os ) ); 160 } // if 161 162 // if string starts line, must reset to determine open state because separator is off 163 sepReset( os ); // reset separator 164 165 // last character IS spacing or opening punctuation => turn off separator for next item 166 size_t len = strlen( str ); 167 ch = str[len - 1]; // must make unsigned 168 if ( sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) { 169 sepOn( os ); 170 } else { 171 sepOff( os ); 172 } // if 173 if ( ch == '\n' ) setNL( os, true ); // check *AFTER* sepPrt call above as it resets NL flag 174 return write( os, str, len ); 175 } // ?|? 176 177 // ostype & ?|?( ostype & os, const char16_t * str ) { 178 // if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 179 // fmt( os, "%ls", str ); 180 // return os; 181 // } // ?|? 182 183 // #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous 184 // ostype & ?|?( ostype & os, const char32_t * str ) { 185 // if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 186 // fmt( os, "%ls", str ); 187 // return os; 188 // } // ?|? 189 // #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) 190 191 // ostype & ?|?( ostype & os, const wchar_t * str ) { 192 // if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 193 // fmt( os, "%ls", str ); 194 // return os; 195 // } // ?|? 196 197 ostype & ?|?( ostype & os, const void * p ) { 198 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 199 fmt( os, "%p", p ); 200 return os; 201 } // ?|? 202 203 204 // manipulators 205 ostype & ?|?( ostype & os, ostype & (* manip)( ostype & ) ) { 206 return manip( os ); 207 } // ?|? 208 209 ostype & sep( ostype & os ) { 210 os | sepGet( os ); 211 return os; 212 } // sep 213 214 ostype & sepTuple( ostype & os ) { 215 os | sepGetTuple( os ); 216 return os; 217 } // sepTuple 218 219 ostype & endl( ostype & os ) { 220 os | '\n'; 221 setNL( os, true ); 222 flush( os ); 223 sepOff( os ); // prepare for next line 224 return os; 225 } // endl 226 227 ostype & sepOn( ostype & os ) { 187 228 sepOn( os ); 188 } else { 229 return os; 230 } // sepOn 231 232 ostype & sepOff( ostype & os ) { 189 233 sepOff( os ); 190 } // if 191 if ( ch == '\n' ) setNL( os, true ); // check *AFTER* sepPrt call above as it resets NL flag 192 return write( os, str, len ); 193 } // ?|? 194 195 // forall( dtype ostype | ostream( ostype ) ) 196 // ostype & ?|?( ostype & os, const char16_t * str ) { 197 // if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 198 // fmt( os, "%ls", str ); 199 // return os; 200 // } // ?|? 201 202 // #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous 203 // forall( dtype ostype | ostream( ostype ) ) 204 // ostype & ?|?( ostype & os, const char32_t * str ) { 205 // if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 206 // fmt( os, "%ls", str ); 207 // return os; 208 // } // ?|? 209 // #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) 210 211 // forall( dtype ostype | ostream( ostype ) ) 212 // ostype & ?|?( ostype & os, const wchar_t * str ) { 213 // if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 214 // fmt( os, "%ls", str ); 215 // return os; 216 // } // ?|? 217 218 forall( dtype ostype | ostream( ostype ) ) 219 ostype & ?|?( ostype & os, const void * p ) { 220 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 221 fmt( os, "%p", p ); 222 return os; 223 } // ?|? 234 return os; 235 } // sepOff 236 237 ostype & sepEnable( ostype & os ) { 238 sepEnable( os ); 239 return os; 240 } // sepEnable 241 242 ostype & sepDisable( ostype & os ) { 243 sepDisable( os ); 244 return os; 245 } // sepDisable 246 } // distribution 224 247 225 248 … … 234 257 } // ?|? 235 258 236 237 // manipulators238 forall( dtype ostype | ostream( ostype ) )239 ostype & ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {240 return manip( os );241 } // ?|?242 243 forall( dtype ostype | ostream( ostype ) )244 ostype & sep( ostype & os ) {245 os | sepGet( os );246 return os;247 } // sep248 249 forall( dtype ostype | ostream( ostype ) )250 ostype & sepTuple( ostype & os ) {251 os | sepGetTuple( os );252 return os;253 } // sepTuple254 255 forall( dtype ostype | ostream( ostype ) )256 ostype & endl( ostype & os ) {257 os | '\n';258 setNL( os, true );259 flush( os );260 sepOff( os ); // prepare for next line261 return os;262 } // endl263 264 forall( dtype ostype | ostream( ostype ) )265 ostype & sepOn( ostype & os ) {266 sepOn( os );267 return os;268 } // sepOn269 270 forall( dtype ostype | ostream( ostype ) )271 ostype & sepOff( ostype & os ) {272 sepOff( os );273 return os;274 } // sepOff275 276 forall( dtype ostype | ostream( ostype ) )277 ostype & sepEnable( ostype & os ) {278 sepEnable( os );279 return os;280 } // sepEnable281 282 forall( dtype ostype | ostream( ostype ) )283 ostype & sepDisable( ostype & os ) {284 sepDisable( os );285 return os;286 } // sepDisable287 288 259 //--------------------------------------- 289 260 261 // writes the range [begin, end) to the given stream 290 262 forall( dtype ostype, otype elt_type | writeable( elt_type, ostype ), otype iterator_type | iterator( iterator_type, elt_type ) ) 291 263 void write( iterator_type begin, iterator_type end, ostype & os ) { … … 302 274 //--------------------------------------- 303 275 304 forall( dtype istype | istream( istype ) ) 305 istype & ?|?( istype & is, _Bool & b ) { 306 char val[6]; 307 fmt( is, "%5s", val ); 308 if ( strcmp( val, "true" ) == 0 ) b = true; 309 else if ( strcmp( val, "false" ) == 0 ) b = false; 310 else { 311 fprintf( stderr, "invalid _Bool constant\n" ); 312 abort(); 313 } // if 314 return is; 315 } // ?|? 316 317 forall( dtype istype | istream( istype ) ) 318 istype & ?|?( istype & is, char & c ) { 319 fmt( is, "%c", &c ); // must pass pointer through varg to fmt 320 return is; 321 } // ?|? 322 323 forall( dtype istype | istream( istype ) ) 324 istype & ?|?( istype & is, signed char & sc ) { 325 fmt( is, "%hhd", &sc ); 326 return is; 327 } // ?|? 328 329 forall( dtype istype | istream( istype ) ) 330 istype & ?|?( istype & is, unsigned char & usc ) { 331 fmt( is, "%hhu", &usc ); 332 return is; 333 } // ?|? 334 335 forall( dtype istype | istream( istype ) ) 336 istype & ?|?( istype & is, short int & si ) { 337 fmt( is, "%hd", &si ); 338 return is; 339 } // ?|? 340 341 forall( dtype istype | istream( istype ) ) 342 istype & ?|?( istype & is, unsigned short int & usi ) { 343 fmt( is, "%hu", &usi ); 344 return is; 345 } // ?|? 346 347 forall( dtype istype | istream( istype ) ) 348 istype & ?|?( istype & is, int & i ) { 349 fmt( is, "%d", &i ); 350 return is; 351 } // ?|? 352 353 forall( dtype istype | istream( istype ) ) 354 istype & ?|?( istype & is, unsigned int & ui ) { 355 fmt( is, "%u", &ui ); 356 return is; 357 } // ?|? 358 359 forall( dtype istype | istream( istype ) ) 360 istype & ?|?( istype & is, long int & li ) { 361 fmt( is, "%ld", &li ); 362 return is; 363 } // ?|? 364 365 forall( dtype istype | istream( istype ) ) 366 istype & ?|?( istype & is, unsigned long int & ulli ) { 367 fmt( is, "%lu", &ulli ); 368 return is; 369 } // ?|? 370 371 forall( dtype istype | istream( istype ) ) 372 istype & ?|?( istype & is, long long int & lli ) { 373 fmt( is, "%lld", &lli ); 374 return is; 375 } // ?|? 376 377 forall( dtype istype | istream( istype ) ) 378 istype & ?|?( istype & is, unsigned long long int & ulli ) { 379 fmt( is, "%llu", &ulli ); 380 return is; 381 } // ?|? 382 383 384 forall( dtype istype | istream( istype ) ) 385 istype & ?|?( istype & is, float & f ) { 386 fmt( is, "%f", &f ); 387 return is; 388 } // ?|? 389 390 forall( dtype istype | istream( istype ) ) 391 istype & ?|?( istype & is, double & d ) { 392 fmt( is, "%lf", &d ); 393 return is; 394 } // ?|? 395 396 forall( dtype istype | istream( istype ) ) 397 istype & ?|?( istype & is, long double & ld ) { 398 fmt( is, "%Lf", &ld ); 399 return is; 400 } // ?|? 401 402 403 forall( dtype istype | istream( istype ) ) 404 istype & ?|?( istype & is, float _Complex & fc ) { 405 float re, im; 406 fmt( is, "%g%gi", &re, &im ); 407 fc = re + im * _Complex_I; 408 return is; 409 } // ?|? 410 411 forall( dtype istype | istream( istype ) ) 412 istype & ?|?( istype & is, double _Complex & dc ) { 413 double re, im; 414 fmt( is, "%lf%lfi", &re, &im ); 415 dc = re + im * _Complex_I; 416 return is; 417 } // ?|? 418 419 forall( dtype istype | istream( istype ) ) 420 istype & ?|?( istype & is, long double _Complex & ldc ) { 421 long double re, im; 422 fmt( is, "%Lf%Lfi", &re, &im ); 423 ldc = re + im * _Complex_I; 424 return is; 425 } // ?|? 426 427 forall( dtype istype | istream( istype ) ) 428 istype & ?|?( istype & is, istype & (* manip)( istype & ) ) { 429 return manip( is ); 430 } // ?|? 431 432 forall( dtype istype | istream( istype ) ) 433 istype & endl( istype & is ) { 434 fmt( is, "%*[ \t\f\n\r\v]" ); // ignore whitespace 435 return is; 436 } // endl 276 forall( dtype istype | istream( istype ) ) { 277 istype & ?|?( istype & is, _Bool & b ) { 278 char val[6]; 279 fmt( is, "%5s", val ); 280 if ( strcmp( val, "true" ) == 0 ) b = true; 281 else if ( strcmp( val, "false" ) == 0 ) b = false; 282 else { 283 fprintf( stderr, "invalid _Bool constant\n" ); 284 abort(); 285 } // if 286 return is; 287 } // ?|? 288 289 istype & ?|?( istype & is, char & c ) { 290 fmt( is, "%c", &c ); // must pass pointer through varg to fmt 291 return is; 292 } // ?|? 293 294 istype & ?|?( istype & is, signed char & sc ) { 295 fmt( is, "%hhd", &sc ); 296 return is; 297 } // ?|? 298 299 istype & ?|?( istype & is, unsigned char & usc ) { 300 fmt( is, "%hhu", &usc ); 301 return is; 302 } // ?|? 303 304 istype & ?|?( istype & is, short int & si ) { 305 fmt( is, "%hd", &si ); 306 return is; 307 } // ?|? 308 309 istype & ?|?( istype & is, unsigned short int & usi ) { 310 fmt( is, "%hu", &usi ); 311 return is; 312 } // ?|? 313 314 istype & ?|?( istype & is, int & i ) { 315 fmt( is, "%d", &i ); 316 return is; 317 } // ?|? 318 319 istype & ?|?( istype & is, unsigned int & ui ) { 320 fmt( is, "%u", &ui ); 321 return is; 322 } // ?|? 323 324 istype & ?|?( istype & is, long int & li ) { 325 fmt( is, "%ld", &li ); 326 return is; 327 } // ?|? 328 329 istype & ?|?( istype & is, unsigned long int & ulli ) { 330 fmt( is, "%lu", &ulli ); 331 return is; 332 } // ?|? 333 334 istype & ?|?( istype & is, long long int & lli ) { 335 fmt( is, "%lld", &lli ); 336 return is; 337 } // ?|? 338 339 istype & ?|?( istype & is, unsigned long long int & ulli ) { 340 fmt( is, "%llu", &ulli ); 341 return is; 342 } // ?|? 343 344 345 istype & ?|?( istype & is, float & f ) { 346 fmt( is, "%f", &f ); 347 return is; 348 } // ?|? 349 350 istype & ?|?( istype & is, double & d ) { 351 fmt( is, "%lf", &d ); 352 return is; 353 } // ?|? 354 355 istype & ?|?( istype & is, long double & ld ) { 356 fmt( is, "%Lf", &ld ); 357 return is; 358 } // ?|? 359 360 361 istype & ?|?( istype & is, float _Complex & fc ) { 362 float re, im; 363 fmt( is, "%g%gi", &re, &im ); 364 fc = re + im * _Complex_I; 365 return is; 366 } // ?|? 367 368 istype & ?|?( istype & is, double _Complex & dc ) { 369 double re, im; 370 fmt( is, "%lf%lfi", &re, &im ); 371 dc = re + im * _Complex_I; 372 return is; 373 } // ?|? 374 375 istype & ?|?( istype & is, long double _Complex & ldc ) { 376 long double re, im; 377 fmt( is, "%Lf%Lfi", &re, &im ); 378 ldc = re + im * _Complex_I; 379 return is; 380 } // ?|? 381 382 383 // manipulators 384 istype & ?|?( istype & is, istype & (* manip)( istype & ) ) { 385 return manip( is ); 386 } // ?|? 387 388 istype & endl( istype & is ) { 389 fmt( is, "%*[ \t\f\n\r\v]" ); // ignore whitespace 390 return is; 391 } // endl 392 } // distribution 437 393 438 394 _Istream_cstrUC cstr( char * str ) { return (_Istream_cstrUC){ str }; } -
TabularUnified src/libcfa/rational ¶
r0182bfa r28f3a19 12 12 // Created On : Wed Apr 6 17:56:25 2016 13 13 // Last Modified By : Peter A. Buhr 14 // Last Modified On : Wed Dec 6 23:12:53 201715 // Update Count : 9714 // Last Modified On : Sat Jun 2 09:10:01 2018 15 // Update Count : 105 16 16 // 17 17 … … 46 46 // implementation 47 47 48 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 49 struct Rational {50 RationalImpl numerator, denominator;// invariant: denominator > 051 }; // Rational48 forall( otype RationalImpl | arithmetic( RationalImpl ) ) { 49 struct Rational { 50 RationalImpl numerator, denominator; // invariant: denominator > 0 51 }; // Rational 52 52 53 // constructors53 // constructors 54 54 55 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 56 void ?{}( Rational(RationalImpl) & r ); 55 void ?{}( Rational(RationalImpl) & r ); 56 void ?{}( Rational(RationalImpl) & r, RationalImpl n ); 57 void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ); 58 void ?{}( Rational(RationalImpl) & r, zero_t ); 59 void ?{}( Rational(RationalImpl) & r, one_t ); 57 60 58 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 59 void ?{}( Rational(RationalImpl) & r, RationalImpl n ); 61 // numerator/denominator getter 60 62 61 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 62 void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ); 63 RationalImpl numerator( Rational(RationalImpl) r ); 64 RationalImpl denominator( Rational(RationalImpl) r ); 65 [ RationalImpl, RationalImpl ] ?=?( & [ RationalImpl, RationalImpl ] dest, Rational(RationalImpl) src ); 63 66 64 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 65 void ?{}( Rational(RationalImpl) & r, zero_t ); 67 // numerator/denominator setter 66 68 67 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 68 void ?{}( Rational(RationalImpl) & r, one_t);69 RationalImpl numerator( Rational(RationalImpl) r, RationalImpl n ); 70 RationalImpl denominator( Rational(RationalImpl) r, RationalImpl d ); 69 71 70 // numerator/denominator getter 72 // comparison 71 73 72 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 73 RationalImpl numerator( Rational(RationalImpl) r ); 74 int ?==?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 75 int ?!=?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 76 int ?<?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 77 int ?<=?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 78 int ?>?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 79 int ?>=?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 74 80 75 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 76 RationalImpl denominator( Rational(RationalImpl) r ); 81 // arithmetic 77 82 78 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 79 [ RationalImpl, RationalImpl ] ?=?( & [ RationalImpl, RationalImpl ] dest, Rational(RationalImpl) src ); 83 Rational(RationalImpl) +?( Rational(RationalImpl) r ); 84 Rational(RationalImpl) -?( Rational(RationalImpl) r ); 85 Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 86 Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 87 Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 88 Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 80 89 81 // numerator/denominator setter 90 // I/O 91 forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } ) 92 istype & ?|?( istype &, Rational(RationalImpl) & ); 82 93 83 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 84 RationalImpl numerator( Rational(RationalImpl) r, RationalImpl n ); 85 86 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 87 RationalImpl denominator( Rational(RationalImpl) r, RationalImpl d ); 88 89 // comparison 90 91 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 92 int ?==?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 93 94 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 95 int ?!=?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 96 97 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 98 int ?<?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 99 100 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 101 int ?<=?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 102 103 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 104 int ?>?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 105 106 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 107 int ?>=?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 108 109 // arithmetic 110 111 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 112 Rational(RationalImpl) +?( Rational(RationalImpl) r ); 113 114 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 115 Rational(RationalImpl) -?( Rational(RationalImpl) r ); 116 117 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 118 Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 119 120 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 121 Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 122 123 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 124 Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 125 126 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 127 Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ); 94 forall( dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, RationalImpl ); } ) 95 ostype & ?|?( ostype &, Rational(RationalImpl ) ); 96 } // distribution 128 97 129 98 // conversion … … 133 102 Rational(RationalImpl) narrow( double f, RationalImpl md ); 134 103 135 // I/O136 forall( otype RationalImpl | arithmetic( RationalImpl ) )137 forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )138 istype & ?|?( istype &, Rational(RationalImpl) & );139 140 forall( otype RationalImpl | arithmetic( RationalImpl ) )141 forall( dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, RationalImpl ); } )142 ostype & ?|?( ostype &, Rational(RationalImpl ) );143 144 104 // Local Variables: // 145 105 // mode: c // -
TabularUnified src/libcfa/rational.c ¶
r0182bfa r28f3a19 10 10 // Created On : Wed Apr 6 17:54:28 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 6 23:13:58 201713 // Update Count : 1 5612 // Last Modified On : Sat Jun 2 09:24:33 2018 13 // Update Count : 162 14 14 // 15 15 … … 18 18 #include "stdlib" 19 19 20 // helper routines 21 22 // Calculate greatest common denominator of two numbers, the first of which may be negative. Used to reduce rationals. 23 // alternative: https://en.wikipedia.org/wiki/Binary_GCD_algorithm 24 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 25 static RationalImpl gcd( RationalImpl a, RationalImpl b ) { 26 for ( ;; ) { // Euclid's algorithm 27 RationalImpl r = a % b; 28 if ( r == (RationalImpl){0} ) break; 29 a = b; 30 b = r; 31 } // for 32 return b; 33 } // gcd 34 35 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 36 static RationalImpl simplify( RationalImpl & n, RationalImpl & d ) { 37 if ( d == (RationalImpl){0} ) { 38 serr | "Invalid rational number construction: denominator cannot be equal to 0." | endl; 39 exit( EXIT_FAILURE ); 40 } // exit 41 if ( d < (RationalImpl){0} ) { d = -d; n = -n; } // move sign to numerator 42 return gcd( abs( n ), d ); // simplify 43 } // Rationalnumber::simplify 44 45 46 // constructors 47 48 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 49 void ?{}( Rational(RationalImpl) & r ) { 50 r{ (RationalImpl){0}, (RationalImpl){1} }; 51 } // rational 52 53 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 54 void ?{}( Rational(RationalImpl) & r, RationalImpl n ) { 55 r{ n, (RationalImpl){1} }; 56 } // rational 57 58 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 59 void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ) { 60 RationalImpl t = simplify( n, d ); // simplify 61 r.numerator = n / t; 62 r.denominator = d / t; 63 } // rational 64 65 66 // getter for numerator/denominator 67 68 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 69 RationalImpl numerator( Rational(RationalImpl) r ) { 70 return r.numerator; 71 } // numerator 72 73 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 74 RationalImpl denominator( Rational(RationalImpl) r ) { 75 return r.denominator; 76 } // denominator 77 78 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 79 [ RationalImpl, RationalImpl ] ?=?( & [ RationalImpl, RationalImpl ] dest, Rational(RationalImpl) src ) { 80 return dest = src.[ numerator, denominator ]; 81 } 82 83 // setter for numerator/denominator 84 85 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 86 RationalImpl numerator( Rational(RationalImpl) r, RationalImpl n ) { 87 RationalImpl prev = r.numerator; 88 RationalImpl t = gcd( abs( n ), r.denominator ); // simplify 89 r.numerator = n / t; 90 r.denominator = r.denominator / t; 91 return prev; 92 } // numerator 93 94 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 95 RationalImpl denominator( Rational(RationalImpl) r, RationalImpl d ) { 96 RationalImpl prev = r.denominator; 97 RationalImpl t = simplify( r.numerator, d ); // simplify 98 r.numerator = r.numerator / t; 99 r.denominator = d / t; 100 return prev; 101 } // denominator 102 103 104 // comparison 105 106 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 107 int ?==?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 108 return l.numerator * r.denominator == l.denominator * r.numerator; 109 } // ?==? 110 111 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 112 int ?!=?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 113 return ! ( l == r ); 114 } // ?!=? 115 116 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 117 int ?<?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 118 return l.numerator * r.denominator < l.denominator * r.numerator; 119 } // ?<? 120 121 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 122 int ?<=?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 123 return l.numerator * r.denominator <= l.denominator * r.numerator; 124 } // ?<=? 125 126 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 127 int ?>?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 128 return ! ( l <= r ); 129 } // ?>? 130 131 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 132 int ?>=?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 133 return ! ( l < r ); 134 } // ?>=? 135 136 137 // arithmetic 138 139 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 140 Rational(RationalImpl) +?( Rational(RationalImpl) r ) { 141 Rational(RationalImpl) t = { r.numerator, r.denominator }; 142 return t; 143 } // +? 144 145 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 146 Rational(RationalImpl) -?( Rational(RationalImpl) r ) { 147 Rational(RationalImpl) t = { -r.numerator, r.denominator }; 148 return t; 149 } // -? 150 151 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 152 Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 153 if ( l.denominator == r.denominator ) { // special case 154 Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator }; 155 return t; 156 } else { 157 Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; 158 return t; 159 } // if 160 } // ?+? 161 162 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 163 Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 164 if ( l.denominator == r.denominator ) { // special case 165 Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator }; 166 return t; 167 } else { 168 Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; 169 return t; 170 } // if 171 } // ?-? 172 173 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 174 Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 175 Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator }; 176 return t; 177 } // ?*? 178 179 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 180 Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 181 if ( r.numerator < (RationalImpl){0} ) { 182 r.numerator = -r.numerator; 183 r.denominator = -r.denominator; 184 } // if 185 Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator }; 186 return t; 187 } // ?/? 188 20 forall( otype RationalImpl | arithmetic( RationalImpl ) ) { 21 // helper routines 22 23 // Calculate greatest common denominator of two numbers, the first of which may be negative. Used to reduce 24 // rationals. alternative: https://en.wikipedia.org/wiki/Binary_GCD_algorithm 25 static RationalImpl gcd( RationalImpl a, RationalImpl b ) { 26 for ( ;; ) { // Euclid's algorithm 27 RationalImpl r = a % b; 28 if ( r == (RationalImpl){0} ) break; 29 a = b; 30 b = r; 31 } // for 32 return b; 33 } // gcd 34 35 static RationalImpl simplify( RationalImpl & n, RationalImpl & d ) { 36 if ( d == (RationalImpl){0} ) { 37 serr | "Invalid rational number construction: denominator cannot be equal to 0." | endl; 38 exit( EXIT_FAILURE ); 39 } // exit 40 if ( d < (RationalImpl){0} ) { d = -d; n = -n; } // move sign to numerator 41 return gcd( abs( n ), d ); // simplify 42 } // Rationalnumber::simplify 43 44 // constructors 45 46 void ?{}( Rational(RationalImpl) & r ) { 47 r{ (RationalImpl){0}, (RationalImpl){1} }; 48 } // rational 49 50 void ?{}( Rational(RationalImpl) & r, RationalImpl n ) { 51 r{ n, (RationalImpl){1} }; 52 } // rational 53 54 void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ) { 55 RationalImpl t = simplify( n, d ); // simplify 56 r.numerator = n / t; 57 r.denominator = d / t; 58 } // rational 59 60 61 // getter for numerator/denominator 62 63 RationalImpl numerator( Rational(RationalImpl) r ) { 64 return r.numerator; 65 } // numerator 66 67 RationalImpl denominator( Rational(RationalImpl) r ) { 68 return r.denominator; 69 } // denominator 70 71 [ RationalImpl, RationalImpl ] ?=?( & [ RationalImpl, RationalImpl ] dest, Rational(RationalImpl) src ) { 72 return dest = src.[ numerator, denominator ]; 73 } // ?=? 74 75 // setter for numerator/denominator 76 77 RationalImpl numerator( Rational(RationalImpl) r, RationalImpl n ) { 78 RationalImpl prev = r.numerator; 79 RationalImpl t = gcd( abs( n ), r.denominator ); // simplify 80 r.numerator = n / t; 81 r.denominator = r.denominator / t; 82 return prev; 83 } // numerator 84 85 RationalImpl denominator( Rational(RationalImpl) r, RationalImpl d ) { 86 RationalImpl prev = r.denominator; 87 RationalImpl t = simplify( r.numerator, d ); // simplify 88 r.numerator = r.numerator / t; 89 r.denominator = d / t; 90 return prev; 91 } // denominator 92 93 // comparison 94 95 int ?==?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 96 return l.numerator * r.denominator == l.denominator * r.numerator; 97 } // ?==? 98 99 int ?!=?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 100 return ! ( l == r ); 101 } // ?!=? 102 103 int ?<?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 104 return l.numerator * r.denominator < l.denominator * r.numerator; 105 } // ?<? 106 107 int ?<=?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 108 return l.numerator * r.denominator <= l.denominator * r.numerator; 109 } // ?<=? 110 111 int ?>?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 112 return ! ( l <= r ); 113 } // ?>? 114 115 int ?>=?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 116 return ! ( l < r ); 117 } // ?>=? 118 119 // arithmetic 120 121 Rational(RationalImpl) +?( Rational(RationalImpl) r ) { 122 Rational(RationalImpl) t = { r.numerator, r.denominator }; 123 return t; 124 } // +? 125 126 Rational(RationalImpl) -?( Rational(RationalImpl) r ) { 127 Rational(RationalImpl) t = { -r.numerator, r.denominator }; 128 return t; 129 } // -? 130 131 Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 132 if ( l.denominator == r.denominator ) { // special case 133 Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator }; 134 return t; 135 } else { 136 Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; 137 return t; 138 } // if 139 } // ?+? 140 141 Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 142 if ( l.denominator == r.denominator ) { // special case 143 Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator }; 144 return t; 145 } else { 146 Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; 147 return t; 148 } // if 149 } // ?-? 150 151 Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 152 Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator }; 153 return t; 154 } // ?*? 155 156 Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 157 if ( r.numerator < (RationalImpl){0} ) { 158 r.numerator = -r.numerator; 159 r.denominator = -r.denominator; 160 } // if 161 Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator }; 162 return t; 163 } // ?/? 164 165 // I/O 166 167 forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } ) 168 istype & ?|?( istype & is, Rational(RationalImpl) & r ) { 169 RationalImpl t; 170 is | r.numerator | r.denominator; 171 t = simplify( r.numerator, r.denominator ); 172 r.numerator /= t; 173 r.denominator /= t; 174 return is; 175 } // ?|? 176 177 forall( dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, RationalImpl ); } ) 178 ostype & ?|?( ostype & os, Rational(RationalImpl ) r ) { 179 return os | r.numerator | '/' | r.denominator; 180 } // ?|? 181 } // distribution 189 182 190 183 // conversion … … 195 188 } // widen 196 189 197 // http://www.ics.uci.edu/~eppstein/numth/frap.c198 190 forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); RationalImpl convert( double ); } ) 199 191 Rational(RationalImpl) narrow( double f, RationalImpl md ) { 192 // http://www.ics.uci.edu/~eppstein/numth/frap.c 200 193 if ( md <= (RationalImpl){1} ) { // maximum fractional digits too small? 201 194 return (Rational(RationalImpl)){ convert( f ), (RationalImpl){1}}; // truncate fraction … … 224 217 } // narrow 225 218 226 227 // I/O228 229 forall( otype RationalImpl | arithmetic( RationalImpl ) )230 forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )231 istype & ?|?( istype & is, Rational(RationalImpl) & r ) {232 RationalImpl t;233 is | r.numerator | r.denominator;234 t = simplify( r.numerator, r.denominator );235 r.numerator /= t;236 r.denominator /= t;237 return is;238 } // ?|?239 240 forall( otype RationalImpl | arithmetic( RationalImpl ) )241 forall( dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, RationalImpl ); } )242 ostype & ?|?( ostype & os, Rational(RationalImpl ) r ) {243 return os | r.numerator | '/' | r.denominator;244 } // ?|?245 246 219 // Local Variables: // 247 220 // tab-width: 4 // -
TabularUnified src/libcfa/stdhdr/assert.h ¶
r0182bfa r28f3a19 33 33 #define verify(x) assert(x) 34 34 #define verifyf(x, ...) assertf(x, __VA_ARGS__) 35 #define __CFA_WITH_VERIFY__ 35 36 #else 36 37 #define verify(x) -
TabularUnified src/libcfa/stdlib ¶
r0182bfa r28f3a19 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 16 07:53:10201813 // Update Count : 30 012 // Last Modified On : Sat Jun 2 08:46:35 2018 13 // Update Count : 306 14 14 // 15 15 16 16 #pragma once 17 17 18 #include <stdlib.h> // strto*, *abs 18 #include <stdlib.h> // allocation, strto*, *abs 19 extern "C" { 20 void * memalign( size_t align, size_t size ); 21 void * aligned_alloc( size_t align, size_t size ); 22 void * memset( void * dest, int c, size_t size ); 23 } // extern "C" 19 24 20 25 //--------------------------------------- … … 27 32 //--------------------------------------- 28 33 29 // C dynamic allocation30 34 static inline forall( dtype T | sized(T) ) { 35 // C dynamic allocation 36 31 37 T * malloc( void ) { 32 38 // printf( "* malloc\n" ); … … 51 57 } // realloc 52 58 53 extern "C" { void * memalign( size_t align, size_t size ); } // use default C routine for void *54 59 T * memalign( size_t align ) { 55 60 //printf( "X4\n" ); … … 57 62 } // memalign 58 63 59 extern "C" { void * aligned_alloc( size_t align, size_t size ); } // use default C routine for void *60 64 T * aligned_alloc( size_t align ) { 61 65 //printf( "X5\n" ); … … 70 74 71 75 // Cforall dynamic allocation 72 extern "C" { void * memset( void * dest, int c, size_t size ); } // use default C routine for void *73 76 74 77 T * alloc( void ) { … … 103 106 forall( dtype T | sized(T) ) T * alloc( T ptr[], size_t dim, char fill ); 104 107 105 static inline forall( dtype T | sized(T) ) T * align_alloc( size_t align ) { 106 //printf( "X13\n" ); 107 return (T *)memalign( align, sizeof(T) ); 108 } // align_alloc 109 static inline forall( dtype T | sized(T) ) T * align_alloc( size_t align, char fill ) { 110 //printf( "X14\n" ); 111 T * ptr = (T *)memalign( align, sizeof(T) ); 112 return (T *)memset( ptr, (int)fill, sizeof(T) ); 113 } // align_alloc 114 115 static inline forall( dtype T | sized(T) ) T * align_alloc( size_t align, size_t dim ) { 116 //printf( "X15\n" ); 117 return (T *)memalign( align, dim * sizeof(T) ); 118 } // align_alloc 119 static inline forall( dtype T | sized(T) ) T * align_alloc( size_t align, size_t dim, char fill ) { 120 //printf( "X16\n" ); 121 T * ptr = (T *)memalign( align, dim * sizeof(T) ); 122 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); 123 } // align_alloc 124 125 126 // data, non-array types 127 static inline forall( dtype T | sized(T) ) T * memset( T * dest, char c ) { 128 //printf( "X17\n" ); 129 return (T *)memset( dest, c, sizeof(T) ); 130 } // memset 131 extern "C" { void * memcpy( void * dest, const void * src, size_t size ); } // use default C routine for void * 132 static inline forall( dtype T | sized(T) ) T * memcpy( T * dest, const T * src ) { 133 //printf( "X18\n" ); 134 return (T *)memcpy( dest, src, sizeof(T) ); 135 } // memcpy 136 137 // data, array types 138 static inline forall( dtype T | sized(T) ) T * memset( T dest[], size_t dim, char c ) { 139 //printf( "X19\n" ); 140 return (T *)(void *)memset( dest, c, dim * sizeof(T) ); // C memset 141 } // memset 142 static inline forall( dtype T | sized(T) ) T * memcpy( T dest[], const T src[], size_t dim ) { 143 //printf( "X20\n" ); 144 return (T *)(void *)memcpy( dest, src, dim * sizeof(T) ); // C memcpy 145 } // memcpy 108 109 static inline forall( dtype T | sized(T) ) { 110 T * align_alloc( size_t align ) { 111 //printf( "X13\n" ); 112 return (T *)memalign( align, sizeof(T) ); 113 } // align_alloc 114 115 T * align_alloc( size_t align, char fill ) { 116 //printf( "X14\n" ); 117 T * ptr = (T *)memalign( align, sizeof(T) ); 118 return (T *)memset( ptr, (int)fill, sizeof(T) ); 119 } // align_alloc 120 121 T * align_alloc( size_t align, size_t dim ) { 122 //printf( "X15\n" ); 123 return (T *)memalign( align, dim * sizeof(T) ); 124 } // align_alloc 125 126 T * align_alloc( size_t align, size_t dim, char fill ) { 127 //printf( "X16\n" ); 128 T * ptr = (T *)memalign( align, dim * sizeof(T) ); 129 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); 130 } // align_alloc 131 } // distribution 132 133 134 static inline forall( dtype T | sized(T) ) { 135 // data, non-array types 136 137 T * memset( T * dest, char c ) { 138 //printf( "X17\n" ); 139 return (T *)memset( dest, c, sizeof(T) ); 140 } // memset 141 142 extern "C" { void * memcpy( void * dest, const void * src, size_t size ); } // use default C routine for void * 143 144 T * memcpy( T * dest, const T * src ) { 145 //printf( "X18\n" ); 146 return (T *)memcpy( dest, src, sizeof(T) ); 147 } // memcpy 148 } // distribution 149 150 static inline forall( dtype T | sized(T) ) { 151 // data, array types 152 153 T * memset( T dest[], size_t dim, char c ) { 154 //printf( "X19\n" ); 155 return (T *)(void *)memset( dest, c, dim * sizeof(T) ); // C memset 156 } // memset 157 158 T * memcpy( T dest[], const T src[], size_t dim ) { 159 //printf( "X20\n" ); 160 return (T *)(void *)memcpy( dest, src, dim * sizeof(T) ); // C memcpy 161 } // memcpy 162 } // distribution 146 163 147 164 // allocation/deallocation and constructor/destructor, non-array types … … 189 206 //--------------------------------------- 190 207 191 forall( otype E | { int ?<?( E, E ); } ) 192 E * bsearch( E key, const E * vals, size_t dim ); 193 194 forall( otype E | { int ?<?( E, E ); } ) 195 size_t bsearch( E key, const E * vals, size_t dim ); 196 197 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 198 E * bsearch( K key, const E * vals, size_t dim ); 199 200 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 201 size_t bsearch( K key, const E * vals, size_t dim ); 202 203 204 forall( otype E | { int ?<?( E, E ); } ) 205 E * bsearchl( E key, const E * vals, size_t dim ); 206 207 forall( otype E | { int ?<?( E, E ); } ) 208 size_t bsearchl( E key, const E * vals, size_t dim ); 209 210 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 211 E * bsearchl( K key, const E * vals, size_t dim ); 212 213 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 214 size_t bsearchl( K key, const E * vals, size_t dim ); 215 216 217 forall( otype E | { int ?<?( E, E ); } ) 218 E * bsearchu( E key, const E * vals, size_t dim ); 219 220 forall( otype E | { int ?<?( E, E ); } ) 221 size_t bsearchu( E key, const E * vals, size_t dim ); 222 223 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 224 E * bsearchu( K key, const E * vals, size_t dim ); 225 226 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 227 size_t bsearchu( K key, const E * vals, size_t dim ); 228 229 230 forall( otype E | { int ?<?( E, E ); } ) 231 void qsort( E * vals, size_t dim ); 208 forall( otype E | { int ?<?( E, E ); } ) { 209 E * bsearch( E key, const E * vals, size_t dim ); 210 size_t bsearch( E key, const E * vals, size_t dim ); 211 E * bsearchl( E key, const E * vals, size_t dim ); 212 size_t bsearchl( E key, const E * vals, size_t dim ); 213 E * bsearchu( E key, const E * vals, size_t dim ); 214 size_t bsearchu( E key, const E * vals, size_t dim ); 215 216 void qsort( E * vals, size_t dim ); 217 } // distribution 218 219 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) { 220 E * bsearch( K key, const E * vals, size_t dim ); 221 size_t bsearch( K key, const E * vals, size_t dim ); 222 E * bsearchl( K key, const E * vals, size_t dim ); 223 size_t bsearchl( K key, const E * vals, size_t dim ); 224 E * bsearchu( K key, const E * vals, size_t dim ); 225 size_t bsearchu( K key, const E * vals, size_t dim ); 226 } // distribution 232 227 233 228 //--------------------------------------- -
TabularUnified src/libcfa/stdlib.c ¶
r0182bfa r28f3a19 10 10 // Created On : Thu Jan 28 17:10:29 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jan 3 08:29:29201813 // Update Count : 44 412 // Last Modified On : Sat Jun 2 06:15:05 2018 13 // Update Count : 448 14 14 // 15 15 … … 130 130 //--------------------------------------- 131 131 132 forall( otype E | { int ?<?( E, E ); } ) 133 E * bsearch( E key, const E * vals, size_t dim ) { 134 int cmp( const void * t1, const void * t2 ) { 135 return *(E *)t1 < *(E *)t2 ? -1 : *(E *)t2 < *(E *)t1 ? 1 : 0; 136 } // cmp 137 return (E *)bsearch( &key, vals, dim, sizeof(E), cmp ); 138 } // bsearch 139 140 forall( otype E | { int ?<?( E, E ); } ) 141 size_t bsearch( E key, const E * vals, size_t dim ) { 142 E * result = bsearch( key, vals, dim ); 143 return result ? result - vals : dim; // pointer subtraction includes sizeof(E) 144 } // bsearch 145 146 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 147 E * bsearch( K key, const E * vals, size_t dim ) { 148 int cmp( const void * t1, const void * t2 ) { 149 return *(K *)t1 < getKey( *(E *)t2 ) ? -1 : getKey( *(E *)t2 ) < *(K *)t1 ? 1 : 0; 150 } // cmp 151 return (E *)bsearch( &key, vals, dim, sizeof(E), cmp ); 152 } // bsearch 153 154 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 155 size_t bsearch( K key, const E * vals, size_t dim ) { 156 E * result = bsearch( key, vals, dim ); 157 return result ? result - vals : dim; // pointer subtraction includes sizeof(E) 158 } // bsearch 159 160 161 forall( otype E | { int ?<?( E, E ); } ) 162 size_t bsearchl( E key, const E * vals, size_t dim ) { 163 size_t l = 0, m, h = dim; 164 while ( l < h ) { 165 m = (l + h) / 2; 166 if ( (E &)(vals[m]) < key ) { // cast away const 167 l = m + 1; 168 } else { 169 h = m; 170 } // if 171 } // while 172 return l; 173 } // bsearchl 174 175 forall( otype E | { int ?<?( E, E ); } ) 176 E * bsearchl( E key, const E * vals, size_t dim ) { 177 size_t posn = bsearchl( key, vals, dim ); 178 return (E *)(&vals[posn]); // cast away const 179 } // bsearchl 180 181 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 182 size_t bsearchl( K key, const E * vals, size_t dim ) { 183 size_t l = 0, m, h = dim; 184 while ( l < h ) { 185 m = (l + h) / 2; 186 if ( getKey( vals[m] ) < key ) { 187 l = m + 1; 188 } else { 189 h = m; 190 } // if 191 } // while 192 return l; 193 } // bsearchl 194 195 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 196 E * bsearchl( K key, const E * vals, size_t dim ) { 197 size_t posn = bsearchl( key, vals, dim ); 198 return (E *)(&vals[posn]); // cast away const 199 } // bsearchl 200 201 202 forall( otype E | { int ?<?( E, E ); } ) 203 size_t bsearchu( E key, const E * vals, size_t dim ) { 204 size_t l = 0, m, h = dim; 205 while ( l < h ) { 206 m = (l + h) / 2; 207 if ( ! ( key < (E &)(vals[m]) ) ) { // cast away const 208 l = m + 1; 209 } else { 210 h = m; 211 } // if 212 } // while 213 return l; 214 } // bsearchu 215 216 forall( otype E | { int ?<?( E, E ); } ) 217 E * bsearchu( E key, const E * vals, size_t dim ) { 218 size_t posn = bsearchu( key, vals, dim ); 219 return (E *)(&vals[posn]); 220 } // bsearchu 221 222 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 223 size_t bsearchu( K key, const E * vals, size_t dim ) { 224 size_t l = 0, m, h = dim; 225 while ( l < h ) { 226 m = (l + h) / 2; 227 if ( ! ( key < getKey( vals[m] ) ) ) { 228 l = m + 1; 229 } else { 230 h = m; 231 } // if 232 } // while 233 return l; 234 } // bsearchu 235 236 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) 237 E * bsearchu( K key, const E * vals, size_t dim ) { 238 size_t posn = bsearchu( key, vals, dim ); 239 return (E *)(&vals[posn]); 240 } // bsearchu 241 242 243 forall( otype E | { int ?<?( E, E ); } ) 244 void qsort( E * vals, size_t dim ) { 245 int cmp( const void * t1, const void * t2 ) { 246 return *(E *)t1 < *(E *)t2 ? -1 : *(E *)t2 < *(E *)t1 ? 1 : 0; 247 } // cmp 248 qsort( vals, dim, sizeof(E), cmp ); 249 } // qsort 132 forall( otype E | { int ?<?( E, E ); } ) { 133 E * bsearch( E key, const E * vals, size_t dim ) { 134 int cmp( const void * t1, const void * t2 ) { 135 return *(E *)t1 < *(E *)t2 ? -1 : *(E *)t2 < *(E *)t1 ? 1 : 0; 136 } // cmp 137 return (E *)bsearch( &key, vals, dim, sizeof(E), cmp ); 138 } // bsearch 139 140 size_t bsearch( E key, const E * vals, size_t dim ) { 141 E * result = bsearch( key, vals, dim ); 142 return result ? result - vals : dim; // pointer subtraction includes sizeof(E) 143 } // bsearch 144 145 size_t bsearchl( E key, const E * vals, size_t dim ) { 146 size_t l = 0, m, h = dim; 147 while ( l < h ) { 148 m = (l + h) / 2; 149 if ( (E &)(vals[m]) < key ) { // cast away const 150 l = m + 1; 151 } else { 152 h = m; 153 } // if 154 } // while 155 return l; 156 } // bsearchl 157 158 E * bsearchl( E key, const E * vals, size_t dim ) { 159 size_t posn = bsearchl( key, vals, dim ); 160 return (E *)(&vals[posn]); // cast away const 161 } // bsearchl 162 163 size_t bsearchu( E key, const E * vals, size_t dim ) { 164 size_t l = 0, m, h = dim; 165 while ( l < h ) { 166 m = (l + h) / 2; 167 if ( ! ( key < (E &)(vals[m]) ) ) { // cast away const 168 l = m + 1; 169 } else { 170 h = m; 171 } // if 172 } // while 173 return l; 174 } // bsearchu 175 176 E * bsearchu( E key, const E * vals, size_t dim ) { 177 size_t posn = bsearchu( key, vals, dim ); 178 return (E *)(&vals[posn]); 179 } // bsearchu 180 181 182 void qsort( E * vals, size_t dim ) { 183 int cmp( const void * t1, const void * t2 ) { 184 return *(E *)t1 < *(E *)t2 ? -1 : *(E *)t2 < *(E *)t1 ? 1 : 0; 185 } // cmp 186 qsort( vals, dim, sizeof(E), cmp ); 187 } // qsort 188 } // distribution 189 190 191 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) { 192 E * bsearch( K key, const E * vals, size_t dim ) { 193 int cmp( const void * t1, const void * t2 ) { 194 return *(K *)t1 < getKey( *(E *)t2 ) ? -1 : getKey( *(E *)t2 ) < *(K *)t1 ? 1 : 0; 195 } // cmp 196 return (E *)bsearch( &key, vals, dim, sizeof(E), cmp ); 197 } // bsearch 198 199 size_t bsearch( K key, const E * vals, size_t dim ) { 200 E * result = bsearch( key, vals, dim ); 201 return result ? result - vals : dim; // pointer subtraction includes sizeof(E) 202 } // bsearch 203 204 size_t bsearchl( K key, const E * vals, size_t dim ) { 205 size_t l = 0, m, h = dim; 206 while ( l < h ) { 207 m = (l + h) / 2; 208 if ( getKey( vals[m] ) < key ) { 209 l = m + 1; 210 } else { 211 h = m; 212 } // if 213 } // while 214 return l; 215 } // bsearchl 216 217 E * bsearchl( K key, const E * vals, size_t dim ) { 218 size_t posn = bsearchl( key, vals, dim ); 219 return (E *)(&vals[posn]); // cast away const 220 } // bsearchl 221 222 size_t bsearchu( K key, const E * vals, size_t dim ) { 223 size_t l = 0, m, h = dim; 224 while ( l < h ) { 225 m = (l + h) / 2; 226 if ( ! ( key < getKey( vals[m] ) ) ) { 227 l = m + 1; 228 } else { 229 h = m; 230 } // if 231 } // while 232 return l; 233 } // bsearchu 234 235 E * bsearchu( K key, const E * vals, size_t dim ) { 236 size_t posn = bsearchu( key, vals, dim ); 237 return (E *)(&vals[posn]); 238 } // bsearchu 239 } // distribution 250 240 251 241 //--------------------------------------- -
TabularUnified src/main.cc ¶
r0182bfa r28f3a19 11 11 // Created On : Fri May 15 23:12:02 2015 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Mon May 7 14:35:57 201814 // Update Count : 49 213 // Last Modified On : Wed Jun 6 15:51:47 2018 14 // Update Count : 498 15 15 // 16 16 … … 160 160 << "." << endl; 161 161 backtrace( 2 ); // skip first 2 stack frames 162 exit( EXIT_FAILURE ); 162 //_exit( EXIT_FAILURE ); 163 abort(); 163 164 } // sigSegvBusHandler 164 165 … … 261 262 } // if 262 263 263 PASS( " mutate", ControlStruct::mutate( translationUnit ) );264 PASS( "fixLabels", ControlStruct::fixLabels( translationUnit ) ); 264 265 PASS( "fixNames", CodeGen::fixNames( translationUnit ) ); 265 266 PASS( "genInit", InitTweak::genInit( translationUnit ) ); … … 571 572 yyin = input; 572 573 yylineno = 1; 573 typedefTable.enterScope();574 574 int parseStatus = yyparse(); 575 575 -
TabularUnified src/prelude/Makefile.am ¶
r0182bfa r28f3a19 37 37 # create forward declarations for gcc builtins 38 38 gcc-builtins.cf : gcc-builtins.c prototypes.sed 39 ${AM_V_GEN}@BACKEND_CC@ -E -P $< | sed -r -f prototypes.sed > $@39 ${AM_V_GEN}@BACKEND_CC@ @CFA_FLAGS@ -E -P $< | sed -r -f prototypes.sed > $@ 40 40 41 41 gcc-builtins.c : builtins.def prototypes.awk sync-builtins.cf 42 ${AM_V_GEN}@BACKEND_CC@ -E prototypes.c | awk -f prototypes.awk > $@42 ${AM_V_GEN}@BACKEND_CC@ @CFA_FLAGS@ -E prototypes.c | awk -f prototypes.awk > $@ 43 43 44 44 builtins.def : -
TabularUnified src/prelude/Makefile.in ¶
r0182bfa r28f3a19 506 506 # create forward declarations for gcc builtins 507 507 gcc-builtins.cf : gcc-builtins.c prototypes.sed 508 ${AM_V_GEN}@BACKEND_CC@ -E -P $< | sed -r -f prototypes.sed > $@508 ${AM_V_GEN}@BACKEND_CC@ @CFA_FLAGS@ -E -P $< | sed -r -f prototypes.sed > $@ 509 509 510 510 gcc-builtins.c : builtins.def prototypes.awk sync-builtins.cf 511 ${AM_V_GEN}@BACKEND_CC@ -E prototypes.c | awk -f prototypes.awk > $@511 ${AM_V_GEN}@BACKEND_CC@ @CFA_FLAGS@ -E prototypes.c | awk -f prototypes.awk > $@ 512 512 513 513 builtins.def : -
TabularUnified src/prelude/extras.regx ¶
r0182bfa r28f3a19 1 1 typedef.* size_t; 2 2 typedef.* ptrdiff_t; 3 typedef.* __int8_t; 4 typedef.* __int16_t; 5 typedef.* __int32_t; 6 typedef.* __int64_t; 7 typedef.* __uint8_t; 8 typedef.* __uint16_t; 9 typedef.* __uint32_t; 10 typedef.* __uint64_t; 3 11 typedef.* int8_t; 4 12 typedef.* int16_t; -
TabularUnified src/prelude/prelude.cf ¶
r0182bfa r28f3a19 458 458 signed long long int ?=?( signed long long int &, signed long long int ), ?=?( volatile signed long long int &, signed long long int ); 459 459 unsigned long long int ?=?( unsigned long long int &, unsigned long long int ), ?=?( volatile unsigned long long int &, unsigned long long int ); 460 __int128 ?=?( __int128 &, __int128 ), ?=?( volatile __int128 &, __int128 );461 460 zero_t ?=?( zero_t &, zero_t ); 462 461 one_t ?=?( one_t &, one_t ); -
TabularUnified src/prelude/sync-builtins.cf ¶
r0182bfa r28f3a19 7 7 long long int __sync_fetch_and_add(volatile long long int *, long long int,...); 8 8 long long int __sync_fetch_and_add_8(volatile long long int *, long long int,...); 9 #if defined(__SIZEOF_INT128__) 9 10 __int128 __sync_fetch_and_add(volatile __int128 *, __int128,...); 10 11 __int128 __sync_fetch_and_add_16(volatile __int128 *, __int128,...); 12 #endif 11 13 12 14 char __sync_fetch_and_sub(volatile char *, char,...); … … 18 20 long long int __sync_fetch_and_sub(volatile long long int *, long long int,...); 19 21 long long int __sync_fetch_and_sub_8(volatile long long int *, long long int,...); 22 #if defined(__SIZEOF_INT128__) 20 23 __int128 __sync_fetch_and_sub(volatile __int128 *, __int128,...); 21 24 __int128 __sync_fetch_and_sub_16(volatile __int128 *, __int128,...); 25 #endif 22 26 23 27 char __sync_fetch_and_or(volatile char *, char,...); … … 29 33 long long int __sync_fetch_and_or(volatile long long int *, long long int,...); 30 34 long long int __sync_fetch_and_or_8(volatile long long int *, long long int,...); 35 #if defined(__SIZEOF_INT128__) 31 36 __int128 __sync_fetch_and_or(volatile __int128 *, __int128,...); 32 37 __int128 __sync_fetch_and_or_16(volatile __int128 *, __int128,...); 38 #endif 33 39 34 40 char __sync_fetch_and_and(volatile char *, char,...); … … 40 46 long long int __sync_fetch_and_and(volatile long long int *, long long int,...); 41 47 long long int __sync_fetch_and_and_8(volatile long long int *, long long int,...); 48 #if defined(__SIZEOF_INT128__) 42 49 __int128 __sync_fetch_and_and(volatile __int128 *, __int128,...); 43 50 __int128 __sync_fetch_and_and_16(volatile __int128 *, __int128,...); 51 #endif 44 52 45 53 char __sync_fetch_and_xor(volatile char *, char,...); … … 51 59 long long int __sync_fetch_and_xor(volatile long long int *, long long int,...); 52 60 long long int __sync_fetch_and_xor_8(volatile long long int *, long long int,...); 61 #if defined(__SIZEOF_INT128__) 53 62 __int128 __sync_fetch_and_xor(volatile __int128 *, __int128,...); 54 63 __int128 __sync_fetch_and_xor_16(volatile __int128 *, __int128,...); 64 #endif 55 65 56 66 char __sync_fetch_and_nand(volatile char *, char,...); … … 62 72 long long int __sync_fetch_and_nand(volatile long long int *, long long int,...); 63 73 long long int __sync_fetch_and_nand_8(volatile long long int *, long long int,...); 74 #if defined(__SIZEOF_INT128__) 64 75 __int128 __sync_fetch_and_nand(volatile __int128 *, __int128,...); 65 76 __int128 __sync_fetch_and_nand_16(volatile __int128 *, __int128,...); 77 #endif 66 78 67 79 char __sync_add_and_fetch(volatile char *, char,...); … … 73 85 long long int __sync_add_and_fetch(volatile long long int *, long long int,...); 74 86 long long int __sync_add_and_fetch_8(volatile long long int *, long long int,...); 87 #if defined(__SIZEOF_INT128__) 75 88 __int128 __sync_add_and_fetch(volatile __int128 *, __int128,...); 76 89 __int128 __sync_add_and_fetch_16(volatile __int128 *, __int128,...); 90 #endif 77 91 78 92 char __sync_sub_and_fetch(volatile char *, char,...); … … 84 98 long long int __sync_sub_and_fetch(volatile long long int *, long long int,...); 85 99 long long int __sync_sub_and_fetch_8(volatile long long int *, long long int,...); 100 #if defined(__SIZEOF_INT128__) 86 101 __int128 __sync_sub_and_fetch(volatile __int128 *, __int128,...); 87 102 __int128 __sync_sub_and_fetch_16(volatile __int128 *, __int128,...); 103 #endif 88 104 89 105 char __sync_or_and_fetch(volatile char *, char,...); … … 95 111 long long int __sync_or_and_fetch(volatile long long int *, long long int,...); 96 112 long long int __sync_or_and_fetch_8(volatile long long int *, long long int,...); 113 #if defined(__SIZEOF_INT128__) 97 114 __int128 __sync_or_and_fetch(volatile __int128 *, __int128,...); 98 115 __int128 __sync_or_and_fetch_16(volatile __int128 *, __int128,...); 116 #endif 99 117 100 118 char __sync_and_and_fetch(volatile char *, char,...); … … 106 124 long long int __sync_and_and_fetch(volatile long long int *, long long int,...); 107 125 long long int __sync_and_and_fetch_8(volatile long long int *, long long int,...); 126 #if defined(__SIZEOF_INT128__) 108 127 __int128 __sync_and_and_fetch(volatile __int128 *, __int128,...); 109 128 __int128 __sync_and_and_fetch_16(volatile __int128 *, __int128,...); 129 #endif 110 130 111 131 char __sync_xor_and_fetch(volatile char *, char,...); … … 117 137 long long int __sync_xor_and_fetch(volatile long long int *, long long int,...); 118 138 long long int __sync_xor_and_fetch_8(volatile long long int *, long long int,...); 139 #if defined(__SIZEOF_INT128__) 119 140 __int128 __sync_xor_and_fetch(volatile __int128 *, __int128,...); 120 141 __int128 __sync_xor_and_fetch_16(volatile __int128 *, __int128,...); 142 #endif 121 143 122 144 char __sync_nand_and_fetch(volatile char *, char,...); … … 128 150 long long int __sync_nand_and_fetch(volatile long long int *, long long int,...); 129 151 long long int __sync_nand_and_fetch_8(volatile long long int *, long long int,...); 152 #if defined(__SIZEOF_INT128__) 130 153 __int128 __sync_nand_and_fetch(volatile __int128 *, __int128,...); 131 154 __int128 __sync_nand_and_fetch_16(volatile __int128 *, __int128,...); 155 #endif 132 156 133 157 _Bool __sync_bool_compare_and_swap(volatile char *, char, char,...); … … 139 163 _Bool __sync_bool_compare_and_swap(volatile long long int *, long long int, long long int,...); 140 164 _Bool __sync_bool_compare_and_swap_8(volatile long long int *, long long int, long long int,...); 165 #if defined(__SIZEOF_INT128__) 141 166 _Bool __sync_bool_compare_and_swap(volatile __int128 *, __int128, __int128,...); 142 167 _Bool __sync_bool_compare_and_swap_16(volatile __int128 *, __int128, __int128,...); 168 #endif 143 169 144 170 char __sync_val_compare_and_swap(volatile char *, char, char,...); … … 150 176 long long int __sync_val_compare_and_swap(volatile long long int *, long long int, long long int,...); 151 177 long long int __sync_val_compare_and_swap_8(volatile long long int *, long long int, long long int,...); 178 #if defined(__SIZEOF_INT128__) 152 179 __int128 __sync_val_compare_and_swap(volatile __int128 *, __int128, __int128,...); 153 180 __int128 __sync_val_compare_and_swap_16(volatile __int128 *, __int128, __int128,...); 181 #endif 154 182 155 183 char __sync_lock_test_and_set(volatile char *, char,...); … … 161 189 long long int __sync_lock_test_and_set(volatile long long int *, long long int,...); 162 190 long long int __sync_lock_test_and_set_8(volatile long long int *, long long int,...); 191 #if defined(__SIZEOF_INT128__) 163 192 __int128 __sync_lock_test_and_set(volatile __int128 *, __int128,...); 164 193 __int128 __sync_lock_test_and_set_16(volatile __int128 *, __int128,...); 194 #endif 165 195 166 196 void __sync_lock_release(volatile char *,...); … … 172 202 void __sync_lock_release(volatile long long int *,...); 173 203 void __sync_lock_release_8(volatile long long int *,...); 204 #if defined(__SIZEOF_INT128__) 174 205 void __sync_lock_release(volatile __int128 *,...); 175 206 void __sync_lock_release_16(volatile __int128 *,...); 207 #endif 176 208 177 209 void __sync_synchronize(); … … 185 217 _Bool __atomic_test_and_set(volatile int *, int); 186 218 _Bool __atomic_test_and_set(volatile long long int *, int); 219 #if defined(__SIZEOF_INT128__) 187 220 _Bool __atomic_test_and_set(volatile __int128 *, int); 221 #endif 222 188 223 void __atomic_clear(volatile _Bool *, int); 189 224 void __atomic_clear(volatile char *, int); … … 191 226 void __atomic_clear(volatile int *, int); 192 227 void __atomic_clear(volatile long long int *, int); 228 #if defined(__SIZEOF_INT128__) 193 229 void __atomic_clear(volatile __int128 *, int); 230 #endif 194 231 195 232 char __atomic_exchange_n(volatile char *, volatile char *, int); … … 205 242 long long int __atomic_exchange_8(volatile long long int *, long long int, int); 206 243 void __atomic_exchange(volatile long long int *, volatile long long int *, volatile long long int *, int); 244 #if defined(__SIZEOF_INT128__) 207 245 __int128 __atomic_exchange_n(volatile __int128 *, volatile __int128 *, int); 208 246 __int128 __atomic_exchange_16(volatile __int128 *, __int128, int); 209 247 void __atomic_exchange(volatile __int128 *, volatile __int128 *, volatile __int128 *, int); 210 248 #endif 249 250 _Bool __atomic_load_n(const volatile _Bool *, int); 251 void __atomic_load(const volatile _Bool *, volatile _Bool *, int); 211 252 char __atomic_load_n(const volatile char *, int); 212 253 char __atomic_load_1(const volatile char *, int); … … 221 262 long long int __atomic_load_8(const volatile long long int *, int); 222 263 void __atomic_load(const volatile long long int *, volatile long long int *, int); 264 #if defined(__SIZEOF_INT128__) 223 265 __int128 __atomic_load_n(const volatile __int128 *, int); 224 266 __int128 __atomic_load_16(const volatile __int128 *, int); 225 267 void __atomic_load(const volatile __int128 *, volatile __int128 *, int); 268 #endif 226 269 227 270 _Bool __atomic_compare_exchange_n(volatile char *, char *, char, _Bool, int, int); … … 237 280 _Bool __atomic_compare_exchange_8(volatile long long int *, long long int *, long long int, _Bool, int, int); 238 281 _Bool __atomic_compare_exchange (volatile long long int *, long long int *, long long int *, _Bool, int, int); 282 #if defined(__SIZEOF_INT128__) 239 283 _Bool __atomic_compare_exchange_n (volatile __int128 *, __int128 *, __int128, _Bool, int, int); 240 284 _Bool __atomic_compare_exchange_16(volatile __int128 *, __int128 *, __int128, _Bool, int, int); 241 285 _Bool __atomic_compare_exchange (volatile __int128 *, __int128 *, __int128 *, _Bool, int, int); 286 #endif 242 287 243 288 void __atomic_store_n(volatile _Bool *, _Bool, int); 244 void __atomic_store_1(volatile _Bool *, _Bool, int);245 289 void __atomic_store(volatile _Bool *, _Bool *, int); 246 290 void __atomic_store_n(volatile char *, char, int); … … 256 300 void __atomic_store_8(volatile long long int *, long long int, int); 257 301 void __atomic_store(volatile long long int *, long long int *, int); 302 #if defined(__SIZEOF_INT128__) 258 303 void __atomic_store_n(volatile __int128 *, __int128, int); 259 304 void __atomic_store_16(volatile __int128 *, __int128, int); 260 305 void __atomic_store(volatile __int128 *, __int128 *, int); 306 #endif 261 307 262 308 char __atomic_add_fetch (volatile char *, char, int); … … 268 314 long long int __atomic_add_fetch (volatile long long int *, long long int, int); 269 315 long long int __atomic_add_fetch_8(volatile long long int *, long long int, int); 316 #if defined(__SIZEOF_INT128__) 270 317 __int128 __atomic_add_fetch (volatile __int128 *, __int128, int); 271 318 __int128 __atomic_add_fetch_16(volatile __int128 *, __int128, int); 319 #endif 272 320 273 321 char __atomic_sub_fetch (volatile char *, char, int); … … 279 327 long long int __atomic_sub_fetch (volatile long long int *, long long int, int); 280 328 long long int __atomic_sub_fetch_8(volatile long long int *, long long int, int); 329 #if defined(__SIZEOF_INT128__) 281 330 __int128 __atomic_sub_fetch (volatile __int128 *, __int128, int); 282 331 __int128 __atomic_sub_fetch_16(volatile __int128 *, __int128, int); 332 #endif 283 333 284 334 char __atomic_and_fetch (volatile char *, char, int); … … 290 340 long long int __atomic_and_fetch (volatile long long int *, long long int, int); 291 341 long long int __atomic_and_fetch_8(volatile long long int *, long long int, int); 342 #if defined(__SIZEOF_INT128__) 292 343 __int128 __atomic_and_fetch (volatile __int128 *, __int128, int); 293 344 __int128 __atomic_and_fetch_16(volatile __int128 *, __int128, int); 345 #endif 294 346 295 347 char __atomic_nand_fetch (volatile char *, char, int); … … 301 353 long long int __atomic_nand_fetch (volatile long long int *, long long int, int); 302 354 long long int __atomic_nand_fetch_8(volatile long long int *, long long int, int); 355 #if defined(__SIZEOF_INT128__) 303 356 __int128 __atomic_nand_fetch (volatile __int128 *, __int128, int); 304 357 __int128 __atomic_nand_fetch_16(volatile __int128 *, __int128, int); 358 #endif 305 359 306 360 char __atomic_xor_fetch (volatile char *, char, int); … … 312 366 long long int __atomic_xor_fetch (volatile long long int *, long long int, int); 313 367 long long int __atomic_xor_fetch_8(volatile long long int *, long long int, int); 368 #if defined(__SIZEOF_INT128__) 314 369 __int128 __atomic_xor_fetch (volatile __int128 *, __int128, int); 315 370 __int128 __atomic_xor_fetch_16(volatile __int128 *, __int128, int); 371 #endif 316 372 317 373 char __atomic_or_fetch (volatile char *, char, int); … … 323 379 long long int __atomic_or_fetch (volatile long long int *, long long int, int); 324 380 long long int __atomic_or_fetch_8(volatile long long int *, long long int, int); 381 #if defined(__SIZEOF_INT128__) 325 382 __int128 __atomic_or_fetch (volatile __int128 *, __int128, int); 326 383 __int128 __atomic_or_fetch_16(volatile __int128 *, __int128, int); 384 #endif 327 385 328 386 char __atomic_fetch_add (volatile char *, char, int); … … 334 392 long long int __atomic_fetch_add (volatile long long int *, long long int, int); 335 393 long long int __atomic_fetch_add_8(volatile long long int *, long long int, int); 394 #if defined(__SIZEOF_INT128__) 336 395 __int128 __atomic_fetch_add (volatile __int128 *, __int128, int); 337 396 __int128 __atomic_fetch_add_16(volatile __int128 *, __int128, int); 397 #endif 338 398 339 399 char __atomic_fetch_sub (volatile char *, char, int); … … 345 405 long long int __atomic_fetch_sub (volatile long long int *, long long int, int); 346 406 long long int __atomic_fetch_sub_8(volatile long long int *, long long int, int); 407 #if defined(__SIZEOF_INT128__) 347 408 __int128 __atomic_fetch_sub (volatile __int128 *, __int128, int); 348 409 __int128 __atomic_fetch_sub_16(volatile __int128 *, __int128, int); 410 #endif 349 411 350 412 char __atomic_fetch_and (volatile char *, char, int); … … 356 418 long long int __atomic_fetch_and (volatile long long int *, long long int, int); 357 419 long long int __atomic_fetch_and_8(volatile long long int *, long long int, int); 420 #if defined(__SIZEOF_INT128__) 358 421 __int128 __atomic_fetch_and (volatile __int128 *, __int128, int); 359 422 __int128 __atomic_fetch_and_16(volatile __int128 *, __int128, int); 423 #endif 360 424 361 425 char __atomic_fetch_nand (volatile char *, char, int); … … 367 431 long long int __atomic_fetch_nand (volatile long long int *, long long int, int); 368 432 long long int __atomic_fetch_nand_8(volatile long long int *, long long int, int); 433 #if defined(__SIZEOF_INT128__) 369 434 __int128 __atomic_fetch_nand (volatile __int128 *, __int128, int); 370 435 __int128 __atomic_fetch_nand_16(volatile __int128 *, __int128, int); 436 #endif 371 437 372 438 char __atomic_fetch_xor (volatile char *, char, int); … … 378 444 long long int __atomic_fetch_xor (volatile long long int *, long long int, int); 379 445 long long int __atomic_fetch_xor_8(volatile long long int *, long long int, int); 446 #if defined(__SIZEOF_INT128__) 380 447 __int128 __atomic_fetch_xor (volatile __int128 *, __int128, int); 381 448 __int128 __atomic_fetch_xor_16(volatile __int128 *, __int128, int); 449 #endif 382 450 383 451 char __atomic_fetch_or (volatile char *, char, int); … … 389 457 long long int __atomic_fetch_or (volatile long long int *, long long int, int); 390 458 long long int __atomic_fetch_or_8(volatile long long int *, long long int, int); 459 #if defined(__SIZEOF_INT128__) 391 460 __int128 __atomic_fetch_or (volatile __int128 *, __int128, int); 392 461 __int128 __atomic_fetch_or_16(volatile __int128 *, __int128, int); 462 #endif 393 463 394 464 _Bool __atomic_always_lock_free(unsigned long, const volatile void *); -
TabularUnified src/tests/.gitignore ¶
r0182bfa r28f3a19 1 1 .out/ 2 2 .err/ 3 .type -
TabularUnified src/tests/Makefile.am ¶
r0182bfa r28f3a19 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Mon Nov 27 21:34:33 201714 ## Update Count : 4 813 ## Last Modified On : Wed Jun 6 16:42:20 2018 14 ## Update Count : 49 15 15 ############################################################################### 16 16 … … 28 28 DEBUG_FLAGS = 29 29 30 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ 30 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -I. 31 31 if !BUILD_DEBUG 32 32 BUILD_FLAGS += -nodebug … … 92 92 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} 93 93 94 literals : literals.c @CFA_BINDIR@/@CFA_NAME@95 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@}96 97 94 sched-ext-parse : sched-ext-parse.c @CFA_BINDIR@/@CFA_NAME@ 98 95 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} -
TabularUnified src/tests/Makefile.in ¶
r0182bfa r28f3a19 309 309 # applies to both programs 310 310 DEBUG_FLAGS = 311 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ \311 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -I. \ 312 312 $(am__append_1) $(am__append_2) $(am__append_3) 313 313 TEST_FLAGS = $(if $(test), 2> $(test), ) … … 769 769 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} 770 770 771 literals : literals.c @CFA_BINDIR@/@CFA_NAME@772 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@}773 774 771 sched-ext-parse : sched-ext-parse.c @CFA_BINDIR@/@CFA_NAME@ 775 772 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} -
TabularUnified src/tests/builtins/sync.c ¶
r0182bfa r28f3a19 8 8 volatile int * vp4 = 0; int * rp4 = 0; int v4 = 0; 9 9 volatile long long int * vp8 = 0; long long int * rp8 = 0; long long int v8 = 0; 10 #if defined(__SIZEOF_INT128__) 10 11 volatile __int128 * vp16 = 0; __int128 * rp16 = 0; __int128 v16 = 0; 12 #endif 11 13 12 14 { char ret; ret = __sync_fetch_and_add(vp1, v1); } … … 18 20 { long long int ret; ret = __sync_fetch_and_add(vp8, v8); } 19 21 { long long int ret; ret = __sync_fetch_and_add_8(vp8, v8); } 22 #if defined(__SIZEOF_INT128__) 20 23 { __int128 ret; ret = __sync_fetch_and_add(vp16, v16); } 21 24 { __int128 ret; ret = __sync_fetch_and_add_16(vp16, v16); } 25 #endif 22 26 23 27 { char ret; ret = __sync_fetch_and_sub(vp1, v1); } … … 29 33 { long long int ret; ret = __sync_fetch_and_sub(vp8, v8); } 30 34 { long long int ret; ret = __sync_fetch_and_sub_8(vp8, v8); } 35 #if defined(__SIZEOF_INT128__) 31 36 { __int128 ret; ret = __sync_fetch_and_sub(vp16, v16); } 32 37 { __int128 ret; ret = __sync_fetch_and_sub_16(vp16, v16); } 38 #endif 33 39 34 40 { char ret; ret = __sync_fetch_and_or(vp1, v1); } … … 40 46 { long long int ret; ret = __sync_fetch_and_or(vp8, v8); } 41 47 { long long int ret; ret = __sync_fetch_and_or_8(vp8, v8); } 48 #if defined(__SIZEOF_INT128__) 42 49 { __int128 ret; ret = __sync_fetch_and_or(vp16, v16); } 43 50 { __int128 ret; ret = __sync_fetch_and_or_16(vp16, v16); } 51 #endif 44 52 45 53 { char ret; ret = __sync_fetch_and_and(vp1, v1); } … … 51 59 { long long int ret; ret = __sync_fetch_and_and(vp8, v8); } 52 60 { long long int ret; ret = __sync_fetch_and_and_8(vp8, v8); } 61 #if defined(__SIZEOF_INT128__) 53 62 { __int128 ret; ret = __sync_fetch_and_and(vp16, v16); } 54 63 { __int128 ret; ret = __sync_fetch_and_and_16(vp16, v16); } 64 #endif 55 65 56 66 { char ret; ret = __sync_fetch_and_xor(vp1, v1); } … … 62 72 { long long int ret; ret = __sync_fetch_and_xor(vp8, v8); } 63 73 { long long int ret; ret = __sync_fetch_and_xor_8(vp8, v8); } 74 #if defined(__SIZEOF_INT128__) 64 75 { __int128 ret; ret = __sync_fetch_and_xor(vp16, v16); } 65 76 { __int128 ret; ret = __sync_fetch_and_xor_16(vp16, v16); } 77 #endif 66 78 67 79 { char ret; ret = __sync_fetch_and_nand(vp1, v1); } … … 73 85 { long long int ret; ret = __sync_fetch_and_nand(vp8, v8); } 74 86 { long long int ret; ret = __sync_fetch_and_nand_8(vp8, v8); } 87 #if defined(__SIZEOF_INT128__) 75 88 { __int128 ret; ret = __sync_fetch_and_nand(vp16, v16); } 76 89 { __int128 ret; ret = __sync_fetch_and_nand_16(vp16, v16); } 90 #endif 77 91 78 92 { char ret; ret = __sync_add_and_fetch(vp1, v1); } … … 84 98 { long long int ret; ret = __sync_add_and_fetch(vp8, v8); } 85 99 { long long int ret; ret = __sync_add_and_fetch_8(vp8, v8); } 100 #if defined(__SIZEOF_INT128__) 86 101 { __int128 ret; ret = __sync_add_and_fetch(vp16, v16); } 87 102 { __int128 ret; ret = __sync_add_and_fetch_16(vp16, v16); } 103 #endif 88 104 89 105 { char ret; ret = __sync_sub_and_fetch(vp1, v1); } … … 95 111 { long long int ret; ret = __sync_sub_and_fetch(vp8, v8); } 96 112 { long long int ret; ret = __sync_sub_and_fetch_8(vp8, v8); } 113 #if defined(__SIZEOF_INT128__) 97 114 { __int128 ret; ret = __sync_sub_and_fetch(vp16, v16); } 98 115 { __int128 ret; ret = __sync_sub_and_fetch_16(vp16, v16); } 116 #endif 99 117 100 118 { char ret; ret = __sync_or_and_fetch(vp1, v1); } … … 106 124 { long long int ret; ret = __sync_or_and_fetch(vp8, v8); } 107 125 { long long int ret; ret = __sync_or_and_fetch_8(vp8, v8); } 126 #if defined(__SIZEOF_INT128__) 108 127 { __int128 ret; ret = __sync_or_and_fetch(vp16, v16); } 109 128 { __int128 ret; ret = __sync_or_and_fetch_16(vp16, v16); } 129 #endif 110 130 111 131 { char ret; ret = __sync_and_and_fetch(vp1, v1); } … … 117 137 { long long int ret; ret = __sync_and_and_fetch(vp8, v8); } 118 138 { long long int ret; ret = __sync_and_and_fetch_8(vp8, v8); } 139 #if defined(__SIZEOF_INT128__) 119 140 { __int128 ret; ret = __sync_and_and_fetch(vp16, v16); } 120 141 { __int128 ret; ret = __sync_and_and_fetch_16(vp16, v16); } 142 #endif 121 143 122 144 { char ret; ret = __sync_xor_and_fetch(vp1, v1); } … … 128 150 { long long int ret; ret = __sync_xor_and_fetch(vp8, v8); } 129 151 { long long int ret; ret = __sync_xor_and_fetch_8(vp8, v8); } 152 #if defined(__SIZEOF_INT128__) 130 153 { __int128 ret; ret = __sync_xor_and_fetch(vp16, v16); } 131 154 { __int128 ret; ret = __sync_xor_and_fetch_16(vp16, v16); } 155 #endif 132 156 133 157 { char ret; ret = __sync_nand_and_fetch(vp1, v1); } … … 139 163 { long long int ret; ret = __sync_nand_and_fetch(vp8, v8); } 140 164 { long long int ret; ret = __sync_nand_and_fetch_8(vp8, v8); } 165 #if defined(__SIZEOF_INT128__) 141 166 { __int128 ret; ret = __sync_nand_and_fetch(vp16, v16); } 142 167 { __int128 ret; ret = __sync_nand_and_fetch_16(vp16, v16); } 168 #endif 143 169 144 170 { _Bool ret; ret = __sync_bool_compare_and_swap(vp1, v1, v1); } … … 150 176 { _Bool ret; ret = __sync_bool_compare_and_swap(vp8, v8, v8); } 151 177 { _Bool ret; ret = __sync_bool_compare_and_swap_8(vp8, v8, v8); } 178 #if defined(__SIZEOF_INT128__) 152 179 { _Bool ret; ret = __sync_bool_compare_and_swap(vp16, v16, v16); } 153 180 { _Bool ret; ret = __sync_bool_compare_and_swap_16(vp16, v16,v16); } 181 #endif 154 182 155 183 { char ret; ret = __sync_val_compare_and_swap(vp1, v1, v1); } … … 161 189 { long long int ret; ret = __sync_val_compare_and_swap(vp8, v8, v8); } 162 190 { long long int ret; ret = __sync_val_compare_and_swap_8(vp8, v8, v8); } 191 #if defined(__SIZEOF_INT128__) 163 192 { __int128 ret; ret = __sync_val_compare_and_swap(vp16, v16, v16); } 164 193 { __int128 ret; ret = __sync_val_compare_and_swap_16(vp16, v16,v16); } 194 #endif 165 195 166 196 { char ret; ret = __sync_lock_test_and_set(vp1, v1); } … … 172 202 { long long int ret; ret = __sync_lock_test_and_set(vp8, v8); } 173 203 { long long int ret; ret = __sync_lock_test_and_set_8(vp8, v8); } 204 #if defined(__SIZEOF_INT128__) 174 205 { __int128 ret; ret = __sync_lock_test_and_set(vp16, v16); } 175 206 { __int128 ret; ret = __sync_lock_test_and_set_16(vp16, v16); } 207 #endif 176 208 177 209 { __sync_lock_release(vp1); } … … 183 215 { __sync_lock_release(vp8); } 184 216 { __sync_lock_release_8(vp8); } 217 #if defined(__SIZEOF_INT128__) 185 218 { __sync_lock_release(vp16); } 186 219 { __sync_lock_release_16(vp16); } 220 #endif 187 221 188 222 { __sync_synchronize(); } … … 208 242 { long long int ret; ret = __atomic_exchange_8(vp8, v8, __ATOMIC_SEQ_CST); } 209 243 { long long int ret; __atomic_exchange(vp8, &v8, &ret, __ATOMIC_SEQ_CST); } 244 #if defined(__SIZEOF_INT128__) 210 245 { __int128 ret; ret = __atomic_exchange_n(vp16, &v16, __ATOMIC_SEQ_CST); } 211 246 { __int128 ret; ret = __atomic_exchange_16(vp16, v16, __ATOMIC_SEQ_CST); } 212 247 { __int128 ret; __atomic_exchange(vp16, &v16, &ret, __ATOMIC_SEQ_CST); } 248 #endif 213 249 214 250 { char ret; ret = __atomic_load_n(vp1, __ATOMIC_SEQ_CST); } … … 224 260 { long long int ret; ret = __atomic_load_8(vp8, __ATOMIC_SEQ_CST); } 225 261 { long long int ret; __atomic_load(vp8, &ret, __ATOMIC_SEQ_CST); } 262 #if defined(__SIZEOF_INT128__) 226 263 { __int128 ret; ret = __atomic_load_n(vp16, __ATOMIC_SEQ_CST); } 227 264 { __int128 ret; ret = __atomic_load_16(vp16, __ATOMIC_SEQ_CST); } 228 265 { __int128 ret; __atomic_load(vp16, &ret, __ATOMIC_SEQ_CST); } 266 #endif 229 267 230 268 { _Bool ret; ret = __atomic_compare_exchange_n(vp1, rp1, v1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } … … 240 278 { _Bool ret; ret = __atomic_compare_exchange_8(vp8, rp8, v8, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 241 279 { _Bool ret; ret = __atomic_compare_exchange(vp8, rp8, &v8, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 280 #if defined(__SIZEOF_INT128__) 242 281 { _Bool ret; ret = __atomic_compare_exchange_n(vp16, rp16, v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 243 282 { _Bool ret; ret = __atomic_compare_exchange_16(vp16, rp16, v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 244 283 { _Bool ret; ret = __atomic_compare_exchange(vp16, rp16, &v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 284 #endif 245 285 246 286 { __atomic_store_n(vp1, v1, __ATOMIC_SEQ_CST); } … … 256 296 { __atomic_store_8(vp8, v8, __ATOMIC_SEQ_CST); } 257 297 { __atomic_store(vp8, &v8, __ATOMIC_SEQ_CST); } 298 #if defined(__SIZEOF_INT128__) 258 299 { __atomic_store_n(vp16, v16, __ATOMIC_SEQ_CST); } 259 300 { __atomic_store_16(vp16, v16, __ATOMIC_SEQ_CST); } 260 301 { __atomic_store(vp16, &v16, __ATOMIC_SEQ_CST); } 302 #endif 261 303 262 304 { char ret; ret = __atomic_add_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 268 310 { long long int ret; ret = __atomic_add_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 269 311 { long long int ret; ret = __atomic_add_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 312 #if defined(__SIZEOF_INT128__) 270 313 { __int128 ret; ret = __atomic_add_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 271 314 { __int128 ret; ret = __atomic_add_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 315 #endif 272 316 273 317 { char ret; ret = __atomic_sub_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 279 323 { long long int ret; ret = __atomic_sub_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 280 324 { long long int ret; ret = __atomic_sub_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 325 #if defined(__SIZEOF_INT128__) 281 326 { __int128 ret; ret = __atomic_sub_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 282 327 { __int128 ret; ret = __atomic_sub_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 328 #endif 283 329 284 330 { char ret; ret = __atomic_and_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 290 336 { long long int ret; ret = __atomic_and_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 291 337 { long long int ret; ret = __atomic_and_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 338 #if defined(__SIZEOF_INT128__) 292 339 { __int128 ret; ret = __atomic_and_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 293 340 { __int128 ret; ret = __atomic_and_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 341 #endif 294 342 295 343 { char ret; ret = __atomic_nand_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 301 349 { long long int ret; ret = __atomic_nand_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 302 350 { long long int ret; ret = __atomic_nand_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 351 #if defined(__SIZEOF_INT128__) 303 352 { __int128 ret; ret = __atomic_nand_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 304 353 { __int128 ret; ret = __atomic_nand_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 354 #endif 305 355 306 356 { char ret; ret = __atomic_xor_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 312 362 { long long int ret; ret = __atomic_xor_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 313 363 { long long int ret; ret = __atomic_xor_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 364 #if defined(__SIZEOF_INT128__) 314 365 { __int128 ret; ret = __atomic_xor_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 315 366 { __int128 ret; ret = __atomic_xor_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 367 #endif 316 368 317 369 { char ret; ret = __atomic_or_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 323 375 { long long int ret; ret = __atomic_or_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 324 376 { long long int ret; ret = __atomic_or_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 377 #if defined(__SIZEOF_INT128__) 325 378 { __int128 ret; ret = __atomic_or_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 326 379 { __int128 ret; ret = __atomic_or_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 380 #endif 327 381 328 382 { char ret; ret = __atomic_fetch_add(vp1, v1, __ATOMIC_SEQ_CST); } … … 334 388 { long long int ret; ret = __atomic_fetch_add(vp8, v8, __ATOMIC_SEQ_CST); } 335 389 { long long int ret; ret = __atomic_fetch_add_8(vp8, v8, __ATOMIC_SEQ_CST); } 390 #if defined(__SIZEOF_INT128__) 336 391 { __int128 ret; ret = __atomic_fetch_add(vp16, v16, __ATOMIC_SEQ_CST); } 337 392 { __int128 ret; ret = __atomic_fetch_add_16(vp16, v16, __ATOMIC_SEQ_CST); } 393 #endif 338 394 339 395 { char ret; ret = __atomic_fetch_sub(vp1, v1, __ATOMIC_SEQ_CST); } … … 345 401 { long long int ret; ret = __atomic_fetch_sub(vp8, v8, __ATOMIC_SEQ_CST); } 346 402 { long long int ret; ret = __atomic_fetch_sub_8(vp8, v8, __ATOMIC_SEQ_CST); } 403 #if defined(__SIZEOF_INT128__) 347 404 { __int128 ret; ret = __atomic_fetch_sub(vp16, v16, __ATOMIC_SEQ_CST); } 348 405 { __int128 ret; ret = __atomic_fetch_sub_16(vp16, v16, __ATOMIC_SEQ_CST); } 406 #endif 349 407 350 408 { char ret; ret = __atomic_fetch_and(vp1, v1, __ATOMIC_SEQ_CST); } … … 356 414 { long long int ret; ret = __atomic_fetch_and(vp8, v8, __ATOMIC_SEQ_CST); } 357 415 { long long int ret; ret = __atomic_fetch_and_8(vp8, v8, __ATOMIC_SEQ_CST); } 416 #if defined(__SIZEOF_INT128__) 358 417 { __int128 ret; ret = __atomic_fetch_and(vp16, v16, __ATOMIC_SEQ_CST); } 359 418 { __int128 ret; ret = __atomic_fetch_and_16(vp16, v16, __ATOMIC_SEQ_CST); } 419 #endif 360 420 361 421 { char ret; ret = __atomic_fetch_nand(vp1, v1, __ATOMIC_SEQ_CST); } … … 367 427 { long long int ret; ret = __atomic_fetch_nand(vp8, v8, __ATOMIC_SEQ_CST); } 368 428 { long long int ret; ret = __atomic_fetch_nand_8(vp8, v8, __ATOMIC_SEQ_CST); } 429 #if defined(__SIZEOF_INT128__) 369 430 { __int128 ret; ret = __atomic_fetch_nand(vp16, v16, __ATOMIC_SEQ_CST); } 370 431 { __int128 ret; ret = __atomic_fetch_nand_16(vp16, v16, __ATOMIC_SEQ_CST); } 432 #endif 371 433 372 434 { char ret; ret = __atomic_fetch_xor(vp1, v1, __ATOMIC_SEQ_CST); } … … 378 440 { long long int ret; ret = __atomic_fetch_xor(vp8, v8, __ATOMIC_SEQ_CST); } 379 441 { long long int ret; ret = __atomic_fetch_xor_8(vp8, v8, __ATOMIC_SEQ_CST); } 442 #if defined(__SIZEOF_INT128__) 380 443 { __int128 ret; ret = __atomic_fetch_xor(vp16, v16, __ATOMIC_SEQ_CST); } 381 444 { __int128 ret; ret = __atomic_fetch_xor_16(vp16, v16, __ATOMIC_SEQ_CST); } 445 #endif 382 446 383 447 { char ret; ret = __atomic_fetch_or(vp1, v1, __ATOMIC_SEQ_CST); } … … 389 453 { long long int ret; ret = __atomic_fetch_or(vp8, v8, __ATOMIC_SEQ_CST); } 390 454 { long long int ret; ret = __atomic_fetch_or_8(vp8, v8, __ATOMIC_SEQ_CST); } 455 #if defined(__SIZEOF_INT128__) 391 456 { __int128 ret; ret = __atomic_fetch_or(vp16, v16, __ATOMIC_SEQ_CST); } 392 457 { __int128 ret; ret = __atomic_fetch_or_16(vp16, v16, __ATOMIC_SEQ_CST); } 458 #endif 393 459 394 460 { _Bool ret; ret = __atomic_always_lock_free(sizeof(int), vp4); } -
TabularUnified src/tests/concurrent/coroutineYield.c ¶
r0182bfa r28f3a19 4 4 #include <thread> 5 5 #include <time> 6 7 #define __kick_rate 150000ul 8 #include "long_tests.h" 6 9 7 10 #ifndef PREEMPTION_RATE … … 13 16 } 14 17 15 #ifdef LONG_TEST18 #ifdef TEST_LONG 16 19 static const unsigned long N = 600_000ul; 17 20 #else … … 23 26 void main(Coroutine& this) { 24 27 while(true) { 25 sout | "Coroutine 1" | endl; 28 #if !defined(TEST_FOREVER) 29 sout | "Coroutine 1" | endl; 30 #endif 26 31 yield(); 27 sout | "Coroutine 2" | endl; 32 #if !defined(TEST_FOREVER) 33 sout | "Coroutine 2" | endl; 34 #endif 28 35 suspend(); 29 36 } … … 33 40 int main(int argc, char* argv[]) { 34 41 Coroutine c; 35 for(int i = 0; i < N; i++) { 36 sout | "Thread 1" | endl; 42 for(int i = 0; TEST(i < N); i++) { 43 #if !defined(TEST_FOREVER) 44 sout | "Thread 1" | endl; 45 #endif 37 46 resume(c); 38 sout | "Thread 2" | endl; 47 #if !defined(TEST_FOREVER) 48 sout | "Thread 2" | endl; 49 #endif 39 50 yield(); 51 KICK_WATCHDOG; 40 52 } 41 53 } -
TabularUnified src/tests/concurrent/examples/datingService.c ¶
r0182bfa r28f3a19 8 8 // Created On : Mon Oct 30 12:56:20 2017 9 9 // Last Modified By : Peter A. Buhr 10 // Last Modified On : Wed Mar 14 22:48:40201811 // Update Count : 2 310 // Last Modified On : Sun May 27 09:05:18 2018 11 // Update Count : 26 12 12 // 13 13 … … 18 18 #include <unistd.h> // getpid 19 19 20 enum { NoOfPairs = 20 };20 enum { CompCodes = 20 }; // number of compatibility codes 21 21 22 22 monitor DatingService { 23 condition Girls[ NoOfPairs], Boys[NoOfPairs];23 condition Girls[CompCodes], Boys[CompCodes]; 24 24 unsigned int GirlPhoneNo, BoyPhoneNo; 25 25 }; // DatingService … … 47 47 } // DatingService boy 48 48 49 unsigned int girlck[ NoOfPairs];50 unsigned int boyck[ NoOfPairs];49 unsigned int girlck[CompCodes]; 50 unsigned int boyck[CompCodes]; 51 51 52 52 thread Girl { … … 88 88 int main() { 89 89 DatingService TheExchange; 90 Girl * girls[ NoOfPairs];91 Boy * boys[ NoOfPairs];90 Girl * girls[CompCodes]; 91 Boy * boys[CompCodes]; 92 92 93 93 srandom( /*getpid()*/ 103 ); 94 94 95 for ( unsigned int i = 0; i < NoOfPairs; i += 1 ) {95 for ( unsigned int i = 0; i < CompCodes; i += 1 ) { 96 96 girls[i] = new( &TheExchange, i, i ); 97 boys[i] = new( &TheExchange, i, NoOfPairs - ( i + 1 ) );97 boys[i] = new( &TheExchange, i, CompCodes - ( i + 1 ) ); 98 98 } // for 99 99 100 for ( unsigned int i = 0; i < NoOfPairs; i += 1 ) {100 for ( unsigned int i = 0; i < CompCodes; i += 1 ) { 101 101 delete( boys[i] ); 102 102 delete( girls[i] ); 103 103 } // for 104 104 105 for ( unsigned int i = 0; i < NoOfPairs; i += 1 ) {105 for ( unsigned int i = 0; i < CompCodes; i += 1 ) { 106 106 if ( girlck[ boyck[i] ] != boyck[ girlck[i] ] ) abort(); 107 107 } // for -
TabularUnified src/tests/concurrent/preempt.c ¶
r0182bfa r28f3a19 2 2 #include <thread> 3 3 #include <time> 4 5 #include "long_tests.h" 4 6 5 7 #ifndef PREEMPTION_RATE … … 11 13 } 12 14 13 #ifdef LONG_TEST15 #ifdef TEST_LONG 14 16 static const unsigned long N = 30_000ul; 15 17 #else … … 30 32 31 33 void main(worker_t & this) { 32 while( counter < N) {34 while(TEST(counter < N)) { 33 35 __cfaabi_check_preemption(); 34 36 if( (counter % 7) == this.value ) { … … 40 42 } 41 43 __cfaabi_check_preemption(); 44 KICK_WATCHDOG; 42 45 } 43 46 } -
TabularUnified src/tests/concurrent/signal/block.c ¶
r0182bfa r28f3a19 14 14 #include <time> 15 15 16 #include "long_tests.h" 17 16 18 #ifndef PREEMPTION_RATE 17 19 #define PREEMPTION_RATE 10`ms … … 22 24 } 23 25 24 #ifdef LONG_TEST26 #ifdef TEST_LONG 25 27 static const unsigned long N = 150_000ul; 26 28 #else … … 40 42 } 41 43 42 void ^?{} ( global_data_t & this ) {}44 void ^?{} ( global_data_t & mutex this ) {} 43 45 44 46 global_data_t globalA, globalB; … … 66 68 thread Waiter {}; 67 69 void main( Waiter & this ) { 68 for( int i = 0; i < N; i++ ) {70 for( int i = 0; TEST(i < N); i++ ) { 69 71 wait_op( globalA, globalB, i ); 72 KICK_WATCHDOG; 70 73 } 71 74 } -
TabularUnified src/tests/concurrent/signal/disjoint.c ¶
r0182bfa r28f3a19 4 4 #include <thread> 5 5 #include <time> 6 7 #include "long_tests.h" 6 8 7 9 #ifndef PREEMPTION_RATE … … 13 15 } 14 16 15 #ifdef LONG_TEST17 #ifdef TEST_LONG 16 18 static const unsigned long N = 300_000ul; 17 19 #else … … 26 28 monitor global_data_t; 27 29 void ?{}( global_data_t & this ); 28 void ^?{} ( global_data_t & this );30 void ^?{} ( global_data_t & mutex this ); 29 31 30 32 monitor global_data_t { … … 42 44 } 43 45 44 void ^?{} ( global_data_t & this ) {}46 void ^?{} ( global_data_t & mutex this ) {} 45 47 46 48 //------------------------------------------------------------------------------ … … 67 69 } 68 70 69 d.counter++; 71 #if !defined(TEST_FOREVER) 72 d.counter++; 73 if( (d.counter % 1000) == 0 ) sout | d.counter | endl; 74 #endif 70 75 71 if( (d.counter % 1000) == 0 ) sout | d.counter | endl; 72 73 return d.counter < N; 76 return TEST(d.counter < N); 74 77 } 75 78 … … 77 80 78 81 void main( Waiter & this ) { 79 while( wait( mut, data ) ) { yield(); }82 while( wait( mut, data ) ) { KICK_WATCHDOG; yield(); } 80 83 } 81 84 … … 94 97 95 98 //This is technically a mutual exclusion violation but the mutex monitor protects us 96 bool running = data.counter < N&& data.counter > 0;99 bool running = TEST(data.counter < N) && data.counter > 0; 97 100 if( data.state != SIGNAL && running ) { 98 101 sout | "ERROR Eager signal" | data.state | endl; -
TabularUnified src/tests/concurrent/signal/wait.c ¶
r0182bfa r28f3a19 12 12 #include <time> 13 13 14 #define __kick_rate 12000ul 15 #include "long_tests.h" 16 14 17 #ifndef PREEMPTION_RATE 15 18 #define PREEMPTION_RATE 10`ms … … 20 23 } 21 24 22 #ifdef LONG_TEST25 #ifdef TEST_LONG 23 26 static const unsigned long N = 375_000ul; 24 27 #else … … 90 93 // Waiter ABC 91 94 void main( WaiterABC & this ) { 92 for( int i = 0; i < N; i++ ) {95 for( int i = 0; TEST(i < N); i++ ) { 93 96 wait( condABC, globalA, globalB, globalC ); 97 KICK_WATCHDOG; 94 98 } 95 99 … … 100 104 // Waiter AB 101 105 void main( WaiterAB & this ) { 102 for( int i = 0; i < N; i++ ) {106 for( int i = 0; TEST(i < N); i++ ) { 103 107 wait( condAB , globalA, globalB ); 108 KICK_WATCHDOG; 104 109 } 105 110 … … 110 115 // Waiter AC 111 116 void main( WaiterAC & this ) { 112 for( int i = 0; i < N; i++ ) {117 for( int i = 0; TEST(i < N); i++ ) { 113 118 wait( condAC , globalA, globalC ); 119 KICK_WATCHDOG; 114 120 } 115 121 … … 120 126 // Waiter BC 121 127 void main( WaiterBC & this ) { 122 for( int i = 0; i < N; i++ ) {128 for( int i = 0; TEST(i < N); i++ ) { 123 129 wait( condBC , globalB, globalC ); 130 KICK_WATCHDOG; 124 131 } 125 132 -
TabularUnified src/tests/ifwhileCtl.c ¶
r0182bfa r28f3a19 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // if cond.c --7 // ifwhileCtl.c -- 8 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat Aug 26 10:13:11 2017 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Fri Sep 01 15:22:19 201713 // Update Count : 1411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jun 6 17:15:09 2018 13 // Update Count : 21 14 14 // 15 15 … … 40 40 sout | "x != y incorrect" | endl; 41 41 } // if 42 43 if ( struct S { int i; } s = { 3 }; s.i < 4 ) { 44 S s1; 45 sout | "s.i < 4 correct" | endl; 46 } else { 47 S s1; 48 sout | "s.i >= 4 incorrect" | endl; 49 } // if 50 51 while ( int x = 1 ) { 52 sout | "x != 0 correct" | endl; 53 break; 54 } // while 55 56 while ( int x = 4, y = 0 ) { 57 sout | "x != 0 && y != 0 incorrect" | endl; 58 } // while 59 60 while ( int x = 5, y = f( x ); x == y ) { 61 sout | "x == y correct" | endl; 62 break; 63 } // while 64 65 while ( struct S { int i; } s = { 3 }; s.i < 4 ) { 66 S s1; 67 sout | "s.i < 4 correct" | endl; 68 break; 69 } // while 42 70 } // main 43 71 44 72 // Local Variables: // 45 73 // tab-width: 4 // 46 // compile-command: "cfa if cond.c" //74 // compile-command: "cfa ifwhileCtl.c" // 47 75 // End: // -
TabularUnified src/tests/preempt_longrun/Makefile.am ¶
r0182bfa r28f3a19 19 19 preempt=10ul\`ms 20 20 debug=-debug 21 type=LONG 21 22 22 23 REPEAT = ${abs_top_srcdir}/tools/repeat 24 WATCHDOG = ${abs_top_srcdir}/tools/watchdog 23 25 TIME = /usr/bin/time -f "%E" 24 26 25 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -DLONG_TEST 27 # $(shell ./update-type $(type)) 28 # ./update-type $(type) 29 30 UPDATED_TYPE = $(shell ./update-type $(type)) 31 32 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -I.. -I. -DTEST_$(shell cat .type | tr a-z A-Z) 26 33 CFLAGS = ${BUILD_FLAGS} 27 34 CC = @CFA_BINDIR@/@CFA_NAME@ … … 29 36 TESTS = block coroutine create disjoint enter enter3 processor stack wait yield 30 37 31 .INTERMEDIATE: ${TESTS}38 # .INTERMEDIATE: ${TESTS} 32 39 33 40 all-local: ${TESTS:=.run} 34 41 42 runall : ${TESTS:=.run} 43 @ echo "All programs terminated normally" 44 45 watchall : ${TESTS:=.watch} 46 @ echo "All programs terminated normally" 47 48 compileall : ${TESTS} 49 @ echo "Compiled" 50 35 51 clean-local: 36 rm -f ${TESTS} 52 rm -f ${TESTS} core* out.log .type 37 53 38 % : %.c ${CC} 54 % : %.c ${CC} ${UPDATED_TYPE} 39 55 ${AM_V_GEN}${CC} ${CFLAGS} ${<} $(debug) -o ${@} 40 56 41 57 %.run : % ${REPEAT} 42 58 @ time ${REPEAT} -r out.log -i -s $(repeats) timeout ${max_time} ./${<} 59 @ rm ${<} 60 @ echo -e "${<}: SUCCESS\n" 61 62 %.watch : % ${WATCHDOG} 63 @ time ${WATCHDOG} ./${<} 43 64 @ rm ${<} 44 65 @ echo -e "${<}: SUCCESS\n" … … 49 70 @ echo -e "${<}: SUCCESS\n" 50 71 51 ${REPEAT}: 72 ${REPEAT}: ${abs_top_srcdir}/tools/Makefile 52 73 @+make -C ${abs_top_srcdir}/tools/ 74 75 ${WATCHDOG}: ${abs_top_srcdir}/tools/Makefile 76 @+make -C ${abs_top_srcdir}/tools/ -
TabularUnified src/tests/preempt_longrun/Makefile.in ¶
r0182bfa r28f3a19 452 452 preempt = 10ul\`ms 453 453 debug = -debug 454 type = LONG 454 455 REPEAT = ${abs_top_srcdir}/tools/repeat 456 WATCHDOG = ${abs_top_srcdir}/tools/watchdog 455 457 TIME = /usr/bin/time -f "%E" 456 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -DLONG_TEST 458 459 # $(shell ./update-type $(type)) 460 # ./update-type $(type) 461 UPDATED_TYPE = $(shell ./update-type $(type)) 462 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -I.. -I. -DTEST_$(shell cat .type | tr a-z A-Z) 457 463 TESTS = block coroutine create disjoint enter enter3 processor stack wait yield 458 464 all: all-am … … 873 879 874 880 875 .INTERMEDIATE: ${TESTS}881 # .INTERMEDIATE: ${TESTS} 876 882 877 883 all-local: ${TESTS:=.run} 878 884 885 runall : ${TESTS:=.run} 886 @ echo "All programs terminated normally" 887 888 watchall : ${TESTS:=.watch} 889 @ echo "All programs terminated normally" 890 891 compileall : ${TESTS} 892 @ echo "Compiled" 893 879 894 clean-local: 880 rm -f ${TESTS} 881 882 % : %.c ${CC} 895 rm -f ${TESTS} core* out.log .type 896 897 % : %.c ${CC} ${UPDATED_TYPE} 883 898 ${AM_V_GEN}${CC} ${CFLAGS} ${<} $(debug) -o ${@} 884 899 … … 888 903 @ echo -e "${<}: SUCCESS\n" 889 904 905 %.watch : % ${WATCHDOG} 906 @ time ${WATCHDOG} ./${<} 907 @ rm ${<} 908 @ echo -e "${<}: SUCCESS\n" 909 890 910 %.time : % ${REPEAT} 891 911 @ ${REPEAT} -i -s -- $(repeats) $(TIME) -a -o times.log ./${<} … … 893 913 @ echo -e "${<}: SUCCESS\n" 894 914 895 ${REPEAT}: 915 ${REPEAT}: ${abs_top_srcdir}/tools/Makefile 916 @+make -C ${abs_top_srcdir}/tools/ 917 918 ${WATCHDOG}: ${abs_top_srcdir}/tools/Makefile 896 919 @+make -C ${abs_top_srcdir}/tools/ 897 920 -
TabularUnified src/tests/preempt_longrun/create.c ¶
r0182bfa r28f3a19 2 2 #include <thread> 3 3 #include <time> 4 5 #include "long_tests.h" 4 6 5 7 #ifndef PREEMPTION_RATE … … 19 21 int main(int argc, char* argv[]) { 20 22 processor p; 21 for(int i = 0; i < N; i++) {23 for(int i = 0; TEST(i < N); i++) { 22 24 worker_t w[7]; 25 KICK_WATCHDOG; 23 26 } 24 27 } -
TabularUnified src/tests/preempt_longrun/enter.c ¶
r0182bfa r28f3a19 3 3 #include <thread> 4 4 #include <time> 5 6 #define __kick_rate 75000ul 7 #include "long_tests.h" 5 8 6 9 #ifndef PREEMPTION_RATE … … 15 18 16 19 monitor mon_t {}; 20 void foo( mon_t & mutex this ) { 21 KICK_WATCHDOG; 22 } 17 23 18 24 mon_t mon; 19 20 void foo( mon_t & mutex this ) {}21 22 25 thread worker_t {}; 23 24 26 void main( worker_t & this ) { 25 for( unsigned long i = 0; i < N; i++ ) {27 for( unsigned long i = 0; TEST(i < N); i++ ) { 26 28 foo( mon ); 27 29 } 28 }29 30 extern "C" {31 static worker_t * workers;32 30 } 33 31 … … 36 34 { 37 35 worker_t w[7]; 38 workers = w;39 36 } 40 37 } -
TabularUnified src/tests/preempt_longrun/enter3.c ¶
r0182bfa r28f3a19 3 3 #include <thread> 4 4 #include <time> 5 6 #define __kick_rate 75000ul 7 #include "long_tests.h" 5 8 6 9 #ifndef PREEMPTION_RATE … … 18 21 mon_t mon1, mon2, mon3; 19 22 20 void foo( mon_t & mutex a, mon_t & mutex b, mon_t & mutex c ) {} 23 void foo( mon_t & mutex a, mon_t & mutex b, mon_t & mutex c ) { 24 KICK_WATCHDOG; 25 } 21 26 22 27 thread worker_t {}; 23 28 24 29 void main( worker_t & this ) { 25 for( unsigned long i = 0; i < N; i++ ) {30 for( unsigned long i = 0; TEST(i < N); i++ ) { 26 31 foo( mon1, mon2, mon3 ); 27 32 } -
TabularUnified src/tests/preempt_longrun/processor.c ¶
r0182bfa r28f3a19 2 2 #include <thread> 3 3 #include <time> 4 5 #include <unistd.h> 6 7 #include "long_tests.h" 4 8 5 9 #ifndef PREEMPTION_RATE … … 11 15 } 12 16 13 static const unsigned long N = 5 _000ul;17 static const unsigned long N = 50_000ul; 14 18 15 19 int main(int argc, char* argv[]) { … … 18 22 p[pi] = new(); 19 23 } 20 for ( int i = 0; i < N; i++) {24 for ( int i = 0; TEST(i < N); i++) { 21 25 int pi = i % 15; 22 26 delete( p[pi] ); 23 27 p[pi] = new(); 28 KICK_WATCHDOG; 29 } 30 for ( int pi = 0; pi < 15; pi++ ) { 31 delete( p[pi] ); 24 32 } 25 33 } -
TabularUnified src/tests/preempt_longrun/stack.c ¶
r0182bfa r28f3a19 3 3 #include <thread> 4 4 #include <time> 5 6 #define __kick_rate 5000000ul 7 #include "long_tests.h" 5 8 6 9 #ifndef PREEMPTION_RATE … … 15 18 16 19 void main(worker_t & this) { 17 volatile long long p = 5_021_609ul; 18 volatile long long a = 326_417ul; 19 volatile long long n = 1l; 20 for (volatile long long i = 0; i < p; i++) { 21 n *= a; 22 n %= p; 23 } 20 while(TEST(0)) { 21 volatile long long p = 5_021_609ul; 22 volatile long long a = 326_417ul; 23 volatile long long n = 1l; 24 for (volatile long long i = 0; i < p; i++) { 25 n *= a; 26 n %= p; 27 KICK_WATCHDOG; 28 } 24 29 25 if( n != a ) { 26 abort(); 30 if( !TEST(n == a) ) { 31 abort(); 32 } 27 33 } 28 34 } -
TabularUnified src/tests/preempt_longrun/yield.c ¶
r0182bfa r28f3a19 2 2 #include <thread> 3 3 #include <time> 4 5 #define __kick_rate 550000ul 6 #include "long_tests.h" 4 7 5 8 #ifndef PREEMPTION_RATE … … 11 14 } 12 15 13 #ifdef LONG_TEST16 #ifdef TEST_LONG 14 17 static const unsigned long N = 9_750_000ul; 15 18 #else … … 20 23 21 24 void main(worker_t & this) { 22 for(int i = 0; i < N; i++) {25 for(int i = 0; TEST(i < N); i++) { 23 26 yield(); 27 KICK_WATCHDOG; 24 28 } 25 29 } -
TabularUnified src/tests/pybin/tools.py ¶
r0182bfa r28f3a19 83 83 return sh(cmd) 84 84 85 def which(program): 86 import os 87 def is_exe(fpath): 88 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 89 90 fpath, fname = os.path.split(program) 91 if fpath: 92 if is_exe(program): 93 return program 94 else: 95 for path in os.environ["PATH"].split(os.pathsep): 96 exe_file = os.path.join(path, program) 97 if is_exe(exe_file): 98 return exe_file 99 100 return None 85 101 ################################################################################ 86 102 # file handling … … 219 235 return False 220 236 237 def fancy_print(text): 238 column = which('column') 239 if column: 240 cmd = "%s 2> /dev/null" % column 241 print(cmd) 242 proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True) 243 proc.communicate(input=text) 244 else: 245 print(text) 221 246 222 247 settings.set_machine_default( getMachineType ) -
TabularUnified src/tests/raii/.expect/ctor-autogen-ERR1.txt ¶
r0182bfa r28f3a19 1 raii/ctor-autogen.c:102:1 error: No reasonable alternatives for expression Applying untyped:2 Name: ?{}3 ...to: 4 Cast of:5 Variable Expression: x: instance of struct Managed with body 16 ... to:7 reference to instance of struct Managed with body 18 constant expression (123 123: signed int)1 raii/ctor-autogen.c:102:1 error: Unique best alternative includes deleted identifier in Cast of: 2 Application of 3 Deleted Expression 4 Variable Expression: ?{}: static inline function 5 ... with parameters 6 _dst: reference to instance of struct Managed with body 1 7 x: signed int 8 ... returning nothing 9 9 10 ... deleted by: ?{}: function 11 ... with parameters 12 m: reference to instance of struct Managed with body 1 13 ... returning nothing 14 ... with body 15 CompoundStmt 16 Expression Statement: 17 Application of 18 Variable Expression: ?=?: function 19 ... with parameters 20 intrinsic reference to signed int 21 intrinsic signed int 22 ... returning 23 _retval__operator_assign: signed int 24 ... with attributes: 25 Attribute with name: unused 26 27 28 ... to arguments 29 Cast of: 30 Member Expression, with field: 31 x: signed int 32 ... from aggregate: 33 Cast of: 34 Variable Expression: m: reference to instance of struct Managed with body 1 35 ... to: 36 instance of struct Managed with body 1 37 ... to: 38 reference to signed int 39 Cast of: 40 constant expression (0 0: zero_t) 41 ... to: 42 signed int 43 44 ... with environment: 45 Types: 46 Non-types: 47 48 49 ... to arguments 50 Cast of: 51 Variable Expression: x: instance of struct Managed with body 1 52 ... to: 53 reference to instance of struct Managed with body 1 54 constant expression (123 123: signed int) 55 56 ... to: nothing -
TabularUnified src/tests/sum.c ¶
r0182bfa r28f3a19 11 11 // Created On : Wed May 27 17:56:53 2015 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : S at Feb 17 11:49:17201814 // Update Count : 27 313 // Last Modified On : Sun Jun 3 19:23:41 2018 14 // Update Count : 278 15 15 // 16 16 … … 18 18 #include <stdlib> 19 19 20 void ?{}( int & c, zero_t ) { c = 0; } 20 void ?{}( int & c, zero_t ) { c = 0; } // not in prelude 21 21 22 22 trait sumable( otype T ) { 23 void ?{}( T &, zero_t ); // constructor from 0 literal23 void ?{}( T &, zero_t ); // 0 literal constructor 24 24 T ?+?( T, T ); // assortment of additions 25 25 T ?+=?( T &, T ); … … 29 29 30 30 forall( otype T | sumable( T ) ) // use trait 31 T sum( unsigned int size, T a[] ) {32 T total = 0; // in stantiate T from 0 by callingconstructor33 for ( unsigned int i = 0; i < size; i += 1 )31 T sum( size_t size, T a[] ) { 32 T total = 0; // initialize by 0 constructor 33 for ( size_t i = 0; i < size; i += 1 ) 34 34 total += a[i]; // select appropriate + 35 35 return total; … … 111 111 for ( int i = 0; i < size; i += 1, v += 1 ) { 112 112 s += (int)v; 113 gs.x[i] = (int)v; // set fi led array in generic type113 gs.x[i] = (int)v; // set field array in generic type 114 114 } // for 115 115 sout | "sum from" | low | "to" | High | "is" 116 | sum( size, gs.x ) | ", check" | (int)s | endl; // add fi led array in generic type116 | sum( size, gs.x ) | ", check" | (int)s | endl; // add field array in generic type 117 117 } // main 118 118 -
TabularUnified src/tests/test.py ¶
r0182bfa r28f3a19 277 277 elif options.list : 278 278 print("Listing for %s:%s"% (settings.arch.string, settings.debug.string)) 279 print("\n".join(map(lambda t: "%s" % (t.toString()), tests)))279 fancy_print("\n".join(map(lambda t: "%s" % (t.toString()), tests))) 280 280 281 281 else : -
TabularUnified tools/Makefile.am ¶
r0182bfa r28f3a19 18 18 CFLAGS = -Wall -Wextra -O2 -g 19 19 20 noinst_PROGRAMS = busy catchsig repeat 20 noinst_PROGRAMS = busy catchsig repeat watchdog 21 21 22 22 busy_SOURCES = busy.c … … 24 24 catchsig_SOURCES = catchsig.c 25 25 repeat_SOURCES = repeat.c 26 watchdog_SOURCES = watchdog.c -
TabularUnified tools/Makefile.in ¶
r0182bfa r28f3a19 92 92 build_triplet = @build@ 93 93 host_triplet = @host@ 94 noinst_PROGRAMS = busy$(EXEEXT) catchsig$(EXEEXT) repeat$(EXEEXT) 94 noinst_PROGRAMS = busy$(EXEEXT) catchsig$(EXEEXT) repeat$(EXEEXT) \ 95 watchdog$(EXEEXT) 95 96 subdir = tools 96 97 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 … … 115 116 repeat_OBJECTS = $(am_repeat_OBJECTS) 116 117 repeat_LDADD = $(LDADD) 118 am_watchdog_OBJECTS = watchdog.$(OBJEXT) 119 watchdog_OBJECTS = $(am_watchdog_OBJECTS) 120 watchdog_LDADD = $(LDADD) 117 121 AM_V_P = $(am__v_P_@AM_V@) 118 122 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) … … 143 147 am__v_CCLD_0 = @echo " CCLD " $@; 144 148 am__v_CCLD_1 = 145 SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) 146 DIST_SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) 149 SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) \ 150 $(watchdog_SOURCES) 151 DIST_SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) \ 152 $(watchdog_SOURCES) 147 153 am__can_run_installinfo = \ 148 154 case $$AM_UPDATE_INFO_DIR in \ … … 295 301 catchsig_SOURCES = catchsig.c 296 302 repeat_SOURCES = repeat.c 303 watchdog_SOURCES = watchdog.c 297 304 all: all-am 298 305 … … 344 351 $(AM_V_CCLD)$(LINK) $(repeat_OBJECTS) $(repeat_LDADD) $(LIBS) 345 352 353 watchdog$(EXEEXT): $(watchdog_OBJECTS) $(watchdog_DEPENDENCIES) $(EXTRA_watchdog_DEPENDENCIES) 354 @rm -f watchdog$(EXEEXT) 355 $(AM_V_CCLD)$(LINK) $(watchdog_OBJECTS) $(watchdog_LDADD) $(LIBS) 356 346 357 mostlyclean-compile: 347 358 -rm -f *.$(OBJEXT) … … 353 364 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/catchsig.Po@am__quote@ 354 365 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repeat.Po@am__quote@ 366 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watchdog.Po@am__quote@ 355 367 356 368 .c.o: -
TabularUnified tools/prettyprinter/lex.ll ¶
r0182bfa r28f3a19 10 10 * Created On : Sat Dec 15 11:45:59 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Sun Apr 15 21:28:33201813 * Update Count : 27 112 * Last Modified On : Thu May 31 08:49:58 2018 13 * Update Count : 274 14 14 */ 15 15 … … 77 77 } 78 78 79 <INITIAL,C_CODE>"//"[^\n]* "\n" {// C++ style comments79 <INITIAL,C_CODE>"//"[^\n]* { // C++ style comments 80 80 #if defined(DEBUG_ALL) | defined(DEBUG_COMMENT) 81 81 cerr << "\"//\"[^\\n]*\"\n\" : " << yytext << endl;
Note:
See TracChangeset
for help on using the changeset viewer.