Changes in / [b21c77a:97397a26]
- Files:
-
- 7 added
- 22 deleted
- 121 edited
-
Jenkins/TestRegen (modified) (4 diffs)
-
Jenkinsfile (modified) (2 diffs)
-
README (modified) (2 diffs)
-
doc/papers/OOPSLA17/Makefile (modified) (4 diffs)
-
doc/papers/concurrency/Makefile (modified) (4 diffs)
-
doc/papers/concurrency/Paper.tex (modified) (77 diffs)
-
doc/papers/concurrency/figures/ext_monitor.fig (modified) (1 diff)
-
doc/papers/concurrency/figures/monitor.fig (modified) (4 diffs)
-
doc/papers/general/Makefile (modified) (3 diffs)
-
doc/papers/general/Paper.tex (modified) (2 diffs)
-
doc/proposals/ctordtor/Makefile (modified) (3 diffs)
-
doc/proposals/ctordtor/ctor.tex (modified) (5 diffs)
-
doc/proposals/tuples/Makefile (modified) (3 diffs)
-
doc/proposals/tuples/tuples.tex (modified) (4 diffs)
-
doc/proposals/user_conversions.md (modified) (9 diffs)
-
doc/refrat/Makefile (modified) (2 diffs)
-
doc/theses/aaron_moss/comp_II/Makefile (modified) (3 diffs)
-
doc/theses/thierry_delisle/.gitignore (modified) (1 diff)
-
doc/theses/thierry_delisle/Makefile (modified) (5 diffs)
-
doc/user/Makefile (modified) (2 diffs)
-
doc/working/glen_conversions/float_promo.dia (deleted)
-
doc/working/glen_conversions/float_promo.png (deleted)
-
doc/working/glen_conversions/index.html (deleted)
-
src/CodeGen/CodeGenerator.cc (modified) (5 diffs)
-
src/CodeGen/CodeGenerator.h (modified) (1 diff)
-
src/Common/Debug.h (modified) (1 diff)
-
src/Common/PassVisitor.h (modified) (4 diffs)
-
src/Common/PassVisitor.impl.h (modified) (7 diffs)
-
src/Common/SemanticError.cc (modified) (2 diffs)
-
src/Concurrency/Keywords.cc (modified) (3 diffs)
-
src/ControlStruct/ForExprMutator.cc (modified) (1 diff)
-
src/ControlStruct/ForExprMutator.h (modified) (2 diffs)
-
src/ControlStruct/Mutate.cc (modified) (1 diff)
-
src/ControlStruct/Mutate.h (modified) (2 diffs)
-
src/GenPoly/Lvalue.cc (modified) (3 diffs)
-
src/Parser/DeclarationNode.cc (modified) (14 diffs)
-
src/Parser/ExpressionNode.cc (modified) (2 diffs)
-
src/Parser/InitializerNode.cc (modified) (4 diffs)
-
src/Parser/ParseNode.h (modified) (9 diffs)
-
src/Parser/StatementNode.cc (modified) (20 diffs)
-
src/Parser/TypeData.cc (modified) (7 diffs)
-
src/Parser/TypedefTable.cc (modified) (4 diffs)
-
src/Parser/TypedefTable.h (modified) (3 diffs)
-
src/Parser/lex.ll (modified) (5 diffs)
-
src/Parser/parser.yy (modified) (54 diffs)
-
src/ResolvExpr/Alternative.cc (modified) (1 diff)
-
src/ResolvExpr/AlternativeFinder.cc (modified) (15 diffs)
-
src/ResolvExpr/CommonType.cc (modified) (3 diffs)
-
src/ResolvExpr/ConversionCost.cc (modified) (1 diff)
-
src/ResolvExpr/ExplodedActual.h (modified) (1 diff)
-
src/ResolvExpr/Resolver.cc (modified) (4 diffs)
-
src/ResolvExpr/Resolver.h (modified) (1 diff)
-
src/ResolvExpr/TypeEnvironment.cc (modified) (11 diffs)
-
src/ResolvExpr/TypeEnvironment.h (modified) (5 diffs)
-
src/ResolvExpr/Unify.cc (modified) (3 diffs)
-
src/ResolvExpr/Unify.h (modified) (3 diffs)
-
src/ResolvExpr/WidenMode.h (deleted)
-
src/SymTab/Indexer.cc (modified) (5 diffs)
-
src/SymTab/Mangler.cc (modified) (3 diffs)
-
src/SymTab/Validate.cc (modified) (3 diffs)
-
src/SynTree/BasicType.cc (modified) (1 diff)
-
src/SynTree/Declaration.cc (modified) (1 diff)
-
src/SynTree/Declaration.h (modified) (1 diff)
-
src/SynTree/Expression.cc (modified) (1 diff)
-
src/SynTree/Expression.h (modified) (1 diff)
-
src/SynTree/Mutator.h (modified) (1 diff)
-
src/SynTree/ReferenceToType.cc (modified) (5 diffs)
-
src/SynTree/Statement.cc (modified) (1 diff)
-
src/SynTree/Statement.h (modified) (1 diff)
-
src/SynTree/SynTree.h (modified) (1 diff)
-
src/SynTree/Type.cc (modified) (4 diffs)
-
src/SynTree/Type.h (modified) (1 diff)
-
src/SynTree/Visitor.h (modified) (1 diff)
-
src/benchmark/Makefile.am (modified) (5 diffs)
-
src/benchmark/Makefile.in (modified) (5 diffs)
-
src/benchmark/ctxswitch/cfa_thrd2.c (deleted)
-
src/benchmark/ctxswitch/kos_fibre.cpp (deleted)
-
src/benchmark/ctxswitch/kos_fibre2.cpp (deleted)
-
src/benchmark/fetch_add.c (deleted)
-
src/benchmark/function.c (deleted)
-
src/benchmark/loop.c (deleted)
-
src/benchmark/mutex/fetch_add.c (added)
-
src/benchmark/mutex/function.c (added)
-
src/libcfa/Makefile.am (modified) (1 diff)
-
src/libcfa/Makefile.in (modified) (10 diffs)
-
src/libcfa/bits/containers.h (modified) (2 diffs)
-
src/libcfa/bits/locks.h (modified) (2 diffs)
-
src/libcfa/concurrency/invoke.h (modified) (3 diffs)
-
src/libcfa/concurrency/kernel (modified) (5 diffs)
-
src/libcfa/concurrency/kernel.c (modified) (14 diffs)
-
src/libcfa/concurrency/kernel_private.h (modified) (3 diffs)
-
src/libcfa/concurrency/monitor.c (modified) (1 diff)
-
src/libcfa/concurrency/mutex (deleted)
-
src/libcfa/concurrency/mutex.c (deleted)
-
src/libcfa/concurrency/preemption.c (modified) (9 diffs)
-
src/libcfa/fstream (modified) (3 diffs)
-
src/libcfa/fstream.c (modified) (3 diffs)
-
src/libcfa/iostream (modified) (3 diffs)
-
src/libcfa/iostream.c (modified) (4 diffs)
-
src/libcfa/rational (modified) (3 diffs)
-
src/libcfa/rational.c (modified) (4 diffs)
-
src/libcfa/stdhdr/assert.h (modified) (1 diff)
-
src/libcfa/stdlib (modified) (7 diffs)
-
src/libcfa/stdlib.c (modified) (2 diffs)
-
src/main.cc (modified) (4 diffs)
-
src/prelude/Makefile.am (modified) (1 diff)
-
src/prelude/Makefile.in (modified) (1 diff)
-
src/prelude/extras.regx (modified) (1 diff)
-
src/prelude/prelude.cf (modified) (1 diff)
-
src/prelude/sync-builtins.cf (modified) (34 diffs)
-
src/tests/.expect/ifcond.txt (added)
-
src/tests/.expect/ifwhileCtl.txt (deleted)
-
src/tests/.expect/literals.txt (deleted)
-
src/tests/.expect/literals.x64.txt (added)
-
src/tests/.expect/literals.x86.txt (added)
-
src/tests/.gitignore (modified) (1 diff)
-
src/tests/Makefile.am (modified) (3 diffs)
-
src/tests/Makefile.in (modified) (2 diffs)
-
src/tests/builtins/sync.c (modified) (33 diffs)
-
src/tests/concurrent/coroutineYield.c (modified) (4 diffs)
-
src/tests/concurrent/examples/datingService.c (modified) (4 diffs)
-
src/tests/concurrent/preempt.c (modified) (4 diffs)
-
src/tests/concurrent/signal/barge.c (added)
-
src/tests/concurrent/signal/block.c (modified) (4 diffs)
-
src/tests/concurrent/signal/disjoint.c (modified) (7 diffs)
-
src/tests/concurrent/signal/wait.c (modified) (6 diffs)
-
src/tests/ifcond.c (added)
-
src/tests/ifwhileCtl.c (deleted)
-
src/tests/long_tests.h (deleted)
-
src/tests/preempt_longrun/Makefile.am (modified) (3 diffs)
-
src/tests/preempt_longrun/Makefile.in (modified) (4 diffs)
-
src/tests/preempt_longrun/create.c (modified) (2 diffs)
-
src/tests/preempt_longrun/enter.c (modified) (3 diffs)
-
src/tests/preempt_longrun/enter3.c (modified) (2 diffs)
-
src/tests/preempt_longrun/processor.c (modified) (3 diffs)
-
src/tests/preempt_longrun/stack.c (modified) (2 diffs)
-
src/tests/preempt_longrun/update-type (deleted)
-
src/tests/preempt_longrun/yield.c (modified) (3 diffs)
-
src/tests/pybin/tools.py (modified) (2 diffs)
-
src/tests/raii/.expect/ctor-autogen-ERR1.txt (modified) (1 diff)
-
src/tests/sum.c (modified) (4 diffs)
-
src/tests/test.py (modified) (1 diff)
-
tools/Makefile.am (modified) (2 diffs)
-
tools/Makefile.in (modified) (6 diffs)
-
tools/busy (deleted)
-
tools/error (deleted)
-
tools/error.c (deleted)
-
tools/prettyprinter/lex.ll (modified) (2 diffs)
-
tools/watchdog (deleted)
-
tools/watchdog.c (deleted)
Legend:
- Unmodified
- Added
- Removed
-
Jenkins/TestRegen
rb21c77a r97397a26 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 s://cforall.uwaterloo.ca:8082/dashboard.html.103 generated http://plg2:8082/dashboard. 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 s://cforall.uwaterloo.ca:8082/dashboard.html.120 generated http://plg2:8082/dashboard. 121 121 122 122 Test generation encoutered an error please see attached logs -
Jenkinsfile
rb21c77a r97397a26 174 174 175 175 def notify_server(int wait) { 176 sh """curl --data "wait=${wait}" -X POST http s://cforall.uwaterloo.ca:8082/jenkins/notify > /dev/null || true"""176 sh """curl --data "wait=${wait}" -X POST http://plg2: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 s://cforall.uwaterloo.ca:8082/jenkins/publish > /dev/null || true'331 sh 'curl -H \'Content-Type: application/json\' --data @bench.json http://plg2:8082/jenkins/publish > /dev/null || true' 332 332 } 333 333 } -
README
rb21c77a r97397a26 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 s://cforall.uwaterloo.ca117 http://plg.uwaterloo.ca/~cforall -
doc/papers/OOPSLA17/Makefile
rb21c77a r97397a26 33 33 34 34 DOCUMENT = generic_types.pdf 35 BASE = ${basename ${DOCUMENT}}36 35 37 36 # Directives # … … 42 41 43 42 clean : 44 @rm -frv ${DOCUMENT} ${ BASE}.ps ${Build}43 @rm -frv ${DOCUMENT} ${basename ${DOCUMENT}}.ps ${Build} 45 44 46 45 # File Dependencies # 47 46 48 ${DOCUMENT} : ${ BASE}.ps47 ${DOCUMENT} : ${basename ${DOCUMENT}}.ps 49 48 ps2pdf $< 50 49 51 ${ BASE}.ps : ${BASE}.dvi50 ${basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi 52 51 dvips ${Build}/$< -o $@ 53 52 54 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 55 ../../bibliography/pl.bib | ${Build} 53 ${basename ${DOCUMENT}}.dvi : Makefile ${Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ../../bibliography/pl.bib 56 54 # Must have *.aux file containing citations for bibtex 57 55 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi … … 65 63 ## Define the default recipes. 66 64 67 ${Build} :65 ${Build}: 68 66 mkdir -p ${Build} 69 67 … … 71 69 gnuplot -e Build="'${Build}/'" evaluation/timing.gp 72 70 73 %.tex : %.fig | ${Build}71 %.tex : %.fig 74 72 fig2dev -L eepic $< > ${Build}/$@ 75 73 76 %.ps : %.fig | ${Build}74 %.ps : %.fig 77 75 fig2dev -L ps $< > ${Build}/$@ 78 76 79 %.pstex : %.fig | ${Build}77 %.pstex : %.fig 80 78 fig2dev -L pstex $< > ${Build}/$@ 81 79 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t -
doc/papers/concurrency/Makefile
rb21c77a r97397a26 20 20 21 21 FIGURES = ${addsuffix .tex, \ 22 monitor \ 23 ext_monitor \ 22 24 int_monitor \ 23 25 dependency \ … … 25 27 26 28 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 ASE}.out.ps WileyNJD-AMA.bst ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \62 annex/local.bib ../../bibliography/pl.bib | ${Build}61 ${BASE}.dvi : Makefile ${Build} ${BASE}.out.ps WileyNJD-AMA.bst ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 62 annex/local.bib ../../bibliography/pl.bib 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 -
doc/papers/concurrency/Paper.tex
rb21c77a r97397a26 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}}} 58 61 \newcommand{\uC}{$\mu$\CC} 59 \newcommand{\TODO}[1]{{\Textbf{#1}}} 62 \newcommand{\cit}{\textsuperscript{[Citation Needed]}\xspace} 63 \newcommand{\TODO}{{\Textbf{TODO}}} 60 64 61 65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% … … 254 258 \section{Introduction} 255 259 256 This paper provides a minimal concurrency \newterm{A pplicationProgram Interface} (API) that is simple, efficient and can be used to build other concurrency features.260 This paper provides a minimal concurrency \newterm{Abstract Program Interface} (API) that is simple, efficient and can be used to build other concurrency features. 257 261 While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master. 258 262 An easier approach for programmers is to support higher-level constructs as the basis of concurrency. … … 271 275 Hence, there are two problems to be solved: concurrency and parallelism. 272 276 While these two concepts are often combined, they are distinct, requiring different tools~\cite[\S~2]{Buhr05a}. 273 Concurrency tools handle mutual exclusion and synchronization, while parallelism tools handle performance, cost,and resource utilization.277 Concurrency tools handle synchronization and mutual exclusion, while parallelism tools handle performance, cost and resource utilization. 274 278 275 279 The proposed concurrency API is implemented in a dialect of C, called \CFA. … … 282 286 Extended versions and explanation of the following code examples are available at the \CFA website~\cite{Cforall} or in Moss~\etal~\cite{Moss18}. 283 287 284 \CFA is a non-object-orientedextension of ISO-C, and hence, supports all C paradigms.288 \CFA is an extension of ISO-C, and hence, supports all C paradigms. 285 289 %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. 286 Like C, the b uilding blocks of \CFA are structures and routines.290 Like C, the basics of \CFA revolve around structures and functions. 287 291 Virtually all of the code generated by the \CFA translator respects C memory layouts and calling conventions. 288 292 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}. … … 296 300 int x = 1, y = 2, z = 3; 297 301 int * p1 = &x, ** p2 = &p1, *** p3 = &p2, $\C{// pointers to x}$ 298 `&` r1 = x, `&&` r2 = r1,`&&&` r3 = r2; $\C{// references to x}$302 `&` r1 = x, `&&` r2 = r1, `&&&` r3 = r2; $\C{// references to x}$ 299 303 int * p4 = &z, `&` r4 = z; 300 304 … … 345 349 'with' '(' $\emph{expression-list}$ ')' $\emph{compound-statement}$ 346 350 \end{cfa} 347 and may appear as the body of a routine or nested within a routinebody.351 and may appear as the body of a function or nested within a function body. 348 352 Each expression in the expression-list provides a type and object. 349 353 The type must be an aggregate type. … … 356 360 357 361 \CFA maximizes the ability to reuse names via overloading to aggressively address the naming problem. 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.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. 359 363 \begin{cquote} 360 364 \vspace*{-\baselineskip}%??? … … 411 415 \end{cquote} 412 416 Overloading is important for \CFA concurrency since the runtime system relies on creating different types to represent concurrency objects. 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: 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: 416 421 \begin{cfa} 417 422 struct S { int `i`; int j; double m; } s; … … 427 432 } 428 433 \end{cfa} 429 For parallel semantics, both @s.i@ and @t.i@ are visible withthe same type, so only @i@ is ambiguous without qualification.434 For parallel semantics, both @s.i@ and @t.i@ are visible the same type, so only @i@ is ambiguous without qualification. 430 435 431 436 … … 433 438 434 439 Overloading also extends to operators. 435 Operator-overloading syntax creates a routine name with anoperator symbol and question marks for the operands:440 Operator-overloading syntax names a routine with the operator symbol and question marks for the operands: 436 441 \begin{cquote} 437 442 \lstDeleteShortInline@% … … 467 472 \end{cquote} 468 473 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. 469 518 470 519 … … 495 544 \CFA also provides @new@ and @delete@, which behave like @malloc@ and @free@, in addition to constructing and destructing objects: 496 545 \begin{cfa} 497 { 498 ... struct S s = {10}; ... $\C{// allocation, call constructor}$546 { struct S s = {10}; $\C{// allocation, call constructor}$ 547 ... 499 548 } $\C{// deallocation, call destructor}$ 500 549 struct S * s = new(); $\C{// allocation, call constructor}$ … … 502 551 delete( s ); $\C{// deallocation, call destructor}$ 503 552 \end{cfa} 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. 553 \CFA concurrency uses object lifetime as a means of synchronization and/or mutual exclusion. 550 554 551 555 … … 580 584 \subsection{\protect\CFA's Thread Building Blocks} 581 585 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.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. 583 587 As such, library support for threading is far from widespread. 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.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. 586 590 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. 587 591 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. … … 621 625 \newbox\myboxA 622 626 \begin{lrbox}{\myboxA} 623 \begin{ cfa}[aboveskip=0pt,belowskip=0pt]627 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt] 624 628 `int f1, f2, state = 1;` // single global variables 625 629 int fib() { … … 638 642 } 639 643 } 640 \end{ cfa}644 \end{lstlisting} 641 645 \end{lrbox} 642 646 643 647 \newbox\myboxB 644 648 \begin{lrbox}{\myboxB} 645 \begin{ cfa}[aboveskip=0pt,belowskip=0pt]649 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt] 646 650 #define FIB_INIT `{ 0, 1 }` 647 651 typedef struct { int f2, f1; } Fib; … … 660 664 } 661 665 } 662 \end{ cfa}666 \end{lstlisting} 663 667 \end{lrbox} 664 668 … … 673 677 \newbox\myboxA 674 678 \begin{lrbox}{\myboxA} 675 \begin{ cfa}[aboveskip=0pt,belowskip=0pt]679 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt] 676 680 `coroutine` Fib { int fn; }; 677 681 void main( Fib & fib ) with( fib ) { … … 693 697 } 694 698 } 695 \end{ cfa}699 \end{lstlisting} 696 700 \end{lrbox} 697 701 \newbox\myboxB 698 702 \begin{lrbox}{\myboxB} 699 \begin{ cfa}[aboveskip=0pt,belowskip=0pt]703 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt] 700 704 `coroutine` Fib { int ret; }; 701 705 void main( Fib & f ) with( fib ) { … … 717 721 718 722 719 \end{ cfa}723 \end{lstlisting} 720 724 \end{lrbox} 721 725 \subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA} … … 727 731 728 732 Using a coroutine, it is possible to express the Fibonacci formula directly without any of the C problems. 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@. 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@. 730 738 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. 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@;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@; 733 741 on restart, the Fibonacci field, @fn@, contains the next value in the sequence, which is returned. 734 742 The first @resume@ is special because it cocalls the coroutine at its coroutine main and allocates the stack; … … 761 769 \newbox\myboxA 762 770 \begin{lrbox}{\myboxA} 763 \begin{ cfa}[aboveskip=0pt,belowskip=0pt]771 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt] 764 772 `coroutine` Format { 765 773 char ch; // used for communication … … 793 801 } 794 802 } 795 \end{ cfa}803 \end{lstlisting} 796 804 \end{lrbox} 797 805 798 806 \newbox\myboxB 799 807 \begin{lrbox}{\myboxB} 800 \begin{ cfa}[aboveskip=0pt,belowskip=0pt]808 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt] 801 809 struct Format { 802 810 char ch; … … 830 838 format( &fmt ); 831 839 } 832 \end{ cfa}840 \end{lstlisting} 833 841 \end{lrbox} 834 842 \subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA} … … 839 847 \end{figure} 840 848 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 routinefor another coroutine, which eventually forms a resuming-call cycle.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 function for another coroutine, which eventually forms a resuming-call cycle. 844 852 (The trivial cycle is a coroutine resuming itself.) 845 853 This control flow is similar to recursion for normal routines, but again there is no stack growth from the context switch. … … 923 931 Figure~\ref{f:ProdCons} shows a producer/consumer symmetric-coroutine performing bi-directional communication. 924 932 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@. 925 The @start@ routinecommunicates both the number of elements to be produced and the consumer into the producer's coroutine structure.933 The @start@ function communicates both the number of elements to be produced and the consumer into the producer's coroutine structure. 926 934 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. 927 935 @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. … … 929 937 The producer call to @delivery@ transfers values into the consumer's communication variables, resumes the consumer, and returns the consumer status. 930 938 For the first resume, @cons@'s stack is initialized, creating local variables retained between subsequent activations of the coroutine. 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).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). 932 940 The call from the consumer to the @payment@ introduces the cycle between producer and consumer. 933 941 When @payment@ is called, the consumer copies values into the producer's communication variable and a resume is executed. … … 959 967 \end{cfa} 960 968 and the programming language (and possibly its tool set, \eg debugger) may need to understand @baseCoroutine@ because of the stack. 961 Furthermore, the execution of constructs/destructors is in the wrong order for certain operations .962 For example, for threadsif 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.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. 963 971 964 972 An alternatively is composition: … … 972 980 However, there is nothing preventing wrong placement or multiple declarations. 973 981 974 For coroutines as for threads, many implementations are based on routine pointers or routineobjects~\cite{Butenhof97, C++14, MS:VisualC++, BoostCoroutines15}.982 For coroutines as for threads, many implementations are based on routine pointers or function objects~\cite{Butenhof97, C++14, MS:VisualC++, BoostCoroutines15}. 975 983 For example, Boost implements coroutines in terms of four functor object-types: 976 984 \begin{cfa} … … 980 988 symmetric_coroutine<>::yield_type 981 989 \end{cfa} 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}.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}. 983 991 However, the generic thread-handle (identifier) is limited (few operations), unless it is wrapped in a custom type. 984 992 \begin{cfa} … … 994 1002 \end{cfa} 995 1003 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.)1001 1004 1002 1005 The selected approach is to use language support by introducing a new kind of aggregate (structure): … … 1011 1014 Furthermore, implementing coroutines without language supports also displays the power of a programming language. 1012 1015 While this is ultimately the option used for idiomatic \CFA code, coroutines and threads can still be constructed without using the language support. 1013 The reserved keyword simplyeases 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 &);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( dtype T ) { 1021 void main( T & this ); 1022 coroutine_desc * get_coroutine( T & this ); 1020 1023 }; 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 Th e 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 themis 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@.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 This 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. 1029 1032 The \CFA keyword @coroutine@ implicitly implements the getter and forward declarations required for implementing the coroutine main: 1030 1033 \begin{cquote} … … 1036 1039 }; 1037 1040 \end{cfa} 1038 & 1039 {\Large $\Rightarrow$} 1040 & 1041 & {\Large $\Rightarrow$} & 1041 1042 \begin{tabular}{@{}ccc@{}} 1042 1043 \begin{cfa} … … 1072 1073 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: 1073 1074 \begin{cquote} 1074 \begin{tabular}{@{}c@{\hspace{ 3\parindentlnth}}c@{}}1075 \begin{tabular}{@{}c@{\hspace{2\parindentlnth}}c@{}} 1075 1076 \begin{cfa} 1076 1077 thread myThread { … … 1082 1083 & 1083 1084 \begin{cfa} 1084 trait is_thread( `dtype`T ) {1085 void main( T & );1086 thread_desc * get_thread( T & );1087 void ^?{}( T & `mutex` );1085 trait is_thread( dtype T ) { 1086 void main( T & this ); 1087 thread_desc * get_thread( T & this ); 1088 void ^?{}( T & `mutex` this ); 1088 1089 }; 1089 1090 \end{cfa} … … 1091 1092 \end{cquote} 1092 1093 (The qualifier @mutex@ for the destructor parameter is discussed in Section~\ref{s:Monitors}.) 1093 Like a coroutine, the statically-typed @main@ routineis the starting point (first stack frame) of a user thread.1094 Like a coroutine, the statically-typed @main@ function is the starting point (first stack frame) of a user thread. 1094 1095 The difference is that a coroutine borrows a thread from its caller, so the first thread resuming a coroutine creates an instance of @main@; 1095 1096 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{ 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.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. 1098 1099 1099 1100 \begin{comment} % put in appendix with coroutine version ??? … … 1108 1109 1109 1110 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. 1110 With the static semantics it is trivial to write a thread type that takes a routinepointer as a parameter and executes it on its stack asynchronously.1111 \begin{cfa} 1112 typedef void (*void Rtn)(int);1113 1114 thread RtnRunner {1115 void Rtnfunc;1111 With the static semantics it is trivial to write a thread type that takes a function pointer as a parameter and executes it on its stack asynchronously. 1112 \begin{cfa} 1113 typedef void (*voidFunc)(int); 1114 1115 thread FuncRunner { 1116 voidFunc func; 1116 1117 int arg; 1117 1118 }; 1118 1119 1119 void ?{}( RtnRunner & this, voidRtn inRtn, int arg) {1120 this.func = in Rtn;1120 void ?{}(FuncRunner & this, voidFunc inFunc, int arg) { 1121 this.func = inFunc; 1121 1122 this.arg = arg; 1122 1123 } 1123 1124 1124 void main( RtnRunner & this) {1125 // thread starts here and runs the routine1125 void main(FuncRunner & this) { 1126 // thread starts here and runs the function 1126 1127 this.func( this.arg ); 1127 1128 } … … 1132 1133 1133 1134 int main() { 1134 RtnRunner f = {hello, 42};1135 FuncRunner f = {hello, 42}; 1135 1136 return 0? 1136 1137 } 1137 1138 \end{cfa} 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}.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}. 1139 1140 \end{comment} 1140 1141 … … 1185 1186 void main( Adder & adder ) with( adder ) { 1186 1187 subtotal = 0; 1187 for ( int c = 0; c < cols; c += 1 ) { subtotal += row[c]; } 1188 for ( int c = 0; c < cols; c += 1 ) { 1189 subtotal += row[c]; 1190 } 1188 1191 } 1189 1192 int main() { … … 1207 1210 1208 1211 1209 \section{ Mutual Exclusion / Synchronization}1212 \section{Synchronization / Mutual Exclusion} 1210 1213 1211 1214 Uncontrolled non-deterministic execution is meaningless. 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 manipulatetwo sets of design patterns.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 learn two sets of design patterns. 1217 1220 While this distinction can be hidden away in library code, effective use of the library still has to take both paradigms into account. 1218 1221 In contrast, approaches based on statefull models more closely resemble the standard call/return programming-model, resulting in a single programming paradigm. 1219 1222 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}.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}. 1221 1224 However, for productivity it is always desirable to use the highest-level construct that provides the necessary efficiency~\cite{Hochstein05}. 1222 A newer approach for restricting non-determinismis transactional memory~\cite{Herlihy93}.1225 A newer approach is transactional memory~\cite{Herlihy93}. 1223 1226 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. 1224 1227 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. 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.. 1229 1233 1230 1234 … … 1232 1236 1233 1237 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}. 1234 The generalization is calleda \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.1238 A generalization is 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. 1235 1239 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. 1236 \newterm{Mutual exclusion} enforces th at the correct kind and number of threads are using a critical section.1240 \newterm{Mutual exclusion} enforces the correction number of threads are using a critical section at the same time. 1237 1241 1238 1242 However, many solutions exist for mutual exclusion, which vary in terms of performance, flexibility and ease of use. 1239 1243 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. 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 canoffer.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. 1244 1248 1245 1249 … … 1247 1251 1248 1252 Synchronization enforces relative ordering of execution, and synchronization tools provide numerous mechanisms to establish these timing relationships. 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). 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. 1254 1259 Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs. 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. 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. 1259 1263 1260 1264 … … 1262 1266 \label{s:Monitors} 1263 1267 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 ) { 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; 1340 }; 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. 1358 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 f2(const monitor & mutex m); 1366 int f3(monitor ** mutex m); 1367 int f4(monitor * mutex m []); 1368 int f5(graph(monitor *) & mutex m); 1369 \end{cfa} 1370 The problem is to identify which object(s) should be acquired. 1371 Furthermore, 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, this ambiguity is part of the C type-system with 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 f3(monitor mutex m []); // Not Okay : Array of unknown length 1385 int f4(monitor ** mutex m); // Not Okay : Could be an array 1386 int f5(monitor * mutex m []); // Not Okay : Array of unknown length 1387 \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 deadlocks is tricky. 1403 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 ); 1445 } 1446 \end{cfa} 1447 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 and requires careful engineering. 1449 1450 1451 \subsection{\protect\lstinline|mutex| statement} \label{mutex-stmt} 1452 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] 1463 monitor M {}; 1464 void foo( M & mutex m1, M & mutex m2 ) { 1465 // critical section 1466 } 1467 1468 void bar( M & m1, M & m2 ) { 1469 foo( m1, m2 ); 1470 } 1471 \end{cfa}&\begin{cfa}[tabsize=3] 1472 monitor M {}; 1473 void bar( M & m1, M & m2 ) { 1474 mutex(m1, m2) { 1475 // critical section 1476 } 1477 } 1478 1479 1480 \end{cfa} 1481 \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; 1499 }; 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) { 1274 1519 monitor_desc * get_monitor( T & ); 1275 1520 void ^?{}( T & mutex ); 1276 1521 }; 1277 1522 \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. 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. 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. 1372 Having language support for such a feature is therefore a significant asset for \CFA. 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}$ 1400 } 1401 \end{cfa} 1402 This example shows a trivial solution to the bank-account transfer problem~\cite{BankTransfer}. 1403 Without multi- and bulk acquire, the solution to this problem requires careful engineering. 1404 1405 1406 \subsection{\protect\lstinline|mutex| statement} \label{mutex-stmt} 1407 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} 1414 monitor M {}; 1415 void foo( M & mutex m1, M & mutex m2 ) { 1416 // critical section 1417 } 1418 void bar( M & m1, M & m2 ) { 1419 foo( m1, m2 ); 1420 } 1421 \end{cfa} 1422 & 1423 \begin{cfa} 1424 1425 void bar( M & m1, M & m2 ) { 1426 mutex( m1, m2 ) { // remove refactoring and naming 1427 // critical section 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) { 1545 ... 1546 // Wait for cooperation from bar() 1547 wait(a1.e); 1548 ... 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 1428 1727 } 1429 } 1430 1431 \end{cfa} 1432 \end{tabular} 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; 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 1478 1740 } 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} 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} 1530 1772 \end{figure} 1531 1773 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; 1569 }; 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 1596 }; 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}$ 1696 ... 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 ) { 1712 ... 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} 1747 \end{figure} 1748 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} 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. 1762 1789 Figure~\ref{f:dependency} shows a slightly different example where a third thread is waiting on monitor @A@, using a different condition variable. 1763 1790 Because the third thread is signalled when secretly holding @B@, the goal becomes unreachable. … … 1773 1800 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. 1774 1801 1775 1776 1802 \subsubsection{Dependency graphs} 1803 1777 1804 1778 1805 \begin{figure} … … 1851 1878 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. 1852 1879 Resolving dependency graphs being a complex and expensive endeavour, this solution is not the preferred one. 1853 \end{comment} 1854 1855 1856 \begin{comment} 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 % ====================================================================== 1857 1985 \section{External scheduling} \label{extsched} 1858 1986 % ====================================================================== 1987 % ====================================================================== 1988 An alternative to internal scheduling is external scheduling (see Table~\ref{tbl:sched}). 1859 1989 \begin{table} 1860 1990 \begin{tabular}{|c|c|c|} … … 1920 2050 \label{tbl:sched} 1921 2051 \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. 1922 2059 1923 2060 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. 1924 2061 On the other hand, external scheduling guarantees that while routine @P@ is waiting, no other routine than @V@ can acquire the monitor. 1925 \end{comment} 1926 1927 2062 2063 % ====================================================================== 2064 % ====================================================================== 1928 2065 \subsection{Loose Object Definitions} 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} 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} 1948 2101 For the first two conditions, it is easy to implement a check that can evaluate the condition in a few instructions. 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.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}. 1951 2104 1952 2105 \begin{figure} 1953 2106 \centering 1954 \subfloat[Classical monitor] {2107 \subfloat[Classical Monitor] { 1955 2108 \label{fig:ClassicalMonitor} 1956 {\resizebox{0.45\textwidth}{!}{\input{monitor .pstex_t}}}2109 {\resizebox{0.45\textwidth}{!}{\input{monitor}}} 1957 2110 }% subfloat 1958 \q uad1959 \subfloat[ Bulk acquire monitor] {2111 \qquad 2112 \subfloat[\textbf{bulk-acq} Monitor] { 1960 2113 \label{fig:BulkMonitor} 1961 {\resizebox{0.45\textwidth}{!}{\input{ext_monitor .pstex_t}}}2114 {\resizebox{0.45\textwidth}{!}{\input{ext_monitor}}} 1962 2115 }% subfloat 1963 \caption{Monitor Implementation} 1964 \label{f:MonitorImplementation} 2116 \caption{External Scheduling Monitor} 1965 2117 \end{figure} 1966 2118 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} 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 1976 2132 \begin{figure} 1977 2133 \begin{cfa}[caption={Example of nested external scheduling},label={f:nest-ext}] … … 1989 2145 \end{figure} 1990 2146 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 routinepointer and a set of monitors, as is discussed in the next section.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 function pointer and a set of monitors, as is discussed in the next section. 1992 2148 These details are omitted from the picture for the sake of simplicity. 1993 2149 … … 1997 2153 In the end, the most flexible approach has been chosen since it allows users to write programs that would otherwise be hard to write. 1998 2154 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. 1999 \end{comment} 2000 2001 2155 2156 % ====================================================================== 2157 % ====================================================================== 2002 2158 \subsection{Multi-Monitor Scheduling} 2003 \label{s:Multi-MonitorScheduling} 2159 % ====================================================================== 2160 % ====================================================================== 2004 2161 2005 2162 External scheduling, like internal scheduling, becomes significantly more complex when introducing multi-monitor syntax. 2006 Even in the simplest possible case, new semantics needs to be established:2163 Even in the simplest possible case, some new semantics needs to be established: 2007 2164 \begin{cfa} 2008 2165 monitor M {}; 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. 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 2020 2175 \begin{cfa} 2021 2176 monitor M {}; 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. 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. 2028 2202 2029 2203 An important behaviour to note is when a set of monitors only match partially: 2204 2030 2205 \begin{cfa} 2031 2206 mutex struct A {}; 2207 2032 2208 mutex struct B {}; 2033 void g( A & mutex m1, B & mutex m2 ) { 2034 waitfor( f, m1, m2 ); 2035 } 2209 2210 void g(A & mutex a, B & mutex b) { 2211 waitfor(f, a, b); 2212 } 2213 2036 2214 A a1, a2; 2037 2215 B b; 2216 2038 2217 void foo() { 2039 g( a1, b ); // block on accept 2040 } 2218 g(a1, b); // block on accept 2219 } 2220 2041 2221 void bar() { 2042 f( a2, b); // fulfill cooperation2222 f(a2, b); // fulfill cooperation 2043 2223 } 2044 2224 \end{cfa} … … 2047 2227 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. 2048 2228 2049 2229 % ====================================================================== 2230 % ====================================================================== 2050 2231 \subsection{\protect\lstinline|waitfor| Semantics} 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. 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. 2055 2238 Figure~\ref{f:waitfor} shows various usages of the waitfor statement and which are acceptable. 2056 The choice of the routinetype is made ignoring any non-@mutex@ parameter.2239 The choice of the function type is made ignoring any non-@mutex@ parameter. 2057 2240 One limitation of the current implementation is that it does not handle overloading, but overloading is possible. 2058 2241 \begin{figure} … … 2080 2263 waitfor(f2, a1, a2); // Incorrect : Mutex arguments don't match 2081 2264 waitfor(f1, 1); // Incorrect : 1 not a mutex argument 2082 waitfor(f9, a1); // Incorrect : f9 routinedoes not exist2265 waitfor(f9, a1); // Incorrect : f9 function does not exist 2083 2266 waitfor(*fp, a1 ); // Incorrect : fp not an identifier 2084 2267 waitfor(f4, a1); // Incorrect : f4 ambiguous … … 2090 2273 2091 2274 Finally, for added flexibility, \CFA supports constructing a complex @waitfor@ statement using the @or@, @timeout@ and @else@. 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 routineexecuted, @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 routinecall already arrived and otherwise continues.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 function executed, @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 function call already arrived and otherwise continues. 2095 2278 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. 2096 2279 Figure~\ref{f:waitfor2} demonstrates several complex masks and some incorrect ones. … … 2147 2330 \end{figure} 2148 2331 2149 2332 % ====================================================================== 2333 % ====================================================================== 2150 2334 \subsection{Waiting For The Destructor} 2151 2335 % ====================================================================== 2336 % ====================================================================== 2152 2337 An interesting use for the @waitfor@ statement is destructor semantics. 2153 2338 Indeed, the @waitfor@ statement can accept any @mutex@ routine, which includes the destructor (see section \ref{data}). … … 2176 2361 2177 2362 2363 % ###### # ###### # # # ####### # ### ##### # # 2364 % # # # # # # # # # # # # # # # ## ## 2365 % # # # # # # # # # # # # # # # # # # 2366 % ###### # # ###### # # # # ##### # # ##### # # # 2367 % # ####### # # ####### # # # # # # # # 2368 % # # # # # # # # # # # # # # # # 2369 % # # # # # # # ####### ####### ####### ####### ### ##### # # 2178 2370 \section{Parallelism} 2179 2180 2371 Historically, computer performance was about processor speeds and instruction counts. 2181 2372 However, with heat dissipation being a direct consequence of speed increase, parallelism has become the new source for increased performance~\cite{Sutter05, Sutter05b}. … … 2187 2378 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. 2188 2379 2189 2190 2380 \section{Paradigms} 2191 2192 2193 2381 \subsection{User-Level Threads} 2194 2195 2382 A direct improvement on the \textbf{kthread} approach is to use \textbf{uthread}. 2196 2383 These threads offer most of the same features that the operating system already provides but can be used on a much larger scale. … … 2201 2388 Examples of languages that support \textbf{uthread} are Erlang~\cite{Erlang} and \uC~\cite{uC++book}. 2202 2389 2203 2204 2390 \subsection{Fibers : User-Level Threads Without Preemption} \label{fibers} 2205 2206 2391 A popular variant of \textbf{uthread} is what is often referred to as \textbf{fiber}. 2207 2392 However, \textbf{fiber} do not present meaningful semantic differences with \textbf{uthread}. … … 2212 2397 An example of a language that uses fibers is Go~\cite{Go} 2213 2398 2214 2215 2399 \subsection{Jobs and Thread Pools} 2216 2217 2400 An approach on the opposite end of the spectrum is to base parallelism on \textbf{pool}. 2218 2401 Indeed, \textbf{pool} offer limited flexibility but at the benefit of a simpler user interface. … … 2225 2408 The gold standard of this implementation is Intel's TBB library~\cite{TBB}. 2226 2409 2227 2228 2410 \subsection{Paradigm Performance} 2229 2230 2411 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. 2231 2412 Indeed, in many situations one of these paradigms may show better performance but it all strongly depends on the workload. … … 2235 2416 Finally, if the units of uninterrupted work are large, enough the paradigm choice is largely amortized by the actual work done. 2236 2417 2237 2238 2418 \section{The \protect\CFA\ Kernel : Processors, Clusters and Threads}\label{kernel} 2239 2240 2419 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}. 2241 2420 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. … … 2245 2424 Currently \CFA only supports one \textbf{cfacluster}, the initial one. 2246 2425 2247 2248 2426 \subsection{Future Work: Machine Setup}\label{machine} 2249 2250 2427 While this was not done in the context of this paper, another important aspect of clusters is affinity. 2251 2428 While many common desktop and laptop PCs have homogeneous CPUs, other devices often have more heterogeneous setups. … … 2253 2430 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. 2254 2431 2255 2256 2432 \subsection{Paradigms}\label{cfaparadigms} 2257 2258 2433 Given these building blocks, it is possible to reproduce all three of the popular paradigms. 2259 2434 Indeed, \textbf{uthread} is the default paradigm in \CFA. … … 2263 2438 2264 2439 2440 2265 2441 \section{Behind the Scenes} 2266 2267 2442 There are several challenges specific to \CFA when implementing concurrency. 2268 These challenges are a direct result of bulk acquireand loose object definitions.2443 These challenges are a direct result of \textbf{bulk-acq} and loose object definitions. 2269 2444 These two constraints are the root cause of most design decisions in the implementation. 2270 2445 Furthermore, to avoid contention from dynamically allocating memory in a concurrent environment, the internal-scheduling design is (almost) entirely free of mallocs. … … 2274 2449 The main memory concern for concurrency is queues. 2275 2450 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. 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.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. 2277 2452 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. 2278 2453 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. 2279 2454 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. 2280 2455 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 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 % ====================================================================== 2284 2460 \section{Mutex Routines} 2461 % ====================================================================== 2462 % ====================================================================== 2285 2463 2286 2464 The first step towards the monitor implementation is simple @mutex@ routines. … … 2317 2495 \end{figure} 2318 2496 2319 2320 2497 \subsection{Details: Interaction with polymorphism} 2321 2322 2498 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. 2323 2499 However, it is shown that entry-point locking solves most of the issues. … … 2388 2564 void foo(T * mutex t); 2389 2565 2390 // Correct: this routineonly works on monitors (any monitor)2566 // Correct: this function only works on monitors (any monitor) 2391 2567 forall(dtype T | is_monitor(T)) 2392 2568 void bar(T * mutex t)); … … 2395 2571 Both entry point and \textbf{callsite-locking} are feasible implementations. 2396 2572 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. 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 routinebody.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 function body. 2398 2574 For example, the monitor call can appear in the middle of an expression. 2399 2575 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. 2400 2576 2401 2577 % ====================================================================== 2578 % ====================================================================== 2402 2579 \section{Threading} \label{impl:thread} 2580 % ====================================================================== 2581 % ====================================================================== 2403 2582 2404 2583 Figure \ref{fig:system1} shows a high-level picture if the \CFA runtime system in regards to concurrency. … … 2413 2592 \end{figure} 2414 2593 2415 2416 2594 \subsection{Processors} 2417 2418 2595 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. 2419 2596 Indeed, any parallelism must go through operating-system libraries. … … 2423 2600 Processors internally use coroutines to take advantage of the existing context-switching semantics. 2424 2601 2425 2426 2602 \subsection{Stack Management} 2427 2428 2603 One of the challenges of this system is to reduce the footprint as much as possible. 2429 2604 Specifically, all @pthread@s created also have a stack created with them, which should be used as much as possible. … … 2432 2607 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. 2433 2608 2434 2435 2609 \subsection{Context Switching} 2436 2437 2610 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. 2438 To improve performance and simplicity, context-switching is implemented using the following assumption: all context-switches happen inside a specific routinecall.2611 To improve performance and simplicity, context-switching is implemented using the following assumption: all context-switches happen inside a specific function call. 2439 2612 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. 2440 Note that the instruction pointer can be left untouched since the context-switch is always inside the same routine2613 Note that the instruction pointer can be left untouched since the context-switch is always inside the same function. 2441 2614 Threads, however, do not context-switch between each other directly. 2442 2615 They context-switch to the scheduler. … … 2448 2621 This option is not currently present in \CFA, but the changes required to add it are strictly additive. 2449 2622 2450 2451 2623 \subsection{Preemption} \label{preemption} 2452 2453 2624 Finally, an important aspect for any complete threading system is preemption. 2454 2625 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. … … 2477 2648 As a result, a signal handler can start on one kernel thread and terminate on a second kernel thread (but the same user thread). 2478 2649 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. 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}.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.}. 2480 2651 However, since the kernel thread handling preemption requires a different signal mask, executing user threads on the kernel-alarm thread can cause deadlocks. 2481 2652 For this reason, the alarm thread is in a tight loop around a system call to @sigwaitinfo@, requiring very little CPU time for preemption. … … 2484 2655 Indeed, @sigwait@ can differentiate signals sent from @pthread_sigqueue@ from signals sent from alarms or the kernel. 2485 2656 2486 2487 2657 \subsection{Scheduler} 2488 2658 Finally, an aspect that was not mentioned yet is the scheduling algorithm. … … 2490 2660 Further discussion on scheduling is present in section \ref{futur:sched}. 2491 2661 2492 2662 % ====================================================================== 2663 % ====================================================================== 2493 2664 \section{Internal Scheduling} \label{impl:intsched} 2494 2665 % ====================================================================== 2666 % ====================================================================== 2495 2667 The following figure is the traditional illustration of a monitor (repeated from page~\pageref{fig:ClassicalMonitor} for convenience): 2496 2668 2497 2669 \begin{figure} 2498 2670 \begin{center} 2499 {\resizebox{0.4\textwidth}{!}{\input{monitor .pstex_t}}}2671 {\resizebox{0.4\textwidth}{!}{\input{monitor}}} 2500 2672 \end{center} 2501 2673 \caption{Traditional illustration of a monitor} … … 2506 2678 2507 2679 For \CFA, this picture does not have support for blocking multiple monitors on a single condition. 2508 To support bulk acquiretwo changes to this picture are required.2680 To support \textbf{bulk-acq} two changes to this picture are required. 2509 2681 First, it is no longer helpful to attach the condition to \emph{a single} monitor. 2510 2682 Secondly, the thread waiting on the condition has to be separated across multiple monitors, seen in figure \ref{fig:monitor_cfa}. … … 2555 2727 \end{figure} 2556 2728 2557 The solution discussed in \ref{ s:InternalScheduling} can be seen in the exit routine of listing \ref{f:entry2}.2729 The solution discussed in \ref{intsched} can be seen in the exit routine of listing \ref{f:entry2}. 2558 2730 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. 2559 2731 This solution is deadlock safe as well as preventing any potential barging. … … 2791 2963 } 2792 2964 \end{cfa} 2793 This routineis called by the kernel to fetch the default preemption rate, where 0 signifies an infinite time-slice, \ie no preemption.2965 This function is called by the kernel to fetch the default preemption rate, where 0 signifies an infinite time-slice, \ie no preemption. 2794 2966 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} 2795 2967 \begin{figure} … … 2976 3148 For monitors, the simplest approach is to measure how long it takes to enter and leave a monitor routine. 2977 3149 Figure~\ref{f:mutex} shows the code for \CFA. 2978 To put the results in context, the cost of entering a non-inline routineand the cost of acquiring and releasing a @pthread_mutex@ lock is also measured.3150 To put the results in context, the cost of entering a non-inline function and the cost of acquiring and releasing a @pthread_mutex@ lock is also measured. 2979 3151 The results can be shown in table \ref{tab:mutex}. 2980 3152 … … 3227 3399 Therefore, there is still significant work to improve performance. 3228 3400 Many of the data structures and algorithms may change in the future to more efficient versions. 3229 For example, the number of monitors in a single bulk acquireis only bound by the stack size, this is probably unnecessarily generous.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. 3230 3402 It may be possible that limiting the number helps increase performance. 3231 3403 However, it is not obvious that the benefit would be significant. -
doc/papers/concurrency/figures/ext_monitor.fig
rb21c77a r97397a26 8 8 -2 9 9 1200 2 10 5 1 0 1 -1 -1 0 0 -1 0.000 0 1 0 0 1575.000 3450.000 1575 3150 1275 3450 1575375011 5 1 0 1 -1 -1 0 0 -1 0.000 0 1 0 0 1575.000 4350.000 1575 4050 1275 4350 1575465012 6 4275 1950 4575225013 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4425 2100 105 105 4425 2100 4530220514 4 1 -1 0 0 0 10 0.0000 2 105 90 44252160 d\00110 5 1 0 1 -1 -1 0 0 -1 0.000 0 1 0 0 3150.000 3450.000 3150 3150 2850 3450 3150 3750 11 5 1 0 1 -1 -1 0 0 -1 0.000 0 1 0 0 3150.000 4350.000 3150 4050 2850 4350 3150 4650 12 6 5850 1950 6150 2250 13 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6000 2100 105 105 6000 2100 6105 2205 14 4 1 -1 0 0 0 10 0.0000 2 105 90 6000 2160 d\001 15 15 -6 16 6 4275 1650 4575 195017 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4425 1800 105 105 4425 1800 4530 190518 4 1 -1 0 0 0 10 0.0000 2 105 90 4425 1860 b\00116 6 5100 2100 5400 2400 17 1 3 0 1 -1 -1 1 0 4 0.000 1 0.0000 5250 2250 105 105 5250 2250 5355 2250 18 4 1 -1 0 0 0 10 0.0000 2 105 120 5250 2295 X\001 19 19 -6 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 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 27 23 -6 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 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 27 -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 35 -6 36 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3300 3600 105 105 3300 3600 3405 3705 37 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3600 3600 105 105 3600 3600 3705 3705 38 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6600 3900 105 105 6600 3900 6705 4005 39 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6900 3900 105 105 6900 3900 7005 4005 40 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6000 2700 105 105 6000 2700 6105 2805 41 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6000 2400 105 105 6000 2400 6105 2505 42 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5100 4575 80 80 5100 4575 5180 4655 30 43 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 33 -6 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 37 -6 38 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 44 4050 2925 5475 2925 5475 3225 4050 3225 4050 2925 45 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 4 46 3150 3750 3750 3750 3750 4050 3150 4050 47 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 3 48 3150 3450 3750 3450 3900 3675 49 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 50 3750 3150 3600 3375 51 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 3 52 3150 4350 3750 4350 3900 4575 53 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 54 3750 4050 3600 4275 55 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 4 56 3150 4650 3750 4650 3750 4950 4950 4950 57 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 58 6450 3750 6300 3975 59 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 60 4950 4950 5175 5100 61 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 6450 3750 63 6450 2850 6150 2850 6150 1650 64 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 5850 4200 66 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 67 1 1 1.00 60.00 120.00 68 7 1 1.00 60.00 120.00 69 5250 3150 5250 2400 70 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 45 74 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 46 2475 2925 3900 2925 3900 3225 2475 3225 2475 2925 47 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 4 48 1575 3750 2175 3750 2175 4050 1575 4050 49 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 3 50 1575 3450 2175 3450 2325 3675 51 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 52 2175 3150 2025 3375 53 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 3 54 1575 4350 2175 4350 2325 4575 55 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 56 2175 4050 2025 4275 57 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 4 58 1575 4650 2175 4650 2175 4950 3375 4950 59 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 60 4875 3750 4725 3975 61 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2 62 3375 4950 3600 5100 63 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 9 64 3675 4950 4875 4950 4875 4050 5475 4050 5475 3750 4875 3750 65 4875 2850 4575 2850 4575 1650 66 2 2 1 1 -1 -1 0 0 -1 4.000 0 0 0 0 0 5 67 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 69 1 1 1.00 60.00 120.00 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 73 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 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 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 -
doc/papers/concurrency/figures/monitor.fig
rb21c77a r97397a26 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 4 75 2700 1500 2700 2100 3300 2100 3300 1500 74 76 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 9 75 77 3600 4200 4800 4200 4800 3300 5400 3300 5400 3000 4800 3000 … … 77 79 2 2 1 1 -1 -1 0 0 -1 4.000 0 0 0 0 0 5 78 80 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 480 2700 1500 2700 2100 3300 2100 3300 150081 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 40 0 0 12 0.0000 2 135 135 2550 1425 X\00192 4 1 40 0 0 12 0.0000 2 135 135 3450 1425 Y\00191 4 1 -1 0 0 0 12 0.0000 2 135 135 2550 1425 X\001 92 4 1 -1 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 -
doc/papers/general/Makefile
rb21c77a r97397a26 59 59 dvips ${Build}/$< -o $@ 60 60 61 ${BASE}.dvi : Makefile ${B ASE}.out.ps WileyNJD-AMA.bst ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \62 ../../bibliography/pl.bib | ${Build}61 ${BASE}.dvi : Makefile ${Build} ${BASE}.out.ps WileyNJD-AMA.bst ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 62 ../../bibliography/pl.bib 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 -
doc/papers/general/Paper.tex
rb21c77a r97397a26 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 hobby projects to commercial operating-systems.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. 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 hobby projects to commercial operating-systems.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. 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. -
doc/proposals/ctordtor/Makefile
rb21c77a r97397a26 1 ## Define the configuration variables.1 ## Define the appropriate configuration variables. 2 2 3 Build = build 4 Figures = figures 5 Macros = ../../LaTeXmacros 6 Bib = ../../bibliography 3 MACROS = ../../LaTeXmacros 4 BIB = ../../bibliography 7 5 8 TeXLIB = .:$ {Macros}:${MACROS}/listings:${MACROS}/enumitem:${Bib}/:9 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build}6 TeXLIB = .:$(MACROS):$(MACROS)/listings:$(MACROS)/enumitem:$(BIB)/: 7 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error 10 8 BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex 11 12 MAKEFLAGS = --no-print-directory # --silent13 VPATH = ${Build} ${Figures}14 9 15 10 ## Define the text source files. … … 34 29 35 30 DOCUMENT = ctor.pdf 36 BASE = ${basename ${DOCUMENT}}37 31 38 32 # Directives # 39 40 .PHONY : all clean # not file names41 33 42 34 all : ${DOCUMENT} 43 35 44 36 clean : 45 @rm -frv ${DOCUMENT} ${BASE}.ps ${Build} 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} 46 39 47 40 # File Dependencies # 48 41 49 ${DOCUMENT} : ${ BASE}.ps42 ${DOCUMENT} : ${basename ${DOCUMENT}}.ps 50 43 ps2pdf $< 51 44 52 ${ BASE}.ps : ${BASE}.dvi53 dvips $ {Build}/$< -o $@45 ${basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi 46 dvips $< -o $@ 54 47 55 ${ BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES}\56 $ {Macros}/common.tex ${Macros}/indexstyle ${Bib}/pl.bib | ${Build}48 ${basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex \ 49 $(MACROS)/common.tex $(MACROS)/indexstyle $(BIB)/cfa.bib 57 50 # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run. 58 #if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi51 if [ ! -r ${basename $@}.ind ] ; then touch ${basename $@}.ind ; fi 59 52 # Must have *.aux file containing citations for bibtex 60 53 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi 61 -${BibTeX} ${ Build}/${basename $@}62 # Some citations reference others so run again to resolve these citations54 -${BibTeX} ${basename $@} 55 # Some citations reference others so run steps again to resolve these citations 63 56 ${LaTeX} ${basename $@}.tex 64 -${BibTeX} ${ Build}/${basename $@}57 -${BibTeX} ${basename $@} 65 58 # Make index from *.aux entries and input index at end of document 66 #makeindex -s ${Macros}/indexstyle ${Build}/${basename $@}.idx 67 # Run again to finish citations 59 makeindex -s $(MACROS)/indexstyle ${basename $@}.idx 68 60 ${LaTeX} ${basename $@}.tex 69 61 # Run again to get index title into table of contents … … 75 67 ## Define the default recipes. 76 68 77 ${Build}: 78 mkdir -p ${Build}69 %.tex : %.fig 70 fig2dev -L eepic $< > $@ 79 71 80 %. tex : %.fig | ${Build}81 fig2dev -L eepic $< > ${Build}/$@72 %.ps : %.fig 73 fig2dev -L ps $< > $@ 82 74 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 75 %.pstex : %.fig 76 fig2dev -L pstex $< > $@ 77 fig2dev -L pstex_t -p $@ $< > $@_t 89 78 90 79 # Local Variables: # -
doc/proposals/ctordtor/ctor.tex
rb21c77a r97397a26 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 1 9 \documentclass[twoside,11pt]{article} 2 10 … … 7 15 \usepackage{textcomp} 8 16 \usepackage[latin1]{inputenc} 9 10 17 \usepackage{fullpage,times,comment} 11 18 \usepackage{epic,eepic} 12 \usepackage{upquote} % switch curled `'" to straight19 \usepackage{upquote} % switch curled `'" to straight 13 20 \usepackage{calc} 14 21 \usepackage{xspace} 15 22 \usepackage{graphicx} 16 \usepackage{varioref} % extended references17 \usepackage{listings} % format program code18 \usepackage[flushmargin]{footmisc} % support label/reference in footnote23 \usepackage{varioref} % extended references 24 \usepackage{listings} % format program code 25 \usepackage[flushmargin]{footmisc} % support label/reference in footnote 19 26 \usepackage{latexsym} % \Box glyph 20 27 \usepackage{mathptmx} % better math font with "times" … … 27 34 \renewcommand{\UrlFont}{\small\sf} 28 35 29 \setlength{\topmargin}{-0.45in} % move running title into header36 \setlength{\topmargin}{-0.45in} % move running title into header 30 37 \setlength{\headsep}{0.25in} 31 38 … … 36 43 37 44 \interfootnotelinepenalty=10000 38 39 \CFAStyle % use default CFA format-style40 % 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 48 45 49 46 \title{ … … 86 83 \thispagestyle{plain} 87 84 \pagenumbering{arabic} 85 88 86 89 87 -
doc/proposals/tuples/Makefile
rb21c77a r97397a26 1 ## Define the configuration variables.1 ## Define the appropriate configuration variables. 2 2 3 Build = build 4 Figures = figures 5 Macros = ../../LaTeXmacros 6 Bib = ../../bibliography 3 MACROS = ../../LaTeXmacros 4 BIB = ../../bibliography 7 5 8 TeXLIB = .:$ {Macros}:${MACROS}/listings:${MACROS}/enumitem:${Bib}/:9 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build}6 TeXLIB = .:$(MACROS):$(MACROS)/listings:$(MACROS)/enumitem:$(BIB)/: 7 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error 10 8 BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex 11 12 MAKEFLAGS = --no-print-directory --silent #13 VPATH = ${Build} ${Figures}14 9 15 10 ## Define the text source files. … … 34 29 35 30 DOCUMENT = tuples.pdf 36 BASE = ${basename ${DOCUMENT}}37 31 38 32 # Directives # 39 40 .PHONY : all clean # not file names41 33 42 34 all : ${DOCUMENT} 43 35 44 36 clean : 45 @rm -frv ${DOCUMENT} ${BASE}.ps ${Build} 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} 46 39 47 40 # File Dependencies # 48 41 49 ${DOCUMENT} : ${ BASE}.ps42 ${DOCUMENT} : ${basename ${DOCUMENT}}.ps 50 43 ps2pdf $< 51 44 52 ${ BASE}.ps : ${BASE}.dvi53 dvips $ {Build}/$< -o $@45 ${basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi 46 dvips $< -o $@ 54 47 55 ${ BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES}\56 $ {Macros}/common.tex ${Macros}/indexstyle ${Bib}/pl.bib | ${Build}48 ${basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex \ 49 $(MACROS)/common.tex $(MACROS)/indexstyle $(BIB)/cfa.bib 57 50 # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run. 58 #if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi51 if [ ! -r ${basename $@}.ind ] ; then touch ${basename $@}.ind ; fi 59 52 # Must have *.aux file containing citations for bibtex 60 53 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi 61 -${BibTeX} ${ Build}/${basename $@}62 # Some citations reference others so run again to resolve these citations54 -${BibTeX} ${basename $@} 55 # Some citations reference others so run steps again to resolve these citations 63 56 ${LaTeX} ${basename $@}.tex 64 -${BibTeX} ${ Build}/${basename $@}57 -${BibTeX} ${basename $@} 65 58 # Make index from *.aux entries and input index at end of document 66 #makeindex -s ${Macros}/indexstyle ${Build}/${basename $@}.idx 67 # Run again to finish citations 59 makeindex -s $(MACROS)/indexstyle ${basename $@}.idx 68 60 ${LaTeX} ${basename $@}.tex 69 61 # Run again to get index title into table of contents … … 75 67 ## Define the default recipes. 76 68 77 ${Build}: 78 mkdir -p ${Build}69 %.tex : %.fig 70 fig2dev -L eepic $< > $@ 79 71 80 %. tex : %.fig | ${Build}81 fig2dev -L eepic $< > ${Build}/$@72 %.ps : %.fig 73 fig2dev -L ps $< > $@ 82 74 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 75 %.pstex : %.fig 76 fig2dev -L pstex $< > $@ 77 fig2dev -L pstex_t -p $@ $< > $@_t 89 78 90 79 # Local Variables: # -
doc/proposals/tuples/tuples.tex
rb21c77a r97397a26 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 1 9 \documentclass[twoside,11pt]{article} 2 10 … … 7 15 \usepackage{textcomp} 8 16 \usepackage[latin1]{inputenc} 9 10 17 \usepackage{fullpage,times,comment} 11 18 \usepackage{epic,eepic} 12 \usepackage{upquote} % switch curled `'" to straight19 \usepackage{upquote} % switch curled `'" to straight 13 20 \usepackage{calc} 14 21 \usepackage{xspace} 15 22 \usepackage{graphicx} 16 \usepackage{varioref} % extended references17 \usepackage{listings} % format program code18 \usepackage[flushmargin]{footmisc} % support label/reference in footnote23 \usepackage{varioref} % extended references 24 \usepackage{listings} % format program code 25 \usepackage[flushmargin]{footmisc} % support label/reference in footnote 19 26 \usepackage{latexsym} % \Box glyph 20 27 \usepackage{mathptmx} % better math font with "times" … … 27 34 \renewcommand{\UrlFont}{\small\sf} 28 35 29 \setlength{\topmargin}{-0.45in} % move running title into header36 \setlength{\topmargin}{-0.45in} % move running title into header 30 37 \setlength{\headsep}{0.25in} 31 38 … … 35 42 36 43 \interfootnotelinepenalty=10000 37 38 \CFAStyle % use default CFA format-style39 % 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 47 44 48 45 \title{ -
doc/proposals/user_conversions.md
rb21c77a r97397a26 5 5 There is also a set of _explicit_ conversions that are only allowed through a 6 6 cast expression. 7 I propose that safe, unsafe, and explicit (cast) conversions be expressed as 8 constructor variants. 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. 9 11 Throughout this article, I will use the following operator names for 10 12 constructors and conversion functions from `From` to `To`: 11 13 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 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 19 23 conversions; this is elegant, but interacts poorly with tuples. 20 24 Essentially, without making this distinction, a constructor like the following … … 22 26 multiplying the space of possible interpretations of all functions: 23 27 24 void ?{}( Coord &this, int x, int y );28 void ?{}( Coord *this, int x, int y ); 25 29 26 30 That said, it would certainly be possible to make a multiple-argument implicit … … 28 32 used infrequently: 29 33 30 void ?{unsafe}( Coord &this, int x, int y );34 void ?{unsafe}( Coord *this, int x, int y ); 31 35 32 36 An alternate possibility would be to only count two-arg constructors 33 `void ?{} ( To &, From )` as unsafe conversions; under this semantics, safe and37 `void ?{} ( To*, From )` as unsafe conversions; under this semantics, safe and 34 38 explicit conversions should also have a compiler-enforced restriction to 35 39 ensure that they are two-arg functions (this restriction may be valuable … … 39 43 is convertable to `To`. 40 44 If user-defined conversions are not added to the language, 41 `void ?{} ( To &, From )` may be a suitable representation, relying on45 `void ?{} ( To*, From )` may be a suitable representation, relying on 42 46 conversions on the argument types to account for transitivity. 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 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`. 53 50 54 51 ### Constructor Idiom ### … … 56 53 that we can use the full range of Cforall features for conversions, including 57 54 polymorphism. 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 ) { 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 ) { 66 62 Safe tmp = /* some expression involving that */; 67 this{ tmp }; // initialize fromassertion parameter63 *this = tmp; // uses assertion parameter 68 64 } 69 65 … … 71 67 unsafe conversions. 72 68 73 Glen's original suggestion said the copy constructor for `To` should also be74 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 the77 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` type87 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 conversion92 this{ tmp }; // initialize from assertion parameter93 }94 95 Given the entirely-boilerplate nature of this code, but negative performance96 implications of the unmodified constructor idiom, it might be fruitful to have97 transitive and single step conversion operators, and let CFA build the98 transitive conversions; some possible names:99 100 void ?{safe} (To&, From); void ?{final safe} (To&, From); // single-step101 void ?{safe*} (To&, From); void ?{safe} (To&, From); // transitive102 103 69 What selective non-use of the constructor idiom gives us is the ability to 104 70 define a conversion that may only be the *last* conversion in a chain of such. 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 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). 115 79 116 80 ### Appendix A: Partial and Total Orders ### … … 189 153 convert from `int` to `unsigned long`, so we just put in a direct conversion 190 154 and make the compiler smart enough to figure out the costs" - this is the 191 approach taken by the existing compi ler, but given that in a user-defined155 approach taken by the existing compipler, but given that in a user-defined 192 156 conversion proposal the users can build an arbitrary graph of conversions, 193 157 this case still needs to be handled. … … 196 160 exists a chain of conversions from `a` to `b` (see Appendix A for description 197 161 of preorders and related constructs). 198 This preorder roughly correspondsto a more usual type-theoretic concept of162 This preorder corresponds roughly to a more usual type-theoretic concept of 199 163 subtyping ("if I can convert `a` to `b`, `a` is a more specific type than 200 164 `b`"); however, since this graph is arbitrary, it may contain cycles, so if … … 228 192 and so is considered to be the nearer type. 229 193 By transitivity, then, the conversion from `X` to `Y2` should be cheaper than 230 the conversion from `X` to `W`, but in this case the ` Y2` and `W` are194 the conversion from `X` to `W`, but in this case the `X` and `W` are 231 195 incomparable by the conversion preorder, so the tie is broken by the shorter 232 196 path from `X` to `W` in favour of `W`, contradicting the transitivity property -
doc/refrat/Makefile
rb21c77a r97397a26 53 53 dvips ${Build}/$< -o $@ 54 54 55 ${BASE}.dvi : Makefile ${ GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \56 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib | ${Build}55 ${BASE}.dvi : Makefile ${Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 56 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib 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 -
doc/theses/aaron_moss/comp_II/Makefile
rb21c77a r97397a26 32 32 33 33 DOCUMENT = comp_II.pdf 34 BASE = ${basename ${DOCUMENT}}35 34 36 35 # Directives # … … 41 40 42 41 clean : 43 @rm -frv ${DOCUMENT} ${ BASE}.ps ${Build}42 @rm -frv ${DOCUMENT} ${basename ${DOCUMENT}}.ps ${Build} 44 43 45 44 # File Dependencies # 46 45 47 ${DOCUMENT} : ${ BASE}.ps46 ${DOCUMENT} : ${basename ${DOCUMENT}}.ps 48 47 ps2pdf $< 49 48 50 ${ BASE}.ps : ${BASE}.dvi49 ${basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi 51 50 dvips ${Build}/$< -o $@ 52 51 53 ${ BASE}.dvi : Makefile${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \54 ${Macros}/common.tex ${Macros}/indexstyle ../../../bibliography/pl.bib | ${Build}52 ${basename ${DOCUMENT}}.dvi : Makefile ${Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 53 ${Macros}/common.tex ${Macros}/indexstyle ../../../bibliography/pl.bib 55 54 # Must have *.aux file containing citations for bibtex 56 55 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi … … 67 66 mkdir -p ${Build} 68 67 69 %.tex : %.fig ${Build}68 %.tex : %.fig 70 69 fig2dev -L eepic $< > ${Build}/$@ 71 70 72 %.ps : %.fig | ${Build}71 %.ps : %.fig 73 72 fig2dev -L ps $< > ${Build}/$@ 74 73 75 %.pstex : %.fig | ${Build}74 %.pstex : %.fig 76 75 fig2dev -L pstex $< > ${Build}/$@ 77 76 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t -
doc/theses/thierry_delisle/.gitignore
rb21c77a r97397a26 25 25 *.pdf 26 26 *.png 27 *.ps28 27 figures/*.tex 29 28 -
doc/theses/thierry_delisle/Makefile
rb21c77a r97397a26 51 51 52 52 DOCUMENT = thesis.pdf 53 BASE = ${basename ${DOCUMENT}}54 53 55 54 # Directives # … … 60 59 61 60 clean : 62 @rm -frv ${DOCUMENT} ${ BASE}.ps ${Build}61 @rm -frv ${DOCUMENT} ${basename ${DOCUMENT}}.ps ${Build} 63 62 64 63 # File Dependencies # 65 64 66 ${DOCUMENT} : ${ BASE}.ps65 ${DOCUMENT} : ${basename ${DOCUMENT}}.ps 67 66 ps2pdf $< 68 67 69 ${ BASE}.ps : ${BASE}.dvi68 ${basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi 70 69 dvips ${Build}/$< -o $@ 71 70 72 ${ BASE}.dvi : Makefile${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \73 ${Macros}/common.tex ${Macros}/indexstyle annex/local.bib ../../bibliography/pl.bib | ${Build}71 ${basename ${DOCUMENT}}.dvi : Makefile ${Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 72 ${Macros}/common.tex ${Macros}/indexstyle annex/local.bib ../../bibliography/pl.bib 74 73 # Must have *.aux file containing citations for bibtex 75 74 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi … … 89 88 mkdir -p ${Build} 90 89 91 %.tex : %.fig ${Build}90 %.tex : %.fig 92 91 fig2dev -L eepic $< > ${Build}/$@ 93 92 94 %.ps : %.fig | ${Build}93 %.ps : %.fig 95 94 fig2dev -L ps $< > ${Build}/$@ 96 95 97 %.pstex : %.fig | ${Build}96 %.pstex : %.fig 98 97 fig2dev -L pstex $< > ${Build}/$@ 99 98 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t … … 102 101 # Tools to generate png files 103 102 # to create a png we create a pdf and convert it to png 104 %.png : build/%.pstex figures/%.tex ${Build}103 %.png : build/%.pstex figures/%.tex 105 104 echo ${basename $@} 106 105 ${LaTeX} figures/${basename $@}.tex … … 110 109 111 110 # creating a pdf of a figure requires generating some latex that just includes the figure 112 figures/%.tex: build/%.pstex ${Build}111 figures/%.tex: build/%.pstex 113 112 echo -n "\documentclass[preview]{standalone}\n" \ 114 113 "\usepackage[T1]{fontenc}\n" \ -
doc/user/Makefile
rb21c77a r97397a26 57 57 dvips ${Build}/$< -o $@ 58 58 59 ${BASE}.dvi : Makefile ${ GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \60 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib | ${Build}59 ${BASE}.dvi : Makefile ${Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 60 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib 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 -
src/CodeGen/CodeGenerator.cc
rb21c77a r97397a26 133 133 output << "__attribute__ (("; 134 134 for ( list< Attribute * >::iterator attr( attributes.begin() );; ) { 135 output << (*attr)-> name;136 if ( ! (*attr)-> parameters.empty() ) {135 output << (*attr)->get_name(); 136 if ( ! (*attr)->get_parameters().empty() ) { 137 137 output << "("; 138 genCommaList( (*attr)-> parameters.begin(), (*attr)->parameters.end() );138 genCommaList( (*attr)->get_parameters().begin(), (*attr)->get_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 them175 if ( functionDecl->isDeleted && genC ) return;176 174 extension( functionDecl ); 177 175 genAttributes( functionDecl->get_attributes() ); … … 187 185 functionDecl->get_statements()->accept( *visitor ); 188 186 } // if 189 if ( functionDecl->isDeleted ) {190 output << " = void";191 }192 187 } 193 188 194 189 void CodeGenerator::postvisit( ObjectDecl * objectDecl ) { 195 // deleted decls should never be used, so don't print them196 if ( objectDecl->isDeleted && genC ) return;197 190 if (objectDecl->get_name().empty() && genC ) { 198 191 // only generate an anonymous name when generating C code, otherwise it clutters the output too much … … 213 206 objectDecl->get_init()->accept( *visitor ); 214 207 } // if 215 if ( objectDecl->isDeleted ) {216 output << " = void";217 }218 208 219 209 if ( objectDecl->get_bitfieldWidth() ) { … … 837 827 expr->expr->accept( *visitor ); 838 828 } 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 867 829 868 830 // *** Statements -
src/CodeGen/CodeGenerator.h
rb21c77a r97397a26 94 94 void postvisit( ConstructorExpr * ); 95 95 void postvisit( DeletedExpr * ); 96 void postvisit( DefaultArgExpr * );97 void postvisit( GenericExpr * );98 96 99 97 //*** Statements -
src/Common/Debug.h
rb21c77a r97397a26 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:: Builtin) {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 ) { 31 31 #ifdef DEBUG 32 32 std::list< Declaration * > decls; -
src/Common/PassVisitor.h
rb21c77a r97397a26 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;129 127 130 128 virtual void visit( VoidType * basicType ) override final; … … 227 225 virtual Expression * mutate( InitExpr * initExpr ) override final; 228 226 virtual Expression * mutate( DeletedExpr * delExpr ) override final; 229 virtual Expression * mutate( DefaultArgExpr * argExpr ) override final;230 virtual Expression * mutate( GenericExpr * genExpr ) override final;231 227 232 228 virtual Type * mutate( VoidType * basicType ) override final; … … 262 258 263 259 private: 264 bool inFunction = false;265 266 260 template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); 267 261 template<typename pass_t> friend void mutateAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); … … 319 313 void indexerAddUnionFwd ( UnionDecl * node ) { indexer_impl_addUnionFwd ( pass, 0, node ); } 320 314 void indexerAddTrait ( TraitDecl * node ) { indexer_impl_addTrait ( pass, 0, node ); } 321 void indexerAddWith ( std::list< Expression * > & exprs, BaseSyntaxNode * withStmt ) { indexer_impl_addWith ( pass, 0, exprs, withStmt ); }315 void indexerAddWith ( std::list< Expression * > & exprs, BaseSyntaxNode * withStmt ) { indexer_impl_addWith ( pass, 0, exprs, withStmt ); } 322 316 323 317 -
src/Common/PassVisitor.impl.h
rb21c77a r97397a26 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 enter407 // a new scope if inFunction is true408 ValueGuard< bool > oldInFunction( inFunction );409 inFunction = true;410 406 maybeAccept_impl( node->statements, *this ); 411 407 maybeAccept_impl( node->attributes, *this ); … … 438 434 indexerAddId( func ); 439 435 maybeMutate_impl( node->type, *this ); 440 // function body needs to have the same scope as parameters - CompoundStmt will not enter441 // a new scope if inFunction is true442 ValueGuard< bool > oldInFunction( inFunction );443 inFunction = true;444 436 maybeMutate_impl( node->statements, *this ); 445 437 maybeMutate_impl( node->attributes, *this ); … … 720 712 VISIT_START( node ); 721 713 { 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(); } ); 714 auto guard1 = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 725 715 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 726 inFunction = false;727 716 visitStatementList( node->kids ); 728 717 } … … 734 723 MUTATE_START( node ); 735 724 { 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(); } ); 725 auto guard1 = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 739 726 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 740 inFunction = false;741 727 mutateStatementList( node->kids ); 742 728 } … … 842 828 VISIT_START( node ); 843 829 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 } 830 visitExpression( node->condition ); 831 node->body = visitStatement( node->body ); 851 832 852 833 VISIT_END( node ); … … 857 838 MUTATE_START( node ); 858 839 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 840 node->condition = mutateExpression( node->condition ); 841 node->body = mutateStatement ( node->body ); 867 842 868 843 MUTATE_END( Statement, node ); … … 2099 2074 2100 2075 //-------------------------------------------------------------------------- 2101 // DefaultArgExpr2102 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 // GenericExpr2125 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 //--------------------------------------------------------------------------2155 2076 // VoidType 2156 2077 template< typename pass_type > -
src/Common/SemanticError.cc
rb21c77a r97397a26 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jun 7 08:05:26201813 // Update Count : 1012 // Last Modified On : Wed May 16 15:01:20 2018 13 // Update Count : 9 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 -
src/Concurrency/Keywords.cc
rb21c77a r97397a26 192 192 void postvisit( StructDecl * decl ); 193 193 194 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl* , bool & first);194 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl* ); 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 bool first = false; 434 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first ); 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 435 438 bool isDtor = CodeGen::isDestructor( decl->name ); 436 439 437 // Is this function relevant to monitors438 if( mutexArgs.empty() ) {439 // If this is the destructor for a monitor it must be mutex440 if(isDtor) {441 Type* ty = decl->get_functionType()->get_parameters().front()->get_type();442 443 // If it's a copy, it's not a mutex444 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 mutex448 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 struct453 StructInstType * baseStruct = dynamic_cast< StructInstType * >( base );454 if( !baseStruct ) return;455 456 // Check if its a monitor457 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 exclusion464 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 destructor467 440 if( isDtor && mutexArgs.size() != 1 ) SemanticError( decl, "destructors can only have 1 mutex argument" ); 468 441 469 // Make sure all the mutex arguments are monitors470 442 for(auto arg : mutexArgs) { 471 443 validate( arg ); 472 444 } 473 445 474 // Check if we need to instrument the body475 446 CompoundStmt* body = decl->get_statements(); 476 447 if( ! body ) return; 477 448 478 // Do we have the required headers479 449 if( !monitor_decl || !guard_decl || !dtor_guard_decl ) 480 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor>\n" ); 481 482 // Instrument the body 450 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor>" ); 451 483 452 if( isDtor ) { 484 453 addDtorStatments( decl, body, mutexArgs ); … … 505 474 } 506 475 507 std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl , bool & first) {476 std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl ) { 508 477 std::list<DeclarationWithType*> mutexArgs; 509 478 510 bool once = true;511 479 for( auto arg : decl->get_functionType()->get_parameters()) { 512 480 //Find mutex arguments 513 481 Type* ty = arg->get_type(); 514 482 if( ! ty->get_mutex() ) continue; 515 516 if(once) {first = true;}517 once = false;518 483 519 484 //Append it to the list -
src/ControlStruct/ForExprMutator.cc
rb21c77a r97397a26 45 45 return hoist( forStmt, forStmt->initialization ); 46 46 } 47 Statement *ForExprMutator::postmutate( WhileStmt *whileStmt ) {48 return hoist( whileStmt, whileStmt->initialization );49 }50 47 } // namespace ControlStruct 51 48 -
src/ControlStruct/ForExprMutator.h
rb21c77a r97397a26 18 18 class IfStmt; 19 19 class ForStmt; 20 class WhileStmt;21 20 class Statement; 22 21 … … 26 25 Statement *postmutate( IfStmt * ); 27 26 Statement *postmutate( ForStmt * ); 28 Statement *postmutate( WhileStmt * );29 27 }; 30 28 } // namespace ControlStruct -
src/ControlStruct/Mutate.cc
rb21c77a r97397a26 27 27 #include "SynTree/Visitor.h" // for acceptAll 28 28 29 using namespace std; 30 29 31 namespace ControlStruct { 30 void fixLabels( std::list< Declaration * > & translationUnit ) { 32 void mutate( std::list< Declaration * > translationUnit ) { 33 // hoist initialization out of for statements 34 PassVisitor<ForExprMutator> formut; 35 36 // normalizes label definitions and generates multi-level exit labels 31 37 PassVisitor<LabelFixer> lfix; 38 39 mutateAll( translationUnit, formut ); 32 40 acceptAll( translationUnit, lfix ); 33 }34 35 void hoistControlDecls( std::list< Declaration * > & translationUnit ) {36 PassVisitor<ForExprMutator> formut;37 mutateAll( translationUnit, formut );38 41 } 39 42 } // namespace CodeGen -
src/ControlStruct/Mutate.h
rb21c77a r97397a26 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 structures23 22 namespace ControlStruct { 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 ); 23 /// Desugars Cforall control structures 24 void mutate( std::list< Declaration* > translationUnit ); 29 25 } // namespace ControlStruct 30 26 -
src/GenPoly/Lvalue.cc
rb21c77a r97397a26 145 145 146 146 namespace { 147 // true for intrinsic function calls that return a n lvalue in C147 // true for intrinsic function calls that return a reference 148 148 bool isIntrinsicReference( Expression * expr ) { 149 // known intrinsic-reference prelude functions150 static std::set<std::string> lvalueFunctions = { "*?", "?[?]" };151 149 if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * >( expr ) ) { 152 150 std::string fname = InitTweak::getFunctionName( untyped ); 153 return lvalueFunctions.count(fname); 151 // known intrinsic-reference prelude functions 152 return fname == "*?" || fname == "?[?]"; 154 153 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) { 155 154 if ( DeclarationWithType * func = InitTweak::getFunction( appExpr ) ) { 156 return func->linkage == LinkageSpec::Intrinsic && lvalueFunctions.count(func->name); 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 ); 157 159 } 158 160 } … … 208 210 // TODO: it's likely that the second condition should be ... && ! isIntrinsicReference( arg ), but this requires investigation. 209 211 210 if ( function-> linkage!= LinkageSpec::Intrinsic && isIntrinsicReference( arg ) ) {212 if ( function->get_linkage() != LinkageSpec::Intrinsic && isIntrinsicReference( arg ) ) { 211 213 // needed for definition of prelude functions, etc. 212 214 // if argument is dereference or array subscript, the result isn't REALLY a reference, but non-intrinsic functions expect a reference: take address … … 224 226 arg = new AddressExpr( arg ); 225 227 // } else if ( function->get_linkage() == LinkageSpec::Intrinsic && InitTweak::getPointerBase( arg->result ) ) { 226 } else if ( function-> linkage== LinkageSpec::Intrinsic && arg->result->referenceDepth() != 0 ) {228 } else if ( function->get_linkage() == LinkageSpec::Intrinsic && arg->result->referenceDepth() != 0 ) { 227 229 // argument is a 'real' reference, but function expects a C lvalue: add a dereference to the reference-typed argument 228 230 PRINT( -
src/Parser/DeclarationNode.cc
rb21c77a r97397a26 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Jun 7 12:08:55201813 // Update Count : 107 912 // Last Modified On : Tue May 22 08:39:29 2018 13 // Update Count : 1074 14 14 // 15 15 … … 173 173 } 174 174 175 DeclarationNode * DeclarationNode::newFunction( conststring * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {175 DeclarationNode * DeclarationNode::newFunction( 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( conststring * name ) {246 DeclarationNode * DeclarationNode::newFromTypedef( 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( conststring * name, DeclarationNode * constants, bool body ) {269 DeclarationNode * DeclarationNode::newEnum( 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( conststring * name, ExpressionNode * constant ) {279 DeclarationNode * DeclarationNode::newEnumConstant( 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( conststring * name ) {286 DeclarationNode * DeclarationNode::newName( string * name ) { 287 287 DeclarationNode * newnode = new DeclarationNode; 288 288 newnode->name = name; … … 290 290 } // DeclarationNode::newName 291 291 292 DeclarationNode * DeclarationNode::newFromTypeGen( conststring * name, ExpressionNode * params ) {292 DeclarationNode * DeclarationNode::newFromTypeGen( 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, conststring * name ) {301 DeclarationNode * DeclarationNode::newTypeParam( TypeClass tc, string * name ) { 302 302 DeclarationNode * newnode = new DeclarationNode; 303 303 newnode->type = nullptr; … … 330 330 } // DeclarationNode::newTraitUse 331 331 332 DeclarationNode * DeclarationNode::newTypeDecl( conststring * name, DeclarationNode * typeParams ) {332 DeclarationNode * DeclarationNode::newTypeDecl( 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( conststring * name, ExpressionNode * expr ) {407 DeclarationNode * DeclarationNode::newAttr( string * name, ExpressionNode * expr ) { 408 408 DeclarationNode * newnode = new DeclarationNode; 409 409 newnode->type = nullptr; … … 414 414 } 415 415 416 DeclarationNode * DeclarationNode::newAttr( conststring * name, DeclarationNode * type ) {416 DeclarationNode * DeclarationNode::newAttr( string * name, DeclarationNode * type ) { 417 417 DeclarationNode * newnode = new DeclarationNode; 418 418 newnode->type = nullptr; … … 423 423 } 424 424 425 DeclarationNode * DeclarationNode::newAttribute( conststring * name, ExpressionNode * expr ) {425 DeclarationNode * DeclarationNode::newAttribute( 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; // set forall qualifier 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 ); 547 549 } // if 548 550 } else { // not polymorphic … … 1063 1065 SemanticError( this, "invalid function specifier for " ); 1064 1066 } // if 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; 1067 return buildDecl( type, name ? *name : string( "" ), storageClasses, maybeBuild< Expression >( bitfieldWidth ), funcSpecs, linkage, asmName, maybeBuild< Initializer >(initializer), attributes )->set_extension( extension ); 1072 1068 } // if 1073 1069 -
src/Parser/ExpressionNode.cc
rb21c77a r97397a26 10 10 // Created On : Sat May 16 13:17:07 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jun 4 21:24:45201813 // Update Count : 80 212 // Last Modified On : Thu Mar 22 11:57:39 2018 13 // Update Count : 801 14 14 // 15 15 … … 314 314 315 315 Expression * build_constantStr( string & str ) { 316 assert( str.length() > 0 );317 316 string units; // units 318 317 sepString( str, units, '"' ); // separate constant from units -
src/Parser/InitializerNode.cc
rb21c77a r97397a26 27 27 28 28 InitializerNode::InitializerNode( ExpressionNode * _expr, bool aggrp, ExpressionNode * des ) 29 : expr( _expr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ) , isDelete( false ){29 : expr( _expr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ) { 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 ) , isDelete( false ){38 : expr( nullptr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ) { 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 ) {}50 48 51 49 InitializerNode::~InitializerNode() { … … 86 84 87 85 Initializer * InitializerNode::build() const { 88 assertf( ! isDelete, "Should not build delete stmt InitializerNode" );89 86 if ( aggregate ) { 90 87 // steal designators from children -
src/Parser/ParseNode.h
rb21c77a r97397a26 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jun 6 16:17:18201813 // Update Count : 8 4312 // Last Modified On : Mon Apr 30 09:19:17 2018 13 // Update Count : 831 14 14 // 15 15 … … 77 77 78 78 ParseNode * next = nullptr; 79 conststd::string * name = nullptr;79 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 );90 89 ~InitializerNode(); 91 90 virtual InitializerNode * clone() const { assert( false ); return nullptr; } … … 98 97 InitializerNode * set_maybeConstructed( bool value ) { maybeConstructed = value; return this; } 99 98 bool get_maybeConstructed() const { return maybeConstructed; } 100 101 bool get_isDelete() const { return isDelete; }102 99 103 100 InitializerNode * next_init() const { return kids; } … … 113 110 InitializerNode * kids; 114 111 bool maybeConstructed; 115 bool isDelete;116 112 }; // InitializerNode 117 113 … … 171 167 }; 172 168 173 Expression * build_constantInteger( std::string & str ); // these 4 routines modify the string174 Expression * build_constantFloat( std::string & str );175 Expression * build_constantChar( std::string & str );176 Expression * build_constantStr( std::string & str );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 ); 177 173 Expression * build_field_name_FLOATING_FRACTIONconstant( const std::string & str ); 178 174 Expression * build_field_name_FLOATING_DECIMALconstant( const std::string & str ); … … 230 226 static DeclarationNode * newBuiltinType( BuiltinType ); 231 227 static DeclarationNode * newForall( DeclarationNode * ); 232 static DeclarationNode * newFromTypedef( conststd::string * );233 static DeclarationNode * newFunction( conststd::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );228 static DeclarationNode * newFromTypedef( std::string * ); 229 static DeclarationNode * newFunction( std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ); 234 230 static DeclarationNode * newAggregate( Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ); 235 static DeclarationNode * newEnum( conststd::string * name, DeclarationNode * constants, bool body );236 static DeclarationNode * newEnumConstant( conststd::string * name, ExpressionNode * constant );237 static DeclarationNode * newName( conststd::string * );238 static DeclarationNode * newFromTypeGen( conststd::string *, ExpressionNode * params );239 static DeclarationNode * newTypeParam( TypeClass, conststd::string * );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 * ); 240 236 static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts ); 241 237 static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params ); 242 static DeclarationNode * newTypeDecl( conststd::string * name, DeclarationNode * typeParams );238 static DeclarationNode * newTypeDecl( std::string * name, DeclarationNode * typeParams ); 243 239 static DeclarationNode * newPointer( DeclarationNode * qualifiers, OperKinds kind ); 244 240 static DeclarationNode * newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic ); … … 247 243 static DeclarationNode * newTuple( DeclarationNode * members ); 248 244 static DeclarationNode * newTypeof( ExpressionNode * expr ); 249 static DeclarationNode * newAttr( conststd::string *, ExpressionNode * expr ); // @ attributes250 static DeclarationNode * newAttr( conststd::string *, DeclarationNode * type ); // @ attributes251 static DeclarationNode * newAttribute( conststd::string *, ExpressionNode * expr = nullptr ); // gcc attributes245 static DeclarationNode * newAttr( std::string *, ExpressionNode * expr ); // @ attributes 246 static DeclarationNode * newAttr( std::string *, DeclarationNode * type ); // @ attributes 247 static DeclarationNode * newAttribute( std::string *, ExpressionNode * expr = nullptr ); // gcc attributes 252 248 static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement 253 249 static DeclarationNode * newStaticAssert( ExpressionNode * condition, Expression * message ); … … 403 399 }; 404 400 405 Expression * build_if_control( IfCtl * ctl, std::list< Statement * > & init );406 401 Statement * build_if( IfCtl * ctl, StatementNode * then_stmt, StatementNode * else_stmt ); 407 402 Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ); 408 403 Statement * build_case( ExpressionNode * ctl ); 409 404 Statement * build_default(); 410 Statement * build_while( IfCtl * ctl, StatementNode * stmt ); 411 Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt ); 405 Statement * build_while( ExpressionNode * ctl, StatementNode * stmt, bool kind = false ); 412 406 Statement * build_for( ForCtl * forctl, StatementNode * stmt ); 413 407 Statement * build_branch( BranchStmt::Type kind ); -
src/Parser/StatementNode.cc
rb21c77a r97397a26 10 10 // Created On : Sat May 16 14:59:41 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jun 5 08:58:34201813 // Update Count : 3 6212 // Last Modified On : Mon Apr 30 09:21:16 2018 13 // Update Count : 354 14 14 // 15 15 … … 69 69 caseStmt->get_statements().splice( caseStmt->get_statements().end(), stmts ); 70 70 return this; 71 } // StatementNode::append_last_case71 } 72 72 73 73 Statement * build_expr( ExpressionNode * ctl ) { 74 74 Expression * e = maybeMoveBuild< Expression >( ctl ); 75 75 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 ) { 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; 81 97 if ( ctl->init != 0 ) { 82 98 buildMoveList( ctl->init, init ); … … 86 102 if ( ctl->condition ) { 87 103 // compare the provided condition against 0 88 cond = notZeroExpr( maybeMoveBuild< Expression >(ctl->condition) );104 cond = notZeroExpr( maybeMoveBuild< Expression >(ctl->condition) ); 89 105 } else { 90 106 for ( Statement * stmt : init ) { … … 97 113 } 98 114 delete ctl; 99 return cond;100 } // build_if_control101 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 } // if115 116 std::list< Statement * > init;117 Expression * cond = build_if_control( ctl, init );118 115 return new IfStmt( cond, thenb, elseb, init ); 119 } // build_if116 } 120 117 121 118 Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) { … … 133 130 // branches.size() == 0 for switch (...) {}, i.e., no declaration or statements 134 131 return new SwitchStmt( maybeMoveBuild< Expression >(ctl), branches ); 135 } // build_switch 136 132 } 137 133 Statement * build_case( ExpressionNode * ctl ) { 138 134 std::list< Statement * > branches; 139 135 return new CaseStmt( maybeMoveBuild< Expression >(ctl), branches ); 140 } // build_case 141 136 } 142 137 Statement * build_default() { 143 138 std::list< Statement * > branches; 144 139 return new CaseStmt( nullptr, branches, true ); 145 } // build_default146 147 Statement * build_while( IfCtl * ctl, StatementNode * stmt) {140 } 141 142 Statement * build_while( ExpressionNode * ctl, StatementNode * stmt, bool kind ) { 148 143 std::list< Statement * > branches; 149 144 buildMoveList< Statement, StatementNode >( stmt, branches ); 150 145 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 146 return new WhileStmt( notZeroExpr( maybeMoveBuild< Expression >(ctl) ), branches.front(), kind ); 147 } 165 148 166 149 Statement * build_for( ForCtl * forctl, StatementNode * stmt ) { … … 184 167 delete forctl; 185 168 return new ForStmt( init, cond, incr, branches.front() ); 186 } // build_for169 } 187 170 188 171 Statement * build_branch( BranchStmt::Type kind ) { 189 172 Statement * ret = new BranchStmt( "", kind ); 190 173 return ret; 191 } // build_branch 192 174 } 193 175 Statement * build_branch( std::string * identifier, BranchStmt::Type kind ) { 194 176 Statement * ret = new BranchStmt( * identifier, kind ); 195 177 delete identifier; // allocated by lexer 196 178 return ret; 197 } // build_branch 198 179 } 199 180 Statement * build_computedgoto( ExpressionNode * ctl ) { 200 181 return new BranchStmt( maybeMoveBuild< Expression >(ctl), BranchStmt::Goto ); 201 } // build_computedgoto182 } 202 183 203 184 Statement * build_return( ExpressionNode * ctl ) { … … 205 186 buildMoveList( ctl, exps ); 206 187 return new ReturnStmt( exps.size() > 0 ? exps.back() : nullptr ); 207 } // build_return188 } 208 189 209 190 Statement * build_throw( ExpressionNode * ctl ) { … … 212 193 assertf( exps.size() < 2, "This means we are leaking memory"); 213 194 return new ThrowStmt( ThrowStmt::Terminate, !exps.empty() ? exps.back() : nullptr ); 214 } // build_throw195 } 215 196 216 197 Statement * build_resume( ExpressionNode * ctl ) { … … 219 200 assertf( exps.size() < 2, "This means we are leaking memory"); 220 201 return new ThrowStmt( ThrowStmt::Resume, !exps.empty() ? exps.back() : nullptr ); 221 } // build_resume202 } 222 203 223 204 Statement * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) { … … 225 206 (void)target; 226 207 assertf( false, "resume at (non-local throw) is not yet supported," ); 227 } // build_resume_at208 } 228 209 229 210 Statement * build_try( StatementNode * try_stmt, StatementNode * catch_stmt, StatementNode * finally_stmt ) { … … 233 214 FinallyStmt * finallyBlock = dynamic_cast< FinallyStmt * >(maybeMoveBuild< Statement >(finally_stmt) ); 234 215 return new TryStmt( tryBlock, branches, finallyBlock ); 235 } // build_try 236 216 } 237 217 Statement * build_catch( CatchStmt::Kind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) { 238 218 std::list< Statement * > branches; … … 240 220 assert( branches.size() == 1 ); 241 221 return new CatchStmt( kind, maybeMoveBuild< Declaration >(decl), maybeMoveBuild< Expression >(cond), branches.front() ); 242 } // build_catch 243 222 } 244 223 Statement * build_finally( StatementNode * stmt ) { 245 224 std::list< Statement * > branches; … … 247 226 assert( branches.size() == 1 ); 248 227 return new FinallyStmt( dynamic_cast< CompoundStmt * >( branches.front() ) ); 249 } // build_finally228 } 250 229 251 230 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) { … … 268 247 269 248 return node; 270 } // build_waitfor249 } 271 250 272 251 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when, WaitForStmt * node ) { … … 287 266 288 267 return node; 289 } // build_waitfor268 } 290 269 291 270 WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when ) { … … 296 275 node->timeout.statement = maybeMoveBuild<Statement >( stmt ); 297 276 node->timeout.condition = notZeroExpr( maybeMoveBuild<Expression>( when ) ); 298 } else { 277 } 278 else { 299 279 node->orelse.statement = maybeMoveBuild<Statement >( stmt ); 300 280 node->orelse.condition = notZeroExpr( maybeMoveBuild<Expression>( when ) ); 301 } // if281 } 302 282 303 283 return node; 304 } // build_waitfor_timeout284 } 305 285 306 286 WaitForStmt * build_waitfor_timeout( ExpressionNode * timeout, StatementNode * stmt, ExpressionNode * when, StatementNode * else_stmt, ExpressionNode * else_when ) { … … 315 295 316 296 return node; 317 } // build_waitfor_timeout297 } 318 298 319 299 WithStmt * build_with( ExpressionNode * exprs, StatementNode * stmt ) { … … 322 302 Statement * s = maybeMoveBuild<Statement>( stmt ); 323 303 return new WithStmt( e, s ); 324 } // build_with304 } 325 305 326 306 Statement * build_compound( StatementNode * first ) { … … 328 308 buildMoveList( first, cs->get_kids() ); 329 309 return cs; 330 } // build_compound310 } 331 311 332 312 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) { … … 338 318 buildMoveList( clobber, clob ); 339 319 return new AsmStmt( voltile, instruction, out, in, clob, gotolabels ? gotolabels->labels : noLabels ); 340 } // build_asm320 } 341 321 342 322 Statement * build_directive( string * directive ) { 343 323 return new DirectiveStmt( *directive ); 344 } // build_directive324 } 345 325 346 326 // Local Variables: // -
src/Parser/TypeData.cc
rb21c77a r97397a26 10 10 // Created On : Sat May 16 15:12:51 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jun 6 17:40:33201813 // Update Count : 60 412 // Last Modified On : Thu Apr 26 13:46:07 2018 13 // Update Count : 603 14 14 // 15 15 … … 65 65 case Aggregate: 66 66 // aggregate = new Aggregate_t; 67 aggregate.kind = DeclarationNode::NoAggregate;68 67 aggregate.name = nullptr; 69 68 aggregate.params = nullptr; … … 71 70 aggregate.fields = nullptr; 72 71 aggregate.body = false; 73 aggregate.tagged = false;74 aggregate.parent = nullptr;75 72 break; 76 73 case AggregateInst: … … 201 198 break; 202 199 case Aggregate: 203 newtype->aggregate.kind = aggregate.kind;204 200 newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr; 205 201 newtype->aggregate.params = maybeClone( aggregate.params ); 206 202 newtype->aggregate.actuals = maybeClone( aggregate.actuals ); 207 203 newtype->aggregate.fields = maybeClone( aggregate.fields ); 204 newtype->aggregate.kind = aggregate.kind; 208 205 newtype->aggregate.body = aggregate.body; 209 206 newtype->aggregate.tagged = aggregate.tagged; … … 578 575 579 576 case DeclarationNode::Int128: 580 ret = td->signedness == DeclarationNode::Unsigned? BasicType::UnsignedInt128 : BasicType::SignedInt128;577 ret = td->signedness == 1 ? BasicType::UnsignedInt128 : BasicType::SignedInt128; 581 578 if ( td->length != DeclarationNode::NoLength ) { 582 579 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); … … 602 599 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); 603 600 } // if 604 if ( td->basictype != DeclarationNode::Double&& td->length == DeclarationNode::Long ) {601 if ( td->basictype == DeclarationNode::Float && td->length == DeclarationNode::Long ) { 605 602 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); 606 603 } // if … … 608 605 const_cast<TypeData *>(td)->basictype = DeclarationNode::LongDouble; 609 606 } // 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 }619 607 620 608 ret = floattype[ td->complextype ][ td->basictype - DeclarationNode::Float ]; -
src/Parser/TypedefTable.cc
rb21c77a r97397a26 10 10 // Created On : Sat May 16 15:20:13 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jun 22 06:14:39201813 // Update Count : 20612 // Last Modified On : Tue May 22 08:40:01 2018 13 // Update Count : 121 14 14 // 15 15 … … 17 17 #include "TypedefTable.h" 18 18 #include <cassert> // for assert 19 #include <iostream>20 19 21 20 #if 0 22 #define debugPrint( code ) code 21 #include <iostream> 22 #define debugPrint( x ) cerr << x 23 23 #else 24 #define debugPrint( code)24 #define debugPrint( x ) 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 } // switch39 } // kindName40 )41 42 29 TypedefTable::~TypedefTable() { 43 30 if ( ! SemanticErrorThrow && kindTable.currentScope() != 0 ) { 44 cerr << "Error: cfa-cpp internal error, scope failure " << kindTable.currentScope() << endl; 45 abort(); 31 // std::cerr << "scope failure " << kindTable.currentScope() << endl; 46 32 } // if 47 33 } // TypedefTable::~TypedefTable … … 58 44 } // TypedefTable::isKind 59 45 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 => update 49 } // TypedefTable::changeKind 50 60 51 // SKULLDUGGERY: Generate a typedef for the aggregate name so the aggregate does not have to be qualified by 61 52 // "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the 62 53 // name is explicitly used. 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 // } 54 void TypedefTable::makeTypedef( const string & name ) { 71 55 if ( ! typedefTable.exists( name ) ) { 72 typedefTable.addToEnclosingScope( name, kind, "MTD");56 typedefTable.addToEnclosingScope( name, TYPEDEFname ); 73 57 } // if 74 58 } // TypedefTable::makeTypedef 75 59 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 ); 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 ); 88 64 auto ret = kindTable.insertAt( scope, identifier, kind ); 89 65 if ( ! ret.second ) ret.first->second = kind; // exists => update … … 92 68 void TypedefTable::enterScope() { 93 69 kindTable.beginScope(); 94 debugPrint( cerr << "Entering scope " << kindTable.currentScope() << endl; print());70 debugPrint( "Entering scope " << kindTable.currentScope() << endl ); 95 71 } // TypedefTable::enterScope 96 72 97 73 void TypedefTable::leaveScope() { 98 debugPrint( cerr << "Leaving scope " << kindTable.currentScope() << endl; print());74 debugPrint( "Leaving scope " << kindTable.currentScope() << endl ); 99 75 kindTable.endScope(); 100 76 } // TypedefTable::leaveScope 101 77 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 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 // } 118 88 119 89 // Local Variables: // -
src/Parser/TypedefTable.h
rb21c77a r97397a26 10 10 // Created On : Sat May 16 15:24:36 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jun 22 05:29:58201813 // Update Count : 8612 // Last Modified On : Tue May 22 08:39:29 2018 13 // Update Count : 77 14 14 // 15 15 … … 25 25 typedef ScopedMap< std::string, int > KindTable; 26 26 KindTable kindTable; 27 unsigned int level = 0;28 27 public: 29 28 ~TypedefTable(); … … 31 30 bool exists( const std::string & identifier ); 32 31 int isKind( const std::string & identifier ) const; 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 *);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 ); 36 35 37 36 void enterScope(); 38 37 void leaveScope(); 39 40 void up() { level += 1; }41 void down() { level -= 1; }42 43 void print( void ) const;44 38 }; // TypedefTable 45 39 -
src/Parser/lex.ll
rb21c77a r97397a26 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Wed Jun 20 09:08:28201813 * Update Count : 6 8212 * Last Modified On : Thu May 3 13:42:40 2018 13 * Update Count : 676 14 14 */ 15 15 … … 25 25 //**************************** Includes and Defines **************************** 26 26 27 // trigger before each matching rule's action28 #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 : "";35 27 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 action 36 29 37 30 #include <string> … … 56 49 #define NUMERIC_RETURN(x) rm_underscore(); RETURN_VAL( x ) // numeric constant 57 50 #define KEYWORD_RETURN(x) RETURN_CHAR( x ) // keyword 58 #define QKEYWORD_RETURN(x) RETURN_VAL(x);// quasi-keyword51 #define QKEYWORD_RETURN(x) typedefTable.isKind( yytext ); RETURN_VAL(x); // quasi-keyword 59 52 #define IDENTIFIER_RETURN() RETURN_VAL( typedefTable.isKind( yytext ) ) 60 53 #define ATTRIBUTE_RETURN() RETURN_VAL( ATTR_IDENTIFIER ) … … 239 232 finally { KEYWORD_RETURN(FINALLY); } // CFA 240 233 float { KEYWORD_RETURN(FLOAT); } 241 _Float32 { KEYWORD_RETURN(FLOAT); } // GCC242 _Float32x { KEYWORD_RETURN(FLOAT); } // GCC243 _Float64 { KEYWORD_RETURN(DOUBLE); } // GCC244 _Float64x { KEYWORD_RETURN(DOUBLE); } // GCC245 234 __float80 { KEYWORD_RETURN(FLOAT80); } // GCC 246 235 float80 { KEYWORD_RETURN(FLOAT80); } // GCC 247 _Float128 { KEYWORD_RETURN(FLOAT128); } // GCC248 _Float128x { KEYWORD_RETURN(FLOAT128); } // GCC249 236 __float128 { KEYWORD_RETURN(FLOAT128); } // GCC 250 237 float128 { KEYWORD_RETURN(FLOAT128); } // GCC … … 459 446 460 447 %% 461 462 448 // ----end of lexer---- 463 449 464 450 void yyerror( const char * errmsg ) { 465 SemanticErrorThrow = true;466 451 cout << (yyfilename ? yyfilename : "*unknown file*") << ':' << yylineno << ':' << column - yyleng + 1 467 452 << ": " << ErrorHelpers::error_str() << errmsg << " at token \"" << (yytext[0] == '\0' ? "EOF" : yytext) << '"' << endl; -
src/Parser/parser.yy
rb21c77a r97397a26 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jun 22 13:59:11201813 // Update Count : 3 58612 // Last Modified On : Thu May 24 18:11:59 2018 13 // Update Count : 3369 14 14 // 15 15 … … 136 136 } // build_postfix_name 137 137 138 bool forall = false, xxx = false , yyy = false;// aggregate have one or more forall qualifiers ?138 bool forall = false, xxx = 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;178 177 } 179 178 … … 260 259 %type<flag> asm_volatile_opt 261 260 %type<en> handler_predicate_opt 262 %type<genexpr> generic_association generic_assoc_list263 261 264 262 // statements 265 263 %type<sn> statement labeled_statement compound_statement 266 264 %type<sn> statement_decl statement_decl_list statement_list_nodecl 267 %type<sn> selection_statement if_statement265 %type<sn> selection_statement 268 266 %type<sn> switch_clause_list_opt switch_clause_list 269 267 %type<en> case_value … … 304 302 %type<en> enumerator_value_opt 305 303 306 %type<decl> external_definition external_definition_list external_definition_list_opt 307 308 %type<decl> exception_declaration 304 %type<decl> exception_declaration external_definition external_definition_list external_definition_list_opt 309 305 310 306 %type<decl> field_declaration field_declaration_list_opt field_declarator_opt field_declaring_list … … 328 324 %type<decl> cfa_identifier_parameter_declarator_tuple cfa_identifier_parameter_ptr 329 325 330 %type<decl> cfa_parameter_declaration cfa_parameter_list cfa_parameter_ ellipsis_list_opt326 %type<decl> cfa_parameter_declaration cfa_parameter_list cfa_parameter_type_list_opt 331 327 332 328 %type<decl> cfa_typedef_declaration cfa_variable_declaration cfa_variable_specifier … … 334 330 %type<decl> c_declaration static_assert 335 331 %type<decl> KR_function_declarator KR_function_no_ptr KR_function_ptr KR_function_array 336 %type<decl> KR_ parameter_list KR_parameter_list_opt332 %type<decl> KR_declaration_list KR_declaration_list_opt 337 333 338 334 %type<decl> parameter_declaration parameter_list parameter_type_list_opt … … 406 402 //************************* Namespace Management ******************************** 407 403 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 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. 434 426 435 427 push: … … 505 497 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $5 ) ), $2 ) ); } 506 498 | type_name '.' no_attr_identifier // CFA, nested type 507 // { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 508 { $$ = nullptr; } 499 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 509 500 | type_name '.' '[' field_list ']' // CFA, nested type / tuple field selector 510 // { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 511 { $$ = nullptr; } 501 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 512 502 | GENERIC '(' assignment_expression ',' generic_assoc_list ')' // C11 513 { 514 // add the missing control expression to the GenericExpr and return it 515 $5->control = maybeMoveBuild<Expression>( $3 ); 516 $$ = new ExpressionNode( $5 ); 517 } 503 { SemanticError( yylloc, "_Generic is currently unimplemented." ); $$ = nullptr; } 518 504 ; 519 505 520 506 generic_assoc_list: // C11 521 generic_association507 | generic_association 522 508 | generic_assoc_list ',' generic_association 523 {524 // steal the association node from the singleton and delete the wrapper525 $1->associations.splice($1->associations.end(), $3->associations);526 delete $3;527 $$ = $1;528 }529 509 ; 530 510 531 511 generic_association: // C11 532 512 type_no_function ':' assignment_expression 533 {534 // create a GenericExpr wrapper with one association pair535 $$ = new GenericExpr( nullptr, { { maybeMoveBuildType($1), maybeMoveBuild<Expression>($3) } } );536 }537 513 | DEFAULT ':' assignment_expression 538 { $$ = new GenericExpr( nullptr, { { maybeMoveBuild<Expression>($3) } } ); }539 514 ; 540 515 … … 648 623 // semantics checks, e.g., ++3, 3--, *3, &&3 649 624 | constant 625 { $$ = $1; } 650 626 | string_literal 651 627 { $$ = new ExpressionNode( $1 ); } … … 859 835 // '[' ']' 860 836 // { $$ = new ExpressionNode( build_tuple() ); } 861 // |'[' push assignment_expression pop ']'837 // '[' push assignment_expression pop ']' 862 838 // { $$ = new ExpressionNode( build_tuple( $3 ) ); } 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) ) ); }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 ) ) ); } 867 843 ; 868 844 … … 916 892 '{' '}' 917 893 { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); } 918 | '{' push 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 919 898 local_label_declaration_opt // GCC, local labels 920 899 statement_decl_list // C99, intermix declarations and statements 921 900 pop '}' 922 { $$ = new StatementNode( build_compound( $ 4) ); }901 { $$ = new StatementNode( build_compound( $5 ) ); } 923 902 ; 924 903 925 904 statement_decl_list: // C99 926 905 statement_decl 927 | statement_decl_list statement_decl928 { if ( $1 != 0 ) { $1->set_last( $ 2); $$ = $1; } }906 | statement_decl_list push statement_decl 907 { if ( $1 != 0 ) { $1->set_last( $3 ); $$ = $1; } } 929 908 ; 930 909 … … 944 923 $$ = new StatementNode( $2 ); 945 924 } 946 | statement 925 | statement pop 947 926 ; 948 927 … … 959 938 960 939 selection_statement: 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; } 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 ) ); } 965 945 | SWITCH '(' comma_expression ')' case_clause 966 946 { $$ = new StatementNode( build_switch( true, $3, $5 ) ); } 967 | SWITCH '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop'}' // CFA947 | SWITCH '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt '}' // CFA 968 948 { 969 949 StatementNode *sw = new StatementNode( build_switch( true, $3, $8 ) ); … … 977 957 | CHOOSE '(' comma_expression ')' case_clause // CFA 978 958 { $$ = new StatementNode( build_switch( false, $3, $5 ) ); } 979 | CHOOSE '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt pop'}' // CFA959 | CHOOSE '(' comma_expression ')' '{' push declaration_list_opt switch_clause_list_opt '}' // CFA 980 960 { 981 961 StatementNode *sw = new StatementNode( build_switch( false, $3, $8 ) ); … … 984 964 ; 985 965 986 if_statement:987 IF '(' if_control_expression ')' statement %prec THEN988 // explicitly deal with the shift/reduce conflict on if/else989 { $$ = new StatementNode( build_if( $3, $5, nullptr ) ); }990 | IF '(' if_control_expression ')' statement ELSE statement991 { $$ = new StatementNode( build_if( $3, $5, $7 ) ); }992 ;993 994 966 if_control_expression: 995 comma_expression 967 comma_expression pop 996 968 { $$ = new IfCtl( nullptr, $1 ); } 997 | c_declaration // no semi-colon969 | c_declaration pop // no semi-colon 998 970 { $$ = new IfCtl( $1, nullptr ); } 999 | cfa_declaration // no semi-colon971 | cfa_declaration pop // no semi-colon 1000 972 { $$ = new IfCtl( $1, nullptr ); } 1001 973 | declaration comma_expression // semi-colon separated … … 1054 1026 1055 1027 iteration_statement: 1056 WHILE '(' push if_control_expression ')' statement pop1057 { $$ = new StatementNode( build_while( $ 4, $6) ); }1028 WHILE '(' comma_expression ')' statement 1029 { $$ = new StatementNode( build_while( $3, $5 ) ); } 1058 1030 | DO statement WHILE '(' comma_expression ')' ';' 1059 { $$ = new StatementNode( build_ do_while( $5, $2) ); }1060 | FOR '(' push for_control_expression ')' statement pop1031 { $$ = new StatementNode( build_while( $5, $2, true ) ); } 1032 | FOR '(' push for_control_expression ')' statement 1061 1033 { $$ = new StatementNode( build_for( $4, $6 ) ); } 1062 1034 ; 1063 1035 1064 1036 for_control_expression: 1065 comma_expression_opt ';' comma_expression_opt ';' comma_expression_opt1066 { $$ = new ForCtl( $1, $ 3, $5); }1037 comma_expression_opt pop ';' comma_expression_opt ';' comma_expression_opt 1038 { $$ = new ForCtl( $1, $4, $6 ); } 1067 1039 | declaration comma_expression_opt ';' comma_expression_opt // C99 1068 1040 { $$ = new ForCtl( $1, $2, $4 ); } … … 1186 1158 1187 1159 handler_clause: 1188 handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement pop1189 { $$ = new StatementNode( build_catch( $1, $ 4, $6, $8) ); }1190 | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement pop1191 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, $ 5, $7, $9) ) ); }1160 handler_key '(' push push exception_declaration pop handler_predicate_opt ')' compound_statement pop 1161 { $$ = new StatementNode( build_catch( $1, $5, $7, $9 ) ); } 1162 | handler_clause handler_key '(' push push exception_declaration pop handler_predicate_opt ')' compound_statement pop 1163 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, $6, $8, $10 ) ) ); } 1192 1164 ; 1193 1165 … … 1293 1265 1294 1266 declaration_list_opt: // used at beginning of switch statement 1267 pop // empty 1268 { $$ = nullptr; } 1269 | declaration_list 1270 ; 1271 1272 declaration_list: 1273 declaration 1274 | declaration_list push declaration 1275 { $$ = $1->appendList( $3 ); } 1276 ; 1277 1278 KR_declaration_list_opt: // used to declare parameter types in K&R style functions 1295 1279 // empty 1296 1280 { $$ = nullptr; } 1297 | declaration_list 1298 ; 1299 1300 declaration_list: 1301 declaration 1302 | declaration_list declaration 1303 { $$ = $1->appendList( $2 ); } 1304 ; 1305 1306 KR_parameter_list_opt: // used to declare parameter types in K&R style functions 1307 // empty 1308 { $$ = nullptr; } 1309 | KR_parameter_list 1310 ; 1311 1312 KR_parameter_list: 1281 | KR_declaration_list 1282 ; 1283 1284 KR_declaration_list: 1313 1285 push c_declaration pop ';' 1314 1286 { $$ = $2; } 1315 | KR_ parameter_list push c_declaration pop ';'1287 | KR_declaration_list push c_declaration pop ';' 1316 1288 { $$ = $1->appendList( $3 ); } 1317 1289 ; … … 1333 1305 1334 1306 declaration: // old & new style declarations 1335 c_declaration ';'1336 | cfa_declaration ';'// CFA1337 | static_assert // C111307 c_declaration pop ';' 1308 | cfa_declaration pop ';' // CFA 1309 | static_assert 1338 1310 ; 1339 1311 … … 1341 1313 STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11 1342 1314 { $$ = DeclarationNode::newStaticAssert( $3, $5 ); } 1343 | STATICASSERT '(' constant_expression ')' ';' // CFA1344 { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( *new string( "\"\"" ) ) ); }1345 1315 1346 1316 // C declaration syntax is notoriously confusing and error prone. Cforall provides its own type, variable and function … … 1387 1357 cfa_function_declaration: // CFA 1388 1358 cfa_function_specifier 1359 { $$ = $1; } 1389 1360 | type_qualifier_list cfa_function_specifier 1390 1361 { $$ = $2->addQualifiers( $1 ); } … … 1393 1364 | declaration_qualifier_list type_qualifier_list cfa_function_specifier 1394 1365 { $$ = $3->addQualifiers( $1 )->addQualifiers( $2 ); } 1395 | cfa_function_declaration ',' identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop')'1366 | cfa_function_declaration ',' identifier_or_type_name '(' cfa_parameter_type_list_opt ')' 1396 1367 { 1397 1368 // Append the return type at the start (left-hand-side) to each identifier in the list. 1398 1369 DeclarationNode * ret = new DeclarationNode; 1399 1370 ret->type = maybeClone( $1->type->base ); 1400 $$ = $1->appendList( DeclarationNode::newFunction( $3, ret, $ 6, nullptr ) );1371 $$ = $1->appendList( DeclarationNode::newFunction( $3, ret, $5, nullptr ) ); 1401 1372 } 1402 1373 ; 1403 1374 1404 1375 cfa_function_specifier: // CFA 1405 // '[' ']' identifier_or_type_name '(' push cfa_parameter_ ellipsis_list_opt pop ')' // S/R conflict1376 // '[' ']' identifier_or_type_name '(' push cfa_parameter_type_list_opt pop ')' // S/R conflict 1406 1377 // { 1407 1378 // $$ = DeclarationNode::newFunction( $3, DeclarationNode::newTuple( 0 ), $6, 0, true ); 1408 1379 // } 1409 // '[' ']' identifier '(' push cfa_parameter_ ellipsis_list_opt pop ')'1380 // '[' ']' identifier '(' push cfa_parameter_type_list_opt pop ')' 1410 1381 // { 1411 1382 // typedefTable.setNextIdentifier( *$5 ); 1412 1383 // $$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, 0, true ); 1413 1384 // } 1414 // | '[' ']' TYPEDEFname '(' push cfa_parameter_ ellipsis_list_opt pop ')'1385 // | '[' ']' TYPEDEFname '(' push cfa_parameter_type_list_opt pop ')' 1415 1386 // { 1416 1387 // typedefTable.setNextIdentifier( *$5 ); … … 1420 1391 // identifier_or_type_name must be broken apart because of the sequence: 1421 1392 // 1422 // '[' ']' identifier_or_type_name '(' cfa_parameter_ ellipsis_list_opt ')'1393 // '[' ']' identifier_or_type_name '(' cfa_parameter_type_list_opt ')' 1423 1394 // '[' ']' type_specifier 1424 1395 // 1425 1396 // type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be 1426 1397 // flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name. 1427 cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ ellipsis_list_opt pop ')'1398 cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_type_list_opt pop ')' 1428 1399 // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator). 1429 1400 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); } 1430 | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ ellipsis_list_opt pop ')'1401 | cfa_function_return identifier_or_type_name '(' push cfa_parameter_type_list_opt pop ')' 1431 1402 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); } 1432 1403 ; … … 1443 1414 TYPEDEF cfa_variable_specifier 1444 1415 { 1445 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname , "1");1416 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname ); 1446 1417 $$ = $2->addTypedef(); 1447 1418 } 1448 1419 | TYPEDEF cfa_function_specifier 1449 1420 { 1450 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname , "2");1421 typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname ); 1451 1422 $$ = $2->addTypedef(); 1452 1423 } 1453 1424 | cfa_typedef_declaration pop ',' push no_attr_identifier 1454 1425 { 1455 typedefTable.addToEnclosingScope( *$5, TYPEDEFname , "3");1426 typedefTable.addToEnclosingScope( *$5, TYPEDEFname ); 1456 1427 $$ = $1->appendList( $1->cloneType( $5 ) ); 1457 1428 } … … 1464 1435 TYPEDEF type_specifier declarator 1465 1436 { 1466 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname , "4");1437 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname ); 1467 1438 $$ = $3->addType( $2 )->addTypedef(); 1468 1439 } 1469 1440 | typedef_declaration pop ',' push declarator 1470 1441 { 1471 typedefTable.addToEnclosingScope( *$5->name, TYPEDEFname , "5");1442 typedefTable.addToEnclosingScope( *$5->name, TYPEDEFname ); 1472 1443 $$ = $1->appendList( $1->cloneBaseType( $5 )->addTypedef() ); 1473 1444 } 1474 1445 | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 ) 1475 1446 { 1476 typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname , "6");1447 typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname ); 1477 1448 $$ = $4->addType( $3 )->addQualifiers( $1 )->addTypedef(); 1478 1449 } 1479 1450 | type_specifier TYPEDEF declarator 1480 1451 { 1481 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname , "7");1452 typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname ); 1482 1453 $$ = $3->addType( $1 )->addTypedef(); 1483 1454 } 1484 1455 | type_specifier TYPEDEF type_qualifier_list declarator 1485 1456 { 1486 typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname , "8");1457 typedefTable.addToEnclosingScope( *$4->name, TYPEDEFname ); 1487 1458 $$ = $4->addQualifiers( $1 )->addTypedef()->addType( $1 ); 1488 1459 } … … 1611 1582 1612 1583 forall: 1613 FORALL '(' type_parameter_list')' // CFA1614 { $$ = DeclarationNode::newForall( $ 3); }1584 FORALL '(' push type_parameter_list pop ')' // CFA 1585 { $$ = DeclarationNode::newForall( $4 ); } 1615 1586 ; 1616 1587 … … 1794 1765 { $$ = DeclarationNode::newFromTypedef( $1 ); } 1795 1766 | '.' TYPEDEFname 1796 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }1767 { $$ = DeclarationNode::newFromTypedef( $2 ); } // FIX ME 1797 1768 | type_name '.' TYPEDEFname 1798 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }1769 { $$ = DeclarationNode::newFromTypedef( $3 ); } // FIX ME 1799 1770 | typegen_name 1800 1771 | '.' typegen_name 1801 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }1772 { $$ = $2; } // FIX ME 1802 1773 | type_name '.' typegen_name 1803 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }1774 { $$ = $3; } // FIX ME 1804 1775 ; 1805 1776 … … 1823 1794 ; 1824 1795 1825 fred:1826 // empty1827 { yyy = false; }1828 ;1829 1830 1796 aggregate_type: // struct, union 1831 1797 aggregate_key attribute_list_opt '{' field_declaration_list_opt '}' 1832 1798 { $$ = DeclarationNode::newAggregate( $1, new string( DeclarationNode::anonymous.newName() ), nullptr, $4, true )->addQualifiers( $2 ); } 1833 | aggregate_key attribute_list_opt no_attr_identifier fred1834 { 1835 typedefTable.makeTypedef( *$3 , forall ? TYPEGENname : TYPEDEFname );// create typedef1836 //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update1799 | aggregate_key attribute_list_opt no_attr_identifier_or_type_name 1800 { 1801 typedefTable.makeTypedef( *$3 ); // create typedef 1802 if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update 1837 1803 forall = false; // reset 1838 1804 } 1839 1805 '{' field_declaration_list_opt '}' 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 ); } 1806 { $$ = DeclarationNode::newAggregate( $1, $3, nullptr, $6, true )->addQualifiers( $2 ); } 1849 1807 | aggregate_key attribute_list_opt '(' type_list ')' '{' field_declaration_list_opt '}' // CFA 1850 1808 { $$ = DeclarationNode::newAggregate( $1, new string( DeclarationNode::anonymous.newName() ), $4, $7, false )->addQualifiers( $2 ); } … … 1853 1811 1854 1812 aggregate_type_nobody: // struct, union - {...} 1855 aggregate_key attribute_list_opt no_attr_identifier fred1856 { 1857 typedefTable.makeTypedef( *$3 , forall ? TYPEGENname : TYPEDEFname);1858 //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update1813 aggregate_key attribute_list_opt no_attr_identifier 1814 { 1815 typedefTable.makeTypedef( *$3 ); 1816 if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update 1859 1817 forall = false; // reset 1860 1818 $$ = DeclarationNode::newAggregate( $1, $3, nullptr, nullptr, false )->addQualifiers( $2 ); 1861 1819 } 1862 | aggregate_key attribute_list_opt type_name fred 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 1863 1826 { 1864 1827 // Create new generic declaration with same name as previous forward declaration, where the IDENTIFIER is … … 1874 1837 aggregate_key: 1875 1838 STRUCT 1876 { yyy = true;$$ = DeclarationNode::Struct; }1839 { $$ = DeclarationNode::Struct; } 1877 1840 | UNION 1878 { yyy = true;$$ = DeclarationNode::Union; }1841 { $$ = DeclarationNode::Union; } 1879 1842 | EXCEPTION 1880 { yyy = true;$$ = DeclarationNode::Exception; }1843 { $$ = DeclarationNode::Exception; } 1881 1844 | COROUTINE 1882 { yyy = true;$$ = DeclarationNode::Coroutine; }1845 { $$ = DeclarationNode::Coroutine; } 1883 1846 | MONITOR 1884 { yyy = true;$$ = DeclarationNode::Monitor; }1847 { $$ = DeclarationNode::Monitor; } 1885 1848 | THREAD 1886 { yyy = true;$$ = DeclarationNode::Thread; }1849 { $$ = DeclarationNode::Thread; } 1887 1850 ; 1888 1851 … … 1895 1858 1896 1859 field_declaration: 1897 type_specifier field_declaring_list ';' 1898 { $$ = distAttr( $1, $2 ); } 1860 cfa_field_declaring_list ';' // CFA, new style field declaration 1861 | 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 ); } 1899 1869 | 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 1904 | EXTENSION cfa_field_declaring_list ';' // GCC 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 1870 { 1871 distExt( $3 ); // mark all fields in list 1872 $$ = distAttr( $2, $3 ); 1873 } 1874 | static_assert 1909 1875 ; 1910 1876 … … 1945 1911 { $$ = nullptr; } 1946 1912 | bit_subrange_size 1913 { $$ = $1; } 1947 1914 ; 1948 1915 … … 1955 1922 ENUM attribute_list_opt '{' enumerator_list comma_opt '}' 1956 1923 { $$ = DeclarationNode::newEnum( new string( DeclarationNode::anonymous.newName() ), $4, true )->addQualifiers( $2 ); } 1957 | ENUM attribute_list_opt no_attr_identifier 1924 | ENUM attribute_list_opt no_attr_identifier_or_type_name 1958 1925 { typedefTable.makeTypedef( *$3 ); } 1959 1926 '{' enumerator_list comma_opt '}' 1960 1927 { $$ = DeclarationNode::newEnum( $3, $6, true )->addQualifiers( $2 ); } 1961 | ENUM attribute_list_opt type_name1962 '{' enumerator_list comma_opt '}'1963 { $$ = DeclarationNode::newEnum( $3->type->symbolic.name, $5, true )->addQualifiers( $2 ); }1964 1928 | enum_type_nobody 1965 1929 ; 1966 1930 1967 1931 enum_type_nobody: // enum - {...} 1968 ENUM attribute_list_opt no_attr_identifier 1932 ENUM attribute_list_opt no_attr_identifier_or_type_name 1969 1933 { 1970 1934 typedefTable.makeTypedef( *$3 ); 1971 1935 $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 ); 1972 }1973 | ENUM attribute_list_opt type_name1974 {1975 typedefTable.makeTypedef( *$3->type->symbolic.name );1976 $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 );1977 1936 } 1978 1937 ; … … 1992 1951 ; 1993 1952 1994 cfa_parameter_ ellipsis_list_opt: // CFA, abstract + real1953 cfa_parameter_type_list_opt: // CFA, abstract + real 1995 1954 // empty 1996 1955 { $$ = DeclarationNode::newBasicType( DeclarationNode::Void ); } … … 2125 2084 { $$ = $2; } 2126 2085 | '=' VOID 2127 { $$ = n ew InitializerNode( true ); }2086 { $$ = nullptr; } 2128 2087 | ATassign initializer 2129 2088 { $$ = $2->set_maybeConstructed( false ); } … … 2202 2161 type_parameter_list: // CFA 2203 2162 type_parameter 2163 { $$ = $1; } 2204 2164 | type_parameter_list ',' type_parameter 2205 2165 { $$ = $1->appendList( $3 ); } … … 2215 2175 type_parameter: // CFA 2216 2176 type_class no_attr_identifier_or_type_name 2217 { typedefTable.addTo Scope( *$2, TYPEDEFname, "9"); }2177 { typedefTable.addToEnclosingScope( *$2, TYPEDEFname ); } 2218 2178 type_initializer_opt assertion_list_opt 2219 2179 { $$ = DeclarationNode::newTypeParam( $1, $2 )->addTypeInitializer( $4 )->addAssertions( $5 ); } … … 2249 2209 '|' no_attr_identifier_or_type_name '(' type_list ')' 2250 2210 { $$ = DeclarationNode::newTraitUse( $2, $4 ); } 2251 | '|' '{' push trait_declaration_list pop'}'2211 | '|' '{' push trait_declaration_list '}' 2252 2212 { $$ = $4; } 2253 // | '|' '(' push type_parameter_list pop ')' '{' push trait_declaration_list pop'}' '(' type_list ')'2254 //{ SemanticError( yylloc, "Generic data-type assertion is currently unimplemented." ); $$ = nullptr; }2213 | '|' '(' push type_parameter_list pop ')' '{' push trait_declaration_list '}' '(' type_list ')' 2214 { SemanticError( yylloc, "Generic data-type assertion is currently unimplemented." ); $$ = nullptr; } 2255 2215 ; 2256 2216 … … 2284 2244 no_attr_identifier_or_type_name 2285 2245 { 2286 typedefTable.addToEnclosingScope( *$1, TYPEDEFname , "10");2246 typedefTable.addToEnclosingScope( *$1, TYPEDEFname ); 2287 2247 $$ = DeclarationNode::newTypeDecl( $1, 0 ); 2288 2248 } 2289 | no_attr_identifier_or_type_name '(' type_parameter_list')'2290 { 2291 typedefTable.addToEnclosingScope( *$1, TYPEGENname , "11");2292 $$ = DeclarationNode::newTypeDecl( $1, $ 3);2249 | no_attr_identifier_or_type_name '(' push type_parameter_list pop ')' 2250 { 2251 typedefTable.addToEnclosingScope( *$1, TYPEGENname ); 2252 $$ = DeclarationNode::newTypeDecl( $1, $4 ); 2293 2253 } 2294 2254 ; 2295 2255 2296 2256 trait_specifier: // CFA 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); }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 ); } 2301 2261 ; 2302 2262 2303 2263 trait_declaration_list: // CFA 2304 2264 trait_declaration 2305 | trait_declaration_list p op push trait_declaration2306 { $$ = $1->appendList( $ 4); }2265 | trait_declaration_list push trait_declaration 2266 { $$ = $1->appendList( $3 ); } 2307 2267 ; 2308 2268 2309 2269 trait_declaration: // CFA 2310 cfa_trait_declaring_list ';'2311 | trait_declaring_list ';'2270 cfa_trait_declaring_list pop ';' 2271 | trait_declaring_list pop ';' 2312 2272 ; 2313 2273 … … 2329 2289 2330 2290 translation_unit: 2331 // empty, input file 2291 // empty 2292 {} // empty input file 2332 2293 | external_definition_list 2333 2294 { parseTree = parseTree ? parseTree->appendList( $1 ) : $1; } … … 2335 2296 2336 2297 external_definition_list: 2337 push external_definition pop 2338 { $$ = $2; } 2298 external_definition 2339 2299 | external_definition_list 2340 2300 { forall = xxx; } 2341 push external_definition pop2301 push external_definition 2342 2302 { $$ = $1 ? $1->appendList( $4 ) : $4; } 2343 2303 ; … … 2349 2309 ; 2350 2310 2351 up:2352 { typedefTable.up(); }2353 ;2354 2355 down:2356 { typedefTable.down(); }2357 ;2358 2359 2311 external_definition: 2360 2312 declaration 2361 2313 | external_function_definition 2314 | ASM '(' string_literal ')' ';' // GCC, global assembler statement 2315 { 2316 $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) ); 2317 } 2318 | EXTERN STRINGliteral // C++-style linkage specifier 2319 { 2320 linkageStack.push( linkage ); // handle nested extern "C"/"Cforall" 2321 linkage = LinkageSpec::linkageUpdate( yylloc, linkage, $2 ); 2322 } 2323 '{' external_definition_list_opt '}' 2324 { 2325 linkage = linkageStack.top(); 2326 linkageStack.pop(); 2327 $$ = $5; 2328 } 2362 2329 | EXTENSION external_definition // GCC, multiple __extension__ allowed, meaning unknown 2363 2330 { … … 2365 2332 $$ = $2; 2366 2333 } 2367 | ASM '(' string_literal ')' ';' // GCC, global assembler statement2368 {2369 $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) );2370 }2371 | EXTERN STRINGliteral // C++-style linkage specifier2372 {2373 linkageStack.push( linkage ); // handle nested extern "C"/"Cforall"2374 linkage = LinkageSpec::linkageUpdate( yylloc, linkage, $2 );2375 }2376 '{' up external_definition_list_opt down '}'2377 {2378 linkage = linkageStack.top();2379 linkageStack.pop();2380 $$ = $6;2381 }2382 2334 | type_qualifier_list 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 2335 { if ( $1->type->forall ) xxx = forall = true; } // remember generic type 2336 push '{' external_definition_list '}' // CFA, namespace 2388 2337 { 2389 2338 for ( DeclarationNode * iter = $5; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) { … … 2397 2346 } 2398 2347 | declaration_qualifier_list 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 2348 { if ( $1->type->forall ) xxx = forall = true; } // remember generic type 2349 push '{' external_definition_list '}' // CFA, namespace 2404 2350 { 2405 2351 for ( DeclarationNode * iter = $5; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) { … … 2414 2360 | declaration_qualifier_list type_qualifier_list 2415 2361 { 2416 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 type2418 } 2419 '{' up external_definition_list_opt down '}'// CFA, namespace2362 // forall must be in the type_qualifier_list 2363 if ( $2->type->forall ) xxx = forall = true; // remember generic type 2364 } 2365 push '{' external_definition_list '}' // CFA, namespace 2420 2366 { 2421 2367 for ( DeclarationNode * iter = $6; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) { … … 2441 2387 | function_declarator compound_statement 2442 2388 { $$ = $1->addFunctionBody( $2 ); } 2443 | KR_function_declarator KR_ parameter_list_opt compound_statement2389 | KR_function_declarator KR_declaration_list_opt compound_statement 2444 2390 { $$ = $1->addOldDeclList( $2 )->addFunctionBody( $3 ); } 2445 2391 ; … … 2481 2427 2482 2428 // Old-style K&R function definition, OBSOLESCENT (see 4) 2483 | declaration_specifier KR_function_declarator KR_ parameter_list_opt with_clause_opt compound_statement2429 | declaration_specifier KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement 2484 2430 { 2485 2431 rebindForall( $1, $2 ); … … 2487 2433 } 2488 2434 // handles default int return type, OBSOLESCENT (see 1) 2489 | type_qualifier_list KR_function_declarator KR_ parameter_list_opt with_clause_opt compound_statement2435 | type_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement 2490 2436 { $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 ); } 2491 2437 // handles default int return type, OBSOLESCENT (see 1) 2492 | declaration_qualifier_list KR_function_declarator KR_ parameter_list_opt with_clause_opt compound_statement2438 | declaration_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement 2493 2439 { $$ = $2->addOldDeclList( $3 )->addFunctionBody( $5, $4 )->addQualifiers( $1 ); } 2494 2440 // handles default int return type, OBSOLESCENT (see 1) 2495 | declaration_qualifier_list type_qualifier_list KR_function_declarator KR_ parameter_list_opt with_clause_opt compound_statement2441 | declaration_qualifier_list type_qualifier_list KR_function_declarator KR_declaration_list_opt with_clause_opt compound_statement 2496 2442 { $$ = $3->addOldDeclList( $4 )->addFunctionBody( $6, $5 )->addQualifiers( $2 )->addQualifiers( $1 ); } 2497 2443 ; … … 2738 2684 typedef 2739 2685 // hide type name in enclosing scope by variable name 2740 { typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER , "ID"); }2686 { typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER ); } 2741 2687 | '(' paren_type ')' 2742 2688 { $$ = $2; } … … 3028 2974 '[' ']' 3029 2975 { $$ = DeclarationNode::newArray( 0, 0, false ); } 3030 // multi_array_dimension handles the '[' '*' ']' case2976 // multi_array_dimension handles the '[' '*' ']' case 3031 2977 | '[' push type_qualifier_list '*' pop ']' // remaining C99 3032 2978 { $$ = DeclarationNode::newVarArray( $3 ); } 3033 2979 | '[' push type_qualifier_list pop ']' 3034 2980 { $$ = DeclarationNode::newArray( 0, $3, false ); } 3035 // multi_array_dimension handles the '[' assignment_expression ']' case2981 // multi_array_dimension handles the '[' assignment_expression ']' case 3036 2982 | '[' push type_qualifier_list assignment_expression pop ']' 3037 2983 { $$ = DeclarationNode::newArray( $4, $3, false ); } … … 3169 3115 // 3170 3116 // cfa_abstract_tuple identifier_or_type_name 3171 // '[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_ ellipsis_list_opt ')'3117 // '[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_type_list_opt ')' 3172 3118 // 3173 3119 // since a function return type can be syntactically identical to a tuple type: … … 3228 3174 '[' push cfa_abstract_parameter_list pop ']' 3229 3175 { $$ = 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; }3234 3176 ; 3235 3177 3236 3178 cfa_abstract_function: // CFA 3237 // '[' ']' '(' cfa_parameter_ ellipsis_list_opt ')'3179 // '[' ']' '(' cfa_parameter_type_list_opt ')' 3238 3180 // { $$ = DeclarationNode::newFunction( nullptr, DeclarationNode::newTuple( nullptr ), $4, nullptr ); } 3239 cfa_abstract_tuple '(' push cfa_parameter_ ellipsis_list_opt pop ')'3181 cfa_abstract_tuple '(' push cfa_parameter_type_list_opt pop ')' 3240 3182 { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); } 3241 | cfa_function_return '(' push cfa_parameter_ ellipsis_list_opt pop ')'3183 | cfa_function_return '(' push cfa_parameter_type_list_opt pop ')' 3242 3184 { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); } 3243 3185 ; … … 3270 3212 3271 3213 %% 3272 3273 3214 // ----end of grammar---- 3274 3215 -
src/ResolvExpr/Alternative.cc
rb21c77a r97397a26 30 30 31 31 namespace ResolvExpr { 32 Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( nullptr) {}32 Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( 0 ) {} 33 33 34 34 Alternative::Alternative( Expression *expr, const TypeEnvironment &env, const Cost& cost ) -
src/ResolvExpr/AlternativeFinder.cc
rb21c77a r97397a26 100 100 void postvisit( InitExpr * initExpr ); 101 101 void postvisit( DeletedExpr * delExpr ); 102 void postvisit( GenericExpr * genExpr );103 102 104 103 /// Adds alternatives for anonymous members … … 178 177 selected[ mangleName ] = current; 179 178 } else if ( candidate->cost == mapPlace->second.candidate->cost ) { 180 // if one of the candidates contains a deleted identifier, can pick the other, since 181 // deleted expressions should not be ambiguous if there is another option that is at least as good 182 if ( findDeletedExpr( candidate->expr ) ) { 183 // do nothing 184 PRINT( std::cerr << "candidate is deleted" << std::endl; ) 185 } else if ( findDeletedExpr( mapPlace->second.candidate->expr ) ) { 186 PRINT( std::cerr << "current is deleted" << std::endl; ) 187 selected[ mangleName ] = current; 188 } else { 189 PRINT( 190 std::cerr << "marking ambiguous" << std::endl; 191 ) 192 mapPlace->second.isAmbiguous = true; 193 } 179 PRINT( 180 std::cerr << "marking ambiguous" << std::endl; 181 ) 182 mapPlace->second.isAmbiguous = true; 194 183 } else { 195 184 PRINT( … … 311 300 // 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 312 301 Expression* aggrExpr = alt.expr->clone(); 313 alt.env.apply( aggrExpr-> result);314 Type * aggrType = aggrExpr-> result;302 alt.env.apply( aggrExpr->get_result() ); 303 Type * aggrType = aggrExpr->get_result(); 315 304 if ( dynamic_cast< ReferenceType * >( aggrType ) ) { 316 305 aggrType = aggrType->stripReferences(); … … 318 307 } 319 308 320 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr-> result) ) {309 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) { 321 310 addAggMembers( structInst, aggrExpr, alt.cost+Cost::safe, alt.env, "" ); 322 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr-> result) ) {311 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) { 323 312 addAggMembers( unionInst, aggrExpr, alt.cost+Cost::safe, alt.env, "" ); 324 313 } // if … … 330 319 aggInst->lookup( name, members ); 331 320 332 for ( Declaration * decl : members ) { 333 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( decl ) ) { 334 // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so 335 // can't construct in place and use vector::back 336 Alternative newAlt( new MemberExpr( dwt, expr->clone() ), env, newCost ); 337 renameTypes( newAlt.expr ); 338 addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression. 339 alternatives.push_back( std::move(newAlt) ); 321 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) { 322 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) { 323 alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) ); 324 renameTypes( alternatives.back().expr ); 325 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression. 340 326 } else { 341 327 assert( false ); … … 347 333 if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) { 348 334 // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning 349 auto val = constantExpr->intValue(); 335 // xxx - this should be improved by memoizing the value of constant exprs 336 // during parsing and reusing that information here. 337 std::stringstream ss( constantExpr->get_constant()->get_value() ); 338 int val = 0; 350 339 std::string tmp; 351 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 352 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) ); 340 if ( ss >> val && ! (ss >> tmp) ) { 341 if ( val >= 0 && (unsigned int)val < tupleType->size() ) { 342 alternatives.push_back( Alternative( new TupleIndexExpr( expr, val ), env, newCost ) ); 343 } // if 353 344 } // if 345 } else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) { 346 // xxx - temporary hack until 0/1 are int constants 347 if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) { 348 std::stringstream ss( nameExpr->get_name() ); 349 int val; 350 ss >> val; 351 alternatives.push_back( Alternative( new TupleIndexExpr( expr, val ), env, newCost ) ); 352 } 354 353 } // if 355 354 } … … 438 437 return Cost::infinity; 439 438 } 440 }441 if ( DefaultArgExpr * def = dynamic_cast< DefaultArgExpr * >( *actualExpr ) ) {442 // default arguments should be free - don't include conversion cost.443 // Unwrap them here because they are not relevant to the rest of the system.444 *actualExpr = def->expr;445 ++formal;446 continue;447 439 } 448 440 Type * formalType = (*formal)->get_type(); … … 772 764 ConstantExpr* getDefaultValue( Initializer* init ) { 773 765 if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) { 774 if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->value ) ) { 775 return dynamic_cast<ConstantExpr*>( ce->arg ); 776 } else { 777 return dynamic_cast<ConstantExpr*>( si->value ); 766 if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->get_value() ) ) { 767 return dynamic_cast<ConstantExpr*>( ce->get_arg() ); 778 768 } 779 769 } … … 1036 1026 indexer ) ) { 1037 1027 results.emplace_back( 1038 i, new DefaultArgExpr( cnstExpr ), move(env), move(need), move(have),1028 i, cnstExpr, move(env), move(need), move(have), 1039 1029 move(openVars), nextArg, nTuples ); 1040 1030 } … … 1369 1359 funcFinder.findWithAdjustment( untypedExpr->function ); 1370 1360 // if there are no function alternatives, then proceeding is a waste of time. 1371 // xxx - findWithAdjustment throws, so this check and others like it shouldn't be necessary.1372 1361 if ( funcFinder.alternatives.empty() ) return; 1373 1362 … … 1397 1386 argExpansions.emplace_back(); 1398 1387 auto& argE = argExpansions.back(); 1399 //argE.reserve( arg.alternatives.size() );1388 argE.reserve( arg.alternatives.size() ); 1400 1389 1401 1390 for ( const Alternative& actual : arg ) { … … 1420 1409 std::back_inserter( candidates ) ); 1421 1410 } 1422 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr-> result->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)1423 if ( ClassRef eqvClass = func->env.lookup( typeInst-> name) ) {1411 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer) 1412 if ( ClassRef eqvClass = func->env.lookup( typeInst->get_name() ) ) { 1424 1413 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.get_bound().type ) ) { 1425 1414 Alternative newFunc( *func ); … … 1676 1665 Cost cost = Cost::zero; 1677 1666 Expression * newExpr = data.combine( cost ); 1678 1679 // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so 1680 // can't construct in place and use vector::back 1681 Alternative newAlt( newExpr, env, Cost::zero, cost ); 1667 alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) ); 1682 1668 PRINT( 1683 1669 std::cerr << "decl is "; … … 1688 1674 std::cerr << std::endl; 1689 1675 ) 1690 renameTypes( newAlt.expr ); 1691 addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression. 1692 alternatives.push_back( std::move(newAlt) ); 1676 renameTypes( alternatives.back().expr ); 1677 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression. 1693 1678 } // for 1694 1679 } … … 2057 2042 assertf( false, "AlternativeFinder should never see a DeletedExpr." ); 2058 2043 } 2059 2060 void AlternativeFinder::Finder::postvisit( GenericExpr * ) {2061 assertf( false, "_Generic is not yet supported." );2062 }2063 2044 } // namespace ResolvExpr 2064 2045 -
src/ResolvExpr/CommonType.cc
rb21c77a r97397a26 24 24 #include "SynTree/Type.h" // for BasicType, BasicType::Kind::... 25 25 #include "SynTree/Visitor.h" // for Visitor 26 #include "Unify.h" // for unifyExact, WidenMode26 #include "Unify.h" // for unifyExact, bindVar, 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 ] =178 static const BasicType::Kind combinedType[ BasicType::NUMBER_OF_BASIC_TYPES ][ 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 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 }, 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, }, 206 204 }; 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 );211 205 212 206 CommonType::CommonType( Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) … … 238 232 AssertionSet need, have; 239 233 WidenMode widen( widenFirst, widenSecond ); 240 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return;234 if ( entry != openVars.end() && ! bindVar(var, voidPointer->get_base(), entry->second, env, need, have, openVars, widen, indexer ) ) return; 241 235 } 242 236 } -
src/ResolvExpr/ConversionCost.cc
rb21c77a r97397a26 231 231 */ 232 232 233 static const int costMatrix[][ BasicType::NUMBER_OF_BASIC_TYPES ] = { 234 /* 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 */ 235 /* 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}, 236 /* 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}, 237 /* 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}, 238 /* 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}, 239 /* 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}, 240 /* 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}, 241 /* 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}, 242 /* 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}, 243 /* 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}, 244 /* 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}, 245 /* 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}, 246 /* 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}, 247 248 /* 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}, 249 /* 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}, 250 /* 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}, 251 /* 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}, 252 /* 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}, 253 /* 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}, 254 /* 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}, 255 /* 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}, 256 /* 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}, 257 258 /* 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}, 259 /* 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}, 260 261 /* 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}, 262 /* 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}, 233 static const int costMatrix[ BasicType::NUMBER_OF_BASIC_TYPES ][ BasicType::NUMBER_OF_BASIC_TYPES ] = { 234 /* 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 */ 235 /* Bool */ { 0, 1, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 12, 13, 14, 12, 13, 14, -1, -1, -1, 10, 11, }, 236 /* Char */ { -1, 0, -1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 11, 12, 13, 11, 12, 13, -1, -1, -1, 9, 10, }, 237 /* SChar */ { -1, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 11, 12, 13, 11, 12, 13, -1, -1, -1, 9, 10, }, 238 /* UChar */ { -1, -1, -1, 0, 1, 2, 3, 4, 4, 5, 6, 7, 10, 11, 12, 10, 11, 12, -1, -1, -1, 8, 9, }, 239 /* Short */ { -1, -1, -1, -1, 0, 1, 2, 3, 3, 4, 5, 6, 9, 10, 11, 9, 10, 11, -1, -1, -1, 7, 8, }, 240 /* UShort */{ -1, -1, -1, -1, -1, 0, 1, 2, 2, 3, 4, 5, 8, 9, 10, 8, 9, 10, -1, -1, -1, 6, 7, }, 241 /* Int */ { -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 3, 4, 7, 8, 9, 7, 8, 9, -1, -1, -1, 5, 6, }, 242 /* UInt */ { -1, -1, -1, -1, -1, -1, -1, 0, -1, 1, 2, 3, 6, 7, 8, 6, 7, 8, -1, -1, -1, 4, 5, }, 243 /* Long */ { -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 6, 7, 8, 6, 7, 8, -1, -1, -1, 4, 5, }, 244 /* ULong */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 5, 6, 7, 5, 6, 7, -1, -1, -1, 3, 4, }, 245 /* LLong */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 4, 5, 6, 4, 5, 6, -1, -1, -1, 2, 3, }, 246 /* ULLong */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 4, 5, 3, 4, 5, -1, -1, -1, 1, 2, }, 247 248 /* Float */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 1, 2, 3, -1, -1, -1, -1, -1, }, 249 /* Double */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, 1, 2, -1, -1, -1, -1, -1, }, 250 /* LDbl */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, -1, -1, -1, -1, -1, }, 251 /* FCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, -1, -1, -1, -1, }, 252 /* DCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, -1, -1, -1, -1, }, 253 /* LDCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, }, 254 /* FImag */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 3, 0, 1, 2, -1, -1, }, 255 /* DImag */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, -1, 0, 1, -1, -1, }, 256 /* LDImag */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0, -1, -1, }, 257 258 /* I128 */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 3, 4, 3, 4, 5, -1, -1, -1, 0, 1, }, 259 /* U128 */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 3, 2, 3, 4, -1, -1, -1, -1, 0, }, 263 260 }; 264 static_assert(265 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,266 "Each basic type kind should have a corresponding row in the cost matrix"267 );268 269 261 270 262 void ConversionCost::postvisit( VoidType * ) { -
src/ResolvExpr/ExplodedActual.h
rb21c77a r97397a26 31 31 32 32 ExplodedActual() : env(), cost(Cost::zero), exprs() {} 33 33 34 ExplodedActual( const Alternative& actual, const SymTab::Indexer& indexer ); 34 ExplodedActual(ExplodedActual&&) = default;35 ExplodedActual& operator= (ExplodedActual&&) = default;36 35 }; 37 36 } -
src/ResolvExpr/Resolver.cc
rb21c77a r97397a26 217 217 if ( findDeletedExpr( choice.expr ) ) { 218 218 trace( choice.expr ); 219 SemanticError( untyped->location,choice.expr, "Unique best alternative includes deleted identifier in " );219 SemanticError( choice.expr, "Unique best alternative includes deleted identifier in " ); 220 220 } 221 221 alt = std::move( choice ); … … 252 252 253 253 auto untyped = new CastExpr{ expr }; // cast to void 254 untyped->location = expr->location;255 254 256 255 // set up and resolve expression cast to void … … 278 277 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) { 279 278 assert( untyped && type ); 280 // transfer location to generated cast for error purposes281 CodeLocation location = untyped->location;282 279 untyped = new CastExpr( untyped, type ); 283 untyped->location = location;284 280 findSingleExpression( untyped, indexer ); 285 281 removeExtraneousCast( untyped, indexer ); … … 584 580 585 581 // Make sure we don't widen any existing bindings 586 resultEnv.forbidWidening(); 587 582 for ( auto & i : resultEnv ) { 583 i.allowWidening = false; 584 } 585 588 586 // Find any unbound type variables 589 587 resultEnv.extractOpenVars( openVars ); -
src/ResolvExpr/Resolver.h
rb21c77a r97397a26 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 nullptr39 DeletedExpr * findDeletedExpr( Expression * expr );40 38 } // namespace ResolvExpr 41 39 -
src/ResolvExpr/TypeEnvironment.cc
rb21c77a r97397a26 7 7 // TypeEnvironment.cc -- 8 8 // 9 // Author : Aaron B. Moss9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:19:47 2015 11 // Last Modified By : Aaron B. Moss12 // Last Modified On : Fri Jun 29 15:51:00 201813 // Update Count : 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun May 17 12:23:36 2015 13 // Update Count : 3 14 14 // 15 15 … … 27 27 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 28 28 #include "TypeEnvironment.h" 29 #include "typeops.h" // for occurs30 29 #include "Unify.h" // for unifyInexact 31 30 … … 51 50 #if 0 52 51 void EqvClass::initialize( const EqvClass &src, EqvClass &dest ) { 53 initialize( src, dest, src.type );54 }55 56 void EqvClass::initialize( const EqvClass &src, EqvClass &dest, const Type *ty ) {57 52 dest.vars = src.vars; 58 dest.type = maybeClone( ty);53 dest.type = maybeClone( src.type ); 59 54 dest.allowWidening = src.allowWidening; 60 55 dest.data = src.data; 61 56 } 62 57 63 EqvClass::EqvClass() : type( nullptr ), allowWidening( true ) { 64 } 58 EqvClass::EqvClass() : vars(), type( 0 ), allowWidening( true ), data() {} 59 60 EqvClass::EqvClass( std::vector<interned_string>&& vs, BoundType&& bound ) 61 : vars( vs.begin(), vs.end() ), type( maybeClone( bound.type ) ), 62 allowWidening( bound.allowWidening ), data( bound.data ) {} 65 63 66 64 EqvClass::EqvClass( const EqvClass &other ) { 67 65 initialize( other, *this ); 68 }69 70 EqvClass::EqvClass( const EqvClass &other, const Type *ty ) {71 initialize( other, *this, ty );72 }73 74 EqvClass::EqvClass( EqvClass &&other )75 : vars{std::move(other.vars)}, type{other.type},76 allowWidening{std::move(other.allowWidening)}, data{std::move(other.data)} {77 other.type = nullptr;78 66 } 79 67 … … 83 71 return *this; 84 72 } 85 86 EqvClass &EqvClass::operator=( EqvClass &&other ) {87 if ( this == &other ) return *this;88 89 vars = std::move(other.vars);90 type = other.type;91 allowWidening = std::move(other.allowWidening);92 data = std::move(other.data);93 94 return *this;95 }96 97 void EqvClass::set_type( Type* ty ) { type = ty; }98 73 99 74 void EqvClass::print( std::ostream &os, Indenter indent ) const { … … 113 88 const EqvClass* TypeEnvironment::lookup( const std::string &var ) const { 114 89 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) { 115 if ( i->vars.find( var ) != i->vars.end() ) return &*i; 90 if ( i->vars.find( var ) != i->vars.end() ) { 91 /// std::cout << var << " is in class "; 92 /// i->print( std::cout ); 93 return &*i; 94 } 95 /// std::cout << var << " is not in class "; 96 /// i->print( std::cout ); 116 97 } // for 117 98 return nullptr; … … 137 118 if ( root ) return { this, root }; 138 119 else return { nullptr, var }; 139 }140 141 bool isFtype( Type *type ) {142 if ( dynamic_cast< FunctionType* >( type ) ) {143 return true;144 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {145 return typeInst->get_isFtype();146 } // if147 return false;148 120 } 149 121 … … 316 288 } 317 289 290 void TypeEnvironment::add( const EqvClass &eqvClass ) { 291 filterOverlappingClasses( env, eqvClass ); 292 env.push_back( eqvClass ); 293 } 294 318 295 void TypeEnvironment::add( EqvClass &&eqvClass ) { 319 296 filterOverlappingClasses( env, eqvClass ); … … 326 303 newClass.vars.insert( (*i)->get_name() ); 327 304 newClass.data = TypeDecl::Data{ (*i) }; 328 env.push_back( std::move(newClass));305 env.push_back( newClass ); 329 306 } // for 330 307 } … … 340 317 // transition to TypeSubstitution 341 318 newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false }; 342 add( std::move(newClass));319 add( newClass ); 343 320 } 344 321 } … … 347 324 for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) { 348 325 for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) { 326 /// std::cerr << "adding " << *theVar; 349 327 if ( theClass->type ) { 328 /// std::cerr << " bound to "; 329 /// theClass->type->print( std::cerr ); 330 /// std::cerr << std::endl; 350 331 sub.add( *theVar, theClass->type ); 351 332 } else if ( theVar != theClass->vars.begin() ) { 352 333 TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype ); 334 /// std::cerr << " bound to variable " << *theClass->vars.begin() << std::endl; 353 335 sub.add( *theVar, newTypeInst ); 354 336 } // if 355 337 } // for 356 338 } // for 339 /// std::cerr << "input env is:" << std::endl; 340 /// print( std::cerr, 8 ); 341 /// std::cerr << "sub is:" << std::endl; 342 /// sub.print( std::cerr, 8 ); 357 343 sub.normalize(); 358 344 } 359 345 360 346 void TypeEnvironment::print( std::ostream &os, Indenter indent ) const { 361 for ( const EqvClass & theClass : env) {362 theClass.print( os, indent );347 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) { 348 i->print( os, indent ); 363 349 } // for 364 350 } … … 366 352 std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) { 367 353 for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) { 368 if ( i->vars.count( var ) ) return i; 354 if ( i->vars.find( var ) == i->vars.end() ) { 355 return i; 356 } // if 369 357 } // for 370 358 return env.end(); -
src/ResolvExpr/TypeEnvironment.h
rb21c77a r97397a26 10 10 // Created On : Sun May 17 12:24:58 2015 11 11 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Fri Jun 29 16:00:00 201813 // Update Count : 512 // Last Modified On : Wed Jun 13 16:31:00 2018 13 // Update Count : 4 14 14 // 15 15 … … 24 24 #include <utility> // for pair 25 25 #include <vector> // for vector 26 27 #include "WidenMode.h" // for WidenMode28 26 29 27 #include "Common/InternedString.h" // for interned_string … … 97 95 98 96 void initialize( const EqvClass &src, EqvClass &dest ); 99 void initialize( const EqvClass &src, EqvClass &dest, const Type *ty );100 97 EqvClass(); 98 EqvClass( std::vector<interned_string>&& vars, BoundType&& bound ); 101 99 EqvClass( const EqvClass &other ); 102 EqvClass( const EqvClass &other, const Type *ty );103 EqvClass( EqvClass &&other );104 100 EqvClass &operator=( const EqvClass &other ); 105 EqvClass &operator=( EqvClass &&other );106 101 void print( std::ostream &os, Indenter indent = {} ) const; 107 108 /// Takes ownership of `ty`, freeing old `type` 109 void set_type(Type* ty); 110 }; 111 #endif 112 102 }; 103 #endif 104 113 105 class TypeEnvironment; 114 106 … … 214 206 WidenMode widenMode, const SymTab::Indexer& indexer ); 215 207 #if !1 216 private: 217 void add( EqvClass &&eqvClass ); 218 public: 208 void add( const EqvClass &eqvClass ); 209 void add( EqvClass &&eqvClass ); 219 210 void add( const Type::ForallList &tyDecls ); 220 211 void add( const TypeSubstitution & sub ); … … 235 226 /// and extracts open variables. 236 227 void addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ); 237 238 /// Disallows widening for all bindings in the environment239 void forbidWidening();240 228 #endif 241 229 242 230 iterator begin() { return { this, bindings->begin() }; } 243 231 iterator end() { return { this, bindings->end() }; } 232 #if 0 233 typedef std::list< EqvClass >::const_iterator const_iterator; 234 const_iterator begin() const { return env.begin(); } 235 const_iterator end() const { return env.end(); } 236 #endif 244 237 }; 245 238 -
src/ResolvExpr/Unify.cc
rb21c77a r97397a26 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:27:10 2015 11 // Last Modified By : Aaron B. Moss12 // Last Modified On : Mon Jun 18 11:58:00 201813 // Update Count : 4 311 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Mar 16 16:22:54 2017 13 // Update Count : 42 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 } // if 130 return false; 131 } 132 133 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 ) { 134 // remove references from other, so that type variables can only bind to value types 135 other = other->stripReferences(); 136 OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() ); 137 assert( tyvar != openVars.end() ); 138 if ( ! tyVarCompatible( tyvar->second, other ) ) { 139 return false; 140 } // if 141 if ( occurs( other, typeInst->get_name(), env ) ) { 142 return false; 143 } // if 144 if ( const EqvClass *curClass = env.lookup( typeInst->get_name() ) ) { 145 if ( curClass->type ) { 146 Type *common = 0; 147 // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to 148 Type* newType = curClass->type->clone(); 149 newType->get_qualifiers() = typeInst->get_qualifiers(); 150 if ( unifyInexact( newType, other, env, needAssertions, haveAssertions, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) { 151 if ( common ) { 152 common->get_qualifiers() = Type::Qualifiers(); 153 EqvClass newClass = *curClass; 154 newClass.type = common; 155 env.add( std::move(newClass) ); 156 } // if 157 return true; 158 } else { 159 return false; 160 } // if 161 } else { 162 EqvClass newClass = *curClass; 163 newClass.type = other->clone(); 164 newClass.type->get_qualifiers() = Type::Qualifiers(); 165 newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond; 166 env.add( std::move(newClass) ); 167 } // if 168 } else { 169 EqvClass newClass; 170 newClass.vars.insert( typeInst->get_name() ); 171 newClass.type = other->clone(); 172 newClass.type->get_qualifiers() = Type::Qualifiers(); 173 newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond; 174 newClass.data = data; 175 env.add( newClass ); 176 } // if 177 return true; 178 } 179 180 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 ) { 181 bool result = true; 182 const EqvClass *class1 = env.lookup( var1->get_name() ); 183 const EqvClass *class2 = env.lookup( var2->get_name() ); 184 bool widen1 = false, widen2 = false; 185 Type *type1 = nullptr, *type2 = nullptr; 186 187 if ( class1 ) { 188 if ( class1->type ) { 189 if ( occurs( class1->type, var2->get_name(), env ) ) { 190 return false; 191 } // if 192 type1 = class1->type->clone(); 193 } // if 194 widen1 = widenMode.widenFirst && class1->allowWidening; 195 } // if 196 if ( class2 ) { 197 if ( class2->type ) { 198 if ( occurs( class2->type, var1->get_name(), env ) ) { 199 return false; 200 } // if 201 type2 = class2->type->clone(); 202 } // if 203 widen2 = widenMode.widenSecond && class2->allowWidening; 204 } // if 205 206 if ( type1 && type2 ) { 207 // std::cerr << "has type1 && type2" << std::endl; 208 WidenMode newWidenMode ( widen1, widen2 ); 209 Type *common = 0; 210 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, newWidenMode, indexer, common ) ) { 211 EqvClass newClass1 = *class1; 212 newClass1.vars.insert( class2->vars.begin(), class2->vars.end() ); 213 newClass1.allowWidening = widen1 && widen2; 214 if ( common ) { 215 common->get_qualifiers() = Type::Qualifiers(); 216 newClass1.type = common; 217 } // if 218 env.add( std::move(newClass1) ); 219 } else { 220 result = false; 221 } // if 222 } else if ( class1 && class2 ) { 223 if ( type1 ) { 224 EqvClass newClass1 = *class1; 225 newClass1.vars.insert( class2->vars.begin(), class2->vars.end() ); 226 newClass1.allowWidening = widen1; 227 env.add( std::move(newClass1) ); 228 } else { 229 EqvClass newClass2 = *class2; 230 newClass2.vars.insert( class1->vars.begin(), class1->vars.end() ); 231 newClass2.allowWidening = widen2; 232 env.add( std::move(newClass2) ); 233 } // if 234 } else if ( class1 ) { 235 EqvClass newClass1 = *class1; 236 newClass1.vars.insert( var2->get_name() ); 237 newClass1.allowWidening = widen1; 238 env.add( std::move(newClass1) ); 239 } else if ( class2 ) { 240 EqvClass newClass2 = *class2; 241 newClass2.vars.insert( var1->get_name() ); 242 newClass2.allowWidening = widen2; 243 env.add( std::move(newClass2) ); 244 } else { 245 EqvClass newClass; 246 newClass.vars.insert( var1->get_name() ); 247 newClass.vars.insert( var2->get_name() ); 248 newClass.allowWidening = widen1 && widen2; 249 newClass.data = data; 250 env.add( newClass ); 251 } // if 252 return result; 253 } 254 124 255 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 125 256 OpenVarSet closedVars; … … 159 290 160 291 if ( isopen1 && isopen2 && entry1->second == entry2->second ) { 161 result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );292 result = bindVarToVar( var1, var2, entry1->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer ); 162 293 } else if ( isopen1 ) { 163 result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );294 result = bindVar( var1, type2, entry1->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer ); 164 295 } else if ( isopen2 ) { // TODO: swap widenMode values in call, since type positions are flipped? 165 result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widenMode, indexer );296 result = bindVar( var2, type1, entry2->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer ); 166 297 } else { 167 298 PassVisitor<Unify> comparator( type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer ); -
src/ResolvExpr/Unify.h
rb21c77a r97397a26 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 13:09:04 2015 11 // Last Modified By : Aaron B. Moss12 // Last Modified On : Mon Jun 18 11:58:00 201813 // Update Count : 411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 21 23:09:34 2017 13 // Update Count : 3 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 WidenMode24 23 25 24 class Type; … … 30 29 31 30 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 ); 32 43 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ); 33 44 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ); 34 45 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 );36 46 37 47 template< typename Iterator1, typename Iterator2 > -
src/SymTab/Indexer.cc
rb21c77a r97397a26 106 106 if ( ! CodeGen::isCtorDtorAssign( id ) ) return; 107 107 108 // helpful data structure to organize properties for a type108 // helpful data structure 109 109 struct ValueType { 110 struct DeclBall { // properties for this particular decl110 struct DeclBall { 111 111 IdData decl; 112 bool isUserDefinedFunc; 112 bool isUserDefinedFunc; // properties for this particular decl 113 bool isDefaultCtor; 114 bool isDtor; 113 115 bool isCopyFunc; 114 116 }; 115 117 // properties for this type 118 bool existsUserDefinedFunc = false; // any user-defined function found 119 bool existsUserDefinedCtor = false; // any user-defined constructor found 120 bool existsUserDefinedDtor = false; // any user-defined destructor found 116 121 bool existsUserDefinedCopyFunc = false; // user-defined copy ctor found 117 BaseSyntaxNode * deleteStmt = nullptr; // non-null if a user-defined function isfound122 bool existsUserDefinedDefaultCtor = false; // user-defined default ctor found 118 123 std::list< DeclBall > decls; 119 124 … … 122 127 ValueType & operator+=( IdData data ) { 123 128 DeclarationWithType * function = data.id; 124 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage ); 125 bool isCopyFunc = InitTweak::isCopyFunction( function, function->name ); 126 decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } ); 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); 127 137 existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc); 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 } 138 existsUserDefinedDefaultCtor = existsUserDefinedDefaultCtor || (isUserDefinedFunc && isDefaultCtor); 133 139 return *this; 134 140 } … … 142 148 for ( auto decl : copy ) { 143 149 if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) { 144 std::list< DeclarationWithType * > & params = function-> type->parameters;150 std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters(); 145 151 assert( ! params.empty() ); 146 152 // use base type of pointer, so that qualifiers on the pointer type aren't considered. … … 154 160 155 161 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine 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. 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). 162 167 for ( std::pair< const std::string, ValueType > & pair : funcMap ) { 163 168 ValueType & val = pair.second; 164 169 for ( ValueType::DeclBall ball : val.decls ) { 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 } 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 ); 183 178 } 184 out.push_back( ball.decl );185 179 } 186 180 } … … 477 471 void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) { 478 472 // default handling of conflicts is to raise an error 479 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr , decl->isDeleted ? decl : nullptr);473 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr ); 480 474 } 481 475 -
src/SymTab/Mangler.cc
rb21c77a r97397a26 171 171 "w", // SignedInt128 172 172 "Uw", // UnsignedInt128 173 "x", // Float80174 "y", // Float128175 173 }; 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 );180 174 181 175 printQualifiers( basicType ); 182 assert( basicType->get_kind() < sizeof(btLetter)/sizeof(btLetter[0]) );183 176 mangleName << btLetter[ basicType->get_kind() ]; 184 177 } … … 225 218 GuardValue( inFunctionType ); 226 219 inFunctionType = true; 227 std::list< Type* > returnTypes = getTypes( functionType-> returnVals);220 std::list< Type* > returnTypes = getTypes( functionType->get_returnVals() ); 228 221 acceptAll( returnTypes, *visitor ); 229 222 mangleName << "_"; 230 std::list< Type* > paramTypes = getTypes( functionType-> parameters);223 std::list< Type* > paramTypes = getTypes( functionType->get_parameters() ); 231 224 acceptAll( paramTypes, *visitor ); 232 225 mangleName << "_"; … … 236 229 printQualifiers( refType ); 237 230 238 mangleName << ( refType-> name.length() + prefix.length() ) << prefix << refType->name;231 mangleName << ( refType->get_name().length() + prefix.length() ) << prefix << refType->get_name(); 239 232 240 233 if ( mangleGenericParams ) { 241 std::list< Expression* >& params = refType-> parameters;234 std::list< Expression* >& params = refType->get_parameters(); 242 235 if ( ! params.empty() ) { 243 236 mangleName << "_"; 244 237 for ( std::list< Expression* >::const_iterator param = params.begin(); param != params.end(); ++param ) { 245 238 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); 246 assertf(paramType, "Aggregate parameters should be type expressions: %s", to CString(*param));247 maybeAccept( paramType-> type, *visitor );239 assertf(paramType, "Aggregate parameters should be type expressions: %s", toString(*param).c_str()); 240 maybeAccept( paramType->get_type(), *visitor ); 248 241 } 249 242 mangleName << "_"; -
src/SymTab/Validate.cc
rb21c77a r97397a26 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 ForExprMutator52 51 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd 53 52 #include "Common/ScopedMap.h" // for ScopedMap … … 78 77 class SwitchStmt; 79 78 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 autogenerateRoutines278 277 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay 279 278 Concurrency::implementMutexFuncs( translationUnit ); -
src/SynTree/BasicType.cc
rb21c77a r97397a26 55 55 case DoubleImaginary: 56 56 case LongDoubleImaginary: 57 case Float80:58 case Float128:59 57 return false; 60 58 case NUMBER_OF_BASIC_TYPES: -
src/SynTree/Declaration.cc
rb21c77a r97397a26 92 92 } 93 93 94 95 94 // Local Variables: // 96 95 // tab-width: 4 // -
src/SynTree/Declaration.h
rb21c77a r97397a26 83 83 Expression *asmName; 84 84 std::list< Attribute * > attributes; 85 bool isDeleted = false;86 85 87 86 DeclarationWithType( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage, const std::list< Attribute * > & attributes, Type::FuncSpecifiers fs ); -
src/SynTree/Expression.cc
rb21c77a r97397a26 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 681 642 // Local Variables: // 682 643 // tab-width: 4 // -
src/SynTree/Expression.h
rb21c77a r97397a26 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 expression850 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 it861 };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 876 835 // Local Variables: // 877 836 // tab-width: 4 // -
src/SynTree/Mutator.h
rb21c77a r97397a26 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;97 95 98 96 virtual Type * mutate( VoidType * basicType ) = 0; -
src/SynTree/ReferenceToType.cc
rb21c77a r97397a26 46 46 47 47 namespace { 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);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 ); 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-> name, attributes ), baseStruct( baseStruct ) {}58 Parent( tq, baseStruct->get_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-> members, name, foundDecls );82 doLookup( baseStruct->get_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-> name, attributes ), baseUnion( baseUnion ) {}101 Parent( tq, baseUnion->get_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-> members, name, foundDecls );125 doLookup( baseUnion->get_members(), name, foundDecls ); 126 126 } 127 127 -
src/SynTree/Statement.cc
rb21c77a r97397a26 208 208 } 209 209 210 WhileStmt::WhileStmt( Expression *condition, Statement *body, std::list< Statement * > & initialization,bool isDoWhile ):211 Statement(), condition( condition), body( body), i nitialization( initialization ), isDoWhile( isDoWhile) {210 WhileStmt::WhileStmt( Expression *condition, Statement *body, bool isDoWhile ): 211 Statement(), condition( condition), body( body), isDoWhile( isDoWhile) { 212 212 } 213 213 -
src/SynTree/Statement.h
rb21c77a r97397a26 213 213 Expression *condition; 214 214 Statement *body; 215 std::list<Statement *> initialization;216 215 bool isDoWhile; 217 216 218 217 WhileStmt( Expression *condition, 219 Statement *body, std::list<Statement *> & initialization,bool isDoWhile = false );218 Statement *body, bool isDoWhile = false ); 220 219 WhileStmt( const WhileStmt &other ); 221 220 -
src/SynTree/SynTree.h
rb21c77a r97397a26 101 101 class InitExpr; 102 102 class DeletedExpr; 103 class DefaultArgExpr;104 class GenericExpr;105 103 106 104 class Type; -
src/SynTree/Type.cc
rb21c77a r97397a26 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jun 22 10:17:19 201813 // Update Count : 3 912 // Last Modified On : Mon Sep 25 15:16:32 2017 13 // Update Count : 38 14 14 // 15 15 #include "Type.h" … … 24 24 using namespace std; 25 25 26 const char *BasicType::typeNames[ ] = {26 const char *BasicType::typeNames[BasicType::NUMBER_OF_BASIC_TYPES] = { 27 27 "_Bool", 28 28 "char", … … 48 48 "__int128", 49 49 "unsigned __int128", 50 "__float80",51 "__float128"52 50 }; 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 );57 51 58 52 Type::Type( const Qualifiers &tq, const std::list< Attribute * > & attributes ) : tq( tq ), attributes( attributes ) {} … … 64 58 65 59 // These must remain in the same order as the corresponding bit fields. 66 const char * Type::FuncSpecifiersNames[] = { "inline", " _Noreturn", "fortran" };60 const char * Type::FuncSpecifiersNames[] = { "inline", "fortran", "_Noreturn" }; 67 61 const char * Type::StorageClassesNames[] = { "extern", "static", "auto", "register", "_Thread_local" }; 68 62 const char * Type::QualifiersNames[] = { "const", "restrict", "volatile", "lvalue", "mutex", "_Atomic" }; -
src/SynTree/Type.h
rb21c77a r97397a26 230 230 SignedInt128, 231 231 UnsignedInt128, 232 Float80,233 Float128,234 232 NUMBER_OF_BASIC_TYPES 235 233 } kind; -
src/SynTree/Visitor.h
rb21c77a r97397a26 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;99 97 100 98 virtual void visit( VoidType * basicType ) = 0; -
src/benchmark/Makefile.am
rb21c77a r97397a26 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 ## =========================================================================================================104 94 ctxswitch$(EXEEXT): \ 105 loop.run \106 function.run \107 fetch_add.run \108 95 ctxswitch-pthread.run \ 109 96 ctxswitch-cfa_coroutine.run \ 110 97 ctxswitch-cfa_thread.run \ 111 ctxswitch-cfa_thread2.run \112 98 ctxswitch-upp_coroutine.run \ 113 99 ctxswitch-upp_thread.run \ 114 -ctxswitch-kos_fibre.run \115 -ctxswitch-kos_fibre2.run \116 100 ctxswitch-goroutine.run \ 117 101 ctxswitch-java_thread.run 118 102 103 ctxswitch-cfa_coroutine$(EXEEXT): 104 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 105 106 ctxswitch-cfa_thread$(EXEEXT): 107 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 108 109 ctxswitch-upp_coroutine$(EXEEXT): 110 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 111 112 ctxswitch-upp_thread$(EXEEXT): 113 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 114 119 115 ctxswitch-pthread$(EXEEXT): 120 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 121 122 ctxswitch-cfa_coroutine$(EXEEXT): 123 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 124 125 ctxswitch-cfa_thread$(EXEEXT): 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} 130 131 ctxswitch-upp_coroutine$(EXEEXT): 132 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 133 134 ctxswitch-upp_thread$(EXEEXT): 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 116 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 142 117 143 118 ctxswitch-goroutine$(EXEEXT): … … 152 127 ## ========================================================================================================= 153 128 mutex$(EXEEXT) :\ 154 loop.run \ 155 function.run \ 156 fetch_add.run \ 129 mutex-function.run \ 130 mutex-fetch_add.run \ 157 131 mutex-pthread_lock.run \ 158 132 mutex-upp.run \ … … 161 135 mutex-cfa4.run \ 162 136 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} 163 143 164 144 mutex-pthread_lock$(EXEEXT): … … 297 277 298 278 compile-io$(EXEEXT): 299 @${CC} -quiet -fsyntax-only -w ../tests/io 1.c@CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}279 @${CC} -quiet -fsyntax-only -w ../tests/io.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 300 280 301 281 compile-monitor$(EXEEXT): 302 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}282 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 303 283 304 284 compile-operators$(EXEEXT): … … 309 289 310 290 compile-typeof$(EXEEXT): 311 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}312 291 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 292 -
src/benchmark/Makefile.in
rb21c77a r97397a26 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 516 507 ctxswitch$(EXEEXT): \ 517 loop.run \518 function.run \519 fetch_add.run \520 508 ctxswitch-pthread.run \ 521 509 ctxswitch-cfa_coroutine.run \ 522 510 ctxswitch-cfa_thread.run \ 523 ctxswitch-cfa_thread2.run \524 511 ctxswitch-upp_coroutine.run \ 525 512 ctxswitch-upp_thread.run \ 526 -ctxswitch-kos_fibre.run \527 -ctxswitch-kos_fibre2.run \528 513 ctxswitch-goroutine.run \ 529 514 ctxswitch-java_thread.run 530 515 516 ctxswitch-cfa_coroutine$(EXEEXT): 517 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 518 519 ctxswitch-cfa_thread$(EXEEXT): 520 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 521 522 ctxswitch-upp_coroutine$(EXEEXT): 523 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 524 525 ctxswitch-upp_thread$(EXEEXT): 526 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 527 531 528 ctxswitch-pthread$(EXEEXT): 532 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 533 534 ctxswitch-cfa_coroutine$(EXEEXT): 535 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 536 537 ctxswitch-cfa_thread$(EXEEXT): 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} 542 543 ctxswitch-upp_coroutine$(EXEEXT): 544 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 545 546 ctxswitch-upp_thread$(EXEEXT): 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 529 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 554 530 555 531 ctxswitch-goroutine$(EXEEXT): … … 563 539 564 540 mutex$(EXEEXT) :\ 565 loop.run \ 566 function.run \ 567 fetch_add.run \ 541 mutex-function.run \ 542 mutex-fetch_add.run \ 568 543 mutex-pthread_lock.run \ 569 544 mutex-upp.run \ … … 572 547 mutex-cfa4.run \ 573 548 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} 574 555 575 556 mutex-pthread_lock$(EXEEXT): … … 701 682 702 683 compile-io$(EXEEXT): 703 @${CC} -quiet -fsyntax-only -w ../tests/io 1.c@CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}684 @${CC} -quiet -fsyntax-only -w ../tests/io.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 704 685 705 686 compile-monitor$(EXEEXT): 706 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}687 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 707 688 708 689 compile-operators$(EXEEXT): … … 713 694 714 695 compile-typeof$(EXEEXT): 715 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}696 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 716 697 717 698 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
src/libcfa/Makefile.am
rb21c77a r97397a26 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 concurrency/mutex53 headers += concurrency/coroutine concurrency/thread concurrency/kernel concurrency/monitor 54 54 endif 55 55 -
src/libcfa/Makefile.in
rb21c77a r97397a26 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 concurrency/mutex99 @BUILD_CONCURRENCY_TRUE@am__append_3 = concurrency/coroutine concurrency/thread concurrency/kernel concurrency/monitor 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 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.c155 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.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) \ 164 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_d_a-mutex.$(OBJEXT) 163 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_d_a-monitor.$(OBJEXT) 165 164 am__objects_2 = libcfa_d_a-fstream.$(OBJEXT) \ 166 165 libcfa_d_a-iostream.$(OBJEXT) libcfa_d_a-iterator.$(OBJEXT) \ … … 189 188 containers/result.c containers/vector.c \ 190 189 concurrency/coroutine.c concurrency/thread.c \ 191 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.c190 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.c 195 194 @BUILD_CONCURRENCY_TRUE@am__objects_5 = concurrency/libcfa_a-coroutine.$(OBJEXT) \ 196 195 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-thread.$(OBJEXT) \ 197 196 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-kernel.$(OBJEXT) \ 198 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-monitor.$(OBJEXT) \ 199 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-mutex.$(OBJEXT) 197 @BUILD_CONCURRENCY_TRUE@ concurrency/libcfa_a-monitor.$(OBJEXT) 200 198 am__objects_6 = libcfa_a-fstream.$(OBJEXT) libcfa_a-iostream.$(OBJEXT) \ 201 199 libcfa_a-iterator.$(OBJEXT) libcfa_a-limits.$(OBJEXT) \ … … 266 264 containers/result containers/vector concurrency/coroutine \ 267 265 concurrency/thread concurrency/kernel concurrency/monitor \ 268 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.h266 ${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.h 271 269 HEADERS = $(nobase_cfa_include_HEADERS) 272 270 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) … … 550 548 concurrency/libcfa_d_a-monitor.$(OBJEXT): concurrency/$(am__dirstamp) \ 551 549 concurrency/$(DEPDIR)/$(am__dirstamp) 552 concurrency/libcfa_d_a-mutex.$(OBJEXT): concurrency/$(am__dirstamp) \553 concurrency/$(DEPDIR)/$(am__dirstamp)554 550 concurrency/CtxSwitch-@MACHINE_TYPE@.$(OBJEXT): \ 555 551 concurrency/$(am__dirstamp) \ … … 584 580 concurrency/$(DEPDIR)/$(am__dirstamp) 585 581 concurrency/libcfa_a-monitor.$(OBJEXT): concurrency/$(am__dirstamp) \ 586 concurrency/$(DEPDIR)/$(am__dirstamp)587 concurrency/libcfa_a-mutex.$(OBJEXT): concurrency/$(am__dirstamp) \588 582 concurrency/$(DEPDIR)/$(am__dirstamp) 589 583 concurrency/libcfa_a-alarm.$(OBJEXT): concurrency/$(am__dirstamp) \ … … 641 635 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_a-kernel.Po@am__quote@ 642 636 @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@644 637 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_a-preemption.Po@am__quote@ 645 638 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_a-thread.Po@am__quote@ … … 649 642 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_d_a-kernel.Po@am__quote@ 650 643 @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@652 644 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_d_a-preemption.Po@am__quote@ 653 645 @AMDEP_TRUE@@am__include@ @am__quote@concurrency/$(DEPDIR)/libcfa_d_a-thread.Po@am__quote@ … … 938 930 @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` 939 931 940 concurrency/libcfa_d_a-mutex.o: concurrency/mutex.c941 @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.c942 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) concurrency/$(DEPDIR)/libcfa_d_a-mutex.Tpo concurrency/$(DEPDIR)/libcfa_d_a-mutex.Po943 @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.c946 947 concurrency/libcfa_d_a-mutex.obj: concurrency/mutex.c948 @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.Po950 @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 954 932 libcfa_d_a-assert.o: assert.c 955 933 @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 … … 1259 1237 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 1260 1238 @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.c1263 @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.c1264 @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) concurrency/$(DEPDIR)/libcfa_a-mutex.Tpo concurrency/$(DEPDIR)/libcfa_a-mutex.Po1265 @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.c1268 1269 concurrency/libcfa_a-mutex.obj: concurrency/mutex.c1270 @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.Po1272 @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`1275 1239 1276 1240 libcfa_a-assert.o: assert.c -
src/libcfa/bits/containers.h
rb21c77a r97397a26 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;190 185 } 191 186 #endif … … 266 261 __get( node ).prev = NULL; 267 262 } 268 269 forall(dtype T | sized(T))270 static inline bool ?!=?( __dllist(T) & this, zero_t zero ) {271 return this.head != 0;272 }273 263 #undef next 274 264 #undef prev -
src/libcfa/bits/locks.h
rb21c77a r97397a26 18 18 #include "bits/debug.h" 19 19 #include "bits/defs.h" 20 #include <assert.h>21 22 #ifdef __cforall23 extern "C" {24 #include <pthread.h>25 }26 #endif27 20 28 21 // pause to prevent excess processor bus usage … … 119 112 __atomic_clear( &this.lock, __ATOMIC_RELEASE ); 120 113 } 121 122 123 #ifdef __CFA_WITH_VERIFY__124 extern bool __cfaabi_dbg_in_kernel();125 #endif126 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 }165 114 #endif -
src/libcfa/concurrency/invoke.h
rb21c77a r97397a26 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat May 19 08:23:21201813 // Update Count : 3 112 // Last Modified On : Fri Mar 30 22:33:59 2018 13 // Update Count : 30 14 14 // 15 15 … … 18 18 #include "bits/locks.h" 19 19 20 #define TL_GET( member ) kernelTLS.member 21 #define TL_SET( member, value ) kernelTLS.member = value; 22 20 23 #ifdef __cforall 21 24 extern "C" { … … 25 28 #ifndef _INVOKE_H_ 26 29 #define _INVOKE_H_ 27 28 #ifdef __ARM_ARCH29 // function prototypes are only really used by these macros on ARM30 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 #else42 #define TL_GET( member ) kernelTLS.member43 #define TL_SET( member, value ) kernelTLS.member = value;44 #endif45 30 46 31 #ifdef __cforall -
src/libcfa/concurrency/kernel
rb21c77a r97397a26 23 23 extern "C" { 24 24 #include <pthread.h> 25 #include <semaphore.h>26 25 } 27 26 … … 44 43 extern struct cluster * mainCluster; 45 44 46 enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule, Callback }; 47 48 typedef void (*__finish_callback_fptr_t)(void); 45 enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule }; 49 46 50 47 //TODO use union, many of these fields are mutually exclusive (i.e. MULTI vs NOMULTI) 51 48 struct FinishAction { 52 49 FinishOpCode action_code; 53 /*54 // Union of possible actions55 union {56 // Option 1 : locks and threads57 struct {58 // 1 thread or N thread59 union {60 thread_desc * thrd;61 struct {62 thread_desc ** thrds;63 unsigned short thrd_count;64 };65 };66 // 1 lock or N lock67 union {68 __spinlock_t * lock;69 struct {70 __spinlock_t ** locks;71 unsigned short lock_count;72 };73 };74 };75 // Option 2 : action pointer76 __finish_callback_fptr_t callback;77 };78 /*/79 50 thread_desc * thrd; 80 thread_desc ** thrds;81 unsigned short thrd_count;82 51 __spinlock_t * lock; 83 52 __spinlock_t ** locks; 84 53 unsigned short lock_count; 85 __finish_callback_fptr_t callback;86 //*/54 thread_desc ** thrds; 55 unsigned short thrd_count; 87 56 }; 88 57 static inline void ?{}(FinishAction & this) { … … 113 82 pthread_t kernel_thread; 114 83 84 // Termination 85 // Set to true to notify the processor should terminate 86 volatile bool do_terminate; 87 88 // Termination synchronisation 89 semaphore terminated; 90 115 91 // RunThread data 116 92 // Action to do after a thread is ran … … 125 101 126 102 // Idle lock 127 __bin_sem_t idleLock;128 129 // Termination130 // Set to true to notify the processor should terminate131 volatile bool do_terminate;132 133 // Termination synchronisation134 semaphore terminated;135 103 136 104 // Link lists fields 137 struct __dbg_node_proc{105 struct { 138 106 struct processor * next; 139 107 struct processor * prev; … … 182 150 183 151 // Link lists fields 184 struct __dbg_node_cltr{152 struct { 185 153 cluster * next; 186 154 cluster * prev; -
src/libcfa/concurrency/kernel.c
rb21c77a r97397a26 16 16 //C Includes 17 17 #include <stddef.h> 18 #include <errno.h>19 #include <string.h>20 18 extern "C" { 21 19 #include <stdio.h> … … 51 49 thread_desc * mainThread; 52 50 53 extern "C" { 54 struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters; 55 } 51 struct { __dllist_t(cluster ) list; __spinlock_t lock; } global_clusters; 56 52 57 53 //----------------------------------------------------------------------------- … … 147 143 runner.proc = &this; 148 144 149 idleLock{};150 151 145 start( &this ); 152 146 } 153 147 154 148 void ^?{}(processor & this) with( this ){ 155 if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE)) {149 if( ! do_terminate ) { 156 150 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this); 157 158 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED); 159 wake( &this ); 160 151 terminate(&this); 152 verify(this.do_terminate); 153 verify( kernelTLS.this_processor != &this); 161 154 P( terminated ); 162 155 verify( kernelTLS.this_processor != &this); 163 } 164 165 pthread_join( kernel_thread, NULL ); 156 pthread_join( kernel_thread, NULL ); 157 } 166 158 } 167 159 … … 202 194 203 195 thread_desc * readyThread = NULL; 204 for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ )196 for( unsigned int spin_count = 0; ! this->do_terminate; spin_count++ ) 205 197 { 206 198 readyThread = nextThread( this->cltr ); … … 221 213 else 222 214 { 223 // spin(this, &spin_count); 224 halt(this); 215 spin(this, &spin_count); 225 216 } 226 217 } … … 266 257 // its final actions must be executed from the kernel 267 258 void finishRunning(processor * this) with( this->finish ) { 268 verify( ! kernelTLS.preemption_state.enabled ); 269 choose( action_code ) { 270 case No_Action: 271 break; 272 case Release: 259 if( action_code == Release ) { 260 verify( ! kernelTLS.preemption_state.enabled ); 273 261 unlock( *lock ); 274 case Schedule: 262 } 263 else if( action_code == Schedule ) { 275 264 ScheduleThread( thrd ); 276 case Release_Schedule: 265 } 266 else if( action_code == Release_Schedule ) { 267 verify( ! kernelTLS.preemption_state.enabled ); 277 268 unlock( *lock ); 278 269 ScheduleThread( thrd ); 279 case Release_Multi: 270 } 271 else if( action_code == Release_Multi ) { 272 verify( ! kernelTLS.preemption_state.enabled ); 280 273 for(int i = 0; i < lock_count; i++) { 281 274 unlock( *locks[i] ); 282 275 } 283 case Release_Multi_Schedule: 276 } 277 else if( action_code == Release_Multi_Schedule ) { 284 278 for(int i = 0; i < lock_count; i++) { 285 279 unlock( *locks[i] ); … … 288 282 ScheduleThread( thrds[i] ); 289 283 } 290 case Callback: 291 callback(); 292 default: 293 abort("KERNEL ERROR: Unexpected action to run after thread"); 294 } 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)++; 295 294 } 296 295 … … 397 396 with( *thrd->curr_cluster ) { 398 397 lock ( ready_queue_lock __cfaabi_dbg_ctx2 ); 399 bool was_empty = !(ready_queue != 0);400 398 append( ready_queue, thrd ); 401 399 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 414 400 } 415 401 … … 511 497 } 512 498 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 527 499 // KERNEL ONLY 528 500 void LeaveThread(__spinlock_t * lock, thread_desc * thrd) { … … 546 518 __cfaabi_dbg_print_safe("Kernel : Starting\n"); 547 519 548 __cfa_dbg_global_clusters.list{ __get };549 __cfa_dbg_global_clusters.lock{};520 global_clusters.list{ __get }; 521 global_clusters.lock{}; 550 522 551 523 // Initialize the main cluster … … 628 600 // When its coroutine terminates, it return control to the mainThread 629 601 // which is currently here 630 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);602 mainProcessor->do_terminate = true; 631 603 returnToKernel(); 632 mainThread->self_cor.state = Halted;633 604 634 605 // THE SYSTEM IS NOW COMPLETELY STOPPED … … 646 617 ^(mainThread){}; 647 618 648 ^( __cfa_dbg_global_clusters.list){};649 ^( __cfa_dbg_global_clusters.lock){};619 ^(global_clusters.list){}; 620 ^(global_clusters.lock){}; 650 621 651 622 __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n"); … … 656 627 //============================================================================================= 657 628 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 } 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 // } 681 646 682 647 //============================================================================================= … … 793 758 // Global Queues 794 759 void doregister( cluster & cltr ) { 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 );760 lock ( global_clusters.lock __cfaabi_dbg_ctx2); 761 push_front( global_clusters.list, cltr ); 762 unlock ( global_clusters.lock ); 798 763 } 799 764 800 765 void unregister( cluster & cltr ) { 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 );766 lock ( global_clusters.lock __cfaabi_dbg_ctx2); 767 remove( global_clusters.list, cltr ); 768 unlock( global_clusters.lock ); 804 769 } 805 770 -
src/libcfa/concurrency/kernel_private.h
rb21c77a r97397a26 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);51 50 void LeaveThread(__spinlock_t * lock, thread_desc * thrd); 52 51 … … 57 56 void runThread(processor * this, thread_desc * dst); 58 57 void finishRunning(processor * this); 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 } 58 void terminate(processor * this); 59 void spin(processor * this, unsigned int * spin_count); 71 60 72 61 struct event_kernel_t { … … 76 65 77 66 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; 78 75 79 76 struct __cfa_kernel_preemption_state_t { -
src/libcfa/concurrency/monitor.c
rb21c77a r97397a26 297 297 this.count = count; 298 298 299 // Sort monitors based on address 299 // Sort monitors based on address -> TODO use a sort specialized for small numbers 300 300 __libcfa_small_sort(this.m, count); 301 301 -
src/libcfa/concurrency/preemption.c
rb21c77a r97397a26 10 10 // Created On : Mon Jun 5 14:20:42 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jun 5 17:35:49 201813 // Update Count : 3 712 // Last Modified On : Mon Apr 9 13:52:39 2018 13 // Update Count : 36 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: @% ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);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); 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 > 50000164 163 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); 165 #endif166 164 167 165 // Set enabled flag to false … … 192 190 // Check if we need to prempt the thread because an interrupt was missed 193 191 if( prev == 1 ) { 194 #if GCC_VERSION > 50000195 192 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); 196 #endif197 193 198 194 // Set enabled flag to true … … 221 217 verifyf( prev != 0u, "Incremented from %u\n", prev ); // If this triggers someone is enabled already enabled interrupts 222 218 if( prev == 1 ) { 223 #if GCC_VERSION > 50000224 219 static_assert(__atomic_always_lock_free(sizeof(kernelTLS.preemption_state.enabled), &kernelTLS.preemption_state.enabled), "Must be lock-free"); 225 #endif226 220 // Set enabled flag to true 227 221 // should be atomic to avoid preemption in the middle of the operation. … … 260 254 static void preempt( processor * this ) { 261 255 sigval_t value = { PREEMPT_NORMAL }; 256 pthread_sigqueue( this->kernel_thread, SIGUSR1, value ); 257 } 258 259 // kill wrapper : signal a processor 260 void terminate(processor * this) { 261 this->do_terminate = true; 262 sigval_t value = { PREEMPT_TERMINATE }; 262 263 pthread_sigqueue( this->kernel_thread, SIGUSR1, value ); 263 264 } … … 361 362 choose(sfp->si_value.sival_int) { 362 363 case PREEMPT_NORMAL : ;// Normal case, nothing to do here 363 case PREEMPT_TERMINATE: verify( __atomic_load_n( &kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ));364 case PREEMPT_TERMINATE: verify( kernelTLS.this_processor->do_terminate); 364 365 default: 365 366 abort( "internal error, signal value is %d", sfp->si_value.sival_int ); … … 375 376 376 377 // Clear sighandler mask before context switching. 377 #if GCC_VERSION > 50000378 378 static_assert( sizeof( sigset_t ) == sizeof( cxt->uc_sigmask ), "Expected cxt->uc_sigmask to be of sigset_t" ); 379 #endif380 379 if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), NULL ) == -1 ) { 381 380 abort( "internal error, sigprocmask" ); … … 480 479 } 481 480 482 #ifdef __CFA_WITH_VERIFY__483 bool __cfaabi_dbg_in_kernel() {484 return !kernelTLS.preemption_state.enabled;485 }486 #endif487 488 481 // Local Variables: // 489 482 // mode: c // -
src/libcfa/fstream
rb21c77a r97397a26 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Jun 5 10:20:25 201813 // Update Count : 13 112 // Last Modified On : Thu Dec 7 15:17:26 2017 13 // Update Count : 130 14 14 // 15 15 … … 54 54 void open( ofstream &, const char * name ); 55 55 void close( ofstream & ); 56 ofstream & write( ofstream &, const char * data, size_t size );56 ofstream & write( ofstream &, const char * data, unsigned long int 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, size_t size );76 ifstream & read( ifstream & is, char * data, unsigned long int size ); 77 77 ifstream & ungetc( ifstream & is, char c ); 78 78 int fmt( ifstream &, const char fmt[], ... ); -
src/libcfa/fstream.c
rb21c77a r97397a26 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jun 5 17:02:56 201813 // Update Count : 2 8112 // Last Modified On : Sat Dec 9 09:31:23 2017 13 // Update Count : 275 14 14 // 15 15 … … 116 116 } // close 117 117 118 ofstream & write( ofstream & os, const char * data, size_t size ) {118 ofstream & write( ofstream & os, const char * data, unsigned long int 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, size_t size ) {200 ifstream & read( ifstream & is, char * data, unsigned long int size ) { 201 201 if ( fail( is ) ) { 202 202 fprintf( stderr, "attempt read I/O on failed stream\n" ); -
src/libcfa/iostream
rb21c77a r97397a26 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jun 2 08:07:55201813 // Update Count : 15 312 // Last Modified On : Sat Apr 28 13:08:24 2018 13 // Update Count : 152 14 14 // 15 15 … … 56 56 // implement writable for intrinsic types 57 57 58 forall( dtype ostype | ostream( ostype ) ) { 59 ostype & ?|?( ostype &, _Bool ); 58 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, _Bool ); 60 59 61 ostype & ?|?( ostype &, char );62 ostype & ?|?( ostype &, signed char );63 ostype & ?|?( ostype &, unsigned char );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 ); 64 63 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 );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 ); 73 72 74 ostype & ?|?( ostype &, float ); // FIX ME: should not be required75 ostype & ?|?( ostype &, double );76 ostype & ?|?( ostype &, long double );73 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, float ); // FIX ME: should not be required 74 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, double ); 75 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, long double ); 77 76 78 ostype & ?|?( ostype &, float _Complex );79 ostype & ?|?( ostype &, double _Complex );80 ostype & ?|?( ostype &, long double _Complex );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 ); 81 80 82 ostype & ?|?( ostype &, const char * );83 //ostype & ?|?( ostype &, const char16_t * );81 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, const char * ); 82 //forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, const char16_t * ); 84 83 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous 85 //ostype & ?|?( ostype &, const char32_t * );84 //forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, const char32_t * ); 86 85 #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) 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 86 //forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, const wchar_t * ); 87 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, const void * ); 100 88 101 89 // tuples 102 90 forall( dtype ostype, otype T, ttype Params | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) 103 91 ostype & ?|?( ostype & os, T arg, Params rest ); 92 93 // manipulators 94 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 & ); 104 102 105 103 // writes the range [begin, end) to the given stream … … 126 124 }; // readable 127 125 128 forall( dtype istype | istream( istype ) ) { 129 istype & ?|?( istype &, _Bool & ); 126 forall( dtype istype | istream( istype ) ) istype & ?|?( istype &, _Bool & ); 130 127 131 istype & ?|?( istype &, char & );132 istype & ?|?( istype &, signed char & );133 istype & ?|?( istype &, unsigned char & );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 & ); 134 131 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 & );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 & ); 143 140 144 istype & ?|?( istype &, float & );145 istype & ?|?( istype &, double & );146 istype & ?|?( istype &, long double & );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 & ); 147 144 148 istype & ?|?( istype &, float _Complex & );149 istype & ?|?( istype &, double _Complex & );150 istype & ?|?( istype &, long double _Complex & );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 & ); 151 148 152 // manipulators 153 istype & ?|?( istype &, istype & (*)( istype & ) ); 154 istype & endl( istype & is ); 155 } // distribution 149 // manipulators 150 forall( dtype istype | istream( istype ) ) istype & ?|?( istype &, istype & (*)( istype & ) ); 151 forall( dtype istype | istream( istype ) ) istype & endl( istype & is ); 156 152 157 153 struct _Istream_cstrUC { char * s; }; -
src/libcfa/iostream.c
rb21c77a r97397a26 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jun 2 08:24:56201813 // Update Count : 4 7112 // Last Modified On : Sat Apr 28 13:08:25 2018 13 // Update Count : 469 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 ostype & ?|?( ostype & os, char ch ) { 36 fmt( os, "%c", ch ); 37 if ( ch == '\n' ) setNL( os, true ); 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 ) { 187 sepOn( os ); 188 } else { 38 189 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 // } // ?|? 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 // } // ?|? 182 201 183 202 // #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 // } // ?|? 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 // } // ?|? 189 209 // #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) 190 210 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 ) { 228 sepOn( os ); 229 return os; 230 } // sepOn 231 232 ostype & sepOff( ostype & os ) { 233 sepOff( os ); 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 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 } // ?|? 247 224 248 225 … … 257 234 } // ?|? 258 235 236 237 // manipulators 238 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 } // sep 248 249 forall( dtype ostype | ostream( ostype ) ) 250 ostype & sepTuple( ostype & os ) { 251 os | sepGetTuple( os ); 252 return os; 253 } // sepTuple 254 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 line 261 return os; 262 } // endl 263 264 forall( dtype ostype | ostream( ostype ) ) 265 ostype & sepOn( ostype & os ) { 266 sepOn( os ); 267 return os; 268 } // sepOn 269 270 forall( dtype ostype | ostream( ostype ) ) 271 ostype & sepOff( ostype & os ) { 272 sepOff( os ); 273 return os; 274 } // sepOff 275 276 forall( dtype ostype | ostream( ostype ) ) 277 ostype & sepEnable( ostype & os ) { 278 sepEnable( os ); 279 return os; 280 } // sepEnable 281 282 forall( dtype ostype | ostream( ostype ) ) 283 ostype & sepDisable( ostype & os ) { 284 sepDisable( os ); 285 return os; 286 } // sepDisable 287 259 288 //--------------------------------------- 260 289 261 // writes the range [begin, end) to the given stream262 290 forall( dtype ostype, otype elt_type | writeable( elt_type, ostype ), otype iterator_type | iterator( iterator_type, elt_type ) ) 263 291 void write( iterator_type begin, iterator_type end, ostype & os ) { … … 274 302 //--------------------------------------- 275 303 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 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 393 437 394 438 _Istream_cstrUC cstr( char * str ) { return (_Istream_cstrUC){ str }; } -
src/libcfa/rational
rb21c77a r97397a26 12 12 // Created On : Wed Apr 6 17:56:25 2016 13 13 // Last Modified By : Peter A. Buhr 14 // Last Modified On : Sat Jun 2 09:10:01 201815 // Update Count : 10514 // Last Modified On : Wed Dec 6 23:12:53 2017 15 // Update Count : 97 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 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 ); 55 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 56 void ?{}( Rational(RationalImpl) & r ); 60 57 61 // numerator/denominator getter 58 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 59 void ?{}( Rational(RationalImpl) & r, RationalImpl n ); 62 60 63 RationalImpl numerator( Rational(RationalImpl) r ); 64 RationalImpl denominator( Rational(RationalImpl) r ); 65 [ RationalImpl, RationalImpl ] ?=?( & [ RationalImpl, RationalImpl ] dest, Rational(RationalImpl) src ); 61 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 62 void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ); 66 63 67 // numerator/denominator setter 64 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 65 void ?{}( Rational(RationalImpl) & r, zero_t ); 68 66 69 RationalImpl numerator( Rational(RationalImpl) r, RationalImpl n ); 70 RationalImpl denominator( Rational(RationalImpl) r, RationalImpl d);67 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 68 void ?{}( Rational(RationalImpl) & r, one_t ); 71 69 72 // comparison 70 // numerator/denominator getter 73 71 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 ); 72 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 73 RationalImpl numerator( Rational(RationalImpl) r ); 80 74 81 // arithmetic 75 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 76 RationalImpl denominator( Rational(RationalImpl) r ); 82 77 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 ); 78 forall( otype RationalImpl | arithmetic( RationalImpl ) ) 79 [ RationalImpl, RationalImpl ] ?=?( & [ RationalImpl, RationalImpl ] dest, Rational(RationalImpl) src ); 89 80 90 // I/O 91 forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } ) 92 istype & ?|?( istype &, Rational(RationalImpl) & ); 81 // numerator/denominator setter 93 82 94 forall( dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, RationalImpl ); } ) 95 ostype & ?|?( ostype &, Rational(RationalImpl ) ); 96 } // distribution 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 ); 97 128 98 129 // conversion … … 102 133 Rational(RationalImpl) narrow( double f, RationalImpl md ); 103 134 135 // I/O 136 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 104 144 // Local Variables: // 105 145 // mode: c // -
src/libcfa/rational.c
rb21c77a r97397a26 10 10 // Created On : Wed Apr 6 17:54:28 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jun 2 09:24:33 201813 // Update Count : 1 6212 // Last Modified On : Wed Dec 6 23:13:58 2017 13 // Update Count : 156 14 14 // 15 15 … … 18 18 #include "stdlib" 19 19 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 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 182 189 183 190 // conversion … … 188 195 } // widen 189 196 197 // http://www.ics.uci.edu/~eppstein/numth/frap.c 190 198 forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); RationalImpl convert( double ); } ) 191 199 Rational(RationalImpl) narrow( double f, RationalImpl md ) { 192 // http://www.ics.uci.edu/~eppstein/numth/frap.c193 200 if ( md <= (RationalImpl){1} ) { // maximum fractional digits too small? 194 201 return (Rational(RationalImpl)){ convert( f ), (RationalImpl){1}}; // truncate fraction … … 217 224 } // narrow 218 225 226 227 // I/O 228 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 219 246 // Local Variables: // 220 247 // tab-width: 4 // -
src/libcfa/stdhdr/assert.h
rb21c77a r97397a26 33 33 #define verify(x) assert(x) 34 34 #define verifyf(x, ...) assertf(x, __VA_ARGS__) 35 #define __CFA_WITH_VERIFY__36 35 #else 37 36 #define verify(x) -
src/libcfa/stdlib
rb21c77a r97397a26 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jun 2 08:46:35201813 // Update Count : 30 612 // Last Modified On : Wed May 16 07:53:10 2018 13 // Update Count : 300 14 14 // 15 15 16 16 #pragma once 17 17 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" 18 #include <stdlib.h> // strto*, *abs 24 19 25 20 //--------------------------------------- … … 32 27 //--------------------------------------- 33 28 29 // C dynamic allocation 34 30 static inline forall( dtype T | sized(T) ) { 35 // C dynamic allocation36 37 31 T * malloc( void ) { 38 32 // printf( "* malloc\n" ); … … 57 51 } // realloc 58 52 53 extern "C" { void * memalign( size_t align, size_t size ); } // use default C routine for void * 59 54 T * memalign( size_t align ) { 60 55 //printf( "X4\n" ); … … 62 57 } // memalign 63 58 59 extern "C" { void * aligned_alloc( size_t align, size_t size ); } // use default C routine for void * 64 60 T * aligned_alloc( size_t align ) { 65 61 //printf( "X5\n" ); … … 74 70 75 71 // Cforall dynamic allocation 72 extern "C" { void * memset( void * dest, int c, size_t size ); } // use default C routine for void * 76 73 77 74 T * alloc( void ) { … … 106 103 forall( dtype T | sized(T) ) T * alloc( T ptr[], size_t dim, char fill ); 107 104 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 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 163 146 164 147 // allocation/deallocation and constructor/destructor, non-array types … … 206 189 //--------------------------------------- 207 190 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 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 ); 227 232 228 233 //--------------------------------------- -
src/libcfa/stdlib.c
rb21c77a r97397a26 10 10 // Created On : Thu Jan 28 17:10:29 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jun 2 06:15:05201813 // Update Count : 44 812 // Last Modified On : Wed Jan 3 08:29:29 2018 13 // Update Count : 444 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 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 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 240 250 241 251 //--------------------------------------- -
src/main.cc
rb21c77a r97397a26 11 11 // Created On : Fri May 15 23:12:02 2015 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Wed Jun 6 15:51:47 201814 // Update Count : 49 813 // Last Modified On : Mon May 7 14:35:57 2018 14 // Update Count : 492 15 15 // 16 16 … … 160 160 << "." << endl; 161 161 backtrace( 2 ); // skip first 2 stack frames 162 //_exit( EXIT_FAILURE ); 163 abort(); 162 exit( EXIT_FAILURE ); 164 163 } // sigSegvBusHandler 165 164 … … 262 261 } // if 263 262 264 PASS( " fixLabels", ControlStruct::fixLabels( translationUnit ) );263 PASS( "mutate", ControlStruct::mutate( translationUnit ) ); 265 264 PASS( "fixNames", CodeGen::fixNames( translationUnit ) ); 266 265 PASS( "genInit", InitTweak::genInit( translationUnit ) ); … … 572 571 yyin = input; 573 572 yylineno = 1; 573 typedefTable.enterScope(); 574 574 int parseStatus = yyparse(); 575 575 -
src/prelude/Makefile.am
rb21c77a r97397a26 37 37 # create forward declarations for gcc builtins 38 38 gcc-builtins.cf : gcc-builtins.c prototypes.sed 39 ${AM_V_GEN}@BACKEND_CC@ @CFA_FLAGS@-E -P $< | sed -r -f prototypes.sed > $@39 ${AM_V_GEN}@BACKEND_CC@ -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@ @CFA_FLAGS@-E prototypes.c | awk -f prototypes.awk > $@42 ${AM_V_GEN}@BACKEND_CC@ -E prototypes.c | awk -f prototypes.awk > $@ 43 43 44 44 builtins.def : -
src/prelude/Makefile.in
rb21c77a r97397a26 506 506 # create forward declarations for gcc builtins 507 507 gcc-builtins.cf : gcc-builtins.c prototypes.sed 508 ${AM_V_GEN}@BACKEND_CC@ @CFA_FLAGS@-E -P $< | sed -r -f prototypes.sed > $@508 ${AM_V_GEN}@BACKEND_CC@ -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@ @CFA_FLAGS@-E prototypes.c | awk -f prototypes.awk > $@511 ${AM_V_GEN}@BACKEND_CC@ -E prototypes.c | awk -f prototypes.awk > $@ 512 512 513 513 builtins.def : -
src/prelude/extras.regx
rb21c77a r97397a26 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;11 3 typedef.* int8_t; 12 4 typedef.* int16_t; -
src/prelude/prelude.cf
rb21c77a r97397a26 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 ); 460 461 zero_t ?=?( zero_t &, zero_t ); 461 462 one_t ?=?( one_t &, one_t ); -
src/prelude/sync-builtins.cf
rb21c77a r97397a26 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__)10 9 __int128 __sync_fetch_and_add(volatile __int128 *, __int128,...); 11 10 __int128 __sync_fetch_and_add_16(volatile __int128 *, __int128,...); 12 #endif13 11 14 12 char __sync_fetch_and_sub(volatile char *, char,...); … … 20 18 long long int __sync_fetch_and_sub(volatile long long int *, long long int,...); 21 19 long long int __sync_fetch_and_sub_8(volatile long long int *, long long int,...); 22 #if defined(__SIZEOF_INT128__)23 20 __int128 __sync_fetch_and_sub(volatile __int128 *, __int128,...); 24 21 __int128 __sync_fetch_and_sub_16(volatile __int128 *, __int128,...); 25 #endif26 22 27 23 char __sync_fetch_and_or(volatile char *, char,...); … … 33 29 long long int __sync_fetch_and_or(volatile long long int *, long long int,...); 34 30 long long int __sync_fetch_and_or_8(volatile long long int *, long long int,...); 35 #if defined(__SIZEOF_INT128__)36 31 __int128 __sync_fetch_and_or(volatile __int128 *, __int128,...); 37 32 __int128 __sync_fetch_and_or_16(volatile __int128 *, __int128,...); 38 #endif39 33 40 34 char __sync_fetch_and_and(volatile char *, char,...); … … 46 40 long long int __sync_fetch_and_and(volatile long long int *, long long int,...); 47 41 long long int __sync_fetch_and_and_8(volatile long long int *, long long int,...); 48 #if defined(__SIZEOF_INT128__)49 42 __int128 __sync_fetch_and_and(volatile __int128 *, __int128,...); 50 43 __int128 __sync_fetch_and_and_16(volatile __int128 *, __int128,...); 51 #endif52 44 53 45 char __sync_fetch_and_xor(volatile char *, char,...); … … 59 51 long long int __sync_fetch_and_xor(volatile long long int *, long long int,...); 60 52 long long int __sync_fetch_and_xor_8(volatile long long int *, long long int,...); 61 #if defined(__SIZEOF_INT128__)62 53 __int128 __sync_fetch_and_xor(volatile __int128 *, __int128,...); 63 54 __int128 __sync_fetch_and_xor_16(volatile __int128 *, __int128,...); 64 #endif65 55 66 56 char __sync_fetch_and_nand(volatile char *, char,...); … … 72 62 long long int __sync_fetch_and_nand(volatile long long int *, long long int,...); 73 63 long long int __sync_fetch_and_nand_8(volatile long long int *, long long int,...); 74 #if defined(__SIZEOF_INT128__)75 64 __int128 __sync_fetch_and_nand(volatile __int128 *, __int128,...); 76 65 __int128 __sync_fetch_and_nand_16(volatile __int128 *, __int128,...); 77 #endif78 66 79 67 char __sync_add_and_fetch(volatile char *, char,...); … … 85 73 long long int __sync_add_and_fetch(volatile long long int *, long long int,...); 86 74 long long int __sync_add_and_fetch_8(volatile long long int *, long long int,...); 87 #if defined(__SIZEOF_INT128__)88 75 __int128 __sync_add_and_fetch(volatile __int128 *, __int128,...); 89 76 __int128 __sync_add_and_fetch_16(volatile __int128 *, __int128,...); 90 #endif91 77 92 78 char __sync_sub_and_fetch(volatile char *, char,...); … … 98 84 long long int __sync_sub_and_fetch(volatile long long int *, long long int,...); 99 85 long long int __sync_sub_and_fetch_8(volatile long long int *, long long int,...); 100 #if defined(__SIZEOF_INT128__)101 86 __int128 __sync_sub_and_fetch(volatile __int128 *, __int128,...); 102 87 __int128 __sync_sub_and_fetch_16(volatile __int128 *, __int128,...); 103 #endif104 88 105 89 char __sync_or_and_fetch(volatile char *, char,...); … … 111 95 long long int __sync_or_and_fetch(volatile long long int *, long long int,...); 112 96 long long int __sync_or_and_fetch_8(volatile long long int *, long long int,...); 113 #if defined(__SIZEOF_INT128__)114 97 __int128 __sync_or_and_fetch(volatile __int128 *, __int128,...); 115 98 __int128 __sync_or_and_fetch_16(volatile __int128 *, __int128,...); 116 #endif117 99 118 100 char __sync_and_and_fetch(volatile char *, char,...); … … 124 106 long long int __sync_and_and_fetch(volatile long long int *, long long int,...); 125 107 long long int __sync_and_and_fetch_8(volatile long long int *, long long int,...); 126 #if defined(__SIZEOF_INT128__)127 108 __int128 __sync_and_and_fetch(volatile __int128 *, __int128,...); 128 109 __int128 __sync_and_and_fetch_16(volatile __int128 *, __int128,...); 129 #endif130 110 131 111 char __sync_xor_and_fetch(volatile char *, char,...); … … 137 117 long long int __sync_xor_and_fetch(volatile long long int *, long long int,...); 138 118 long long int __sync_xor_and_fetch_8(volatile long long int *, long long int,...); 139 #if defined(__SIZEOF_INT128__)140 119 __int128 __sync_xor_and_fetch(volatile __int128 *, __int128,...); 141 120 __int128 __sync_xor_and_fetch_16(volatile __int128 *, __int128,...); 142 #endif143 121 144 122 char __sync_nand_and_fetch(volatile char *, char,...); … … 150 128 long long int __sync_nand_and_fetch(volatile long long int *, long long int,...); 151 129 long long int __sync_nand_and_fetch_8(volatile long long int *, long long int,...); 152 #if defined(__SIZEOF_INT128__)153 130 __int128 __sync_nand_and_fetch(volatile __int128 *, __int128,...); 154 131 __int128 __sync_nand_and_fetch_16(volatile __int128 *, __int128,...); 155 #endif156 132 157 133 _Bool __sync_bool_compare_and_swap(volatile char *, char, char,...); … … 163 139 _Bool __sync_bool_compare_and_swap(volatile long long int *, long long int, long long int,...); 164 140 _Bool __sync_bool_compare_and_swap_8(volatile long long int *, long long int, long long int,...); 165 #if defined(__SIZEOF_INT128__)166 141 _Bool __sync_bool_compare_and_swap(volatile __int128 *, __int128, __int128,...); 167 142 _Bool __sync_bool_compare_and_swap_16(volatile __int128 *, __int128, __int128,...); 168 #endif169 143 170 144 char __sync_val_compare_and_swap(volatile char *, char, char,...); … … 176 150 long long int __sync_val_compare_and_swap(volatile long long int *, long long int, long long int,...); 177 151 long long int __sync_val_compare_and_swap_8(volatile long long int *, long long int, long long int,...); 178 #if defined(__SIZEOF_INT128__)179 152 __int128 __sync_val_compare_and_swap(volatile __int128 *, __int128, __int128,...); 180 153 __int128 __sync_val_compare_and_swap_16(volatile __int128 *, __int128, __int128,...); 181 #endif182 154 183 155 char __sync_lock_test_and_set(volatile char *, char,...); … … 189 161 long long int __sync_lock_test_and_set(volatile long long int *, long long int,...); 190 162 long long int __sync_lock_test_and_set_8(volatile long long int *, long long int,...); 191 #if defined(__SIZEOF_INT128__)192 163 __int128 __sync_lock_test_and_set(volatile __int128 *, __int128,...); 193 164 __int128 __sync_lock_test_and_set_16(volatile __int128 *, __int128,...); 194 #endif195 165 196 166 void __sync_lock_release(volatile char *,...); … … 202 172 void __sync_lock_release(volatile long long int *,...); 203 173 void __sync_lock_release_8(volatile long long int *,...); 204 #if defined(__SIZEOF_INT128__)205 174 void __sync_lock_release(volatile __int128 *,...); 206 175 void __sync_lock_release_16(volatile __int128 *,...); 207 #endif208 176 209 177 void __sync_synchronize(); … … 217 185 _Bool __atomic_test_and_set(volatile int *, int); 218 186 _Bool __atomic_test_and_set(volatile long long int *, int); 219 #if defined(__SIZEOF_INT128__)220 187 _Bool __atomic_test_and_set(volatile __int128 *, int); 221 #endif222 223 188 void __atomic_clear(volatile _Bool *, int); 224 189 void __atomic_clear(volatile char *, int); … … 226 191 void __atomic_clear(volatile int *, int); 227 192 void __atomic_clear(volatile long long int *, int); 228 #if defined(__SIZEOF_INT128__)229 193 void __atomic_clear(volatile __int128 *, int); 230 #endif231 194 232 195 char __atomic_exchange_n(volatile char *, volatile char *, int); … … 242 205 long long int __atomic_exchange_8(volatile long long int *, long long int, int); 243 206 void __atomic_exchange(volatile long long int *, volatile long long int *, volatile long long int *, int); 244 #if defined(__SIZEOF_INT128__)245 207 __int128 __atomic_exchange_n(volatile __int128 *, volatile __int128 *, int); 246 208 __int128 __atomic_exchange_16(volatile __int128 *, __int128, int); 247 209 void __atomic_exchange(volatile __int128 *, volatile __int128 *, volatile __int128 *, int); 248 #endif 249 250 _Bool __atomic_load_n(const volatile _Bool *, int); 251 void __atomic_load(const volatile _Bool *, volatile _Bool *, int); 210 252 211 char __atomic_load_n(const volatile char *, int); 253 212 char __atomic_load_1(const volatile char *, int); … … 262 221 long long int __atomic_load_8(const volatile long long int *, int); 263 222 void __atomic_load(const volatile long long int *, volatile long long int *, int); 264 #if defined(__SIZEOF_INT128__)265 223 __int128 __atomic_load_n(const volatile __int128 *, int); 266 224 __int128 __atomic_load_16(const volatile __int128 *, int); 267 225 void __atomic_load(const volatile __int128 *, volatile __int128 *, int); 268 #endif269 226 270 227 _Bool __atomic_compare_exchange_n(volatile char *, char *, char, _Bool, int, int); … … 280 237 _Bool __atomic_compare_exchange_8(volatile long long int *, long long int *, long long int, _Bool, int, int); 281 238 _Bool __atomic_compare_exchange (volatile long long int *, long long int *, long long int *, _Bool, int, int); 282 #if defined(__SIZEOF_INT128__)283 239 _Bool __atomic_compare_exchange_n (volatile __int128 *, __int128 *, __int128, _Bool, int, int); 284 240 _Bool __atomic_compare_exchange_16(volatile __int128 *, __int128 *, __int128, _Bool, int, int); 285 241 _Bool __atomic_compare_exchange (volatile __int128 *, __int128 *, __int128 *, _Bool, int, int); 286 #endif287 242 288 243 void __atomic_store_n(volatile _Bool *, _Bool, int); 244 void __atomic_store_1(volatile _Bool *, _Bool, int); 289 245 void __atomic_store(volatile _Bool *, _Bool *, int); 290 246 void __atomic_store_n(volatile char *, char, int); … … 300 256 void __atomic_store_8(volatile long long int *, long long int, int); 301 257 void __atomic_store(volatile long long int *, long long int *, int); 302 #if defined(__SIZEOF_INT128__)303 258 void __atomic_store_n(volatile __int128 *, __int128, int); 304 259 void __atomic_store_16(volatile __int128 *, __int128, int); 305 260 void __atomic_store(volatile __int128 *, __int128 *, int); 306 #endif307 261 308 262 char __atomic_add_fetch (volatile char *, char, int); … … 314 268 long long int __atomic_add_fetch (volatile long long int *, long long int, int); 315 269 long long int __atomic_add_fetch_8(volatile long long int *, long long int, int); 316 #if defined(__SIZEOF_INT128__)317 270 __int128 __atomic_add_fetch (volatile __int128 *, __int128, int); 318 271 __int128 __atomic_add_fetch_16(volatile __int128 *, __int128, int); 319 #endif320 272 321 273 char __atomic_sub_fetch (volatile char *, char, int); … … 327 279 long long int __atomic_sub_fetch (volatile long long int *, long long int, int); 328 280 long long int __atomic_sub_fetch_8(volatile long long int *, long long int, int); 329 #if defined(__SIZEOF_INT128__)330 281 __int128 __atomic_sub_fetch (volatile __int128 *, __int128, int); 331 282 __int128 __atomic_sub_fetch_16(volatile __int128 *, __int128, int); 332 #endif333 283 334 284 char __atomic_and_fetch (volatile char *, char, int); … … 340 290 long long int __atomic_and_fetch (volatile long long int *, long long int, int); 341 291 long long int __atomic_and_fetch_8(volatile long long int *, long long int, int); 342 #if defined(__SIZEOF_INT128__)343 292 __int128 __atomic_and_fetch (volatile __int128 *, __int128, int); 344 293 __int128 __atomic_and_fetch_16(volatile __int128 *, __int128, int); 345 #endif346 294 347 295 char __atomic_nand_fetch (volatile char *, char, int); … … 353 301 long long int __atomic_nand_fetch (volatile long long int *, long long int, int); 354 302 long long int __atomic_nand_fetch_8(volatile long long int *, long long int, int); 355 #if defined(__SIZEOF_INT128__)356 303 __int128 __atomic_nand_fetch (volatile __int128 *, __int128, int); 357 304 __int128 __atomic_nand_fetch_16(volatile __int128 *, __int128, int); 358 #endif359 305 360 306 char __atomic_xor_fetch (volatile char *, char, int); … … 366 312 long long int __atomic_xor_fetch (volatile long long int *, long long int, int); 367 313 long long int __atomic_xor_fetch_8(volatile long long int *, long long int, int); 368 #if defined(__SIZEOF_INT128__)369 314 __int128 __atomic_xor_fetch (volatile __int128 *, __int128, int); 370 315 __int128 __atomic_xor_fetch_16(volatile __int128 *, __int128, int); 371 #endif372 316 373 317 char __atomic_or_fetch (volatile char *, char, int); … … 379 323 long long int __atomic_or_fetch (volatile long long int *, long long int, int); 380 324 long long int __atomic_or_fetch_8(volatile long long int *, long long int, int); 381 #if defined(__SIZEOF_INT128__)382 325 __int128 __atomic_or_fetch (volatile __int128 *, __int128, int); 383 326 __int128 __atomic_or_fetch_16(volatile __int128 *, __int128, int); 384 #endif385 327 386 328 char __atomic_fetch_add (volatile char *, char, int); … … 392 334 long long int __atomic_fetch_add (volatile long long int *, long long int, int); 393 335 long long int __atomic_fetch_add_8(volatile long long int *, long long int, int); 394 #if defined(__SIZEOF_INT128__)395 336 __int128 __atomic_fetch_add (volatile __int128 *, __int128, int); 396 337 __int128 __atomic_fetch_add_16(volatile __int128 *, __int128, int); 397 #endif398 338 399 339 char __atomic_fetch_sub (volatile char *, char, int); … … 405 345 long long int __atomic_fetch_sub (volatile long long int *, long long int, int); 406 346 long long int __atomic_fetch_sub_8(volatile long long int *, long long int, int); 407 #if defined(__SIZEOF_INT128__)408 347 __int128 __atomic_fetch_sub (volatile __int128 *, __int128, int); 409 348 __int128 __atomic_fetch_sub_16(volatile __int128 *, __int128, int); 410 #endif411 349 412 350 char __atomic_fetch_and (volatile char *, char, int); … … 418 356 long long int __atomic_fetch_and (volatile long long int *, long long int, int); 419 357 long long int __atomic_fetch_and_8(volatile long long int *, long long int, int); 420 #if defined(__SIZEOF_INT128__)421 358 __int128 __atomic_fetch_and (volatile __int128 *, __int128, int); 422 359 __int128 __atomic_fetch_and_16(volatile __int128 *, __int128, int); 423 #endif424 360 425 361 char __atomic_fetch_nand (volatile char *, char, int); … … 431 367 long long int __atomic_fetch_nand (volatile long long int *, long long int, int); 432 368 long long int __atomic_fetch_nand_8(volatile long long int *, long long int, int); 433 #if defined(__SIZEOF_INT128__)434 369 __int128 __atomic_fetch_nand (volatile __int128 *, __int128, int); 435 370 __int128 __atomic_fetch_nand_16(volatile __int128 *, __int128, int); 436 #endif437 371 438 372 char __atomic_fetch_xor (volatile char *, char, int); … … 444 378 long long int __atomic_fetch_xor (volatile long long int *, long long int, int); 445 379 long long int __atomic_fetch_xor_8(volatile long long int *, long long int, int); 446 #if defined(__SIZEOF_INT128__)447 380 __int128 __atomic_fetch_xor (volatile __int128 *, __int128, int); 448 381 __int128 __atomic_fetch_xor_16(volatile __int128 *, __int128, int); 449 #endif450 382 451 383 char __atomic_fetch_or (volatile char *, char, int); … … 457 389 long long int __atomic_fetch_or (volatile long long int *, long long int, int); 458 390 long long int __atomic_fetch_or_8(volatile long long int *, long long int, int); 459 #if defined(__SIZEOF_INT128__)460 391 __int128 __atomic_fetch_or (volatile __int128 *, __int128, int); 461 392 __int128 __atomic_fetch_or_16(volatile __int128 *, __int128, int); 462 #endif463 393 464 394 _Bool __atomic_always_lock_free(unsigned long, const volatile void *); -
src/tests/.gitignore
rb21c77a r97397a26 1 1 .out/ 2 2 .err/ 3 .type -
src/tests/Makefile.am
rb21c77a r97397a26 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Wed Jun 6 16:42:20 201814 ## Update Count : 4 913 ## Last Modified On : Mon Nov 27 21:34:33 2017 14 ## Update Count : 48 15 15 ############################################################################### 16 16 … … 28 28 DEBUG_FLAGS = 29 29 30 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -I.30 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ 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 94 97 sched-ext-parse : sched-ext-parse.c @CFA_BINDIR@/@CFA_NAME@ 95 98 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} -
src/tests/Makefile.in
rb21c77a r97397a26 309 309 # applies to both programs 310 310 DEBUG_FLAGS = 311 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -I.\311 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ \ 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 771 774 sched-ext-parse : sched-ext-parse.c @CFA_BINDIR@/@CFA_NAME@ 772 775 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} -
src/tests/builtins/sync.c
rb21c77a r97397a26 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__)11 10 volatile __int128 * vp16 = 0; __int128 * rp16 = 0; __int128 v16 = 0; 12 #endif13 11 14 12 { char ret; ret = __sync_fetch_and_add(vp1, v1); } … … 20 18 { long long int ret; ret = __sync_fetch_and_add(vp8, v8); } 21 19 { long long int ret; ret = __sync_fetch_and_add_8(vp8, v8); } 22 #if defined(__SIZEOF_INT128__)23 20 { __int128 ret; ret = __sync_fetch_and_add(vp16, v16); } 24 21 { __int128 ret; ret = __sync_fetch_and_add_16(vp16, v16); } 25 #endif26 22 27 23 { char ret; ret = __sync_fetch_and_sub(vp1, v1); } … … 33 29 { long long int ret; ret = __sync_fetch_and_sub(vp8, v8); } 34 30 { long long int ret; ret = __sync_fetch_and_sub_8(vp8, v8); } 35 #if defined(__SIZEOF_INT128__)36 31 { __int128 ret; ret = __sync_fetch_and_sub(vp16, v16); } 37 32 { __int128 ret; ret = __sync_fetch_and_sub_16(vp16, v16); } 38 #endif39 33 40 34 { char ret; ret = __sync_fetch_and_or(vp1, v1); } … … 46 40 { long long int ret; ret = __sync_fetch_and_or(vp8, v8); } 47 41 { long long int ret; ret = __sync_fetch_and_or_8(vp8, v8); } 48 #if defined(__SIZEOF_INT128__)49 42 { __int128 ret; ret = __sync_fetch_and_or(vp16, v16); } 50 43 { __int128 ret; ret = __sync_fetch_and_or_16(vp16, v16); } 51 #endif52 44 53 45 { char ret; ret = __sync_fetch_and_and(vp1, v1); } … … 59 51 { long long int ret; ret = __sync_fetch_and_and(vp8, v8); } 60 52 { long long int ret; ret = __sync_fetch_and_and_8(vp8, v8); } 61 #if defined(__SIZEOF_INT128__)62 53 { __int128 ret; ret = __sync_fetch_and_and(vp16, v16); } 63 54 { __int128 ret; ret = __sync_fetch_and_and_16(vp16, v16); } 64 #endif65 55 66 56 { char ret; ret = __sync_fetch_and_xor(vp1, v1); } … … 72 62 { long long int ret; ret = __sync_fetch_and_xor(vp8, v8); } 73 63 { long long int ret; ret = __sync_fetch_and_xor_8(vp8, v8); } 74 #if defined(__SIZEOF_INT128__)75 64 { __int128 ret; ret = __sync_fetch_and_xor(vp16, v16); } 76 65 { __int128 ret; ret = __sync_fetch_and_xor_16(vp16, v16); } 77 #endif78 66 79 67 { char ret; ret = __sync_fetch_and_nand(vp1, v1); } … … 85 73 { long long int ret; ret = __sync_fetch_and_nand(vp8, v8); } 86 74 { long long int ret; ret = __sync_fetch_and_nand_8(vp8, v8); } 87 #if defined(__SIZEOF_INT128__)88 75 { __int128 ret; ret = __sync_fetch_and_nand(vp16, v16); } 89 76 { __int128 ret; ret = __sync_fetch_and_nand_16(vp16, v16); } 90 #endif91 77 92 78 { char ret; ret = __sync_add_and_fetch(vp1, v1); } … … 98 84 { long long int ret; ret = __sync_add_and_fetch(vp8, v8); } 99 85 { long long int ret; ret = __sync_add_and_fetch_8(vp8, v8); } 100 #if defined(__SIZEOF_INT128__)101 86 { __int128 ret; ret = __sync_add_and_fetch(vp16, v16); } 102 87 { __int128 ret; ret = __sync_add_and_fetch_16(vp16, v16); } 103 #endif104 88 105 89 { char ret; ret = __sync_sub_and_fetch(vp1, v1); } … … 111 95 { long long int ret; ret = __sync_sub_and_fetch(vp8, v8); } 112 96 { long long int ret; ret = __sync_sub_and_fetch_8(vp8, v8); } 113 #if defined(__SIZEOF_INT128__)114 97 { __int128 ret; ret = __sync_sub_and_fetch(vp16, v16); } 115 98 { __int128 ret; ret = __sync_sub_and_fetch_16(vp16, v16); } 116 #endif117 99 118 100 { char ret; ret = __sync_or_and_fetch(vp1, v1); } … … 124 106 { long long int ret; ret = __sync_or_and_fetch(vp8, v8); } 125 107 { long long int ret; ret = __sync_or_and_fetch_8(vp8, v8); } 126 #if defined(__SIZEOF_INT128__)127 108 { __int128 ret; ret = __sync_or_and_fetch(vp16, v16); } 128 109 { __int128 ret; ret = __sync_or_and_fetch_16(vp16, v16); } 129 #endif130 110 131 111 { char ret; ret = __sync_and_and_fetch(vp1, v1); } … … 137 117 { long long int ret; ret = __sync_and_and_fetch(vp8, v8); } 138 118 { long long int ret; ret = __sync_and_and_fetch_8(vp8, v8); } 139 #if defined(__SIZEOF_INT128__)140 119 { __int128 ret; ret = __sync_and_and_fetch(vp16, v16); } 141 120 { __int128 ret; ret = __sync_and_and_fetch_16(vp16, v16); } 142 #endif143 121 144 122 { char ret; ret = __sync_xor_and_fetch(vp1, v1); } … … 150 128 { long long int ret; ret = __sync_xor_and_fetch(vp8, v8); } 151 129 { long long int ret; ret = __sync_xor_and_fetch_8(vp8, v8); } 152 #if defined(__SIZEOF_INT128__)153 130 { __int128 ret; ret = __sync_xor_and_fetch(vp16, v16); } 154 131 { __int128 ret; ret = __sync_xor_and_fetch_16(vp16, v16); } 155 #endif156 132 157 133 { char ret; ret = __sync_nand_and_fetch(vp1, v1); } … … 163 139 { long long int ret; ret = __sync_nand_and_fetch(vp8, v8); } 164 140 { long long int ret; ret = __sync_nand_and_fetch_8(vp8, v8); } 165 #if defined(__SIZEOF_INT128__)166 141 { __int128 ret; ret = __sync_nand_and_fetch(vp16, v16); } 167 142 { __int128 ret; ret = __sync_nand_and_fetch_16(vp16, v16); } 168 #endif169 143 170 144 { _Bool ret; ret = __sync_bool_compare_and_swap(vp1, v1, v1); } … … 176 150 { _Bool ret; ret = __sync_bool_compare_and_swap(vp8, v8, v8); } 177 151 { _Bool ret; ret = __sync_bool_compare_and_swap_8(vp8, v8, v8); } 178 #if defined(__SIZEOF_INT128__)179 152 { _Bool ret; ret = __sync_bool_compare_and_swap(vp16, v16, v16); } 180 153 { _Bool ret; ret = __sync_bool_compare_and_swap_16(vp16, v16,v16); } 181 #endif182 154 183 155 { char ret; ret = __sync_val_compare_and_swap(vp1, v1, v1); } … … 189 161 { long long int ret; ret = __sync_val_compare_and_swap(vp8, v8, v8); } 190 162 { long long int ret; ret = __sync_val_compare_and_swap_8(vp8, v8, v8); } 191 #if defined(__SIZEOF_INT128__)192 163 { __int128 ret; ret = __sync_val_compare_and_swap(vp16, v16, v16); } 193 164 { __int128 ret; ret = __sync_val_compare_and_swap_16(vp16, v16,v16); } 194 #endif195 165 196 166 { char ret; ret = __sync_lock_test_and_set(vp1, v1); } … … 202 172 { long long int ret; ret = __sync_lock_test_and_set(vp8, v8); } 203 173 { long long int ret; ret = __sync_lock_test_and_set_8(vp8, v8); } 204 #if defined(__SIZEOF_INT128__)205 174 { __int128 ret; ret = __sync_lock_test_and_set(vp16, v16); } 206 175 { __int128 ret; ret = __sync_lock_test_and_set_16(vp16, v16); } 207 #endif208 176 209 177 { __sync_lock_release(vp1); } … … 215 183 { __sync_lock_release(vp8); } 216 184 { __sync_lock_release_8(vp8); } 217 #if defined(__SIZEOF_INT128__)218 185 { __sync_lock_release(vp16); } 219 186 { __sync_lock_release_16(vp16); } 220 #endif221 187 222 188 { __sync_synchronize(); } … … 242 208 { long long int ret; ret = __atomic_exchange_8(vp8, v8, __ATOMIC_SEQ_CST); } 243 209 { long long int ret; __atomic_exchange(vp8, &v8, &ret, __ATOMIC_SEQ_CST); } 244 #if defined(__SIZEOF_INT128__)245 210 { __int128 ret; ret = __atomic_exchange_n(vp16, &v16, __ATOMIC_SEQ_CST); } 246 211 { __int128 ret; ret = __atomic_exchange_16(vp16, v16, __ATOMIC_SEQ_CST); } 247 212 { __int128 ret; __atomic_exchange(vp16, &v16, &ret, __ATOMIC_SEQ_CST); } 248 #endif249 213 250 214 { char ret; ret = __atomic_load_n(vp1, __ATOMIC_SEQ_CST); } … … 260 224 { long long int ret; ret = __atomic_load_8(vp8, __ATOMIC_SEQ_CST); } 261 225 { long long int ret; __atomic_load(vp8, &ret, __ATOMIC_SEQ_CST); } 262 #if defined(__SIZEOF_INT128__)263 226 { __int128 ret; ret = __atomic_load_n(vp16, __ATOMIC_SEQ_CST); } 264 227 { __int128 ret; ret = __atomic_load_16(vp16, __ATOMIC_SEQ_CST); } 265 228 { __int128 ret; __atomic_load(vp16, &ret, __ATOMIC_SEQ_CST); } 266 #endif267 229 268 230 { _Bool ret; ret = __atomic_compare_exchange_n(vp1, rp1, v1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } … … 278 240 { _Bool ret; ret = __atomic_compare_exchange_8(vp8, rp8, v8, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 279 241 { _Bool ret; ret = __atomic_compare_exchange(vp8, rp8, &v8, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 280 #if defined(__SIZEOF_INT128__)281 242 { _Bool ret; ret = __atomic_compare_exchange_n(vp16, rp16, v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 282 243 { _Bool ret; ret = __atomic_compare_exchange_16(vp16, rp16, v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 283 244 { _Bool ret; ret = __atomic_compare_exchange(vp16, rp16, &v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 284 #endif285 245 286 246 { __atomic_store_n(vp1, v1, __ATOMIC_SEQ_CST); } … … 296 256 { __atomic_store_8(vp8, v8, __ATOMIC_SEQ_CST); } 297 257 { __atomic_store(vp8, &v8, __ATOMIC_SEQ_CST); } 298 #if defined(__SIZEOF_INT128__)299 258 { __atomic_store_n(vp16, v16, __ATOMIC_SEQ_CST); } 300 259 { __atomic_store_16(vp16, v16, __ATOMIC_SEQ_CST); } 301 260 { __atomic_store(vp16, &v16, __ATOMIC_SEQ_CST); } 302 #endif303 261 304 262 { char ret; ret = __atomic_add_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 310 268 { long long int ret; ret = __atomic_add_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 311 269 { long long int ret; ret = __atomic_add_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 312 #if defined(__SIZEOF_INT128__)313 270 { __int128 ret; ret = __atomic_add_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 314 271 { __int128 ret; ret = __atomic_add_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 315 #endif316 272 317 273 { char ret; ret = __atomic_sub_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 323 279 { long long int ret; ret = __atomic_sub_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 324 280 { long long int ret; ret = __atomic_sub_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 325 #if defined(__SIZEOF_INT128__)326 281 { __int128 ret; ret = __atomic_sub_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 327 282 { __int128 ret; ret = __atomic_sub_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 328 #endif329 283 330 284 { char ret; ret = __atomic_and_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 336 290 { long long int ret; ret = __atomic_and_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 337 291 { long long int ret; ret = __atomic_and_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 338 #if defined(__SIZEOF_INT128__)339 292 { __int128 ret; ret = __atomic_and_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 340 293 { __int128 ret; ret = __atomic_and_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 341 #endif342 294 343 295 { char ret; ret = __atomic_nand_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 349 301 { long long int ret; ret = __atomic_nand_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 350 302 { long long int ret; ret = __atomic_nand_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 351 #if defined(__SIZEOF_INT128__)352 303 { __int128 ret; ret = __atomic_nand_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 353 304 { __int128 ret; ret = __atomic_nand_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 354 #endif355 305 356 306 { char ret; ret = __atomic_xor_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 362 312 { long long int ret; ret = __atomic_xor_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 363 313 { long long int ret; ret = __atomic_xor_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 364 #if defined(__SIZEOF_INT128__)365 314 { __int128 ret; ret = __atomic_xor_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 366 315 { __int128 ret; ret = __atomic_xor_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 367 #endif368 316 369 317 { char ret; ret = __atomic_or_fetch(vp1, v1, __ATOMIC_SEQ_CST); } … … 375 323 { long long int ret; ret = __atomic_or_fetch(vp8, v8, __ATOMIC_SEQ_CST); } 376 324 { long long int ret; ret = __atomic_or_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); } 377 #if defined(__SIZEOF_INT128__)378 325 { __int128 ret; ret = __atomic_or_fetch(vp16, v16, __ATOMIC_SEQ_CST); } 379 326 { __int128 ret; ret = __atomic_or_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); } 380 #endif381 327 382 328 { char ret; ret = __atomic_fetch_add(vp1, v1, __ATOMIC_SEQ_CST); } … … 388 334 { long long int ret; ret = __atomic_fetch_add(vp8, v8, __ATOMIC_SEQ_CST); } 389 335 { long long int ret; ret = __atomic_fetch_add_8(vp8, v8, __ATOMIC_SEQ_CST); } 390 #if defined(__SIZEOF_INT128__)391 336 { __int128 ret; ret = __atomic_fetch_add(vp16, v16, __ATOMIC_SEQ_CST); } 392 337 { __int128 ret; ret = __atomic_fetch_add_16(vp16, v16, __ATOMIC_SEQ_CST); } 393 #endif394 338 395 339 { char ret; ret = __atomic_fetch_sub(vp1, v1, __ATOMIC_SEQ_CST); } … … 401 345 { long long int ret; ret = __atomic_fetch_sub(vp8, v8, __ATOMIC_SEQ_CST); } 402 346 { long long int ret; ret = __atomic_fetch_sub_8(vp8, v8, __ATOMIC_SEQ_CST); } 403 #if defined(__SIZEOF_INT128__)404 347 { __int128 ret; ret = __atomic_fetch_sub(vp16, v16, __ATOMIC_SEQ_CST); } 405 348 { __int128 ret; ret = __atomic_fetch_sub_16(vp16, v16, __ATOMIC_SEQ_CST); } 406 #endif407 349 408 350 { char ret; ret = __atomic_fetch_and(vp1, v1, __ATOMIC_SEQ_CST); } … … 414 356 { long long int ret; ret = __atomic_fetch_and(vp8, v8, __ATOMIC_SEQ_CST); } 415 357 { long long int ret; ret = __atomic_fetch_and_8(vp8, v8, __ATOMIC_SEQ_CST); } 416 #if defined(__SIZEOF_INT128__)417 358 { __int128 ret; ret = __atomic_fetch_and(vp16, v16, __ATOMIC_SEQ_CST); } 418 359 { __int128 ret; ret = __atomic_fetch_and_16(vp16, v16, __ATOMIC_SEQ_CST); } 419 #endif420 360 421 361 { char ret; ret = __atomic_fetch_nand(vp1, v1, __ATOMIC_SEQ_CST); } … … 427 367 { long long int ret; ret = __atomic_fetch_nand(vp8, v8, __ATOMIC_SEQ_CST); } 428 368 { long long int ret; ret = __atomic_fetch_nand_8(vp8, v8, __ATOMIC_SEQ_CST); } 429 #if defined(__SIZEOF_INT128__)430 369 { __int128 ret; ret = __atomic_fetch_nand(vp16, v16, __ATOMIC_SEQ_CST); } 431 370 { __int128 ret; ret = __atomic_fetch_nand_16(vp16, v16, __ATOMIC_SEQ_CST); } 432 #endif433 371 434 372 { char ret; ret = __atomic_fetch_xor(vp1, v1, __ATOMIC_SEQ_CST); } … … 440 378 { long long int ret; ret = __atomic_fetch_xor(vp8, v8, __ATOMIC_SEQ_CST); } 441 379 { long long int ret; ret = __atomic_fetch_xor_8(vp8, v8, __ATOMIC_SEQ_CST); } 442 #if defined(__SIZEOF_INT128__)443 380 { __int128 ret; ret = __atomic_fetch_xor(vp16, v16, __ATOMIC_SEQ_CST); } 444 381 { __int128 ret; ret = __atomic_fetch_xor_16(vp16, v16, __ATOMIC_SEQ_CST); } 445 #endif446 382 447 383 { char ret; ret = __atomic_fetch_or(vp1, v1, __ATOMIC_SEQ_CST); } … … 453 389 { long long int ret; ret = __atomic_fetch_or(vp8, v8, __ATOMIC_SEQ_CST); } 454 390 { long long int ret; ret = __atomic_fetch_or_8(vp8, v8, __ATOMIC_SEQ_CST); } 455 #if defined(__SIZEOF_INT128__)456 391 { __int128 ret; ret = __atomic_fetch_or(vp16, v16, __ATOMIC_SEQ_CST); } 457 392 { __int128 ret; ret = __atomic_fetch_or_16(vp16, v16, __ATOMIC_SEQ_CST); } 458 #endif459 393 460 394 { _Bool ret; ret = __atomic_always_lock_free(sizeof(int), vp4); } -
src/tests/concurrent/coroutineYield.c
rb21c77a r97397a26 4 4 #include <thread> 5 5 #include <time> 6 7 #define __kick_rate 150000ul8 #include "long_tests.h"9 6 10 7 #ifndef PREEMPTION_RATE … … 16 13 } 17 14 18 #ifdef TEST_LONG15 #ifdef LONG_TEST 19 16 static const unsigned long N = 600_000ul; 20 17 #else … … 26 23 void main(Coroutine& this) { 27 24 while(true) { 28 #if !defined(TEST_FOREVER) 29 sout | "Coroutine 1" | endl; 30 #endif 25 sout | "Coroutine 1" | endl; 31 26 yield(); 32 #if !defined(TEST_FOREVER) 33 sout | "Coroutine 2" | endl; 34 #endif 27 sout | "Coroutine 2" | endl; 35 28 suspend(); 36 29 } … … 40 33 int main(int argc, char* argv[]) { 41 34 Coroutine c; 42 for(int i = 0; TEST(i < N); i++) { 43 #if !defined(TEST_FOREVER) 44 sout | "Thread 1" | endl; 45 #endif 35 for(int i = 0; i < N; i++) { 36 sout | "Thread 1" | endl; 46 37 resume(c); 47 #if !defined(TEST_FOREVER) 48 sout | "Thread 2" | endl; 49 #endif 38 sout | "Thread 2" | endl; 50 39 yield(); 51 KICK_WATCHDOG;52 40 } 53 41 } -
src/tests/concurrent/examples/datingService.c
rb21c77a r97397a26 8 8 // Created On : Mon Oct 30 12:56:20 2017 9 9 // Last Modified By : Peter A. Buhr 10 // Last Modified On : Sun May 27 09:05:18201811 // Update Count : 2 610 // Last Modified On : Wed Mar 14 22:48:40 2018 11 // Update Count : 23 12 12 // 13 13 … … 18 18 #include <unistd.h> // getpid 19 19 20 enum { CompCodes = 20 }; // number of compatibility codes20 enum { NoOfPairs = 20 }; 21 21 22 22 monitor DatingService { 23 condition Girls[ CompCodes], Boys[CompCodes];23 condition Girls[NoOfPairs], Boys[NoOfPairs]; 24 24 unsigned int GirlPhoneNo, BoyPhoneNo; 25 25 }; // DatingService … … 47 47 } // DatingService boy 48 48 49 unsigned int girlck[ CompCodes];50 unsigned int boyck[ CompCodes];49 unsigned int girlck[NoOfPairs]; 50 unsigned int boyck[NoOfPairs]; 51 51 52 52 thread Girl { … … 88 88 int main() { 89 89 DatingService TheExchange; 90 Girl * girls[ CompCodes];91 Boy * boys[ CompCodes];90 Girl * girls[NoOfPairs]; 91 Boy * boys[NoOfPairs]; 92 92 93 93 srandom( /*getpid()*/ 103 ); 94 94 95 for ( unsigned int i = 0; i < CompCodes; i += 1 ) {95 for ( unsigned int i = 0; i < NoOfPairs; i += 1 ) { 96 96 girls[i] = new( &TheExchange, i, i ); 97 boys[i] = new( &TheExchange, i, CompCodes - ( i + 1 ) );97 boys[i] = new( &TheExchange, i, NoOfPairs - ( i + 1 ) ); 98 98 } // for 99 99 100 for ( unsigned int i = 0; i < CompCodes; i += 1 ) {100 for ( unsigned int i = 0; i < NoOfPairs; i += 1 ) { 101 101 delete( boys[i] ); 102 102 delete( girls[i] ); 103 103 } // for 104 104 105 for ( unsigned int i = 0; i < CompCodes; i += 1 ) {105 for ( unsigned int i = 0; i < NoOfPairs; i += 1 ) { 106 106 if ( girlck[ boyck[i] ] != boyck[ girlck[i] ] ) abort(); 107 107 } // for -
src/tests/concurrent/preempt.c
rb21c77a r97397a26 2 2 #include <thread> 3 3 #include <time> 4 5 #include "long_tests.h"6 4 7 5 #ifndef PREEMPTION_RATE … … 13 11 } 14 12 15 #ifdef TEST_LONG13 #ifdef LONG_TEST 16 14 static const unsigned long N = 30_000ul; 17 15 #else … … 32 30 33 31 void main(worker_t & this) { 34 while( TEST(counter < N)) {32 while(counter < N) { 35 33 __cfaabi_check_preemption(); 36 34 if( (counter % 7) == this.value ) { … … 42 40 } 43 41 __cfaabi_check_preemption(); 44 KICK_WATCHDOG;45 42 } 46 43 } -
src/tests/concurrent/signal/block.c
rb21c77a r97397a26 14 14 #include <time> 15 15 16 #include "long_tests.h"17 18 16 #ifndef PREEMPTION_RATE 19 17 #define PREEMPTION_RATE 10`ms … … 24 22 } 25 23 26 #ifdef TEST_LONG24 #ifdef LONG_TEST 27 25 static const unsigned long N = 150_000ul; 28 26 #else … … 42 40 } 43 41 44 void ^?{} ( global_data_t & mutexthis ) {}42 void ^?{} ( global_data_t & this ) {} 45 43 46 44 global_data_t globalA, globalB; … … 68 66 thread Waiter {}; 69 67 void main( Waiter & this ) { 70 for( int i = 0; TEST(i < N); i++ ) {68 for( int i = 0; i < N; i++ ) { 71 69 wait_op( globalA, globalB, i ); 72 KICK_WATCHDOG;73 70 } 74 71 } -
src/tests/concurrent/signal/disjoint.c
rb21c77a r97397a26 4 4 #include <thread> 5 5 #include <time> 6 7 #include "long_tests.h"8 6 9 7 #ifndef PREEMPTION_RATE … … 15 13 } 16 14 17 #ifdef TEST_LONG15 #ifdef LONG_TEST 18 16 static const unsigned long N = 300_000ul; 19 17 #else … … 28 26 monitor global_data_t; 29 27 void ?{}( global_data_t & this ); 30 void ^?{} ( global_data_t & mutexthis );28 void ^?{} ( global_data_t & this ); 31 29 32 30 monitor global_data_t { … … 44 42 } 45 43 46 void ^?{} ( global_data_t & mutexthis ) {}44 void ^?{} ( global_data_t & this ) {} 47 45 48 46 //------------------------------------------------------------------------------ … … 69 67 } 70 68 71 #if !defined(TEST_FOREVER) 72 d.counter++; 73 if( (d.counter % 1000) == 0 ) sout | d.counter | endl; 74 #endif 69 d.counter++; 75 70 76 return TEST(d.counter < N); 71 if( (d.counter % 1000) == 0 ) sout | d.counter | endl; 72 73 return d.counter < N; 77 74 } 78 75 … … 80 77 81 78 void main( Waiter & this ) { 82 while( wait( mut, data ) ) { KICK_WATCHDOG;yield(); }79 while( wait( mut, data ) ) { yield(); } 83 80 } 84 81 … … 97 94 98 95 //This is technically a mutual exclusion violation but the mutex monitor protects us 99 bool running = TEST(data.counter < N)&& data.counter > 0;96 bool running = data.counter < N && data.counter > 0; 100 97 if( data.state != SIGNAL && running ) { 101 98 sout | "ERROR Eager signal" | data.state | endl; -
src/tests/concurrent/signal/wait.c
rb21c77a r97397a26 12 12 #include <time> 13 13 14 #define __kick_rate 12000ul15 #include "long_tests.h"16 17 14 #ifndef PREEMPTION_RATE 18 15 #define PREEMPTION_RATE 10`ms … … 23 20 } 24 21 25 #ifdef TEST_LONG22 #ifdef LONG_TEST 26 23 static const unsigned long N = 375_000ul; 27 24 #else … … 93 90 // Waiter ABC 94 91 void main( WaiterABC & this ) { 95 for( int i = 0; TEST(i < N); i++ ) {92 for( int i = 0; i < N; i++ ) { 96 93 wait( condABC, globalA, globalB, globalC ); 97 KICK_WATCHDOG;98 94 } 99 95 … … 104 100 // Waiter AB 105 101 void main( WaiterAB & this ) { 106 for( int i = 0; TEST(i < N); i++ ) {102 for( int i = 0; i < N; i++ ) { 107 103 wait( condAB , globalA, globalB ); 108 KICK_WATCHDOG;109 104 } 110 105 … … 115 110 // Waiter AC 116 111 void main( WaiterAC & this ) { 117 for( int i = 0; TEST(i < N); i++ ) {112 for( int i = 0; i < N; i++ ) { 118 113 wait( condAC , globalA, globalC ); 119 KICK_WATCHDOG;120 114 } 121 115 … … 126 120 // Waiter BC 127 121 void main( WaiterBC & this ) { 128 for( int i = 0; TEST(i < N); i++ ) {122 for( int i = 0; i < N; i++ ) { 129 123 wait( condBC , globalB, globalC ); 130 KICK_WATCHDOG;131 124 } 132 125 -
src/tests/preempt_longrun/Makefile.am
rb21c77a r97397a26 19 19 preempt=10ul\`ms 20 20 debug=-debug 21 type=LONG22 21 23 22 REPEAT = ${abs_top_srcdir}/tools/repeat 24 WATCHDOG = ${abs_top_srcdir}/tools/watchdog25 23 TIME = /usr/bin/time -f "%E" 26 24 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) 25 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -DLONG_TEST 33 26 CFLAGS = ${BUILD_FLAGS} 34 27 CC = @CFA_BINDIR@/@CFA_NAME@ … … 36 29 TESTS = block coroutine create disjoint enter enter3 processor stack wait yield 37 30 38 #.INTERMEDIATE: ${TESTS}31 .INTERMEDIATE: ${TESTS} 39 32 40 33 all-local: ${TESTS:=.run} 41 34 42 runall : ${TESTS:=.run} 43 @ echo "All programs terminated normally"35 clean-local: 36 rm -f ${TESTS} 44 37 45 watchall : ${TESTS:=.watch} 46 @ echo "All programs terminated normally" 47 48 compileall : ${TESTS} 49 @ echo "Compiled" 50 51 clean-local: 52 rm -f ${TESTS} core* out.log .type 53 54 % : %.c ${CC} ${UPDATED_TYPE} 38 % : %.c ${CC} 55 39 ${AM_V_GEN}${CC} ${CFLAGS} ${<} $(debug) -o ${@} 56 40 57 41 %.run : % ${REPEAT} 58 42 @ 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} ./${<}64 43 @ rm ${<} 65 44 @ echo -e "${<}: SUCCESS\n" … … 70 49 @ echo -e "${<}: SUCCESS\n" 71 50 72 ${REPEAT}: ${abs_top_srcdir}/tools/Makefile51 ${REPEAT}: 73 52 @+make -C ${abs_top_srcdir}/tools/ 74 75 ${WATCHDOG}: ${abs_top_srcdir}/tools/Makefile76 @+make -C ${abs_top_srcdir}/tools/ -
src/tests/preempt_longrun/Makefile.in
rb21c77a r97397a26 452 452 preempt = 10ul\`ms 453 453 debug = -debug 454 type = LONG455 454 REPEAT = ${abs_top_srcdir}/tools/repeat 456 WATCHDOG = ${abs_top_srcdir}/tools/watchdog457 455 TIME = /usr/bin/time -f "%E" 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) 456 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -DLONG_TEST 463 457 TESTS = block coroutine create disjoint enter enter3 processor stack wait yield 464 458 all: all-am … … 879 873 880 874 881 #.INTERMEDIATE: ${TESTS}875 .INTERMEDIATE: ${TESTS} 882 876 883 877 all-local: ${TESTS:=.run} 884 878 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 894 879 clean-local: 895 rm -f ${TESTS} core* out.log .type896 897 % : %.c ${CC} ${UPDATED_TYPE}880 rm -f ${TESTS} 881 882 % : %.c ${CC} 898 883 ${AM_V_GEN}${CC} ${CFLAGS} ${<} $(debug) -o ${@} 899 884 … … 903 888 @ echo -e "${<}: SUCCESS\n" 904 889 905 %.watch : % ${WATCHDOG}906 @ time ${WATCHDOG} ./${<}907 @ rm ${<}908 @ echo -e "${<}: SUCCESS\n"909 910 890 %.time : % ${REPEAT} 911 891 @ ${REPEAT} -i -s -- $(repeats) $(TIME) -a -o times.log ./${<} … … 913 893 @ echo -e "${<}: SUCCESS\n" 914 894 915 ${REPEAT}: ${abs_top_srcdir}/tools/Makefile 916 @+make -C ${abs_top_srcdir}/tools/ 917 918 ${WATCHDOG}: ${abs_top_srcdir}/tools/Makefile 895 ${REPEAT}: 919 896 @+make -C ${abs_top_srcdir}/tools/ 920 897 -
src/tests/preempt_longrun/create.c
rb21c77a r97397a26 2 2 #include <thread> 3 3 #include <time> 4 5 #include "long_tests.h"6 4 7 5 #ifndef PREEMPTION_RATE … … 21 19 int main(int argc, char* argv[]) { 22 20 processor p; 23 for(int i = 0; TEST(i < N); i++) {21 for(int i = 0; i < N; i++) { 24 22 worker_t w[7]; 25 KICK_WATCHDOG;26 23 } 27 24 } -
src/tests/preempt_longrun/enter.c
rb21c77a r97397a26 3 3 #include <thread> 4 4 #include <time> 5 6 #define __kick_rate 75000ul7 #include "long_tests.h"8 5 9 6 #ifndef PREEMPTION_RATE … … 18 15 19 16 monitor mon_t {}; 20 void foo( mon_t & mutex this ) { 21 KICK_WATCHDOG; 17 18 mon_t mon; 19 20 void foo( mon_t & mutex this ) {} 21 22 thread worker_t {}; 23 24 void main( worker_t & this ) { 25 for( unsigned long i = 0; i < N; i++ ) { 26 foo( mon ); 27 } 22 28 } 23 29 24 mon_t mon; 25 thread worker_t {}; 26 void main( worker_t & this ) { 27 for( unsigned long i = 0; TEST(i < N); i++ ) { 28 foo( mon ); 29 } 30 extern "C" { 31 static worker_t * workers; 30 32 } 31 33 … … 34 36 { 35 37 worker_t w[7]; 38 workers = w; 36 39 } 37 40 } -
src/tests/preempt_longrun/enter3.c
rb21c77a r97397a26 3 3 #include <thread> 4 4 #include <time> 5 6 #define __kick_rate 75000ul7 #include "long_tests.h"8 5 9 6 #ifndef PREEMPTION_RATE … … 21 18 mon_t mon1, mon2, mon3; 22 19 23 void foo( mon_t & mutex a, mon_t & mutex b, mon_t & mutex c ) { 24 KICK_WATCHDOG; 25 } 20 void foo( mon_t & mutex a, mon_t & mutex b, mon_t & mutex c ) {} 26 21 27 22 thread worker_t {}; 28 23 29 24 void main( worker_t & this ) { 30 for( unsigned long i = 0; TEST(i < N); i++ ) {25 for( unsigned long i = 0; i < N; i++ ) { 31 26 foo( mon1, mon2, mon3 ); 32 27 } -
src/tests/preempt_longrun/processor.c
rb21c77a r97397a26 2 2 #include <thread> 3 3 #include <time> 4 5 #include <unistd.h>6 7 #include "long_tests.h"8 4 9 5 #ifndef PREEMPTION_RATE … … 15 11 } 16 12 17 static const unsigned long N = 5 0_000ul;13 static const unsigned long N = 5_000ul; 18 14 19 15 int main(int argc, char* argv[]) { … … 22 18 p[pi] = new(); 23 19 } 24 for ( int i = 0; TEST(i < N); i++) {20 for ( int i = 0; i < N; i++) { 25 21 int pi = i % 15; 26 22 delete( p[pi] ); 27 23 p[pi] = new(); 28 KICK_WATCHDOG;29 }30 for ( int pi = 0; pi < 15; pi++ ) {31 delete( p[pi] );32 24 } 33 25 } -
src/tests/preempt_longrun/stack.c
rb21c77a r97397a26 3 3 #include <thread> 4 4 #include <time> 5 6 #define __kick_rate 5000000ul7 #include "long_tests.h"8 5 9 6 #ifndef PREEMPTION_RATE … … 18 15 19 16 void main(worker_t & this) { 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 } 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 } 29 24 30 if( !TEST(n == a) ) { 31 abort(); 32 } 25 if( n != a ) { 26 abort(); 33 27 } 34 28 } -
src/tests/preempt_longrun/yield.c
rb21c77a r97397a26 2 2 #include <thread> 3 3 #include <time> 4 5 #define __kick_rate 550000ul6 #include "long_tests.h"7 4 8 5 #ifndef PREEMPTION_RATE … … 14 11 } 15 12 16 #ifdef TEST_LONG13 #ifdef LONG_TEST 17 14 static const unsigned long N = 9_750_000ul; 18 15 #else … … 23 20 24 21 void main(worker_t & this) { 25 for(int i = 0; TEST(i < N); i++) {22 for(int i = 0; i < N; i++) { 26 23 yield(); 27 KICK_WATCHDOG;28 24 } 29 25 } -
src/tests/pybin/tools.py
rb21c77a r97397a26 83 83 return sh(cmd) 84 84 85 def which(program):86 import os87 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 program94 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_file99 100 return None101 85 ################################################################################ 102 86 # file handling … … 235 219 return False 236 220 237 def fancy_print(text):238 column = which('column')239 if column:240 cmd = "%s 2> /dev/null" % column241 print(cmd)242 proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True)243 proc.communicate(input=text)244 else:245 print(text)246 221 247 222 settings.set_machine_default( getMachineType ) -
src/tests/raii/.expect/ctor-autogen-ERR1.txt
rb21c77a r97397a26 1 raii/ctor-autogen.c:102:1 error: Unique best alternative includes deleted identifier in Cast of:2 Application of3 Deleted Expression 4 Variable Expression: ?{}: static inline function5 ... with parameters6 _dst: reference to instance of struct Managed with body 17 x: signed int8 ... returning nothing1 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 1 6 ... to: 7 reference to instance of struct Managed with body 1 8 constant expression (123 123: signed int) 9 9 10 ... deleted by: ?{}: function11 ... with parameters12 m: reference to instance of struct Managed with body 113 ... returning nothing14 ... with body15 CompoundStmt16 Expression Statement:17 Application of18 Variable Expression: ?=?: function19 ... with parameters20 intrinsic reference to signed int21 intrinsic signed int22 ... returning23 _retval__operator_assign: signed int24 ... with attributes:25 Attribute with name: unused26 27 28 ... to arguments29 Cast of:30 Member Expression, with field:31 x: signed int32 ... from aggregate:33 Cast of:34 Variable Expression: m: reference to instance of struct Managed with body 135 ... to:36 instance of struct Managed with body 137 ... to:38 reference to signed int39 Cast of:40 constant expression (0 0: zero_t)41 ... to:42 signed int43 44 ... with environment:45 Types:46 Non-types:47 48 49 ... to arguments50 Cast of:51 Variable Expression: x: instance of struct Managed with body 152 ... to:53 reference to instance of struct Managed with body 154 constant expression (123 123: signed int)55 56 ... to: nothing -
src/tests/sum.c
rb21c77a r97397a26 11 11 // Created On : Wed May 27 17:56:53 2015 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : S un Jun 3 19:23:41201814 // Update Count : 27 813 // Last Modified On : Sat Feb 17 11:49:17 2018 14 // Update Count : 273 15 15 // 16 16 … … 18 18 #include <stdlib> 19 19 20 void ?{}( int & c, zero_t ) { c = 0; } // not in prelude20 void ?{}( int & c, zero_t ) { c = 0; } 21 21 22 22 trait sumable( otype T ) { 23 void ?{}( T &, zero_t ); // 0 literal constructor23 void ?{}( T &, zero_t ); // constructor from 0 literal 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( size_t size, T a[] ) {32 T total = 0; // in itialize by 0constructor33 for ( size_t i = 0; i < size; i += 1 )31 T sum( unsigned int size, T a[] ) { 32 T total = 0; // instantiate T from 0 by calling constructor 33 for ( unsigned int 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 eld array in generic type113 gs.x[i] = (int)v; // set filed 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 eld array in generic type116 | sum( size, gs.x ) | ", check" | (int)s | endl; // add filed array in generic type 117 117 } // main 118 118 -
src/tests/test.py
rb21c77a r97397a26 277 277 elif options.list : 278 278 print("Listing for %s:%s"% (settings.arch.string, settings.debug.string)) 279 fancy_print("\n".join(map(lambda t: "%s" % (t.toString()), tests)))279 print("\n".join(map(lambda t: "%s" % (t.toString()), tests))) 280 280 281 281 else : -
tools/Makefile.am
rb21c77a r97397a26 18 18 CFLAGS = -Wall -Wextra -O2 -g 19 19 20 noinst_PROGRAMS = busy catchsig repeat watchdog20 noinst_PROGRAMS = busy catchsig repeat 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 -
tools/Makefile.in
rb21c77a r97397a26 92 92 build_triplet = @build@ 93 93 host_triplet = @host@ 94 noinst_PROGRAMS = busy$(EXEEXT) catchsig$(EXEEXT) repeat$(EXEEXT) \ 95 watchdog$(EXEEXT) 94 noinst_PROGRAMS = busy$(EXEEXT) catchsig$(EXEEXT) repeat$(EXEEXT) 96 95 subdir = tools 97 96 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 … … 116 115 repeat_OBJECTS = $(am_repeat_OBJECTS) 117 116 repeat_LDADD = $(LDADD) 118 am_watchdog_OBJECTS = watchdog.$(OBJEXT)119 watchdog_OBJECTS = $(am_watchdog_OBJECTS)120 watchdog_LDADD = $(LDADD)121 117 AM_V_P = $(am__v_P_@AM_V@) 122 118 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) … … 147 143 am__v_CCLD_0 = @echo " CCLD " $@; 148 144 am__v_CCLD_1 = 149 SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) \ 150 $(watchdog_SOURCES) 151 DIST_SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) \ 152 $(watchdog_SOURCES) 145 SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) 146 DIST_SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) 153 147 am__can_run_installinfo = \ 154 148 case $$AM_UPDATE_INFO_DIR in \ … … 301 295 catchsig_SOURCES = catchsig.c 302 296 repeat_SOURCES = repeat.c 303 watchdog_SOURCES = watchdog.c304 297 all: all-am 305 298 … … 351 344 $(AM_V_CCLD)$(LINK) $(repeat_OBJECTS) $(repeat_LDADD) $(LIBS) 352 345 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 357 346 mostlyclean-compile: 358 347 -rm -f *.$(OBJEXT) … … 364 353 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/catchsig.Po@am__quote@ 365 354 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repeat.Po@am__quote@ 366 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watchdog.Po@am__quote@367 355 368 356 .c.o: -
tools/prettyprinter/lex.ll
rb21c77a r97397a26 10 10 * Created On : Sat Dec 15 11:45:59 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Thu May 31 08:49:58201813 * Update Count : 27 412 * Last Modified On : Sun Apr 15 21:28:33 2018 13 * Update Count : 271 14 14 */ 15 15 … … 77 77 } 78 78 79 <INITIAL,C_CODE>"//"[^\n]* {// C++ style comments79 <INITIAL,C_CODE>"//"[^\n]*"\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.