Changeset 933f32f
- Timestamp:
- May 24, 2019, 10:19:41 AM (6 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- d908563
- Parents:
- 6a9d4b4 (diff), 292642a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Files:
-
- 143 added
- 9 deleted
- 224 edited
- 9 moved
-
.gitignore (modified) (2 diffs)
-
Jenkins/FullBuild (modified) (7 diffs)
-
Jenkinsfile (modified) (15 diffs)
-
Makefile.am (modified) (2 diffs)
-
Makefile.in (modified) (3 diffs)
-
automake/cfa.m4 (modified) (1 diff)
-
benchmark/Makefile.am (modified) (12 diffs)
-
benchmark/Makefile.in (modified) (11 diffs)
-
benchmark/ctxswitch/cfa_cor.cfa (modified) (1 diff)
-
benchmark/ctxswitch/cfa_cor_then.cfa (added)
-
benchmark/ctxswitch/cfa_thrd2.cfa (modified) (1 diff)
-
benchmark/fixcsv.sh (added)
-
benchmark/jenkins.sh (deleted)
-
benchmark/tls-fetch_add.c (added)
-
configure (modified) (19 diffs)
-
configure.ac (modified) (5 diffs)
-
doc/LaTeXmacros/lstlang.sty (modified) (2 diffs)
-
doc/bibliography/pl.bib (modified) (47 diffs)
-
doc/papers/concurrency/Paper.tex (modified) (15 diffs)
-
doc/papers/concurrency/examples/C++Cor-ts.cpp (added)
-
doc/papers/concurrency/examples/Fib.c (added)
-
doc/papers/concurrency/examples/Fib.cfa (added)
-
doc/papers/concurrency/examples/Fib.cpp (added)
-
doc/papers/concurrency/examples/Fib.py (added)
-
doc/papers/concurrency/examples/Fib.sim (added)
-
doc/papers/concurrency/examples/Fib2.cfa (added)
-
doc/papers/concurrency/examples/Fib2.cpp (added)
-
doc/papers/concurrency/examples/Fib2.py (added)
-
doc/papers/concurrency/examples/FibRefactor.py (added)
-
doc/papers/concurrency/examples/Fmt.sim (added)
-
doc/papers/concurrency/examples/Format.cc (added)
-
doc/papers/concurrency/examples/Format.cfa (added)
-
doc/papers/concurrency/examples/Format.cpp (added)
-
doc/papers/concurrency/examples/Format.py (added)
-
doc/papers/concurrency/examples/Pingpong.cc (added)
-
doc/papers/concurrency/examples/Pingpong.cfa (added)
-
doc/papers/concurrency/examples/Pingpong.py (added)
-
doc/papers/concurrency/examples/ProdCons.cfa (added)
-
doc/papers/concurrency/examples/ProdCons.cpp (added)
-
doc/papers/concurrency/examples/ProdCons.py (added)
-
doc/papers/concurrency/examples/ProdCons.sim (added)
-
doc/papers/concurrency/examples/Refactor.py (added)
-
doc/papers/concurrency/examples/counter.cpp (added)
-
doc/papers/concurrency/mail (modified) (1 diff)
-
doc/proposals/interned_string.cc (added)
-
doc/proposals/interned_string.h (added)
-
doc/proposals/specialized_casts.md (added)
-
doc/proposals/unicode.html (added)
-
doc/proposals/virtual.txt (deleted)
-
doc/proposals/vtable.md (modified) (7 diffs)
-
doc/theses/aaron_moss_PhD/phd/Makefile (modified) (5 diffs)
-
doc/theses/aaron_moss_PhD/phd/background.tex (modified) (12 diffs)
-
doc/theses/aaron_moss_PhD/phd/conclusion.tex (modified) (1 diff)
-
doc/theses/aaron_moss_PhD/phd/evaluation/algo-summary.dat (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/algo-summary.gp (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/bu-summary.dat (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-bu.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-co.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-dca.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-def.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-imm.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-mem-by-time.tsv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-mem.tsv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-plots.gp (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-time.tsv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/data.xlsx (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/generic-timing.dat (modified) (1 diff)
-
doc/theses/aaron_moss_PhD/phd/evaluation/mem-by-max-assns.tsv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/mem-by-max-depth.tsv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/metric-plots.gp (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per-prob-scatter.gp (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per-prob.gp (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per-prob.tsv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/imgui-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/io1-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/io2-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/kernel-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/math1-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/math2-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/math3-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/math4-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/minmax-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/preemption-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/rational-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/searchsort-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/swap-per-prob.csv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/time-by-max-assns.tsv (added)
-
doc/theses/aaron_moss_PhD/phd/evaluation/time-by-max-depth.tsv (added)
-
doc/theses/aaron_moss_PhD/phd/experiments.tex (added)
-
doc/theses/aaron_moss_PhD/phd/figures/bilson-conv-graph.eps (added)
-
doc/theses/aaron_moss_PhD/phd/figures/bilson-conv-graph.odg (added)
-
doc/theses/aaron_moss_PhD/phd/figures/extended-conv-graph.eps (added)
-
doc/theses/aaron_moss_PhD/phd/figures/extended-conv-graph.odg (added)
-
doc/theses/aaron_moss_PhD/phd/figures/persistent-union-find.eps (added)
-
doc/theses/aaron_moss_PhD/phd/figures/persistent-union-find.odg (added)
-
doc/theses/aaron_moss_PhD/phd/figures/resolution-dag.eps (added)
-
doc/theses/aaron_moss_PhD/phd/figures/resolution-dag.odg (added)
-
doc/theses/aaron_moss_PhD/phd/figures/safe-conv-graph.eps (added)
-
doc/theses/aaron_moss_PhD/phd/figures/safe-conv-graph.odg (added)
-
doc/theses/aaron_moss_PhD/phd/figures/union-find-with-classes.eps (added)
-
doc/theses/aaron_moss_PhD/phd/figures/union-find-with-classes.odg (added)
-
doc/theses/aaron_moss_PhD/phd/frontpgs.tex (modified) (6 diffs)
-
doc/theses/aaron_moss_PhD/phd/generic-bench.tex (added)
-
doc/theses/aaron_moss_PhD/phd/generic-types.tex (modified) (28 diffs)
-
doc/theses/aaron_moss_PhD/phd/introduction.tex (modified) (2 diffs)
-
doc/theses/aaron_moss_PhD/phd/macros.tex (modified) (1 diff)
-
doc/theses/aaron_moss_PhD/phd/resolution-heuristics.tex (modified) (1 diff)
-
doc/theses/aaron_moss_PhD/phd/thesis.tex (modified) (4 diffs)
-
doc/theses/aaron_moss_PhD/phd/type-environment.tex (modified) (9 diffs)
-
doc/user/user.tex (modified) (7 diffs)
-
driver/Makefile.am (modified) (1 diff)
-
driver/Makefile.in (modified) (2 diffs)
-
driver/cfa.cc (modified) (5 diffs)
-
libcfa/configure (modified) (3 diffs)
-
libcfa/configure.ac (modified) (2 diffs)
-
libcfa/prelude/builtins.c (modified) (4 diffs)
-
libcfa/prelude/extras.c (modified) (1 diff)
-
libcfa/prelude/extras.regx (modified) (1 diff)
-
libcfa/prelude/prelude-gen.cc (modified) (11 diffs)
-
libcfa/prelude/sync-builtins.cf (modified) (6 diffs)
-
libcfa/src/Makefile.am (modified) (1 diff)
-
libcfa/src/Makefile.in (modified) (1 diff)
-
libcfa/src/bits/containers.hfa (modified) (3 diffs)
-
libcfa/src/concurrency/CtxSwitch-i386.S (modified) (5 diffs)
-
libcfa/src/concurrency/CtxSwitch-x86_64.S (modified) (2 diffs)
-
libcfa/src/concurrency/coroutine.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/coroutine.hfa (modified) (7 diffs)
-
libcfa/src/concurrency/invoke.c (modified) (8 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (6 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (18 diffs)
-
libcfa/src/concurrency/thread.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/thread.hfa (modified) (1 diff)
-
libcfa/src/containers/maybe.cfa (modified) (2 diffs)
-
libcfa/src/containers/result.cfa (modified) (2 diffs)
-
libcfa/src/fstream.cfa (modified) (14 diffs)
-
libcfa/src/fstream.hfa (modified) (2 diffs)
-
libcfa/src/gmp.hfa (modified) (2 diffs)
-
libcfa/src/heap.cfa (modified) (9 diffs)
-
libcfa/src/iostream.cfa (modified) (11 diffs)
-
libcfa/src/iostream.hfa (modified) (7 diffs)
-
libcfa/src/rational.cfa (modified) (9 diffs)
-
libcfa/src/rational.hfa (modified) (2 diffs)
-
libcfa/src/stdhdr/stdbool.h (modified) (1 diff)
-
libcfa/src/stdlib.hfa (modified) (4 diffs)
-
libcfa/src/time.hfa (modified) (5 diffs)
-
libcfa/src/time_t.hfa (modified) (2 diffs)
-
longrun_tests/Makefile.am (added)
-
longrun_tests/Makefile.in (moved) (moved from tests/preempt_longrun/Makefile.in ) (9 diffs)
-
longrun_tests/block.cfa (added)
-
longrun_tests/coroutine.cfa (added)
-
longrun_tests/create.cfa (moved) (moved from tests/preempt_longrun/create.c )
-
longrun_tests/disjoint.cfa (added)
-
longrun_tests/enter.cfa (moved) (moved from tests/preempt_longrun/enter.c ) (1 diff)
-
longrun_tests/enter3.cfa (moved) (moved from tests/preempt_longrun/enter3.c )
-
longrun_tests/preempt.cfa (added)
-
longrun_tests/processor.cfa (moved) (moved from tests/preempt_longrun/processor.c )
-
longrun_tests/stack.cfa (moved) (moved from tests/preempt_longrun/stack.c ) (1 diff)
-
longrun_tests/update-type (moved) (moved from tests/preempt_longrun/update-type )
-
longrun_tests/wait.cfa (added)
-
longrun_tests/yield.cfa (moved) (moved from tests/preempt_longrun/yield.c )
-
src/AST/Attribute.cpp (added)
-
src/AST/Attribute.hpp (added)
-
src/AST/Bitfield.hpp (added)
-
src/AST/CVQualifiers.hpp (added)
-
src/AST/Convert.cpp (added)
-
src/AST/Convert.hpp (added)
-
src/AST/Decl.cpp (added)
-
src/AST/Decl.hpp (added)
-
src/AST/DeclReplacer.cpp (added)
-
src/AST/DeclReplacer.hpp (added)
-
src/AST/Expr.cpp (added)
-
src/AST/Expr.hpp (added)
-
src/AST/FunctionSpec.hpp (added)
-
src/AST/Fwd.hpp (added)
-
src/AST/Init.cpp (added)
-
src/AST/Init.hpp (added)
-
src/AST/Label.hpp (added)
-
src/AST/LinkageSpec.cpp (added)
-
src/AST/LinkageSpec.hpp (added)
-
src/AST/Node.cpp (added)
-
src/AST/Node.hpp (added)
-
src/AST/ParseNode.hpp (added)
-
src/AST/Pass.hpp (added)
-
src/AST/Pass.impl.hpp (added)
-
src/AST/Pass.proto.hpp (added)
-
src/AST/Stmt.cpp (added)
-
src/AST/Stmt.hpp (added)
-
src/AST/StorageClasses.hpp (added)
-
src/AST/Type.cpp (added)
-
src/AST/Type.hpp (added)
-
src/AST/TypeSubstitution.cpp (added)
-
src/AST/TypeSubstitution.hpp (added)
-
src/AST/TypeVar.hpp (added)
-
src/AST/Visitor.hpp (added)
-
src/AST/module.mk (added)
-
src/AST/porting.md (added)
-
src/BasicTypes-gen.cc (added)
-
src/CodeGen/CodeGenerator.cc (modified) (37 diffs)
-
src/CodeGen/CodeGenerator.h (modified) (4 diffs)
-
src/CodeGen/GenType.cc (modified) (19 diffs)
-
src/CodeGen/GenType.h (modified) (2 diffs)
-
src/CodeGen/Options.h (added)
-
src/CodeGen/module.mk (modified) (1 diff)
-
src/Common/Assert.cc (modified) (1 diff)
-
src/Common/Heap.cc (deleted)
-
src/Common/PassVisitor.cc (added)
-
src/Common/PassVisitor.h (modified) (6 diffs)
-
src/Common/PassVisitor.impl.h (modified) (16 diffs)
-
src/Common/PassVisitor.proto.h (modified) (3 diffs)
-
src/Common/PersistentMap.h (added)
-
src/Common/SemanticError.h (modified) (1 diff)
-
src/Common/Stats.h (added)
-
src/Common/Stats/Base.h (added)
-
src/Common/Stats/Counter.cc (added)
-
src/Common/Stats/Counter.h (added)
-
src/Common/Stats/Heap.cc (added)
-
src/Common/Stats/Heap.h (moved) (moved from src/Common/Heap.h ) (1 diff)
-
src/Common/Stats/Stats.cc (added)
-
src/Common/Stats/Time.cc (added)
-
src/Common/Stats/Time.h (added)
-
src/Common/module.mk (modified) (1 diff)
-
src/Common/utility.h (modified) (1 diff)
-
src/CompilationState.cc (modified) (2 diffs)
-
src/CompilationState.h (modified) (2 diffs)
-
src/Concurrency/Waitfor.cc (modified) (1 diff)
-
src/Concurrency/module.mk (modified) (1 diff)
-
src/ControlStruct/ExceptTranslate.cc (modified) (3 diffs)
-
src/ControlStruct/ForExprMutator.cc (modified) (4 diffs)
-
src/ControlStruct/LabelFixer.cc (modified) (7 diffs)
-
src/ControlStruct/LabelGenerator.cc (modified) (3 diffs)
-
src/ControlStruct/module.mk (modified) (1 diff)
-
src/GenPoly/Box.cc (modified) (2 diffs)
-
src/GenPoly/GenPoly.cc (modified) (2 diffs)
-
src/GenPoly/GenPoly.h (modified) (1 diff)
-
src/GenPoly/InstantiateGeneric.cc (modified) (1 diff)
-
src/GenPoly/Specialize.cc (modified) (3 diffs)
-
src/GenPoly/module.mk (modified) (1 diff)
-
src/InitTweak/FixInit.cc (modified) (2 diffs)
-
src/InitTweak/InitTweak.cc (modified) (5 diffs)
-
src/InitTweak/InitTweak.h (modified) (2 diffs)
-
src/InitTweak/module.mk (modified) (1 diff)
-
src/MakeLibCfa.cc (modified) (2 diffs)
-
src/Makefile.am (modified) (4 diffs)
-
src/Makefile.in (modified) (22 diffs)
-
src/Parser/DeclarationNode.cc (modified) (2 diffs)
-
src/Parser/ExpressionNode.cc (modified) (6 diffs)
-
src/Parser/ParseNode.h (modified) (3 diffs)
-
src/Parser/TypeData.cc (modified) (3 diffs)
-
src/Parser/TypeData.h (modified) (5 diffs)
-
src/Parser/lex.ll (modified) (7 diffs)
-
src/Parser/module.mk (modified) (1 diff)
-
src/Parser/parser.yy (modified) (19 diffs)
-
src/ResolvExpr/AlternativeFinder.cc (modified) (1 diff)
-
src/ResolvExpr/CommonType.cc (modified) (4 diffs)
-
src/ResolvExpr/ConversionCost.cc (modified) (8 diffs)
-
src/ResolvExpr/Cost.h (modified) (14 diffs)
-
src/ResolvExpr/RenameVars.cc (modified) (4 diffs)
-
src/ResolvExpr/ResolveAssertions.cc (modified) (14 diffs)
-
src/ResolvExpr/ResolveAssertions.h (modified) (1 diff)
-
src/ResolvExpr/Resolver.cc (modified) (27 diffs)
-
src/ResolvExpr/Resolver.h (modified) (2 diffs)
-
src/ResolvExpr/TypeEnvironment.cc (modified) (4 diffs)
-
src/ResolvExpr/TypeEnvironment.h (modified) (4 diffs)
-
src/ResolvExpr/Unify.cc (modified) (4 diffs)
-
src/ResolvExpr/module.mk (modified) (1 diff)
-
src/ResolvExpr/typeops.h (modified) (3 diffs)
-
src/SymTab/Indexer.cc (modified) (10 diffs)
-
src/SymTab/Indexer.h (modified) (5 diffs)
-
src/SymTab/Mangler.cc (modified) (5 diffs)
-
src/SymTab/Mangler.h (modified) (1 diff)
-
src/SymTab/ManglerCommon.cc (modified) (2 diffs)
-
src/SymTab/Validate.cc (modified) (2 diffs)
-
src/SymTab/module.mk (modified) (1 diff)
-
src/SynTree/AddressExpr.cc (modified) (2 diffs)
-
src/SynTree/Attribute.cc (modified) (1 diff)
-
src/SynTree/BaseSyntaxNode.h (modified) (2 diffs)
-
src/SynTree/BasicType.cc (modified) (3 diffs)
-
src/SynTree/Constant.cc (modified) (2 diffs)
-
src/SynTree/Declaration.cc (modified) (1 diff)
-
src/SynTree/Declaration.h (modified) (8 diffs)
-
src/SynTree/Expression.cc (modified) (48 diffs)
-
src/SynTree/Expression.h (modified) (2 diffs)
-
src/SynTree/Label.h (modified) (1 diff)
-
src/SynTree/Mutator.h (modified) (1 diff)
-
src/SynTree/Statement.h (modified) (23 diffs)
-
src/SynTree/SynTree.h (modified) (3 diffs)
-
src/SynTree/Type.cc (modified) (3 diffs)
-
src/SynTree/Type.h (modified) (3 diffs)
-
src/SynTree/TypeSubstitution.cc (modified) (3 diffs)
-
src/SynTree/TypeSubstitution.h (modified) (11 diffs)
-
src/SynTree/Visitor.h (modified) (1 diff)
-
src/SynTree/module.mk (modified) (1 diff)
-
src/Tuples/TupleExpansion.cc (modified) (4 diffs)
-
src/Tuples/Tuples.h (modified) (3 diffs)
-
src/Tuples/module.mk (modified) (1 diff)
-
src/Validate/module.mk (modified) (1 diff)
-
src/config.h.in (modified) (7 diffs)
-
src/include/cassert (modified) (1 diff)
-
src/main.cc (modified) (22 diffs)
-
tests/.expect/KRfunctions.x64.txt (modified) (2 diffs)
-
tests/.expect/KRfunctions.x86.txt (modified) (2 diffs)
-
tests/.expect/abs.txt (modified) (1 diff)
-
tests/.expect/ato.txt (modified) (1 diff)
-
tests/.expect/attributes.x64.txt (modified) (1 diff)
-
tests/.expect/attributes.x86.txt (modified) (1 diff)
-
tests/.expect/castError.txt (modified) (4 diffs)
-
tests/.expect/completeTypeError.txt (modified) (2 diffs)
-
tests/.expect/complex.txt (modified) (1 diff)
-
tests/.expect/declarationSpecifier.x64.txt (modified) (2 diffs)
-
tests/.expect/declarationSpecifier.x86.txt (modified) (2 diffs)
-
tests/.expect/extension.x64.txt (modified) (1 diff)
-
tests/.expect/extension.x86.txt (modified) (1 diff)
-
tests/.expect/functions.x64.txt (modified) (8 diffs)
-
tests/.expect/functions.x86.txt (modified) (8 diffs)
-
tests/.expect/gccExtensions.x64.txt (modified) (2 diffs)
-
tests/.expect/gccExtensions.x86.txt (modified) (2 diffs)
-
tests/.expect/identity.txt (modified) (1 diff)
-
tests/.expect/io1.txt (modified) (1 diff)
-
tests/.expect/loopctrl.txt (modified) (3 diffs)
-
tests/.expect/math1.txt (modified) (1 diff)
-
tests/.expect/math2.txt (modified) (2 diffs)
-
tests/.expect/math3.txt (modified) (2 diffs)
-
tests/.expect/math4.txt (modified) (1 diff)
-
tests/.expect/minmax.txt (modified) (2 diffs)
-
tests/.expect/references.txt (modified) (1 diff)
-
tests/.expect/sum.txt (modified) (1 diff)
-
tests/Makefile.am (modified) (6 diffs)
-
tests/Makefile.in (modified) (9 diffs)
-
tests/array.cfa (modified) (2 diffs)
-
tests/builtins/sync.cfa (modified) (7 diffs)
-
tests/castError.cfa (modified) (2 diffs)
-
tests/completeTypeError.cfa (modified) (5 diffs)
-
tests/concurrent/coroutineThen.cfa (added)
-
tests/concurrent/examples/.expect/gortn.txt (added)
-
tests/concurrent/examples/boundedBufferEXT.cfa (modified) (3 diffs)
-
tests/concurrent/examples/boundedBufferINT.cfa (modified) (3 diffs)
-
tests/concurrent/examples/datingService.cfa (modified) (3 diffs)
-
tests/concurrent/examples/gortn.cfa (added)
-
tests/concurrent/examples/matrixSum.cfa (modified) (2 diffs)
-
tests/concurrent/examples/quickSort.cfa (modified) (3 diffs)
-
tests/concurrent/examples/quickSort.generic.cfa (added)
-
tests/concurrent/waitfor/parse2.cfa (modified) (2 diffs)
-
tests/config.py.in (modified) (1 diff)
-
tests/coroutine/.expect/devicedriver.txt (added)
-
tests/coroutine/.expect/fmtLines.txt (modified) (2 diffs)
-
tests/coroutine/.in/devicedriver.txt (added)
-
tests/coroutine/.in/fmtLines.txt (modified) (2 diffs)
-
tests/coroutine/cntparens.cfa (added)
-
tests/coroutine/devicedriver.cfa (added)
-
tests/coroutine/fibonacci.cfa (modified) (2 diffs)
-
tests/coroutine/fibonacci_1.cfa (modified) (4 diffs)
-
tests/coroutine/fmtLines.cfa (modified) (2 diffs)
-
tests/coroutine/pingpong.cfa (modified) (4 diffs)
-
tests/coroutine/prodcons.cfa (modified) (2 diffs)
-
tests/coroutine/runningTotal.cfa (modified) (2 diffs)
-
tests/coroutine/suspend_then.cfa (added)
-
tests/declarationSpecifier.cfa (modified) (2 diffs)
-
tests/forall.cfa (modified) (2 diffs)
-
tests/function-operator.cfa (modified) (2 diffs)
-
tests/io1.cfa (modified) (2 diffs)
-
tests/io2.cfa (modified) (2 diffs)
-
tests/literals.cfa (modified) (4 diffs)
-
tests/loopctrl.cfa (modified) (3 diffs)
-
tests/math1.cfa (modified) (2 diffs)
-
tests/numericConstants.cfa (modified) (2 diffs)
-
tests/preempt_longrun/Makefile.am (deleted)
-
tests/preempt_longrun/block.c (deleted)
-
tests/preempt_longrun/coroutine.c (deleted)
-
tests/preempt_longrun/disjoint.c (deleted)
-
tests/preempt_longrun/preempt.c (deleted)
-
tests/preempt_longrun/wait.c (deleted)
-
tests/pybin/settings.py (modified) (7 diffs)
-
tests/pybin/test_run.py (modified) (1 diff)
-
tests/pybin/tools.py (modified) (13 diffs)
-
tests/raii/.expect/ctor-autogen-ERR1.txt (modified) (4 diffs)
-
tests/raii/init_once.cfa (modified) (2 diffs)
-
tests/rational.cfa (modified) (3 diffs)
-
tests/sum.cfa (modified) (2 diffs)
-
tests/test.py (modified) (19 diffs)
-
tests/warnings/.expect/self-assignment.txt (modified) (2 diffs)
-
tests/warnings/self-assignment.cfa (modified) (1 diff)
-
tools/Makefile.in (modified) (1 diff)
-
tools/PrettyGitLogs.sh (modified) (1 diff)
-
tools/expanded-line-count.sh (added)
-
tools/prettyprinter/Makefile.in (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
r6a9d4b4 r933f32f 10 10 config.py 11 11 stamp-h1 12 libtool 12 13 /Makefile 13 14 **/Makefile … … 49 50 libcfa/arm-nolib/ 50 51 51 52 52 # generated by bison and lex from parser.yy and lex.ll 53 53 src/Parser/parser.output -
Jenkins/FullBuild
r6a9d4b4 r933f32f 17 17 18 18 parallel ( 19 gcc_6_x64: { trigger_build( 'gcc-6', 'x64' , true) },20 gcc_6_x86: { trigger_build( 'gcc-6', 'x86' , true) },21 gcc_5_x64: { trigger_build( 'gcc-5', 'x64' , false) },22 gcc_5_x86: { trigger_build( 'gcc-5', 'x86' , false) },23 clang_x64: { trigger_build( 'clang', 'x64' , false) },24 clang_x86: { trigger_build( 'clang', 'x86' , false) },19 gcc_6_x64: { trigger_build( 'gcc-6', 'x64' ) }, 20 gcc_6_x86: { trigger_build( 'gcc-6', 'x86' ) }, 21 gcc_5_x64: { trigger_build( 'gcc-5', 'x64' ) }, 22 gcc_5_x86: { trigger_build( 'gcc-5', 'x86' ) }, 23 clang_x64: { trigger_build( 'clang', 'x64' ) }, 24 clang_x86: { trigger_build( 'clang', 'x86' ) }, 25 25 ) 26 26 } 27 } 27 28 28 //Push latest changes to do-lang repo 29 push_build() 30 } 29 promote_email(true) 31 30 } 32 31 … … 43 42 44 43 //Send email to notify the failure 45 promote_ failure_email()44 promote_email(false) 46 45 } 47 46 … … 57 56 //=========================================================================================================== 58 57 59 def trigger_build(String cc, String arch , Boolean publish) {58 def trigger_build(String cc, String arch) { 60 59 def result = build job: 'Cforall/master', \ 61 60 parameters: [ \ … … 77 76 [$class: 'BooleanParameterValue', \ 78 77 name: 'Publish', \ 79 value: publish], \78 value: true], \ 80 79 [$class: 'BooleanParameterValue', \ 81 80 name: 'Silent', \ … … 89 88 sh("wget -q -O - http://localhost:8084/jenkins/job/Cforall/job/master/${result.number}/consoleText") 90 89 error(result.result) 91 }92 }93 94 def push_build() {95 //Don't use the build_stage function which outputs the compiler96 stage('Push') {97 98 status_prefix = 'Push'99 100 def out_dir = pwd tmp: true101 sh "mkdir -p ${out_dir}"102 103 //checkout the code to make sure this is a valid git repo104 checkout scm105 106 collect_git_info()107 108 //parse git logs to find what changed109 sh "git remote > ${out_dir}/GIT_REMOTE"110 git_remote = readFile("${out_dir}/GIT_REMOTE")111 remoteDoLangExists = git_remote.contains("DoLang")112 113 if( !remoteDoLangExists ) {114 sh 'git remote add DoLang git@gitlab.do-lang.org:internal/cfa-cc.git'115 }116 117 //sh "GIT_SSH_COMMAND=\"ssh -v\" git push DoLang ${gitRefNewValue}:master"118 echo('BUILD NOT PUSH SINCE DO-LANG SERVER WAS DOWN')119 90 } 120 91 } … … 141 112 142 113 //Email notification on a full build failure 143 def promote_ failure_email() {114 def promote_email(boolean success) { 144 115 echo('notifying users') 116 117 def result = success ? "PROMOTE - SUCCESS" : "PROMOTE - FAILURE" 145 118 146 119 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line 147 120 //Configurations for email format 148 def email_subject = "[cforall git][PROMOTE - FAILURE]" 149 def email_body = """This is an automated email from the Jenkins build machine. It was 150 generated because of a git hooks/post-receive script following 151 a ref change was pushed to the repository containing 152 the project "UNNAMED PROJECT". 121 def email_subject = "[cforall git][${result}]" 122 def email_body = """<p>This is an automated email from the Jenkins build machine. It was 123 generated following the result of the C\u2200 nightly build.</p> 153 124 154 Check console output at ${env.BUILD_URL} to view the results. 125 <p>Check console output at ${env.BUILD_URL} to view the results.</p> 155 126 156 - Status -------------------------------------------------------------- 127 <p>- Status --------------------------------------------------------------</p> 157 128 158 PROMOTE FAILURE 129 <p>${result}</p> 130 131 <p>- Performance ---------------------------------------------------------</p> 132 133 <img src="https://cforall.uwaterloo.ca/jenkins/job/Cforall/job/master/plot/Compilation/getPlot?index=0" > 134 135 <p>- Logs ----------------------------------------------------------------</p> 159 136 """ 160 137 … … 162 139 163 140 //send email notification 164 emailext body: email_body, subject: email_subject, to: email_to, attachLog: true141 emailext body: email_body, subject: email_subject, to: email_to, attachLog: !success 165 142 } -
Jenkinsfile
r6a9d4b4 r933f32f 1 1 #!groovy 2 3 import groovy.transform.Field 2 4 3 5 //=========================================================================================================== … … 22 24 wrap([$class: 'TimestamperBuildWrapper']) { 23 25 24 notify_server(0)25 26 26 Settings = prepare_build() 27 27 … … 34 34 checkout() 35 35 36 notify_server(0)37 38 36 build() 39 37 … … 50 48 BuildDir = pwd tmp: true 51 49 SrcDir = pwd tmp: false 52 53 notify_server(45)54 50 } 55 51 } … … 72 68 finally { 73 69 //Send email with final results if this is not a full build 74 if( Settings && !Settings.Silent ) { 75 email(log_needed, Settings.IsSandbox) 76 } 70 email(log_needed) 77 71 78 72 echo 'Build Completed' … … 116 110 //Also specify the compiler by hand 117 111 targets="" 118 if( Settings.RunAllTests ) {112 if( Settings.RunAllTests || Settings.RunBenchmark ) { 119 113 targets="--with-target-hosts='host:debug,host:nodebug'" 120 114 } else { … … 153 147 dir (BuildDir) { 154 148 //Append bench results 155 sh " ${SrcDir}/benchmark/jenkins.sh ${Settings.GitNewRef} ${Settings.Architecture} ${BuildDir}/bench.json"149 sh "make --no-print-directory -C benchmark jenkins" 156 150 } 157 151 } … … 176 170 build_stage('Publish') { 177 171 178 if( !Settings.Publish ) return 172 if( Settings.Publish && !Settings.RunBenchmark ) { echo 'No results to publish!!!' } 173 174 def groupCompile = new PlotGroup('Compilation', 'seconds', true) 175 def groupConcurrency = new PlotGroup('Concurrency', 'nanoseconds', false) 179 176 180 177 //Then publish the results 181 sh 'curl --silent --show-error -H \'Content-Type: application/json\' --data @${BuildDir}/bench.json https://cforall.uwaterloo.ca:8082/jenkins/publish > /dev/null || true' 178 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile' , groupCompile , 'Compilation') 179 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch', groupConcurrency, 'Context Switching') 180 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex' , groupConcurrency, 'Mutual Exclusion') 181 do_plot(Settings.RunBenchmark && Settings.Publish, 'signal' , groupConcurrency, 'Internal and External Scheduling') 182 182 } 183 183 } … … 196 196 197 197 return """ 198 <pre> 198 199 The branch ${env.BRANCH_NAME} has been updated. 199 200 ${gitUpdate} 200 201 Check console output at ${env.BUILD_URL} to view the results. 202 203 - Status -------------------------------------------------------------- 204 205 BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result} 206 207 - Log ----------------------------------------------------------------- 201 </pre> 202 203 <p>Check console output at ${env.BUILD_URL} to view the results.</p> 204 205 <p>- Status --------------------------------------------------------------</p> 206 207 <p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p> 208 209 <p>- Log -----------------------------------------------------------------</p> 210 211 <pre> 208 212 ${gitLog} 209 ----------------------------------------------------------------------- 213 </pre> 214 215 <p>-----------------------------------------------------------------------</p> 216 <pre> 210 217 Summary of changes: 211 218 ${gitDiff} 219 </pre> 212 220 """ 213 221 } 214 222 215 223 //Standard build email notification 216 def email(boolean log , boolean bIsSandbox) {224 def email(boolean log) { 217 225 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line 218 226 //Configurations for email format … … 221 229 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase() 222 230 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}" 223 def email_body = """ This is an automated email from the Jenkins build machine. It was231 def email_body = """<p>This is an automated email from the Jenkins build machine. It was 224 232 generated because of a git hooks/post-receive script following 225 a ref change which was pushed to the C forall repository.233 a ref change which was pushed to the C\u2200 repository.</p> 226 234 """ + GitLogMessage() 227 235 228 def email_to = "cforall@lists.uwaterloo.ca"229 230 if( Settings && !Settings. IsSandbox) {236 def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca" 237 238 if( Settings && !Settings.Silent ) { 231 239 //send email notification 232 240 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log … … 311 319 } 312 320 321 this.IsSandbox = (branch == "jenkins-sandbox") 313 322 this.RunAllTests = param.RunAllTests 314 323 this.RunBenchmark = param.RunBenchmark … … 316 325 this.Publish = param.Publish 317 326 this.Silent = param.Silent 318 this.IsSandbox = (branch == "jenkins-sandbox")319 327 320 328 def full = param.RunAllTests ? " (Full)" : "" … … 333 341 this.GitNewRef = '' 334 342 this.GitOldRef = '' 343 } 344 } 345 346 class PlotGroup implements Serializable { 347 public String name 348 public String unit 349 public boolean log 350 351 PlotGroup(String name, String unit, boolean log) { 352 this.name = name 353 this.unit = unit 354 this.log = log 335 355 } 336 356 } … … 398 418 } 399 419 400 def notify_server(int wait) {401 sh """curl --silent --show-error --data "wait=${wait}" -X POST https://cforall.uwaterloo.ca:8082/jenkins/notify > /dev/null || true"""402 return403 }404 405 420 def make_doc() { 406 421 def err = null … … 417 432 } 418 433 } 434 435 def do_plot(boolean new_data, String file, PlotGroup group, String title) { 436 437 if(new_data) { 438 echo "Publishing new data" 439 } 440 441 def series = new_data ? [[ 442 file: "${file}.csv", 443 exclusionValues: '', 444 displayTableFlag: false, 445 inclusionFlag: 'OFF', 446 url: '' 447 ]] : []; 448 449 echo "file is ${BuildDir}/benchmark/${file}.csv, group ${group}, title ${title}" 450 dir("${BuildDir}/benchmark/") { 451 plot csvFileName: "cforall-${env.BRANCH_NAME}-${file}.csv", 452 csvSeries: series, 453 group: "${group.name}", 454 title: "${title}", 455 style: 'lineSimple', 456 exclZero: false, 457 keepRecords: false, 458 logarithmic: group.log, 459 numBuilds: '120', 460 useDescr: true, 461 yaxis: group.unit, 462 yaxisMaximum: '', 463 yaxisMinimum: '' 464 } 465 } -
Makefile.am
r6a9d4b4 r933f32f 11 11 ## Created On : Sun May 31 22:14:18 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Wed Dec 14 14:20:48 201614 ## Update Count : 1513 ## Last Modified On : Sat Feb 2 16:54:42 2019 14 ## Update Count : 21 15 15 ############################################################################### 16 16 … … 18 18 ACLOCAL_AMFLAGS = -I automake 19 19 20 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* 21 # order important 20 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* # order important 22 21 23 22 SUBDIRS = driver src . @LIBCFA_TARGET_DIRS@ -
Makefile.in
r6a9d4b4 r933f32f 250 250 distcleancheck_listfiles = find . -type f -print 251 251 ACLOCAL = @ACLOCAL@ 252 ALLOCA = @ALLOCA@253 252 AMTAR = @AMTAR@ 254 253 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 396 395 AUTOMAKE_OPTIONS = foreign # do not require all the GNU file names 397 396 ACLOCAL_AMFLAGS = -I automake 398 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* 397 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* # order important 399 398 SUBDIRS = driver src . @LIBCFA_TARGET_DIRS@ 400 399 noinst_DATA = @LIBCFA_TARGET_MAKEFILES@ … … 928 927 .PRECIOUS: Makefile 929 928 930 # order important931 929 932 930 @LIBCFA_TARGET_MAKEFILES@ : Makefile $(srcdir)/libcfa/configure -
automake/cfa.m4
r6a9d4b4 r933f32f 80 80 esac 81 81 ]) 82 83 # http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m4 84 AC_DEFUN([M4CFA_CHECK_COMPILE_FLAG], 85 [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF 86 AS_VAR_PUSHDEF([CACHEVAR],[m4cfa_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl 87 AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ 88 m4cfa_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS 89 _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" 90 AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], 91 [AS_VAR_SET(CACHEVAR,[yes])], 92 [AS_VAR_SET(CACHEVAR,[no])]) 93 _AC_LANG_PREFIX[]FLAGS=$m4cfa_check_save_flags]) 94 AS_VAR_IF(CACHEVAR,yes, 95 [m4_default([$2], :)], 96 [m4_default([$3], :)]) 97 AS_VAR_POPDEF([CACHEVAR])dnl 98 ])dnl M4CFA_CHECK_COMPILE_FLAGS -
benchmark/Makefile.am
r6a9d4b4 r933f32f 21 21 include $(top_srcdir)/src/cfa.make 22 22 23 24 25 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread 26 AM_CFAFLAGS = -quiet -in-tree -nodebug 27 AM_UPPFLAGS = -quiet -nodebug -multi 23 AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread 24 AM_CFAFLAGS = -quiet -nodebug -in-tree 25 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14 26 27 BENCH_V_CC = $(__bench_v_CC_$(__quiet)) 28 BENCH_V_CFA = $(__bench_v_CFA_$(__quiet)) 29 BENCH_V_CXX = $(__bench_v_CXX_$(__quiet)) 30 BENCH_V_GOC = $(__bench_v_GOC_$(__quiet)) 31 BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet)) 32 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet)) 33 34 __quiet = verbose 35 __bench_v_CC_quiet = @ 36 __bench_v_CFA_quiet = @ 37 __bench_v_CXX_quiet = @ 38 __bench_v_GOC_quiet = @ 39 __bench_v_JAVAC_quiet = @ 40 __bench_v_UPP_quiet = @ 41 __bench_v_CC_verbose = $(AM_V_CC) 42 __bench_v_CFA_verbose = $(AM_V_CFA) 43 __bench_v_CXX_verbose = $(AM_V_CXX) 44 __bench_v_GOC_verbose = $(AM_V_GOC) 45 __bench_v_JAVAC_verbose = $(AM_V_JAVAC) 46 __bench_v_UPP_verbose = $(AM_V_UPP) 47 48 28 49 29 50 TOOLSDIR = ${abs_top_builddir}/tools/ … … 46 67 47 68 .NOTPARALLEL: 69 .PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv 48 70 49 71 ## ========================================================================================================= … … 60 82 61 83 %.runquiet : 62 @+make $(basename $@) CFLAGS="-w" 84 @+make $(basename $@) CFLAGS="-w" __quiet=quiet 63 85 @taskset -c 1 ./a.out 64 86 @rm -f a.out … … 73 95 ## ========================================================================================================= 74 96 97 FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@ 98 75 99 jenkins$(EXEEXT): 76 @echo "{"77 @echo -e '\t"githash": "'${githash}'",'78 @echo -e '\t"arch": "' ${arch} '",'79 100 @DOifskipcompile@ 80 @echo -e '\t"compile": {' 81 @+make compile TIME_FORMAT='%e,' PRINT_FORMAT='\t\t\"%s\" :' 82 @echo -e '\t\t"dummy" : {}' 83 @echo -e '\t},' 101 @+make compile.csv 84 102 @DOendif@ 85 @echo -e '\t"ctxswitch": {' 86 @echo -en '\t\t"coroutine":' 87 @+make ctxswitch-cfa_coroutine.runquiet 88 @echo -en '\t\t,"thread":' 89 @+make ctxswitch-cfa_thread.runquiet 90 @echo -e '\t},' 91 @echo -e '\t"mutex": [' 92 @echo -en '\t\t' 93 @+make mutex-cfa1.runquiet 94 @echo -en '\t\t,' 95 @+make mutex-cfa2.runquiet 96 @echo -e '\t],' 97 @echo -e '\t"scheduling": [' 98 @echo -en '\t\t' 99 @+make signal-cfa1.runquiet 100 @echo -en '\t\t,' 101 @+make signal-cfa2.runquiet 102 @echo -en '\t\t,' 103 @+make waitfor-cfa1.runquiet 104 @echo -en '\t\t,' 105 @+make waitfor-cfa2.runquiet 106 @echo -e '\n\t],' 107 @echo -e '\t"epoch": ' $(shell date +%s) 108 @echo "}" 103 @+make ctxswitch.csv 104 @+make mutex.csv 105 @+make signal.csv 106 @DOifskipcompile@ 107 @cat compile.csv 108 @DOendif@ 109 @cat ctxswitch.csv 110 @cat mutex.csv 111 @cat signal.csv 112 113 compile.csv: 114 @echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@ 115 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@ 116 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-attributes.make >> $@ 117 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-empty.make >> $@ 118 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-expression.make >> $@ 119 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-io.make >> $@ 120 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-monitor.make >> $@ 121 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-operators.make >> $@ 122 @+make TIME_FORMAT='%e' PRINT_FORMAT='' compile-typeof.make >> $@ 123 @$(srcdir)/fixcsv.sh $@ 124 125 ctxswitch.csv: 126 @echo "coroutine,thread" > $@ 127 @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@ 128 @+make ctxswitch-cfa_thread.runquiet >> $@ 129 @$(srcdir)/fixcsv.sh $@ 130 131 mutex.csv: 132 @echo "1-monitor,2-monitor" > $@ 133 @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@ 134 @+make mutex-cfa2.runquiet >> $@ 135 @$(srcdir)/fixcsv.sh $@ 136 137 signal.csv: 138 @echo "signal-1,signal-2,waitfor-1,waitfor-2" > $@ 139 @+make signal-cfa1.runquiet >> $@ && echo -n ',' >> $@ 140 @+make signal-cfa2.runquiet >> $@ && echo -n ',' >> $@ 141 @+make waitfor-cfa1.runquiet >> $@ && echo -n ',' >> $@ 142 @+make waitfor-cfa2.runquiet >> $@ 143 @$(srcdir)/fixcsv.sh $@ 109 144 110 145 ## ========================================================================================================= 111 146 loop$(EXEEXT): 112 $( AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c147 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c 113 148 114 149 function$(EXEEXT): 115 $( AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c150 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c 116 151 117 152 fetch_add$(EXEEXT): 118 $(AM_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 153 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 154 155 tls-fetch_add$(EXEEXT): 156 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/tls-fetch_add.c 119 157 120 158 ## ========================================================================================================= … … 123 161 function.run \ 124 162 fetch_add.run \ 163 tls-fetch_add.run \ 125 164 ctxswitch-pthread.run \ 126 165 ctxswitch-cfa_coroutine.run \ … … 139 178 140 179 ctxswitch-kos_fibre$(EXEEXT): 141 $( AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp -I$(LIBFIBRE_DIR) -lfibre180 $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp -I$(LIBFIBRE_DIR) -lfibre 142 181 143 182 ctxswitch-kos_fibre2$(EXEEXT): 144 $( AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre183 $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre 145 184 endif 146 185 … … 148 187 149 188 ctxswitch-pthread$(EXEEXT): 150 $( AM_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c189 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c 151 190 152 191 ctxswitch-cfa_coroutine$(EXEEXT): 153 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa192 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa 154 193 155 194 ctxswitch-cfa_thread$(EXEEXT): 156 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa195 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa 157 196 158 197 ctxswitch-cfa_thread2$(EXEEXT): 159 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa198 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa 160 199 161 200 ctxswitch-upp_coroutine$(EXEEXT): 162 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc201 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc 163 202 164 203 ctxswitch-upp_thread$(EXEEXT): 165 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc204 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc 166 205 167 206 ctxswitch-goroutine$(EXEEXT): 168 $( AM_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go207 $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go 169 208 170 209 ctxswitch-java_thread$(EXEEXT): 171 $( AM_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java210 $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java 172 211 @echo "#!/bin/sh" > a.out 173 212 @echo "java JavaThread" >> a.out … … 187 226 188 227 mutex-pthread_lock$(EXEEXT): 189 $( AM_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c228 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c 190 229 191 230 mutex-upp$(EXEEXT): 192 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc231 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc 193 232 194 233 mutex-cfa1$(EXEEXT): 195 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa1.cfa234 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa1.cfa 196 235 197 236 mutex-cfa2$(EXEEXT): 198 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa2.cfa237 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa2.cfa 199 238 200 239 mutex-cfa4$(EXEEXT): 201 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa4.cfa240 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa4.cfa 202 241 203 242 mutex-java_thread$(EXEEXT): 204 $( AM_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java243 $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java 205 244 @echo "#!/bin/sh" > a.out 206 245 @echo "java JavaThread" >> a.out … … 217 256 218 257 signal-pthread_cond$(EXEEXT): 219 $( AM_V_CC)$(COMPILE) -DBENCH_N=500000 $(srcdir)/schedint/pthreads.c258 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000 $(srcdir)/schedint/pthreads.c 220 259 221 260 signal-upp$(EXEEXT): 222 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc261 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc 223 262 224 263 signal-cfa1$(EXEEXT): 225 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa1.cfa264 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa1.cfa 226 265 227 266 signal-cfa2$(EXEEXT): 228 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa2.cfa267 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa2.cfa 229 268 230 269 signal-cfa4$(EXEEXT): 231 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa4.cfa270 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa4.cfa 232 271 233 272 signal-java_thread$(EXEEXT): 234 $( AM_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java273 $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java 235 274 @echo "#!/bin/sh" > a.out 236 275 @echo "java JavaThread" >> a.out … … 246 285 247 286 waitfor-upp$(EXEEXT): 248 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc287 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc 249 288 250 289 waitfor-cfa1$(EXEEXT): 251 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa1.cfa290 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa1.cfa 252 291 253 292 waitfor-cfa2$(EXEEXT): 254 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa2.cfa293 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa2.cfa 255 294 256 295 waitfor-cfa4$(EXEEXT): 257 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa4.cfa296 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa4.cfa 258 297 259 298 ## ========================================================================================================= … … 269 308 270 309 creation-cfa_coroutine$(EXEEXT): 271 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa310 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa 272 311 273 312 creation-cfa_coroutine_eager$(EXEEXT): 274 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa -DEAGER313 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa -DEAGER 275 314 276 315 creation-cfa_thread$(EXEEXT): 277 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa316 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa 278 317 279 318 creation-upp_coroutine$(EXEEXT): 280 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc319 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc 281 320 282 321 creation-upp_thread$(EXEEXT): 283 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc322 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc 284 323 285 324 creation-pthread$(EXEEXT): 286 $( AM_V_CC)$(COMPILE) -DBENCH_N=250000 $(srcdir)/creation/pthreads.c325 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=250000 $(srcdir)/creation/pthreads.c 287 326 288 327 creation-goroutine$(EXEEXT): 289 $( AM_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go328 $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go 290 329 291 330 creation-java_thread$(EXEEXT): 292 $( AM_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java331 $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java 293 332 @echo "#!/bin/sh" > a.out 294 333 @echo "java JavaThread" >> a.out … … 311 350 312 351 compile-array$(EXEEXT): 313 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa352 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa 314 353 315 354 compile-attributes$(EXEEXT): 316 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa355 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa 317 356 318 357 compile-empty$(EXEEXT): 319 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa358 @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa 320 359 321 360 compile-expression$(EXEEXT): 322 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa361 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa 323 362 324 363 compile-io$(EXEEXT): 325 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa364 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa 326 365 327 366 compile-monitor$(EXEEXT): 328 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa367 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa 329 368 330 369 compile-operators$(EXEEXT): 331 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa370 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa 332 371 333 372 compile-thread$(EXEEXT): 334 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa373 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa 335 374 336 375 compile-typeof$(EXEEXT): 337 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa338 376 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa 377 -
benchmark/Makefile.in
r6a9d4b4 r933f32f 200 200 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 201 201 ACLOCAL = @ACLOCAL@ 202 ALLOCA = @ALLOCA@203 202 AMTAR = @AMTAR@ 204 203 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 372 371 373 372 # applies to both programs 374 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread 375 AM_CFAFLAGS = -quiet -in-tree -nodebug 376 AM_UPPFLAGS = -quiet -nodebug -multi 373 AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread 374 AM_CFAFLAGS = -quiet -nodebug -in-tree 375 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14 376 BENCH_V_CC = $(__bench_v_CC_$(__quiet)) 377 BENCH_V_CFA = $(__bench_v_CFA_$(__quiet)) 378 BENCH_V_CXX = $(__bench_v_CXX_$(__quiet)) 379 BENCH_V_GOC = $(__bench_v_GOC_$(__quiet)) 380 BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet)) 381 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet)) 382 __quiet = verbose 383 __bench_v_CC_quiet = @ 384 __bench_v_CFA_quiet = @ 385 __bench_v_CXX_quiet = @ 386 __bench_v_GOC_quiet = @ 387 __bench_v_JAVAC_quiet = @ 388 __bench_v_UPP_quiet = @ 389 __bench_v_CC_verbose = $(AM_V_CC) 390 __bench_v_CFA_verbose = $(AM_V_CFA) 391 __bench_v_CXX_verbose = $(AM_V_CXX) 392 __bench_v_GOC_verbose = $(AM_V_GOC) 393 __bench_v_JAVAC_verbose = $(AM_V_JAVAC) 394 __bench_v_UPP_verbose = $(AM_V_UPP) 377 395 TOOLSDIR = ${abs_top_builddir}/tools/ 378 396 REPEAT = ${abs_top_builddir}/tools/repeat … … 383 401 PRINT_FORMAT = %20s: #Comments needed for spacing 384 402 dummy_SOURCES = dummyC.c dummyCXX.cpp 403 FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@ 385 404 CTXSWITCH_DEPEND = loop.run function.run fetch_add.run \ 386 ctxswitch-pthread.run ctxswitch-cfa_coroutine.run \387 ctxswitch-cfa_ thread.run ctxswitch-cfa_thread2.run \388 ctxswitch- upp_coroutine.run ctxswitch-upp_thread.run \389 ctxswitch- goroutine.run ctxswitch-java_thread.run \390 $(am__append_1)405 tls-fetch_add.run ctxswitch-pthread.run \ 406 ctxswitch-cfa_coroutine.run ctxswitch-cfa_thread.run \ 407 ctxswitch-cfa_thread2.run ctxswitch-upp_coroutine.run \ 408 ctxswitch-upp_thread.run ctxswitch-goroutine.run \ 409 ctxswitch-java_thread.run $(am__append_1) 391 410 testdir = $(top_srcdir)/tests 392 411 all: all-am … … 713 732 714 733 .NOTPARALLEL: 734 .PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv 715 735 716 736 all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT) … … 726 746 727 747 %.runquiet : 728 @+make $(basename $@) CFLAGS="-w" 748 @+make $(basename $@) CFLAGS="-w" __quiet=quiet 729 749 @taskset -c 1 ./a.out 730 750 @rm -f a.out … … 738 758 739 759 jenkins$(EXEEXT): 740 @echo "{"741 @echo -e '\t"githash": "'${githash}'",'742 @echo -e '\t"arch": "' ${arch} '",'743 760 @DOifskipcompile@ 744 @echo -e '\t"compile": {' 745 @+make compile TIME_FORMAT='%e,' PRINT_FORMAT='\t\t\"%s\" :' 746 @echo -e '\t\t"dummy" : {}' 747 @echo -e '\t},' 761 @+make compile.csv 748 762 @DOendif@ 749 @echo -e '\t"ctxswitch": {' 750 @echo -en '\t\t"coroutine":' 751 @+make ctxswitch-cfa_coroutine.runquiet 752 @echo -en '\t\t,"thread":' 753 @+make ctxswitch-cfa_thread.runquiet 754 @echo -e '\t},' 755 @echo -e '\t"mutex": [' 756 @echo -en '\t\t' 757 @+make mutex-cfa1.runquiet 758 @echo -en '\t\t,' 759 @+make mutex-cfa2.runquiet 760 @echo -e '\t],' 761 @echo -e '\t"scheduling": [' 762 @echo -en '\t\t' 763 @+make signal-cfa1.runquiet 764 @echo -en '\t\t,' 765 @+make signal-cfa2.runquiet 766 @echo -en '\t\t,' 767 @+make waitfor-cfa1.runquiet 768 @echo -en '\t\t,' 769 @+make waitfor-cfa2.runquiet 770 @echo -e '\n\t],' 771 @echo -e '\t"epoch": ' $(shell date +%s) 772 @echo "}" 763 @+make ctxswitch.csv 764 @+make mutex.csv 765 @+make signal.csv 766 @DOifskipcompile@ 767 @cat compile.csv 768 @DOendif@ 769 @cat ctxswitch.csv 770 @cat mutex.csv 771 @cat signal.csv 772 773 compile.csv: 774 @echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@ 775 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@ 776 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-attributes.make >> $@ 777 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-empty.make >> $@ 778 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-expression.make >> $@ 779 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-io.make >> $@ 780 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-monitor.make >> $@ 781 @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-operators.make >> $@ 782 @+make TIME_FORMAT='%e' PRINT_FORMAT='' compile-typeof.make >> $@ 783 @$(srcdir)/fixcsv.sh $@ 784 785 ctxswitch.csv: 786 @echo "coroutine,thread" > $@ 787 @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@ 788 @+make ctxswitch-cfa_thread.runquiet >> $@ 789 @$(srcdir)/fixcsv.sh $@ 790 791 mutex.csv: 792 @echo "1-monitor,2-monitor" > $@ 793 @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@ 794 @+make mutex-cfa2.runquiet >> $@ 795 @$(srcdir)/fixcsv.sh $@ 796 797 signal.csv: 798 @echo "signal-1,signal-2,waitfor-1,waitfor-2" > $@ 799 @+make signal-cfa1.runquiet >> $@ && echo -n ',' >> $@ 800 @+make signal-cfa2.runquiet >> $@ && echo -n ',' >> $@ 801 @+make waitfor-cfa1.runquiet >> $@ && echo -n ',' >> $@ 802 @+make waitfor-cfa2.runquiet >> $@ 803 @$(srcdir)/fixcsv.sh $@ 773 804 774 805 loop$(EXEEXT): 775 $( AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c806 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c 776 807 777 808 function$(EXEEXT): 778 $( AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c809 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c 779 810 780 811 fetch_add$(EXEEXT): 781 $(AM_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 812 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 813 814 tls-fetch_add$(EXEEXT): 815 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/tls-fetch_add.c 782 816 783 817 @WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre$(EXEEXT): 784 @WITH_LIBFIBRE_TRUE@ $( AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp -I$(LIBFIBRE_DIR) -lfibre818 @WITH_LIBFIBRE_TRUE@ $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp -I$(LIBFIBRE_DIR) -lfibre 785 819 786 820 @WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre2$(EXEEXT): 787 @WITH_LIBFIBRE_TRUE@ $( AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre821 @WITH_LIBFIBRE_TRUE@ $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre 788 822 789 823 ctxswitch$(EXEEXT): $(CTXSWITCH_DEPEND) 790 824 791 825 ctxswitch-pthread$(EXEEXT): 792 $( AM_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c826 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c 793 827 794 828 ctxswitch-cfa_coroutine$(EXEEXT): 795 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa829 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa 796 830 797 831 ctxswitch-cfa_thread$(EXEEXT): 798 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa832 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa 799 833 800 834 ctxswitch-cfa_thread2$(EXEEXT): 801 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa835 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa 802 836 803 837 ctxswitch-upp_coroutine$(EXEEXT): 804 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc838 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc 805 839 806 840 ctxswitch-upp_thread$(EXEEXT): 807 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc841 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc 808 842 809 843 ctxswitch-goroutine$(EXEEXT): 810 $( AM_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go844 $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go 811 845 812 846 ctxswitch-java_thread$(EXEEXT): 813 $( AM_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java847 $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java 814 848 @echo "#!/bin/sh" > a.out 815 849 @echo "java JavaThread" >> a.out … … 828 862 829 863 mutex-pthread_lock$(EXEEXT): 830 $( AM_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c864 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c 831 865 832 866 mutex-upp$(EXEEXT): 833 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc867 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc 834 868 835 869 mutex-cfa1$(EXEEXT): 836 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa1.cfa870 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa1.cfa 837 871 838 872 mutex-cfa2$(EXEEXT): 839 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa2.cfa873 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa2.cfa 840 874 841 875 mutex-cfa4$(EXEEXT): 842 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa4.cfa876 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa4.cfa 843 877 844 878 mutex-java_thread$(EXEEXT): 845 $( AM_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java879 $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java 846 880 @echo "#!/bin/sh" > a.out 847 881 @echo "java JavaThread" >> a.out … … 857 891 858 892 signal-pthread_cond$(EXEEXT): 859 $( AM_V_CC)$(COMPILE) -DBENCH_N=500000 $(srcdir)/schedint/pthreads.c893 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000 $(srcdir)/schedint/pthreads.c 860 894 861 895 signal-upp$(EXEEXT): 862 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc896 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc 863 897 864 898 signal-cfa1$(EXEEXT): 865 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa1.cfa899 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa1.cfa 866 900 867 901 signal-cfa2$(EXEEXT): 868 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa2.cfa902 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa2.cfa 869 903 870 904 signal-cfa4$(EXEEXT): 871 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa4.cfa905 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa4.cfa 872 906 873 907 signal-java_thread$(EXEEXT): 874 $( AM_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java908 $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java 875 909 @echo "#!/bin/sh" > a.out 876 910 @echo "java JavaThread" >> a.out … … 884 918 885 919 waitfor-upp$(EXEEXT): 886 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc920 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc 887 921 888 922 waitfor-cfa1$(EXEEXT): 889 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa1.cfa923 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa1.cfa 890 924 891 925 waitfor-cfa2$(EXEEXT): 892 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa2.cfa926 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa2.cfa 893 927 894 928 waitfor-cfa4$(EXEEXT): 895 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa4.cfa929 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa4.cfa 896 930 897 931 creation$(EXEEXT) :\ … … 906 940 907 941 creation-cfa_coroutine$(EXEEXT): 908 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa942 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa 909 943 910 944 creation-cfa_coroutine_eager$(EXEEXT): 911 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa -DEAGER945 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa -DEAGER 912 946 913 947 creation-cfa_thread$(EXEEXT): 914 $( AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa948 $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa 915 949 916 950 creation-upp_coroutine$(EXEEXT): 917 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc951 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc 918 952 919 953 creation-upp_thread$(EXEEXT): 920 $( AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc954 $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc 921 955 922 956 creation-pthread$(EXEEXT): 923 $( AM_V_CC)$(COMPILE) -DBENCH_N=250000 $(srcdir)/creation/pthreads.c957 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=250000 $(srcdir)/creation/pthreads.c 924 958 925 959 creation-goroutine$(EXEEXT): 926 $( AM_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go960 $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go 927 961 928 962 creation-java_thread$(EXEEXT): 929 $( AM_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java963 $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java 930 964 @echo "#!/bin/sh" > a.out 931 965 @echo "java JavaThread" >> a.out … … 943 977 944 978 compile-array$(EXEEXT): 945 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa979 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa 946 980 947 981 compile-attributes$(EXEEXT): 948 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa982 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa 949 983 950 984 compile-empty$(EXEEXT): 951 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa985 @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa 952 986 953 987 compile-expression$(EXEEXT): 954 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa988 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa 955 989 956 990 compile-io$(EXEEXT): 957 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa991 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa 958 992 959 993 compile-monitor$(EXEEXT): 960 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa994 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa 961 995 962 996 compile-operators$(EXEEXT): 963 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa997 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa 964 998 965 999 compile-thread$(EXEEXT): 966 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa1000 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa 967 1001 968 1002 compile-typeof$(EXEEXT): 969 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa1003 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa 970 1004 971 1005 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
benchmark/ctxswitch/cfa_cor.cfa
r6a9d4b4 r933f32f 11 11 } 12 12 13 void main( GreatSuspender & this ) {13 void main( __attribute__((unused)) GreatSuspender & this ) { 14 14 while( true ) { 15 15 suspend(); -
benchmark/ctxswitch/cfa_thrd2.cfa
r6a9d4b4 r933f32f 8 8 thread Fibre {}; 9 9 10 void main( Fibre & this) {10 void main(__attribute__((unused)) Fibre & this) { 11 11 while(!done) { 12 12 yield(); -
configure
r6a9d4b4 r933f32f 637 637 LIBOBJS 638 638 CFA_BACKEND_CC 639 ALLOCA 639 WITH_LIBTCMALLOC_FALSE 640 WITH_LIBTCMALLOC_TRUE 641 WITH_LIBPROFILER_FALSE 642 WITH_LIBPROFILER_TRUE 640 643 WITH_LIBFIBRE_FALSE 641 644 WITH_LIBFIBRE_TRUE … … 1961 1964 } # ac_fn_cxx_try_link 1962 1965 1963 # ac_fn_c_check_type LINENO TYPE VAR INCLUDES1964 # -------------------------------------------1965 # Tests whether TYPE exists after having included INCLUDES, setting cache1966 # variable VAR accordingly.1967 ac_fn_c_check_type ()1968 {1969 as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack1970 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&51971 $as_echo_n "checking for $2... " >&6; }1972 if eval \${$3+:} false; then :1973 $as_echo_n "(cached) " >&61974 else1975 eval "$3=no"1976 cat confdefs.h - <<_ACEOF >conftest.$ac_ext1977 /* end confdefs.h. */1978 $41979 int1980 main ()1981 {1982 if (sizeof ($2))1983 return 0;1984 ;1985 return 0;1986 }1987 _ACEOF1988 if ac_fn_c_try_compile "$LINENO"; then :1989 cat confdefs.h - <<_ACEOF >conftest.$ac_ext1990 /* end confdefs.h. */1991 $41992 int1993 main ()1994 {1995 if (sizeof (($2)))1996 return 0;1997 ;1998 return 0;1999 }2000 _ACEOF2001 if ac_fn_c_try_compile "$LINENO"; then :2002 2003 else2004 eval "$3=yes"2005 fi2006 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext2007 fi2008 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext2009 fi2010 eval ac_res=\$$32011 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&52012 $as_echo "$ac_res" >&6; }2013 eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno2014 2015 } # ac_fn_c_check_type2016 2017 1966 # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES 2018 1967 # ------------------------------------------------------- … … 2106 2055 } # ac_fn_c_check_header_mongrel 2107 2056 2108 # ac_fn_c_ find_intX_t LINENO BITS VAR2109 # ----------------------------------- 2110 # Finds a signed integer type with width BITS, setting cache variable VAR2111 # accordingly.2112 ac_fn_c_ find_intX_t()2057 # ac_fn_c_check_type LINENO TYPE VAR INCLUDES 2058 # ------------------------------------------- 2059 # Tests whether TYPE exists after having included INCLUDES, setting cache 2060 # variable VAR accordingly. 2061 ac_fn_c_check_type () 2113 2062 { 2114 2063 as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack 2115 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&52116 $as_echo_n "checking for int$2_t... " >&6; }2064 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 2065 $as_echo_n "checking for $2... " >&6; } 2117 2066 if eval \${$3+:} false; then : 2118 2067 $as_echo_n "(cached) " >&6 2119 2068 else 2120 2069 eval "$3=no" 2121 # Order is important - never check a type that is potentially smaller 2122 # than half of the expected target width. 2123 for ac_type in int$2_t 'int' 'long int' \ 2124 'long long int' 'short int' 'signed char'; do 2125 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 2070 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 2126 2071 /* end confdefs.h. */ 2127 $ac_includes_default 2128 enum { N = $2 / 2 - 1 }; 2072 $4 2129 2073 int 2130 2074 main () 2131 2075 { 2132 static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; 2133 test_array [0] = 0; 2134 return test_array [0]; 2135 2076 if (sizeof ($2)) 2077 return 0; 2136 2078 ; 2137 2079 return 0; … … 2141 2083 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 2142 2084 /* end confdefs.h. */ 2143 $ac_includes_default 2144 enum { N = $2 / 2 - 1 }; 2085 $4 2145 2086 int 2146 2087 main () 2147 2088 { 2148 static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) 2149 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; 2150 test_array [0] = 0; 2151 return test_array [0]; 2152 2089 if (sizeof (($2))) 2090 return 0; 2153 2091 ; 2154 2092 return 0; … … 2158 2096 2159 2097 else 2160 case $ac_type in #( 2161 int$2_t) : 2162 eval "$3=yes" ;; #( 2163 *) : 2164 eval "$3=\$ac_type" ;; 2165 esac 2098 eval "$3=yes" 2166 2099 fi 2167 2100 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 2168 2101 fi 2169 2102 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 2170 if eval test \"x\$"$3"\" = x"no"; then :2171 2172 else2173 break2174 fi2175 done2176 2103 fi 2177 2104 eval ac_res=\$$3 … … 2180 2107 eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno 2181 2108 2182 } # ac_fn_c_find_intX_t 2183 2184 # ac_fn_c_find_uintX_t LINENO BITS VAR 2185 # ------------------------------------ 2186 # Finds an unsigned integer type with width BITS, setting cache variable VAR 2187 # accordingly. 2188 ac_fn_c_find_uintX_t () 2189 { 2190 as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack 2191 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 2192 $as_echo_n "checking for uint$2_t... " >&6; } 2193 if eval \${$3+:} false; then : 2194 $as_echo_n "(cached) " >&6 2195 else 2196 eval "$3=no" 2197 # Order is important - never check a type that is potentially smaller 2198 # than half of the expected target width. 2199 for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 2200 'unsigned long long int' 'unsigned short int' 'unsigned char'; do 2201 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 2202 /* end confdefs.h. */ 2203 $ac_includes_default 2204 int 2205 main () 2206 { 2207 static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; 2208 test_array [0] = 0; 2209 return test_array [0]; 2210 2211 ; 2212 return 0; 2213 } 2214 _ACEOF 2215 if ac_fn_c_try_compile "$LINENO"; then : 2216 case $ac_type in #( 2217 uint$2_t) : 2218 eval "$3=yes" ;; #( 2219 *) : 2220 eval "$3=\$ac_type" ;; 2221 esac 2222 fi 2223 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 2224 if eval test \"x\$"$3"\" = x"no"; then : 2225 2226 else 2227 break 2228 fi 2229 done 2230 fi 2231 eval ac_res=\$$3 2232 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 2233 $as_echo "$ac_res" >&6; } 2234 eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno 2235 2236 } # ac_fn_c_find_uintX_t 2109 } # ac_fn_c_check_type 2237 2110 cat >config.log <<_ACEOF 2238 2111 This file contains any messages produced by compilers while … … 2667 2540 2668 2541 2542 # http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m4 2543 2669 2544 2670 2545 # don't use the default CFLAGS as they unconditonnaly add -O2 … … 3527 3402 "debug") ;; 3528 3403 "nolib") ;; 3404 "profile") ;; 3529 3405 *) 3530 3406 >&2 echo "Configuration must be 'debug', 'nodebug' or 'nolib'" … … 5183 5059 5184 5060 5185 # deprecated5186 5061 # These are often not installed and people miss seeing the "no", so stop the configure. 5187 5062 for ac_prog in 'bison -y' byacc … … 16734 16609 16735 16610 16736 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&516737 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }16738 set x ${MAKE-make}16739 ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`16740 if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :16741 $as_echo_n "(cached) " >&616742 else16743 cat >conftest.make <<\_ACEOF16744 SHELL = /bin/sh16745 all:16746 @echo '@@@%%%=$(MAKE)=@@@%%%'16747 _ACEOF16748 # GNU make sometimes prints "make[1]: Entering ...", which would confuse us.16749 case `${MAKE-make} -f conftest.make 2>/dev/null` in16750 *@@@%%%=?*=@@@%%%*)16751 eval ac_cv_prog_make_${ac_make}_set=yes;;16752 *)16753 eval ac_cv_prog_make_${ac_make}_set=no;;16754 esac16755 rm -f conftest.make16756 fi16757 if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then16758 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&516759 $as_echo "yes" >&6; }16760 SET_MAKE=16761 else16762 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&516763 $as_echo "no" >&6; }16764 SET_MAKE="MAKE=${MAKE-make}"16765 fi16766 16767 16611 16768 16612 # Checks for libraries. … … 16818 16662 16819 16663 16820 # Checks for header files. 16821 ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" 16822 if test "x$ac_cv_type_size_t" = xyes; then : 16823 16824 else 16825 16826 cat >>confdefs.h <<_ACEOF 16827 #define size_t unsigned int 16828 _ACEOF 16829 16830 fi 16831 16832 # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works 16833 # for constant arguments. Useless! 16834 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 16835 $as_echo_n "checking for working alloca.h... " >&6; } 16836 if ${ac_cv_working_alloca_h+:} false; then : 16664 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ProfilingIsEnabledForAllThreads in -lprofiler" >&5 16665 $as_echo_n "checking for ProfilingIsEnabledForAllThreads in -lprofiler... " >&6; } 16666 if ${ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads+:} false; then : 16837 16667 $as_echo_n "(cached) " >&6 16838 16668 else 16839 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16669 ac_check_lib_save_LIBS=$LIBS 16670 LIBS="-lprofiler $LIBS" 16671 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16840 16672 /* end confdefs.h. */ 16841 #include <alloca.h> 16673 16674 /* Override any GCC internal prototype to avoid an error. 16675 Use char because int might match the return type of a GCC 16676 builtin and then its argument prototype would still apply. */ 16677 #ifdef __cplusplus 16678 extern "C" 16679 #endif 16680 char ProfilingIsEnabledForAllThreads (); 16842 16681 int 16843 16682 main () 16844 16683 { 16845 char *p = (char *) alloca (2 * sizeof (int)); 16846 if (p) return 0; 16684 return ProfilingIsEnabledForAllThreads (); 16847 16685 ; 16848 16686 return 0; … … 16850 16688 _ACEOF 16851 16689 if ac_fn_c_try_link "$LINENO"; then : 16852 ac_cv_ working_alloca_h=yes16853 else 16854 ac_cv_ working_alloca_h=no16690 ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads=yes 16691 else 16692 ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads=no 16855 16693 fi 16856 16694 rm -f core conftest.err conftest.$ac_objext \ 16857 16695 conftest$ac_exeext conftest.$ac_ext 16858 fi 16859 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 16860 $as_echo "$ac_cv_working_alloca_h" >&6; } 16861 if test $ac_cv_working_alloca_h = yes; then 16862 16863 $as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h 16864 16865 fi 16866 16867 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 16868 $as_echo_n "checking for alloca... " >&6; } 16869 if ${ac_cv_func_alloca_works+:} false; then : 16696 LIBS=$ac_check_lib_save_LIBS 16697 fi 16698 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads" >&5 16699 $as_echo "$ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads" >&6; } 16700 if test "x$ac_cv_lib_profiler_ProfilingIsEnabledForAllThreads" = xyes; then : 16701 HAVE_LIBPROFILER=1 16702 else 16703 HAVE_LIBPROFILER=0 16704 fi 16705 16706 if test "$HAVE_LIBPROFILER" -eq 1; then 16707 WITH_LIBPROFILER_TRUE= 16708 WITH_LIBPROFILER_FALSE='#' 16709 else 16710 WITH_LIBPROFILER_TRUE='#' 16711 WITH_LIBPROFILER_FALSE= 16712 fi 16713 16714 16715 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for malloc in -ltcmalloc" >&5 16716 $as_echo_n "checking for malloc in -ltcmalloc... " >&6; } 16717 if ${ac_cv_lib_tcmalloc_malloc+:} false; then : 16870 16718 $as_echo_n "(cached) " >&6 16871 16719 else 16872 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16720 ac_check_lib_save_LIBS=$LIBS 16721 LIBS="-ltcmalloc $LIBS" 16722 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16873 16723 /* end confdefs.h. */ 16874 #ifdef __GNUC__ 16875 # define alloca __builtin_alloca 16876 #else 16877 # ifdef _MSC_VER 16878 # include <malloc.h> 16879 # define alloca _alloca 16880 # else 16881 # ifdef HAVE_ALLOCA_H 16882 # include <alloca.h> 16883 # else 16884 # ifdef _AIX 16885 #pragma alloca 16886 # else 16887 # ifndef alloca /* predefined by HP cc +Olibcalls */ 16888 void *alloca (size_t); 16889 # endif 16890 # endif 16891 # endif 16892 # endif 16724 16725 /* Override any GCC internal prototype to avoid an error. 16726 Use char because int might match the return type of a GCC 16727 builtin and then its argument prototype would still apply. */ 16728 #ifdef __cplusplus 16729 extern "C" 16893 16730 #endif 16894 16731 char malloc (); 16895 16732 int 16896 16733 main () 16897 16734 { 16898 char *p = (char *) alloca (1); 16899 if (p) return 0; 16735 return malloc (); 16900 16736 ; 16901 16737 return 0; … … 16903 16739 _ACEOF 16904 16740 if ac_fn_c_try_link "$LINENO"; then : 16905 ac_cv_ func_alloca_works=yes16906 else 16907 ac_cv_ func_alloca_works=no16741 ac_cv_lib_tcmalloc_malloc=yes 16742 else 16743 ac_cv_lib_tcmalloc_malloc=no 16908 16744 fi 16909 16745 rm -f core conftest.err conftest.$ac_objext \ 16910 16746 conftest$ac_exeext conftest.$ac_ext 16911 fi 16912 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 16913 $as_echo "$ac_cv_func_alloca_works" >&6; } 16914 16915 if test $ac_cv_func_alloca_works = yes; then 16916 16917 $as_echo "#define HAVE_ALLOCA 1" >>confdefs.h 16918 16919 else 16920 # The SVR3 libPW and SVR4 libucb both contain incompatible functions 16921 # that cause trouble. Some versions do not even contain alloca or 16922 # contain a buggy version. If you still want to use their alloca, 16923 # use ar to extract alloca.o from them instead of compiling alloca.c. 16924 16925 ALLOCA=\${LIBOBJDIR}alloca.$ac_objext 16926 16927 $as_echo "#define C_ALLOCA 1" >>confdefs.h 16928 16929 16930 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 16931 $as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } 16932 if ${ac_cv_os_cray+:} false; then : 16933 $as_echo_n "(cached) " >&6 16934 else 16935 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16936 /* end confdefs.h. */ 16937 #if defined CRAY && ! defined CRAY2 16938 webecray 16939 #else 16940 wenotbecray 16941 #endif 16942 16943 _ACEOF 16944 if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | 16945 $EGREP "webecray" >/dev/null 2>&1; then : 16946 ac_cv_os_cray=yes 16947 else 16948 ac_cv_os_cray=no 16949 fi 16950 rm -f conftest* 16951 16952 fi 16953 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 16954 $as_echo "$ac_cv_os_cray" >&6; } 16955 if test $ac_cv_os_cray = yes; then 16956 for ac_func in _getb67 GETB67 getb67; do 16957 as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` 16958 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" 16959 if eval test \"x\$"$as_ac_var"\" = x"yes"; then : 16960 16961 cat >>confdefs.h <<_ACEOF 16962 #define CRAY_STACKSEG_END $ac_func 16963 _ACEOF 16964 16965 break 16966 fi 16967 16968 done 16969 fi 16970 16971 { $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 16972 $as_echo_n "checking stack direction for C alloca... " >&6; } 16973 if ${ac_cv_c_stack_direction+:} false; then : 16974 $as_echo_n "(cached) " >&6 16975 else 16976 if test "$cross_compiling" = yes; then : 16977 ac_cv_c_stack_direction=0 16978 else 16979 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16980 /* end confdefs.h. */ 16981 $ac_includes_default 16982 int 16983 find_stack_direction (int *addr, int depth) 16984 { 16985 int dir, dummy = 0; 16986 if (! addr) 16987 addr = &dummy; 16988 *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; 16989 dir = depth ? find_stack_direction (addr, depth - 1) : 0; 16990 return dir + dummy; 16991 } 16992 16993 int 16994 main (int argc, char **argv) 16995 { 16996 return find_stack_direction (0, argc + !argv + 20) < 0; 16997 } 16998 _ACEOF 16999 if ac_fn_c_try_run "$LINENO"; then : 17000 ac_cv_c_stack_direction=1 17001 else 17002 ac_cv_c_stack_direction=-1 17003 fi 17004 rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ 17005 conftest.$ac_objext conftest.beam conftest.$ac_ext 17006 fi 17007 17008 fi 17009 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 17010 $as_echo "$ac_cv_c_stack_direction" >&6; } 17011 cat >>confdefs.h <<_ACEOF 17012 #define STACK_DIRECTION $ac_cv_c_stack_direction 17013 _ACEOF 17014 17015 17016 fi 17017 17018 for ac_header in fenv.h float.h inttypes.h libintl.h limits.h malloc.h stddef.h stdlib.h string.h unistd.h 16747 LIBS=$ac_check_lib_save_LIBS 16748 fi 16749 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tcmalloc_malloc" >&5 16750 $as_echo "$ac_cv_lib_tcmalloc_malloc" >&6; } 16751 if test "x$ac_cv_lib_tcmalloc_malloc" = xyes; then : 16752 HAVE_LIBTCMALLOC=1 16753 else 16754 HAVE_LIBTCMALLOC=0 16755 fi 16756 16757 if test "$HAVE_LIBTCMALLOC" -eq 1; then 16758 WITH_LIBTCMALLOC_TRUE= 16759 WITH_LIBTCMALLOC_FALSE='#' 16760 else 16761 WITH_LIBTCMALLOC_TRUE='#' 16762 WITH_LIBTCMALLOC_FALSE= 16763 fi 16764 16765 16766 # Checks for header files. 16767 for ac_header in libintl.h malloc.h unistd.h 17019 16768 do : 17020 16769 as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` … … 17025 16774 _ACEOF 17026 16775 16776 else 16777 echo "Error: Missing required header"; exit 1 17027 16778 fi 17028 16779 … … 17031 16782 17032 16783 # Checks for typedefs, structures, and compiler characteristics. 17033 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 17034 $as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } 17035 if ${ac_cv_header_stdbool_h+:} false; then : 16784 ac_fn_c_check_type "$LINENO" "_Float32" "ac_cv_type__Float32" " 16785 " 16786 if test "x$ac_cv_type__Float32" = xyes; then : 16787 16788 cat >>confdefs.h <<_ACEOF 16789 #define HAVE__FLOAT32 1 16790 _ACEOF 16791 16792 16793 $as_echo "#define HAVE_KEYWORDS_FLOATXX /**/" >>confdefs.h 16794 16795 fi 16796 16797 16798 # Checks for compiler flags. 16799 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wcast-function-type" >&5 16800 $as_echo_n "checking whether C compiler accepts -Wcast-function-type... " >&6; } 16801 if ${m4cfa_cv_check_cflags___Wcast_function_type+:} false; then : 17036 16802 $as_echo_n "(cached) " >&6 17037 16803 else 17038 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16804 16805 m4cfa_check_save_flags=$CFLAGS 16806 CFLAGS="$CFLAGS -Wcast-function-type" 16807 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 17039 16808 /* end confdefs.h. */ 17040 17041 #include <stdbool.h>17042 #ifndef bool17043 "error: bool is not defined"17044 #endif17045 #ifndef false17046 "error: false is not defined"17047 #endif17048 #if false17049 "error: false is not 0"17050 #endif17051 #ifndef true17052 "error: true is not defined"17053 #endif17054 #if true != 117055 "error: true is not 1"17056 #endif17057 #ifndef __bool_true_false_are_defined17058 "error: __bool_true_false_are_defined is not defined"17059 #endif17060 17061 struct s { _Bool s: 1; _Bool t; } s;17062 17063 char a[true == 1 ? 1 : -1];17064 char b[false == 0 ? 1 : -1];17065 char c[__bool_true_false_are_defined == 1 ? 1 : -1];17066 char d[(bool) 0.5 == true ? 1 : -1];17067 /* See body of main program for 'e'. */17068 char f[(_Bool) 0.0 == false ? 1 : -1];17069 char g[true];17070 char h[sizeof (_Bool)];17071 char i[sizeof s.t];17072 enum { j = false, k = true, l = false * true, m = true * 256 };17073 /* The following fails for17074 HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */17075 _Bool n[m];17076 char o[sizeof n == m * sizeof n[0] ? 1 : -1];17077 char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1];17078 /* Catch a bug in an HP-UX C compiler. See17079 http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html17080 http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html17081 */17082 _Bool q = true;17083 _Bool *pq = &q;17084 16809 17085 16810 int 17086 16811 main () 17087 16812 { 17088 17089 bool e = &s;17090 *pq |= q;17091 *pq |= ! q;17092 /* Refer to every declared value, to avoid compiler optimizations. */17093 return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l17094 + !m + !n + !o + !p + !q + !pq);17095 16813 17096 16814 ; … … 17099 16817 _ACEOF 17100 16818 if ac_fn_c_try_compile "$LINENO"; then : 17101 ac_cv_header_stdbool_h=yes17102 else 17103 ac_cv_header_stdbool_h=no16819 m4cfa_cv_check_cflags___Wcast_function_type=yes 16820 else 16821 m4cfa_cv_check_cflags___Wcast_function_type=no 17104 16822 fi 17105 16823 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 17106 fi 17107 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 17108 $as_echo "$ac_cv_header_stdbool_h" >&6; } 17109 ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" 17110 if test "x$ac_cv_type__Bool" = xyes; then : 17111 17112 cat >>confdefs.h <<_ACEOF 17113 #define HAVE__BOOL 1 17114 _ACEOF 17115 17116 17117 fi 17118 17119 17120 if test $ac_cv_header_stdbool_h = yes; then 17121 17122 $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h 17123 17124 fi 17125 17126 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 17127 $as_echo_n "checking for inline... " >&6; } 17128 if ${ac_cv_c_inline+:} false; then : 17129 $as_echo_n "(cached) " >&6 17130 else 17131 ac_cv_c_inline=no 17132 for ac_kw in inline __inline__ __inline; do 17133 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 17134 /* end confdefs.h. */ 17135 #ifndef __cplusplus 17136 typedef int foo_t; 17137 static $ac_kw foo_t static_foo () {return 0; } 17138 $ac_kw foo_t foo () {return 0; } 17139 #endif 17140 17141 _ACEOF 17142 if ac_fn_c_try_compile "$LINENO"; then : 17143 ac_cv_c_inline=$ac_kw 17144 fi 17145 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 17146 test "$ac_cv_c_inline" != no && break 17147 done 17148 17149 fi 17150 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 17151 $as_echo "$ac_cv_c_inline" >&6; } 17152 17153 case $ac_cv_c_inline in 17154 inline | yes) ;; 17155 *) 17156 case $ac_cv_c_inline in 17157 no) ac_val=;; 17158 *) ac_val=$ac_cv_c_inline;; 17159 esac 17160 cat >>confdefs.h <<_ACEOF 17161 #ifndef __cplusplus 17162 #define inline $ac_val 17163 #endif 17164 _ACEOF 17165 ;; 17166 esac 17167 17168 ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t" 17169 case $ac_cv_c_int16_t in #( 17170 no|yes) ;; #( 17171 *) 17172 17173 cat >>confdefs.h <<_ACEOF 17174 #define int16_t $ac_cv_c_int16_t 17175 _ACEOF 17176 ;; 17177 esac 17178 17179 ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" 17180 case $ac_cv_c_int32_t in #( 17181 no|yes) ;; #( 17182 *) 17183 17184 cat >>confdefs.h <<_ACEOF 17185 #define int32_t $ac_cv_c_int32_t 17186 _ACEOF 17187 ;; 17188 esac 17189 17190 ac_fn_c_find_intX_t "$LINENO" "8" "ac_cv_c_int8_t" 17191 case $ac_cv_c_int8_t in #( 17192 no|yes) ;; #( 17193 *) 17194 17195 cat >>confdefs.h <<_ACEOF 17196 #define int8_t $ac_cv_c_int8_t 17197 _ACEOF 17198 ;; 17199 esac 17200 17201 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 17202 $as_echo_n "checking for C/C++ restrict keyword... " >&6; } 17203 if ${ac_cv_c_restrict+:} false; then : 17204 $as_echo_n "(cached) " >&6 17205 else 17206 ac_cv_c_restrict=no 17207 # The order here caters to the fact that C++ does not require restrict. 17208 for ac_kw in __restrict __restrict__ _Restrict restrict; do 17209 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 17210 /* end confdefs.h. */ 17211 typedef int * int_ptr; 17212 int foo (int_ptr $ac_kw ip) { 17213 return ip[0]; 17214 } 17215 int 17216 main () 17217 { 17218 int s[1]; 17219 int * $ac_kw t = s; 17220 t[0] = 0; 17221 return foo(t) 17222 ; 17223 return 0; 17224 } 17225 _ACEOF 17226 if ac_fn_c_try_compile "$LINENO"; then : 17227 ac_cv_c_restrict=$ac_kw 17228 fi 17229 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 17230 test "$ac_cv_c_restrict" != no && break 17231 done 17232 17233 fi 17234 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 17235 $as_echo "$ac_cv_c_restrict" >&6; } 17236 17237 case $ac_cv_c_restrict in 17238 restrict) ;; 17239 no) $as_echo "#define restrict /**/" >>confdefs.h 17240 ;; 17241 *) cat >>confdefs.h <<_ACEOF 17242 #define restrict $ac_cv_c_restrict 17243 _ACEOF 17244 ;; 17245 esac 17246 17247 ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" 17248 if test "x$ac_cv_type_size_t" = xyes; then : 17249 17250 else 17251 17252 cat >>confdefs.h <<_ACEOF 17253 #define size_t unsigned int 17254 _ACEOF 17255 17256 fi 17257 17258 ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" 17259 case $ac_cv_c_uint16_t in #( 17260 no|yes) ;; #( 17261 *) 17262 17263 17264 cat >>confdefs.h <<_ACEOF 17265 #define uint16_t $ac_cv_c_uint16_t 17266 _ACEOF 17267 ;; 17268 esac 17269 17270 ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" 17271 case $ac_cv_c_uint32_t in #( 17272 no|yes) ;; #( 17273 *) 17274 17275 $as_echo "#define _UINT32_T 1" >>confdefs.h 17276 17277 17278 cat >>confdefs.h <<_ACEOF 17279 #define uint32_t $ac_cv_c_uint32_t 17280 _ACEOF 17281 ;; 17282 esac 17283 17284 ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" 17285 case $ac_cv_c_uint8_t in #( 17286 no|yes) ;; #( 17287 *) 17288 17289 $as_echo "#define _UINT8_T 1" >>confdefs.h 17290 17291 17292 cat >>confdefs.h <<_ACEOF 17293 #define uint8_t $ac_cv_c_uint8_t 17294 _ACEOF 17295 ;; 17296 esac 17297 17298 17299 # Checks for library functions. 17300 for ac_func in memset putenv strchr strtol 17301 do : 17302 as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` 17303 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" 17304 if eval test \"x\$"$as_ac_var"\" = x"yes"; then : 17305 cat >>confdefs.h <<_ACEOF 17306 #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 17307 _ACEOF 17308 17309 fi 17310 done 16824 CFLAGS=$m4cfa_check_save_flags 16825 fi 16826 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $m4cfa_cv_check_cflags___Wcast_function_type" >&5 16827 $as_echo "$m4cfa_cv_check_cflags___Wcast_function_type" >&6; } 16828 if test "x$m4cfa_cv_check_cflags___Wcast_function_type" = xyes; then : 16829 16830 $as_echo "#define HAVE_CAST_FUNCTION_TYPE /**/" >>confdefs.h 16831 16832 else 16833 : 16834 fi 17311 16835 17312 16836 … … 17321 16845 17322 16846 #============================================================================== 17323 ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile tests/preempt_longrun/Makefile tools/Makefile tools/prettyprinter/Makefile"16847 ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile longrun_tests/Makefile tools/Makefile tools/prettyprinter/Makefile" 17324 16848 17325 16849 … … 17472 16996 if test -z "${WITH_LIBFIBRE_TRUE}" && test -z "${WITH_LIBFIBRE_FALSE}"; then 17473 16997 as_fn_error $? "conditional \"WITH_LIBFIBRE\" was never defined. 16998 Usually this means the macro was only invoked conditionally." "$LINENO" 5 16999 fi 17000 if test -z "${WITH_LIBPROFILER_TRUE}" && test -z "${WITH_LIBPROFILER_FALSE}"; then 17001 as_fn_error $? "conditional \"WITH_LIBPROFILER\" was never defined. 17002 Usually this means the macro was only invoked conditionally." "$LINENO" 5 17003 fi 17004 if test -z "${WITH_LIBTCMALLOC_TRUE}" && test -z "${WITH_LIBTCMALLOC_FALSE}"; then 17005 as_fn_error $? "conditional \"WITH_LIBTCMALLOC\" was never defined. 17474 17006 Usually this means the macro was only invoked conditionally." "$LINENO" 5 17475 17007 fi … … 18459 17991 "benchmark/Makefile") CONFIG_FILES="$CONFIG_FILES benchmark/Makefile" ;; 18460 17992 "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; 18461 " tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES tests/preempt_longrun/Makefile" ;;17993 "longrun_tests/Makefile") CONFIG_FILES="$CONFIG_FILES longrun_tests/Makefile" ;; 18462 17994 "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;; 18463 17995 "tools/prettyprinter/Makefile") CONFIG_FILES="$CONFIG_FILES tools/prettyprinter/Makefile" ;; -
configure.ac
r6a9d4b4 r933f32f 139 139 "debug") ;; 140 140 "nolib") ;; 141 "profile") ;; 141 142 *) 142 143 >&2 echo "Configuration must be 'debug', 'nodebug' or 'nolib'" … … 178 179 AC_PROG_CC 179 180 AM_PROG_AS 180 AM_PROG_CC_C_O # deprecated181 181 # These are often not installed and people miss seeing the "no", so stop the configure. 182 182 AC_PROG_YACC … … 186 186 AC_PROG_LIBTOOL 187 187 AC_PROG_INSTALL 188 AC_PROG_MAKE_SET189 188 190 189 # Checks for libraries. … … 192 191 AM_CONDITIONAL([WITH_LIBFIBRE], [test "$HAVE_LIBFIBRE" -eq 1]) 193 192 193 AC_CHECK_LIB([profiler], [ProfilingIsEnabledForAllThreads], [HAVE_LIBPROFILER=1], [HAVE_LIBPROFILER=0]) 194 AM_CONDITIONAL([WITH_LIBPROFILER], [test "$HAVE_LIBPROFILER" -eq 1]) 195 196 AC_CHECK_LIB([tcmalloc], [malloc], [HAVE_LIBTCMALLOC=1], [HAVE_LIBTCMALLOC=0]) 197 AM_CONDITIONAL([WITH_LIBTCMALLOC], [test "$HAVE_LIBTCMALLOC" -eq 1]) 198 194 199 # Checks for header files. 195 AC_FUNC_ALLOCA 196 AC_CHECK_HEADERS([fenv.h float.h inttypes.h libintl.h limits.h malloc.h stddef.h stdlib.h string.h unistd.h]) 200 AC_CHECK_HEADERS([libintl.h malloc.h unistd.h], [], [echo "Error: Missing required header"; exit 1]) 197 201 198 202 # Checks for typedefs, structures, and compiler characteristics. 199 AC_HEADER_STDBOOL 200 AC_C_INLINE 201 AC_TYPE_INT16_T 202 AC_TYPE_INT32_T 203 AC_TYPE_INT8_T 204 AC_C_RESTRICT 205 AC_TYPE_SIZE_T 206 AC_TYPE_UINT16_T 207 AC_TYPE_UINT32_T 208 AC_TYPE_UINT8_T 209 210 # Checks for library functions. 211 AC_CHECK_FUNCS([memset putenv strchr strtol]) 203 AC_CHECK_TYPES([_Float32], AC_DEFINE([HAVE_KEYWORDS_FLOATXX], [], [Have keywords _FloatXX.]), [], [[]]) 204 205 # Checks for compiler flags. 206 M4CFA_CHECK_COMPILE_FLAG([-Wcast-function-type], AC_DEFINE([HAVE_CAST_FUNCTION_TYPE], [], [Have compiler warning cast-function-type.])) 212 207 213 208 #============================================================================== … … 223 218 benchmark/Makefile 224 219 tests/Makefile 225 tests/preempt_longrun/Makefile220 longrun_tests/Makefile 226 221 tools/Makefile 227 222 tools/prettyprinter/Makefile -
doc/LaTeXmacros/lstlang.sty
r6a9d4b4 r933f32f 8 8 %% Created On : Sat May 13 16:34:42 2017 9 9 %% Last Modified By : Peter A. Buhr 10 %% Last Modified On : Fri Apr 6 23:44:50 201811 %% Update Count : 2 010 %% Last Modified On : Tue Jan 8 14:40:33 2019 11 %% Update Count : 21 12 12 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 13 … … 114 114 _Alignas, _Alignof, __alignof, __alignof__, asm, __asm, __asm__, __attribute, __attribute__, 115 115 auto, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__, 116 coroutine, disable, dtype, enable, __extension__, exception, fallthrough, fallthru, finally,116 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally, 117 117 __float80, float80, __float128, float128, forall, ftype, _Generic, _Imaginary, __imag, __imag__, 118 118 inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or, -
doc/bibliography/pl.bib
r6a9d4b4 r933f32f 330 330 contributer = {pabuhr@plg}, 331 331 author = {Nissim Francez}, 332 title = {Another Advantage of Key word Notation for Parameter Communication with Subprograms},332 title = {Another Advantage of Keyword Notation for Parameter Communication with Subprograms}, 333 333 journal = cacm, 334 334 volume = 20, … … 831 831 year = 2015, 832 832 howpublished= {\href{http://www.boost.org/doc/libs/1_61_0/libs/coroutine/doc/html/index.html} 833 {{http://www.boost.org/\-doc/\-libs/1\_61\_0/\-libs/\-coroutine/\-doc/\-html/\-index.html}}}, 834 optnote = {Accessed: 2016-09}, 833 {http://www.boost.org/\-doc/\-libs/1\_61\_0/\-libs/\-coroutine/\-doc/\-html/\-index.html}}, 834 } 835 836 @misc{BoostThreads, 837 keywords = {Boost Thread Library}, 838 contributer = {pabuhr@plg}, 839 author = {Anthony Williams and Vicente J. Botet Escriba}, 840 title = {Boost Thread Library}, 841 year = 2015, 842 howpublished= {\href{https://www.boost.org/doc/libs/1_61_0/doc/html/thread.html} 843 {https://\-www.boost.org/\-doc/\-libs/\-1\_61\_0/\-doc/\-html/\-thread.html}}, 835 844 } 836 845 … … 939 948 author = {{\textsf{C}{$\mathbf{\forall}$} Features}}, 940 949 howpublished= {\href{https://plg.uwaterloo.ca/~cforall/features}{https://\-plg.uwaterloo.ca/\-$\sim$cforall/\-features}}, 941 optnote = {Accessed: 2018-01-01},942 950 } 943 951 … … 959 967 year = 2018, 960 968 howpublished= {\href{https://cforall.uwaterloo.ca/CFAStackEvaluation.zip}{https://cforall.uwaterloo.ca/\-CFAStackEvaluation.zip}}, 961 optnote = {[Accessed May 2018]},962 969 } 963 970 … … 966 973 contributer = {pabuhr@plg}, 967 974 author = {Aaron Moss and Robert Schluntz and Peter A. Buhr}, 968 title = {\textsf{C}$\mathbf{\forall}$ : Adding Modern Programming Language Features to C},975 title = {\textsf{C}$\mathbf{\forall}$ : Adding Modern Programming Language Features to {C}}, 969 976 journal = spe, 970 977 volume = 48, … … 1086 1093 } 1087 1094 1095 @techreport{Prokopec11, 1096 keywords = {ctrie, concurrent map}, 1097 contributer = {a3moss@uwaterloo.ca}, 1098 title={Cache-aware lock-free concurrent hash tries}, 1099 author={Prokopec, Aleksandar and Bagwell, Phil and Odersky, Martin}, 1100 institution={EPFL}, 1101 year={2011} 1102 } 1103 1088 1104 @article{Buhr85, 1089 1105 keywords = {goto, multi-exit loop}, … … 1132 1148 year = 1998, 1133 1149 note = {{\small\textsf{ftp://\-plg.uwaterloo.ca/\-pub/\-Cforall/\-refrat.ps.gz}}}, 1150 } 1151 1152 @phdthesis{Norrish98, 1153 title={C formalised in HOL}, 1154 author={Norrish, Michael}, 1155 year={1998}, 1156 school={University of Cambridge} 1157 } 1158 1159 @inproceedings{Tarditi18, 1160 keywords = {Checked C}, 1161 contributer = {a3moss@uwaterloo.ca}, 1162 author = {Tarditi, David and Elliott, Archibald Samuel and Ruef, Andrew and Hicks, Michael}, 1163 title = {Checked C: Making C Safe by Extension}, 1164 booktitle = {2018 IEEE Cybersecurity Development (SecDev)}, 1165 year = {2018}, 1166 month = {September}, 1167 pages = {53-60}, 1168 publisher = {IEEE}, 1169 url = {https://www.microsoft.com/en-us/research/publication/checkedc-making-c-safe-by-extension/}, 1170 } 1171 1172 @misc{Clang, 1173 keywords = {clang}, 1174 contributer = {a3moss@uwaterloo.ca}, 1175 title = {Clang: a {C} language family frontend for {LLVM}}, 1176 howpublished= {\href{https://clang.llvm.org/}{https://\-clang.llvm.org/}} 1134 1177 } 1135 1178 … … 1234 1277 } 1235 1278 1279 @inproceedings{Odersky01, 1280 keywords = {Scala}, 1281 contributer = {a3moss@uwaterloo.ca}, 1282 author = {Odersky, Martin and Zenger, Christoph and Zenger, Matthias}, 1283 title = {Colored Local Type Inference}, 1284 booktitle = {Proceedings of the 28th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages}, 1285 series = {POPL '01}, 1286 year = {2001}, 1287 isbn = {1-58113-336-7}, 1288 location = {London, United Kingdom}, 1289 pages = {41--53}, 1290 numpages = {13}, 1291 url = {http://doi.acm.org/10.1145/360204.360207}, 1292 doi = {10.1145/360204.360207}, 1293 acmid = {360207}, 1294 publisher = {ACM}, 1295 address = {New York, NY, USA}, 1296 } 1297 1236 1298 @book{sml:commentary, 1237 1299 author = {Robin Milner and Mads Tofte}, … … 1294 1356 journal = sigplan, 1295 1357 year = 1986, 1296 month = oct, volume = 21, number = 10, pages = {19-28}, 1358 month = oct, 1359 volume = 21, 1360 number = 10, 1361 pages = {19-28}, 1297 1362 note = {Object Oriented Programming Workshop} 1298 1363 } … … 1459 1524 title = {concurrent-locking}, 1460 1525 howpublished= {\href{https://github.com/pabuhr/concurrent-locking}{https://\-github.com/\-pabuhr/\-concurrent-locking}}, 1461 optnote = {[Accessed April 2017]},1462 1526 } 1463 1527 … … 1621 1685 } 1622 1686 1687 @inproceedings{Prokopec12, 1688 keywords={ctrie, hash trie, concurrent map}, 1689 contributer={a3moss@uwaterloo.ca}, 1690 title={Concurrent tries with efficient non-blocking snapshots}, 1691 author={Prokopec, Aleksandar and Bronson, Nathan Grasso and Bagwell, Phil and Odersky, Martin}, 1692 booktitle={ACM SIGPLAN Notices}, 1693 volume={47}, 1694 number={8}, 1695 pages={151--160}, 1696 year={2012}, 1697 organization={ACM} 1698 } 1699 1623 1700 @article{Buhr05a, 1624 1701 keywords = {concurrency, myths}, … … 1747 1824 howpublished= {\href{https://www.airs.com/blog/archives/428} 1748 1825 {https://www.airs.com/\-blog/\-archives/\-428}}, 1749 optnote = {Accessed: 2018-05},1750 1826 } 1751 1827 … … 1843 1919 year = 1965, 1844 1920 note = {Reprinted in \cite{Genuys68} pp. 43--112.} 1921 } 1922 1923 @manual{C++20Coroutine19, 1924 keywords = {coroutine}, 1925 contributer = {pabuhr@plg}, 1926 title = {Coroutines (C++20)}, 1927 organization= {cppreference.com}, 1928 month = apr, 1929 year = 2019, 1930 note = {\href{https://en.cppreference.com/w/cpp/language/coroutines}{https://\-en.cppreference.com/\-w/\-cpp/\-language/\-coroutines}}, 1845 1931 } 1846 1932 … … 2271 2357 } 2272 2358 2359 @article{Ritchie93, 2360 keywords = {C, history}, 2361 contributer = {pabuhr@plg}, 2362 author = {Ritchie, Dennis M.}, 2363 title = {The Development of the {C} Language}, 2364 journal = sigplan, 2365 volume = 28, 2366 number = 3, 2367 month = mar, 2368 year = 1993, 2369 pages = {201--208}, 2370 url = {http://doi.acm.org/10.1145/155360.155580}, 2371 publisher = {ACM}, 2372 address = {New York, NY, USA}, 2373 } 2374 2273 2375 @article{design, 2274 2376 keywords = {Smalltalk, designing classes}, … … 2278 2380 journal = joop, 2279 2381 year = 1988, 2280 volume = 1, number = 2, pages = {22-35}, 2382 volume = 1, 2383 number = 2, 2384 pages = {22-35}, 2281 2385 comment = { 2282 2386 Abstract classes represent standard protocols. ``It is better to … … 2363 2467 year = 1990, 2364 2468 pages = {315-323} 2469 } 2470 2471 @misc{Dotty-github, 2472 keywords = {dotty,scala}, 2473 contributer = {a3moss@uwaterloo.ca}, 2474 author = {Martin Odersky}, 2475 title = {Dotty}, 2476 howpublished = {\href{https://github.com/lampepfl/dotty}{https://\-github.com/\-lampepfl/\-dotty}}, 2477 note = {Acessed: 2019-02-22} 2365 2478 } 2366 2479 … … 2470 2583 pages = {325-361}, 2471 2584 } 2585 2586 @article{Tarjan75, 2587 keywords = {union-find}, 2588 contributer = {a3moss@uwaterloo.ca}, 2589 author = {Tarjan, Robert Endre}, 2590 title = {Efficiency of a Good But Not Linear Set Union Algorithm}, 2591 journal = {J. ACM}, 2592 issue_date = {April 1975}, 2593 volume = {22}, 2594 number = {2}, 2595 month = apr, 2596 year = {1975}, 2597 issn = {0004-5411}, 2598 pages = {215--225}, 2599 numpages = {11}, 2600 url = {http://doi.acm.org/10.1145/321879.321884}, 2601 doi = {10.1145/321879.321884}, 2602 acmid = {321884}, 2603 publisher = {ACM}, 2604 address = {New York, NY, USA}, 2605 } 2472 2606 2473 2607 @book{Eiffel, … … 2906 3040 year = 2014, 2907 3041 howpublished= {\href{https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/C-Extensions.html}{https://\-gcc.gnu.org/\-onlinedocs/\-gcc-4.7.2/\-gcc/\-C\-Extensions.html}}, 2908 optnote = {Accessed: 2017-04-02},2909 3042 } 2910 3043 … … 2990 3123 } 2991 3124 3125 @manual{WindowsFibers, 3126 keywords = {threads, fibers}, 3127 contributer = {pabuhr@plg}, 3128 author = {Windows}, 3129 title = {Fibers}, 3130 organization= {Microsoft, Windows Development Center}, 3131 address = {\href{https://docs.microsoft.com/en-us/windows/desktop/ProcThread/fibers}{https://\-docs.microsoft.com/\-en-us/\-windows/\-desktop/\-ProcThread/\-fibers}}, 3132 year = 2018, 3133 } 3134 2992 3135 @inproceedings{F-bound, 2993 3136 keywords = {}, … … 3037 3180 } 3038 3181 3182 @manual{Folly, 3183 keywords = {Folly}, 3184 contributer = {pabuhr@plg}, 3185 author = {Folly}, 3186 title = {Facebook Open-source Library}, 3187 organization= {Facebook}, 3188 address = {\href{https://github.com/facebook/folly}{https://\-github.com/\-facebook/\-folly}}, 3189 year = 2018, 3190 } 3191 3192 @article{Leroy09, 3193 keywords = {C formalization}, 3194 contributer = {a3moss@uwaterloo.ca}, 3195 author = {Leroy, Xavier}, 3196 title = {Formal Verification of a Realistic Compiler}, 3197 journal = {Commun. ACM}, 3198 issue_date = {July 2009}, 3199 volume = {52}, 3200 number = {7}, 3201 month = jul, 3202 year = {2009}, 3203 issn = {0001-0782}, 3204 pages = {107--115}, 3205 numpages = {9}, 3206 url = {http://doi.acm.org/10.1145/1538788.1538814}, 3207 doi = {10.1145/1538788.1538814}, 3208 acmid = {1538814}, 3209 publisher = {ACM}, 3210 address = {New York, NY, USA}, 3211 } 3212 3039 3213 @manual{Fortran95, 3040 3214 keywords = {Fortran 95}, … … 3057 3231 address = {\href{https://www.iso.org/standard/50459.html}{https://\-www.iso.org/\-standard/\-50459.html}}, 3058 3232 year = 2010, 3233 } 3234 3235 @manual{Fortran18, 3236 keywords = {ISO/IEC Fortran 10}, 3237 contributer = {pabuhr@plg}, 3238 author = {Fortran18}, 3239 title = {Programming Languages -- {Fortran} Part 1:Base Language ISO/IEC 1539-1:2018}, 3240 edition = {4rd}, 3241 publisher = {International Standard Organization}, 3242 address = {\href{https://www.iso.org/standard/72320.html}{https://\-www.iso.org/\-standard/\-72320.html}}, 3243 year = 2018, 3059 3244 } 3060 3245 … … 3306 3491 year = 2014, 3307 3492 howpublished= {https://developer.gnome.org/gobject/stable/}, 3308 optnote = {Accessed: 2017-04},3309 3493 } 3310 3494 … … 3621 3805 year = {1964}, 3622 3806 publisher = {ACM} 3807 } 3808 3809 @phdthesis{Barghi18, 3810 keywords = {concurrency, user threads, actors}, 3811 contributer = {pabuhr@plg}, 3812 author = {Saman Barghi}, 3813 title = {Improving the Performance of User-level Runtime Systems for Concurrent Applications}, 3814 school = {School of Computer Science, University of Waterloo}, 3815 year = 2018, 3816 month = sep, 3817 optaddress = {Waterloo, Ontario, Canada, N2L 3G1}, 3818 note = {\href{https://uwspace.uwaterloo.ca/handle/10012/13935}{https://\-uwspace.uwaterloo.ca/\-handle/\-10012/\-13935}}, 3819 } 3820 3821 @article{Swift05, 3822 contributer = {pabuhr@plg}, 3823 author = {Michael M. Swift and Brian N. Bershad and Henry M. Levy}, 3824 title = {Improving the Reliability of Commodity Operating Systems}, 3825 journal = tocs, 3826 volume = 23, 3827 number = 1, 3828 month = feb, 3829 year = 2005, 3830 pages = {77-110}, 3623 3831 } 3624 3832 … … 3927 4135 } 3928 4136 4137 @article{Morgado13, 4138 keywords = {expression resolution}, 4139 contributer = {a3moss@uwaterloo.ca}, 4140 title={Iterative and core-guided {MaxSAT} solving: A survey and assessment}, 4141 author={Morgado, Antonio and Heras, Federico and Liffiton, Mark and Planes, Jordi and Marques-Silva, Joao}, 4142 journal={Constraints}, 4143 volume={18}, 4144 number={4}, 4145 pages={478--534}, 4146 year={2013}, 4147 publisher={Springer} 4148 } 4149 3929 4150 % J 3930 4151 … … 3948 4169 year = 2015, 3949 4170 edition = {{J}ava {SE} 8}, 4171 } 4172 4173 @manual{Java11, 4174 keywords = {Java SE 11}, 4175 contributer = {pabuhr@plg}, 4176 author = {James Gosling and Bill Joy and Guy Steele and Gilad Bracha and Alex Buckley and Daniel Smith}, 4177 title = {{Java} Language Specification}, 4178 publisher = {Oracle}, 4179 month = sep, 4180 year = 2018, 4181 edition = {{J}ava {SE} 11}, 4182 } 4183 4184 @manual{JDK1.1, 4185 keywords = {JDK 1.1}, 4186 contributer = {pabuhr@plg}, 4187 author = {{Multithreading Models}}, 4188 title = {JDK 1.1 for Solaris Developer's Guide}, 4189 publisher = {Oracle}, 4190 address = {\href{https://docs.oracle.com/cd/E19455-01/806-3461/6jck06gqk/index.html#ch2mt-41}{https://\-docs.oracle.com/\-cd/\-E19455-01/\-806-3461/\-6jck06gqk/\-index.html\#ch2mt-41}}, 4191 year = 2010, 3950 4192 } 3951 4193 … … 4129 4371 } 4130 4372 4373 @manual{libmill, 4374 keywords = {libmill}, 4375 contributer = {pabuhr@plg}, 4376 author = {libmill}, 4377 title = {{G}o-style concurrency in {C}, Version 1.18}, 4378 organization= {libmill}, 4379 address = {\href{http://libmill.org/documentation.html}{http://\-libmill.org/\-documentation.html}}, 4380 month = jan, 4381 year = 2017, 4382 } 4383 4131 4384 @book{Weissman67, 4132 4385 keywords = {lisp}, … … 4138 4391 } 4139 4392 4393 @article{Pierce00, 4394 keywords = {Scala}, 4395 contributer = {a3moss@uwaterloo.ca}, 4396 author = {Pierce, Benjamin C. and Turner, David N.}, 4397 title = {Local Type Inference}, 4398 journal = {ACM Trans. Program. Lang. Syst.}, 4399 issue_date = {Jan. 2000}, 4400 volume = {22}, 4401 number = {1}, 4402 month = jan, 4403 year = {2000}, 4404 issn = {0164-0925}, 4405 pages = {1--44}, 4406 numpages = {44}, 4407 url = {http://doi.acm.org/10.1145/345099.345100}, 4408 doi = {10.1145/345099.345100}, 4409 acmid = {345100}, 4410 publisher = {ACM}, 4411 address = {New York, NY, USA}, 4412 keywords = {polymorphism, subtyping, type inference}, 4413 } 4414 4140 4415 @article{Sundell08, 4141 4416 keywords = {lock free, deque}, … … 4148 4423 year = 2008, 4149 4424 pages = {1008-1020}, 4425 } 4426 4427 @misc{Matsakis17, 4428 keywords = {Rust, Chalk, PROLOG}, 4429 contributer = {a3moss@uwaterloo.ca}, 4430 author = {Nicholas Matsakis}, 4431 title = {Lowering {Rust} traits to logic}, 4432 month = jan, 4433 year = 2017, 4434 howpublished= {\href{http://smallcultfollowing.com/babysteps/blog/2017/01/26/lowering-rust-traits-to-logic/} 4435 {http://smallcultfollowing.com/\-babysteps/\-blog/\-2017/\-01/\-26/\-lowering-rust-traits-to-logic/}}, 4436 optnote = {Accessed: 2019-01}, 4150 4437 } 4151 4438 … … 4164 4451 } 4165 4452 4453 @manual{Lua, 4454 keywords = {Lua}, 4455 contributer = {pabuhr@plg}, 4456 author = {Lua}, 4457 title = {Lua 5.3 Reference Manual}, 4458 address = {\href{https://www.lua.org/manual/5.3}{https://\-www.lua.org/\-manual/\-5.3}}, 4459 year = 2018, 4460 } 4461 4166 4462 % M 4167 4463 … … 4173 4469 publisher = {Motorola}, 4174 4470 year = 1992, 4471 } 4472 4473 @misc{Haberman16, 4474 keywords = {C++ template expansion}, 4475 contributer = {a3moss@uwaterloo.ca}, 4476 author = {Josh Haberman}, 4477 title = {Making arbitrarily-large binaries from fixed-size {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} code}, 4478 year = 2016, 4479 howpublished= {\href{http://blog.reverberate.org/2016/01/making-arbitrarily-large-binaries-from.html} 4480 { 4481 {http://blog.reverberate.org/\-2016/\-01/\-making-arbitrarily-large-binaries-from.html} 4482 }}, 4483 optnote = {Accessed: 2016-09}, 4175 4484 } 4176 4485 … … 4491 4800 } 4492 4801 % editor = {Allen Kent and James G. Williams}, 4802 4803 @incollection{MPC, 4804 keywords = {user-level threading}, 4805 contributer = {pabuhr@plg}, 4806 author = {Marc P\'erache and Herv\'e Jourdren and Raymond Namyst}, 4807 title = {MPC: A Unified Parallel Runtime for Clusters of {NUMA} Machines}, 4808 booktitle = {Euro-Par 2008}, 4809 pages = {329-342}, 4810 publisher = {Springer}, 4811 address = {Berlin, Heidelberg}, 4812 year = 2008, 4813 volume = 5168, 4814 series = {Lecture Notes in Computer Science}, 4815 } 4493 4816 4494 4817 @manual{MPI, … … 4917 5240 year = 2014, 4918 5241 howpublished= {\href{https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC}{https://\-developer.apple.com/\-library/archive/\-documentation/\-Cocoa/\-Conceptual/\-ProgrammingWithObjectiveC}}, 4919 optnote = {Accessed: 2018-03}4920 5242 } 4921 5243 … … 4927 5249 year = 2015, 4928 5250 howpublished= {\href{https://developer.apple.com/library/content/documentation/Xcode/Conceptual/RN-Xcode-Archive/Chapters/xc7_release_notes.html}{https://\-developer.apple.com/\-library/\-content/\-documentation/\-Xcode/\-Conceptual/\-RN-Xcode-Archive/\-Chapters/\-xc7\_release\_notes.html}}, 4929 optnote = {Accessed: 2017-04}4930 5251 } 4931 5252 … … 5062 5383 note = {\href{https://www.openmp.org/wp-content/uploads/openmp-4.5.pdf}{https://\-www.openmp.org/\-wp-content/\-uploads/\-openmp-4.5.pdf}}, 5063 5384 } 5385 5386 @inproceedings{Krebbers14, 5387 keywords = {c formalization}, 5388 contributer = {a3moss@uwaterloo.ca}, 5389 author = {Krebbers, Robbert}, 5390 title = {An Operational and Axiomatic Semantics for Non-determinism and Sequence Points in C}, 5391 booktitle = {Proceedings of the 41st ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages}, 5392 series = {POPL '14}, 5393 year = {2014}, 5394 isbn = {978-1-4503-2544-8}, 5395 location = {San Diego, California, USA}, 5396 pages = {101--112}, 5397 numpages = {12}, 5398 url = {http://doi.acm.org/10.1145/2535838.2535878}, 5399 doi = {10.1145/2535838.2535878}, 5400 acmid = {2535878}, 5401 publisher = {ACM}, 5402 address = {New York, NY, USA}, 5403 } 5064 5404 5065 5405 @book{Deitel04, … … 5440 5780 year = 2012, 5441 5781 howpublished= {\href{http://cs.brown.edu/research/pubs/theses/masters/2012/verch.pdf}{http://cs.brown.edu/\-research/\-pubs/\-theses/\-masters/\-2012/\-verch.pdf}}, 5442 optnote = {Accessed: 2013-10-4}5443 5782 } 5444 5783 … … 5764 6103 address = {\href{https://www.iso.org/standard/64029.html}{https://\-www.iso.org/\-standard/\-64029.html}}, 5765 6104 year = 2014, 6105 } 6106 6107 @manual{C++17, 6108 keywords = {ISO/IEC C++ 17}, 6109 contributer = {pabuhr@plg}, 6110 key = {C++17}, 6111 title = {{C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Programming Language ISO/IEC 14882:2017}, 6112 edition = {5th}, 6113 publisher = {International Standard Organization}, 6114 address = {\href{https://www.iso.org/standard/68564.html}{https://\-www.iso.org/\-standard/\-68564.html}}, 6115 year = 2017, 5766 6116 } 5767 6117 … … 5917 6267 institution = {Carnegie Mellon University}, 5918 6268 year = 1991, 5919 month = feb, number = "CMU-CS-91-106", 6269 month = feb, 6270 number = {CMU-CS-91-106}, 5920 6271 annote = { 5921 6272 Discusses a typed lambda calculus with … … 5974 6325 journal = sigplan, 5975 6326 year = 1988, 5976 month = jul, volume = 23, number = 7, pages = {260-267}, 5977 note = {Proceedings of the SIGPLAN '88 Conference on Programming Language 5978 Design and Implementation}, 6327 month = jul, 6328 volume = 23, 6329 number = 7, 6330 pages = {260-267}, 6331 note = {Proceedings of the SIGPLAN '88 Conference on Programming Language Design and Implementation}, 5979 6332 abstract = { 5980 6333 This paper deals with the integration of an efficient asynchronous … … 6026 6379 } 6027 6380 6381 @misc{Pthreads, 6382 keywords = {pthreads, C concurrency}, 6383 contributer = {pabuhr@plg}, 6384 key = {pthreads}, 6385 title = {{Pthread}.h, Specifications Issue 7, {IEEE} Std 1003.1-2017}, 6386 author = {IEEE and {The Open Group}}, 6387 year = 2018, 6388 howpublished= {\href{http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/pthread.h.html} 6389 {http://\-pubs.opengroup.org/\-onlinepubs/\-9699919799/\-basedefs/\-pthread.h.html}}, 6390 } 6391 6028 6392 @manual{Python, 6029 6393 keywords = {Python}, 6030 6394 contributer = {pabuhr@plg}, 6031 title = {Python Reference Manual, Release 2.5},6032 author = {Guido van Rossum},6395 author = {Python}, 6396 title = {Python Language Reference, Release 3.7.2}, 6033 6397 organization= {Python Software Foundation}, 6034 month = sep, 6035 year = 2006, 6036 note = {Fred L. Drake, Jr., editor}, 6398 address = {\href{https://docs.python.org/3/reference/index.html}{https://\-docs.python.org/\-3/\-reference/\-index.html}}, 6399 year = 2018, 6037 6400 } 6038 6401 6039 6402 % Q 6403 6404 @inproceedings{Qthreads, 6405 keywords = {user-level threading}, 6406 author = {Kyle B. Wheeler and Richard C. Murphy and Douglas Thain}, 6407 title = {Qthreads: An API for Programming with Millions of Lightweight Threads}, 6408 booktitle = {International Symposium on Parallel and Distributed Processing}, 6409 organization= {IEEE}, 6410 address = {Miami, FL, USA}, 6411 month = apr, 6412 year = 2008, 6413 } 6040 6414 6041 6415 @article{Grossman06, … … 6074 6448 } 6075 6449 6450 @manual{Quasar, 6451 keywords = {Quasar}, 6452 contributer = {pabuhr@plg}, 6453 author = {Quasar}, 6454 title = {Quasar Documentation, Release 0.8.0}, 6455 organization= {Parallel Universe}, 6456 address = {\href{http://docs.paralleluniverse.co/quasar}{http://\-docs.paralleluniverse.co/\-quasar}}, 6457 year = 2018, 6458 } 6459 6076 6460 % R 6077 6461 … … 6187 6571 number = 10, 6188 6572 pages = {27-32}, 6573 } 6574 6575 @article{Hesselink06, 6576 author = {Wim H. Hesselink}, 6577 title = {Refinement Verification of the Lazy Caching Algorithm}, 6578 journal = acta, 6579 year = 2006, 6580 month = oct, 6581 volume = 43, 6582 number = 3, 6583 pages = {195--222}, 6189 6584 } 6190 6585 … … 6325 6720 } 6326 6721 6722 @manual{Ruby, 6723 keywords = {Ruby}, 6724 contributer = {pabuhr@plg}, 6725 author = {Ruby}, 6726 title = {Ruby Documentation, Release 2.6.0}, 6727 organization= {Python Software Foundation}, 6728 address = {\href{https://www.ruby-lang.org/en/documentation}{https://\-www.ruby-lang.org/\-en/\-documentation}}, 6729 year = 2018, 6730 } 6731 6327 6732 % S 6328 6733 … … 7061 7466 } 7062 7467 7468 @article{SysVABI, 7469 keywords = {System V ABI}, 7470 contributer = {a3moss@uwaterloo.ca}, 7471 title={System {V} application binary interface}, 7472 author={Matz, Michael and Hubicka, Jan and Jaeger, Andreas and Mitchell, Mark}, 7473 journal={AMD64 Architecture Processor Supplement, Draft v0}, 7474 volume={99}, 7475 year={2013} 7476 } 7477 7063 7478 % T 7064 7479 … … 7115 7530 author = {{TIOBE Index}}, 7116 7531 howpublished= {\href{http://www.tiobe.com/tiobe_index}{http://\-www.tiobe.com/\-tiobe\_index}}, 7117 optnote = {Accessed: 2018-09}, 7532 } 7533 7534 @misc{ThreadModel, 7535 contributer = {pabuhr@plg}, 7536 key = {ThreadModel}, 7537 title = {Thread (computing)}, 7538 author = {{Threading Model}}, 7539 howpublished= {\href{https://en.wikipedia.org/wiki/Thread_(computing)}{https://\-en.wikipedia.org/\-wiki/\-Thread\_(computing)}}, 7118 7540 } 7119 7541 … … 7277 7699 } 7278 7700 7701 @techreport{Black90, 7702 title={Typechecking polymorphism in {Emerald}}, 7703 author={Black, Andrew P and Hutchinson, Norman C}, 7704 year={1990}, 7705 institution={Cambridge Research Laboratory, Digital Equipment Corporation} 7706 } 7707 7279 7708 @article{Cormack90, 7280 7709 keywords = {polymorphism}, … … 7447 7876 year = 2017, 7448 7877 howpublished= {\url{https://wiki.gnome.org/Projects/Vala/Manual}}, 7449 optnote = {Accessed: 2017-04}7450 7878 } 7451 7879 … … 7621 8049 % Y 7622 8050 8051 @article{Boehm12, 8052 keywords = {memory model, race condition}, 8053 contributer = {pabuhr@plg}, 8054 author = {Boehm, Hans-J. and Adve, Sarita V.}, 8055 title = {You Don'T Know Jack About Shared Variables or Memory Models}, 8056 journal = cacm, 8057 volume = 55, 8058 number = 2, 8059 month = feb, 8060 year = 2012, 8061 pages = {48--54}, 8062 publisher = {ACM}, 8063 address = {New York, NY, USA}, 8064 } 8065 7623 8066 % Z 7624 8067 -
doc/papers/concurrency/Paper.tex
r6a9d4b4 r933f32f 215 215 {} 216 216 \lstnewenvironment{Go}[1][] 217 {\lstset{#1}} 217 {\lstset{language=go,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}} 218 {} 219 \lstnewenvironment{python}[1][] 220 {\lstset{language=python,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}} 218 221 {} 219 222 … … 228 231 } 229 232 230 \title{\texorpdfstring{ Concurrency in \protect\CFA}{Concurrencyin Cforall}}233 \title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}} 231 234 232 235 \author[1]{Thierry Delisle} … … 238 241 \corres{*Peter A. Buhr, Cheriton School of Computer Science, University of Waterloo, 200 University Avenue West, Waterloo, ON, N2L 3G1, Canada. \email{pabuhr{\char`\@}uwaterloo.ca}} 239 242 240 \fundingInfo{Natural Sciences and Engineering Research Council of Canada}243 % \fundingInfo{Natural Sciences and Engineering Research Council of Canada} 241 244 242 245 \abstract[Summary]{ 243 \CFA is a modern, polymorphic, \emph{non-object-oriented} extension of the C programming language. 244 This paper discusses the design of the concurrency and parallelism features in \CFA, and its concurrent runtime-system. 245 These features are created from scratch as ISO C lacks concurrency, relying largely on the pthreads library for concurrency. 246 Coroutines and lightweight (user) threads are introduced into \CFA; 247 as well, monitors are added as a high-level mechanism for mutual exclusion and synchronization. 248 A unique contribution of this work is allowing multiple monitors to be safely acquired \emph{simultaneously}. 249 All features respect the expectations of C programmers, while being fully integrate with the \CFA polymorphic type-system and other language features. 246 \CFA is a polymorphic, non-object-oriented, concurrent, backwards-compatible extension of the C programming language. 247 This paper discusses the design philosophy and implementation of its advanced control-flow and concurrent/parallel features, along with the supporting runtime. 248 These features are created from scratch as ISO C has only low-level and/or unimplemented concurrency, so C programmers continue to rely on library features like C pthreads. 249 \CFA introduces modern language-level control-flow mechanisms, like coroutines, user-level threading, and monitors for mutual exclusion and synchronization. 250 Library extension for executors, futures, and actors are built on these basic mechanisms. 251 The runtime provides significant programmer simplification and safety by eliminating spurious wakeup and reducing monitor barging. 252 The runtime also ensures multiple monitors can be safely acquired \emph{simultaneously} (deadlock free), and this feature is fully integrated with all monitor synchronization mechanisms. 253 All language features integrate with the \CFA polymorphic type-system and exception handling, while respecting the expectations and style of C programmers. 250 254 Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming-languages. 251 255 }% 252 256 253 \keywords{co ncurrency, parallelism, coroutines, threads, monitors, runtime, C, Cforall}257 \keywords{coroutines, concurrency, parallelism, threads, monitors, runtime, C, \CFA (Cforall)} 254 258 255 259 … … 262 266 \section{Introduction} 263 267 268 This paper discusses the design philosophy and implementation of advanced language-level control-flow and concurrent/parallel features in \CFA~\cite{Moss18} and its runtime. 269 \CFA is a modern, polymorphic, non-object-oriented\footnote{ 270 \CFA has features often associated with object-oriented programming languages, such as constructors, destructors, virtuals and simple inheritance. 271 However, functions \emph{cannot} be nested in structures, so there is no lexical binding between a structure and set of functions (member/method) implemented by an implicit \lstinline@this@ (receiver) parameter.}, 272 backwards-compatible extension of the C programming language. 273 Within the \CFA framework, new control-flow features are created from scratch. 274 ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}. 275 However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}. 276 Furthermore, \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and a few locks, which is low-level and error prone; 277 no high-level language concurrency features are defined. 278 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-8 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach. 279 Finally, while the \Celeven standard does not state a threading model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}. 280 281 In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages. 282 As multi-core hardware became available in the 1980/90s, both user and kernel threading were examined. 283 Kernel threading was chosen, largely because of its simplicity and fit with the simpler operating systems and hardware architectures at the time, which gave it a performance advantage~\cite{Drepper03}. 284 Libraries like pthreads were developed for C, and the Solaris operating-system switched from user (JDK 1.1~\cite{JDK1.1}) to kernel threads. 285 As a result, languages like Java, Scala~\cite{Scala}, Objective-C~\cite{obj-c-book}, \CCeleven~\cite{C11}, and C\#~\cite{Csharp} adopt the 1:1 kernel-threading model, with a variety of presentation mechanisms. 286 From 2000 onwards, languages like Go~\cite{Go}, Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, D~\cite{D}, and \uC~\cite{uC++,uC++book} have championed the M:N user-threading model, and many user-threading libraries have appeared~\cite{Qthreads,MPC,BoostThreads}, including putting green threads back into Java~\cite{Quasar}. 287 The main argument for user-level threading is that they are lighter weight than kernel threads (locking and context switching do not cross the kernel boundary), so there is less restriction on programming styles that encourage large numbers of threads performing smaller work-units to facilitate load balancing by the runtime~\cite{Verch12}. 288 As well, user-threading facilitates a simpler concurrency approach using thread objects that leverage sequential patterns versus events with call-backs~\cite{vonBehren03}. 289 Finally, performant user-threading implementations (both time and space) are largely competitive with direct kernel-threading implementations, while achieving the programming advantages of high concurrency levels and safety. 290 291 A further effort over the past two decades is the development of language memory-models to deal with the conflict between language features and compiler/hardware optimizations, i.e., some language features are unsafe in the presence of aggressive sequential optimizations~\cite{Buhr95a,Boehm05}. 292 The consequence is that a language must provide sufficient tools to program around safety issues, as inline and library code is all sequential to the compiler. 293 One solution is low-level qualifiers and functions (e.g., @volatile@ and atomics) allowing \emph{programmers} to explicitly write safe (race-free~\cite{Boehm12}) programs. 294 A safer solution is high-level language constructs so the \emph{compiler} knows the optimization boundaries, and hence, provides implicit safety. 295 This problem is best know with respect to concurrency, but applies to other complex control-flow, like exceptions\footnote{ 296 \CFA exception handling will be presented in a separate paper. 297 The key feature that dovetails with this paper is non-local exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++} 298 } and coroutines. 299 Finally, solutions in the language allows matching constructs with language paradigm, i.e., imperative and functional languages have different presentations of the same concept. 300 301 Finally, it is important for a language to provide safety over performance \emph{as the default}, allowing careful reduction of safety for performance when necessary. 302 Two concurrency violations of this philosophy are \emph{spurious wakeup} and \emph{barging}, i.e., random wakeup~\cite[\S~8]{Buhr05a} and signalling-as-hints~\cite[\S~8]{Buhr05a}, where one begats the other. 303 If you believe spurious wakeup is a foundational concurrency property, than unblocking (signalling) a thread is always a hint. 304 If you \emph{do not} believe spurious wakeup is foundational, than signalling-as-hints is a performance decision. 305 Most importantly, removing spurious wakeup and signals-as-hints makes concurrent programming significantly safer because it removes local non-determinism. 306 Clawing back performance where the local non-determinism is unimportant, should be an option not the default. 307 308 \begin{comment} 309 For example, it is possible to provide exceptions, coroutines, monitors, and tasks as specialized types in an object-oriented language, integrating these constructs to allow leveraging the type-system (static type-checking) and all other object-oriented capabilities~\cite{uC++}. 310 It is also possible to leverage call/return for blocking communication via new control structures, versus switching to alternative communication paradigms, like channels or message passing. 311 As well, user threading is often a complementary feature, allowing light-weight threading to match with low-cost objects, while hiding the application/kernel boundary. 312 User threading also allows layering of implicit concurrency models (no explicit thread creation), such executors, data-flow, actors, into a single language, so programmers can chose the model that best fits an algorithm.\footnote{ 313 All implicit concurrency models have explicit threading in their implementation, and hence, can be build from explicit threading; 314 however, the reverse is seldom true, i.e., given implicit concurrency, e.g., actors, it is virtually impossible to create explicit concurrency, e.g., blocking thread objects.} 315 Finally, with extended language features and user-level threading it is possible to discretely fold locking and non-blocking I/O multiplexing into the language's I/O libraries, so threading implicitly dovetails with the I/O subsystem. 316 \CFA embraces language extensions and user-level threading to provide advanced control-flow (exception handling\footnote{ 317 \CFA exception handling will be presented in a separate paper. 318 The key feature that dovetails with this paper is non-local exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++} 319 } and coroutines) and concurrency. 320 321 Most augmented traditional (Fortran 18~\cite{Fortran18}, Cobol 14~\cite{Cobol14}, Ada 12~\cite{Ada12}, Java 11~\cite{Java11}) and new languages (Go~\cite{Go}, Rust~\cite{Rust}, and D~\cite{D}), except \CC, diverge from C with different syntax and semantics, only interoperate indirectly with C, and are not systems languages, for those with managed memory. 322 As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten. 323 While \CC, like \CFA, takes an evolutionary approach to extend C, \CC's constantly growing complex and interdependent features-set (e.g., objects, inheritance, templates, etc.) mean idiomatic \CC code is difficult to use from C, and C programmers must expend significant effort learning \CC. 324 Hence, rewriting and retraining costs for these languages, even \CC, are prohibitive for companies with a large C software-base. 325 \CFA with its orthogonal feature-set, its high-performance runtime, and direct access to all existing C libraries circumvents these problems. 326 \end{comment} 327 328 \CFA embraces user-level threading, language extensions for advanced control-flow, and safety as the default. 329 We present comparative examples so the reader can judge if the \CFA control-flow extensions are better and safer than those in or proposed for \Celeven, \CC and other concurrent, imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms. 330 The main contributions of this work are: 331 \begin{itemize} 332 \item 333 expressive language-level coroutines and user-level threading, which respect the expectations of C programmers. 334 \item 335 monitor synchronization without barging. 336 \item 337 safely acquiring multiple monitors \emph{simultaneously} (deadlock free), while seamlessly integrating this capability with all monitor synchronization mechanisms. 338 \item 339 providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features. 340 \item 341 library extensions for executors, futures, and actors built on the basic mechanisms. 342 \item 343 a runtime system with no spurious wakeup. 344 \item 345 experimental results showing comparable performance of the new features with similar mechanisms in other concurrent programming-languages. 346 \end{itemize} 347 348 \begin{comment} 264 349 This paper provides a minimal concurrency \newterm{Application Program Interface} (API) that is simple, efficient and can be used to build other concurrency features. 265 350 While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master. … … 281 366 The proposed concurrency API is implemented in a dialect of C, called \CFA (pronounced C-for-all). 282 367 The paper discusses how the language features are added to the \CFA translator with respect to parsing, semantics, and type checking, and the corresponding high-performance runtime-library to implement the concurrent features. 283 284 368 \end{comment} 369 370 371 \begin{comment} 285 372 \section{\CFA Overview} 286 373 … … 551 638 \end{cfa} 552 639 where the return type supplies the type/size of the allocation, which is impossible in most type systems. 553 554 555 \section{Concurrency} 556 \label{s:Concurrency} 557 558 At its core, concurrency is based on multiple call-stacks and scheduling threads executing on these stacks. 559 Multiple call stacks (or contexts) and a single thread of execution, called \newterm{coroutining}~\cite{Conway63,Marlin80}, does \emph{not} imply concurrency~\cite[\S~2]{Buhr05a}. 560 In coroutining, the single thread is self-scheduling across the stacks, so execution is deterministic, \ie the execution path from input to output is fixed and predictable. 561 A \newterm{stackless} coroutine executes on the caller's stack~\cite{Python} but this approach is restrictive, \eg preventing modularization and supporting only iterator/generator-style programming; 562 a \newterm{stackful} coroutine executes on its own stack, allowing full generality. 563 Only stackful coroutines are a stepping stone to concurrency. 564 565 The transition to concurrency, even for execution with a single thread and multiple stacks, occurs when coroutines also context switch to a \newterm{scheduling oracle}, introducing non-determinism from the coroutine perspective~\cite[\S~3]{Buhr05a}. 566 Therefore, a minimal concurrency system is possible using coroutines (see Section \ref{coroutine}) in conjunction with a scheduler to decide where to context switch next. 567 The resulting execution system now follows a cooperative threading-model, called \newterm{non-preemptive scheduling}. 568 569 Because the scheduler is special, it can either be a stackless or stackful coroutine. 570 For stackless, the scheduler performs scheduling on the stack of the current coroutine and switches directly to the next coroutine, so there is one context switch. 571 For stackful, the current coroutine switches to the scheduler, which performs scheduling, and it then switches to the next coroutine, so there are two context switches. 572 A stackful scheduler is often used for simplicity and security. 573 574 Regardless of the approach used, a subset of concurrency related challenges start to appear. 575 For the complete set of concurrency challenges to occur, the missing feature is \newterm{preemption}, where context switching occurs randomly between any two instructions, often based on a timer interrupt, called \newterm{preemptive scheduling}. 576 While a scheduler introduces uncertainty in the order of execution, preemption introduces uncertainty about where context switches occur. 577 Interestingly, uncertainty is necessary for the runtime (operating) system to give the illusion of parallelism on a single processor and increase performance on multiple processors. 578 The reason is that only the runtime has complete knowledge about resources and how to best utilized them. 579 However, the introduction of unrestricted non-determinism results in the need for \newterm{mutual exclusion} and \newterm{synchronization} to restrict non-determinism for correctness; 580 otherwise, it is impossible to write meaningful programs. 581 Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows. 582 583 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. 584 As such, library support for threading is far from widespread. 585 At the time of writing the paper, neither \protect\lstinline@gcc@ nor \protect\lstinline@clang@ support \protect\lstinline@threads.h@ in their standard libraries.}. 586 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. 587 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. 588 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. 589 Hence, concurrent programs should be written using high-level mechanisms, and only step down to lower-level mechanisms when performance bottlenecks are encountered. 590 591 592 \subsection{Coroutines: A Stepping Stone}\label{coroutine} 593 594 While the focus of this discussion is concurrency and parallelism, it is important to address coroutines, which are a significant building block of a concurrency system (but not concurrent among themselves). 640 \end{comment} 641 642 643 \section{Coroutines: Stepping Stone} 644 \label{coroutine} 645 595 646 Coroutines are generalized routines allowing execution to be temporarily suspended and later resumed. 596 647 Hence, unlike a normal routine, a coroutine may not terminate when it returns to its caller, allowing it to be restarted with the values and execution location present at the point of suspension. … … 616 667 \centering 617 668 \newbox\myboxA 669 % \begin{lrbox}{\myboxA} 670 % \begin{cfa}[aboveskip=0pt,belowskip=0pt] 671 % `int fn1, fn2, state = 1;` // single global variables 672 % int fib() { 673 % int fn; 674 % `switch ( state )` { // explicit execution state 675 % case 1: fn = 0; fn1 = fn; state = 2; break; 676 % case 2: fn = 1; fn2 = fn1; fn1 = fn; state = 3; break; 677 % case 3: fn = fn1 + fn2; fn2 = fn1; fn1 = fn; break; 678 % } 679 % return fn; 680 % } 681 % int main() { 682 % 683 % for ( int i = 0; i < 10; i += 1 ) { 684 % printf( "%d\n", fib() ); 685 % } 686 % } 687 % \end{cfa} 688 % \end{lrbox} 618 689 \begin{lrbox}{\myboxA} 619 690 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 620 `int f1, f2, state = 1;` // single global variables 621 int fib() { 622 int fn; 623 `switch ( state )` { // explicit execution state 624 case 1: fn = 0; f1 = fn; state = 2; break; 625 case 2: fn = 1; f2 = f1; f1 = fn; state = 3; break; 626 case 3: fn = f1 + f2; f2 = f1; f1 = fn; break; 627 } 628 return fn; 629 } 691 #define FIB_INIT { 0, 1 } 692 typedef struct { int fn1, fn; } Fib; 693 int fib( Fib * f ) { 694 695 int ret = f->fn1; 696 f->fn1 = f->fn; 697 f->fn = ret + f->fn; 698 return ret; 699 } 700 701 702 630 703 int main() { 631 704 Fib f1 = FIB_INIT, f2 = FIB_INIT; 632 705 for ( int i = 0; i < 10; i += 1 ) { 633 printf( "%d\n", fib() ); 706 printf( "%d %d\n", 707 fib( &f1 ), fib( &f2 ) ); 634 708 } 635 709 } … … 640 714 \begin{lrbox}{\myboxB} 641 715 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 642 #define FIB_INIT `{ 0, 1 }` 643 typedef struct { int f2, f1; } Fib; 644 int fib( Fib * f ) { 645 646 int ret = f->f2; 647 int fn = f->f1 + f->f2; 648 f->f2 = f->f1; f->f1 = fn; 649 650 return ret; 651 } 652 int main() { 653 Fib f1 = FIB_INIT, f2 = FIB_INIT; 654 for ( int i = 0; i < 10; i += 1 ) { 655 printf( "%d %d\n", fib( &f1 ), fib( &f2 ) ); 716 `coroutine` Fib { int fn1; }; 717 void main( Fib & fib ) with( fib ) { 718 int fn; 719 [fn1, fn] = [0, 1]; 720 for () { 721 `suspend();` 722 [fn1, fn] = [fn, fn1 + fn]; 656 723 } 657 724 } 658 \end{cfa} 659 \end{lrbox} 660 661 \subfloat[3 States: global variables]{\label{f:GlobalVariables}\usebox\myboxA} 662 \qquad 663 \subfloat[1 State: external variables]{\label{f:ExternalState}\usebox\myboxB} 664 \caption{C Fibonacci Implementations} 665 \label{f:C-fibonacci} 666 667 \bigskip 668 669 \newbox\myboxA 670 \begin{lrbox}{\myboxA} 671 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 672 `coroutine` Fib { int fn; }; 673 void main( Fib & fib ) with( fib ) { 674 int f1, f2; 675 fn = 0; f1 = fn; `suspend()`; 676 fn = 1; f2 = f1; f1 = fn; `suspend()`; 677 for ( ;; ) { 678 fn = f1 + f2; f2 = f1; f1 = fn; `suspend()`; 679 } 680 } 681 int next( Fib & fib ) with( fib ) { 682 `resume( fib );` 683 return fn; 725 int ?()( Fib & fib ) with( fib ) { 726 `resume( fib );` return fn1; 684 727 } 685 728 int main() { 686 729 Fib f1, f2; 687 for ( int i = 1; i <= 10; i += 1 ) { 688 sout | next( f1 ) | next( f2 ); 689 } 690 } 730 for ( 10 ) { 731 sout | f1() | f2(); 732 } 733 734 691 735 \end{cfa} 692 736 \end{lrbox} 693 \newbox\myboxB 694 \begin{lrbox}{\myboxB} 695 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 696 `coroutine` Fib { int ret; }; 697 void main( Fib & f ) with( fib ) { 698 int fn, f1 = 1, f2 = 0; 699 for ( ;; ) { 700 ret = f2; 701 702 fn = f1 + f2; f2 = f1; f1 = fn; `suspend();` 703 } 704 } 705 int next( Fib & fib ) with( fib ) { 706 `resume( fib );` 707 return ret; 708 } 709 710 711 712 713 714 715 \end{cfa} 737 738 \newbox\myboxC 739 \begin{lrbox}{\myboxC} 740 \begin{python}[aboveskip=0pt,belowskip=0pt] 741 742 def Fib(): 743 744 fn1, fn = 0, 1 745 while True: 746 `yield fn1` 747 fn1, fn = fn, fn1 + fn 748 749 750 // next prewritten 751 752 753 f1 = Fib() 754 f2 = Fib() 755 for i in range( 10 ): 756 print( next( f1 ), next( f2 ) ) 757 758 759 760 \end{python} 716 761 \end{lrbox} 717 \subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA} 718 \qquad\qquad 719 \subfloat[1 State, internal variables]{\label{f:Coroutine1State}\usebox\myboxB} 720 \caption{\CFA Coroutine Fibonacci Implementations} 721 \label{f:cfa-fibonacci} 762 763 \subfloat[C]{\label{f:GlobalVariables}\usebox\myboxA} 764 \hspace{3pt} 765 \vrule 766 \hspace{3pt} 767 \subfloat[\CFA]{\label{f:ExternalState}\usebox\myboxB} 768 \hspace{3pt} 769 \vrule 770 \hspace{3pt} 771 \subfloat[Python]{\label{f:ExternalState}\usebox\myboxC} 772 \caption{Fibonacci Generator} 773 \label{f:C-fibonacci} 774 775 % \bigskip 776 % 777 % \newbox\myboxA 778 % \begin{lrbox}{\myboxA} 779 % \begin{cfa}[aboveskip=0pt,belowskip=0pt] 780 % `coroutine` Fib { int fn; }; 781 % void main( Fib & fib ) with( fib ) { 782 % fn = 0; int fn1 = fn; `suspend()`; 783 % fn = 1; int fn2 = fn1; fn1 = fn; `suspend()`; 784 % for () { 785 % fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `suspend()`; } 786 % } 787 % int next( Fib & fib ) with( fib ) { `resume( fib );` return fn; } 788 % int main() { 789 % Fib f1, f2; 790 % for ( 10 ) 791 % sout | next( f1 ) | next( f2 ); 792 % } 793 % \end{cfa} 794 % \end{lrbox} 795 % \newbox\myboxB 796 % \begin{lrbox}{\myboxB} 797 % \begin{python}[aboveskip=0pt,belowskip=0pt] 798 % 799 % def Fibonacci(): 800 % fn = 0; fn1 = fn; `yield fn` # suspend 801 % fn = 1; fn2 = fn1; fn1 = fn; `yield fn` 802 % while True: 803 % fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `yield fn` 804 % 805 % 806 % f1 = Fibonacci() 807 % f2 = Fibonacci() 808 % for i in range( 10 ): 809 % print( `next( f1 )`, `next( f2 )` ) # resume 810 % 811 % \end{python} 812 % \end{lrbox} 813 % \subfloat[\CFA]{\label{f:Coroutine3States}\usebox\myboxA} 814 % \qquad 815 % \subfloat[Python]{\label{f:Coroutine1State}\usebox\myboxB} 816 % \caption{Fibonacci input coroutine, 3 states, internal variables} 817 % \label{f:cfa-fibonacci} 722 818 \end{figure} 723 819 … … 759 855 \begin{lrbox}{\myboxA} 760 856 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 761 `coroutine` F ormat {762 char ch; // used for communication763 int g, b; // global because used in destructor857 `coroutine` Fmt { 858 char ch; // communication variables 859 int g, b; // needed in destructor 764 860 }; 765 void main( F ormat & fmt ) with( fmt ) {766 for ( ;;) {767 for ( g = 0; g < 5; g += 1 ) { // group768 for ( b = 0; b < 4; b += 1 ) { // block 861 void main( Fmt & fmt ) with( fmt ) { 862 for () { 863 for ( g = 0; g < 5; g += 1 ) { // groups 864 for ( b = 0; b < 4; b += 1 ) { // blocks 769 865 `suspend();` 770 sout | ch; // separator 771 } 772 sout | " "; // separator 773 } 774 sout | nl; 775 } 776 } 777 void ?{}( Format & fmt ) { `resume( fmt );` } 778 void ^?{}( Format & fmt ) with( fmt ) { 779 if ( g != 0 || b != 0 ) sout | nl; 780 } 781 void format( Format & fmt ) { 782 `resume( fmt );` 783 } 866 sout | ch; } // print character 867 sout | " "; } // block separator 868 sout | nl; } // group separator 869 } 870 void ?{}( Fmt & fmt ) { `resume( fmt );` } // prime 871 void ^?{}( Fmt & fmt ) with( fmt ) { // destructor 872 if ( g != 0 || b != 0 ) // special case 873 sout | nl; } 874 void send( Fmt & fmt, char c ) { fmt.ch = c; `resume( fmt )`; } 784 875 int main() { 785 Format fmt; 786 eof: for ( ;; ) { 787 sin | fmt.ch; 788 if ( eof( sin ) ) break eof; 789 format( fmt ); 790 } 876 Fmt fmt; 877 sout | nlOff; // turn off auto newline 878 for ( 41 ) 879 send( fmt, 'a' ); 791 880 } 792 881 \end{cfa} … … 795 884 \newbox\myboxB 796 885 \begin{lrbox}{\myboxB} 797 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 798 struct Format { 799 char ch; 800 int g, b; 801 }; 802 void format( struct Format * fmt ) { 803 if ( fmt->ch != -1 ) { // not EOF ? 804 printf( "%c", fmt->ch ); 805 fmt->b += 1; 806 if ( fmt->b == 4 ) { // block 807 printf( " " ); // separator 808 fmt->b = 0; 809 fmt->g += 1; 810 } 811 if ( fmt->g == 5 ) { // group 812 printf( "\n" ); // separator 813 fmt->g = 0; 814 } 815 } else { 816 if ( fmt->g != 0 || fmt->b != 0 ) printf( "\n" ); 817 } 818 } 819 int main() { 820 struct Format fmt = { 0, 0, 0 }; 821 for ( ;; ) { 822 scanf( "%c", &fmt.ch ); 823 if ( feof( stdin ) ) break; 824 format( &fmt ); 825 } 826 fmt.ch = -1; 827 format( &fmt ); 828 } 829 \end{cfa} 886 \begin{python}[aboveskip=0pt,belowskip=0pt] 887 888 889 890 def Fmt(): 891 try: 892 while True: 893 for g in range( 5 ): 894 for b in range( 4 ): 895 896 print( `(yield)`, end='' ) 897 print( ' ', end='' ) 898 print() 899 900 901 except GeneratorExit: 902 if g != 0 | b != 0: 903 print() 904 905 906 fmt = Fmt() 907 `next( fmt )` # prime 908 for i in range( 41 ): 909 `fmt.send( 'a' );` # send to yield 910 911 \end{python} 830 912 \end{lrbox} 831 \subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}913 \subfloat[\CFA]{\label{f:CFAFmt}\usebox\myboxA} 832 914 \qquad 833 \subfloat[ C Linearized]{\label{f:CFmt}\usebox\myboxB}834 \caption{ Formatting text into lines of 5 blocks of 4 characters.}915 \subfloat[Python]{\label{f:CFmt}\usebox\myboxB} 916 \caption{Output formatting text} 835 917 \label{f:fmt-line} 836 918 \end{figure} … … 853 935 void main( Prod & prod ) with( prod ) { 854 936 // 1st resume starts here 855 for ( i nt i = 0; i < N; i += 1) {937 for ( i; N ) { 856 938 int p1 = random( 100 ), p2 = random( 100 ); 857 939 sout | p1 | " " | p2; … … 869 951 } 870 952 void start( Prod & prod, int N, Cons &c ) { 871 &prod.c = &c; 953 &prod.c = &c; // reassignable reference 872 954 prod.[N, receipt] = [N, 0]; 873 955 `resume( prod );` … … 884 966 Prod & p; 885 967 int p1, p2, status; 886 _Bool done;968 bool done; 887 969 }; 888 970 void ?{}( Cons & cons, Prod & p ) { 889 &cons.p = &p; 971 &cons.p = &p; // reassignable reference 890 972 cons.[status, done ] = [0, false]; 891 973 } … … 945 1027 @start@ returns and the program main terminates. 946 1028 1029 One \emph{killer} application for a coroutine is device drivers, which at one time caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}. 1030 Many device drivers are a finite state-machine parsing a protocol, e.g.: 1031 \begin{tabbing} 1032 \ldots STX \= \ldots message \ldots \= ESC \= ETX \= \ldots message \ldots \= ETX \= 2-byte crc \= \ldots \kill 1033 \ldots STX \> \ldots message \ldots \> ESC \> ETX \> \ldots message \ldots \> ETX \> 2-byte crc \> \ldots 1034 \end{tabbing} 1035 where a network message begins with the control character STX and ends with an ETX, followed by a 2-byte cyclic-redundancy check. 1036 Control characters may appear in a message if preceded by an ESC. 1037 Because FSMs can be complex and occur frequently in important domains, direct support of the coroutine is crucial in a systems programminglanguage. 1038 1039 \begin{figure} 1040 \begin{cfa} 1041 enum Status { CONT, MSG, ESTX, ELNTH, ECRC }; 1042 `coroutine` Driver { 1043 Status status; 1044 char * msg, byte; 1045 }; 1046 void ?{}( Driver & d, char * m ) { d.msg = m; } $\C[3.0in]{// constructor}$ 1047 Status next( Driver & d, char b ) with( d ) { $\C{// 'with' opens scope}$ 1048 byte = b; `resume( d );` return status; 1049 } 1050 void main( Driver & d ) with( d ) { 1051 enum { STX = '\002', ESC = '\033', ETX = '\003', MaxMsg = 64 }; 1052 unsigned short int crc; $\C{// error checking}$ 1053 msg: for () { $\C{// parse message}$ 1054 status = CONT; 1055 unsigned int lnth = 0, sum = 0; 1056 while ( byte != STX ) `suspend();` 1057 emsg: for () { 1058 `suspend();` $\C{// process byte}$ 1059 choose ( byte ) { $\C{// switch with default break}$ 1060 case STX: 1061 status = ESTX; `suspend();` continue msg; 1062 case ETX: 1063 break emsg; 1064 case ESC: 1065 suspend(); 1066 } // choose 1067 if ( lnth >= MaxMsg ) { $\C{// buffer full ?}$ 1068 status = ELNTH; `suspend();` continue msg; } 1069 msg[lnth++] = byte; 1070 sum += byte; 1071 } // for 1072 msg[lnth] = '\0'; $\C{// terminate string}\CRT$ 1073 `suspend();` 1074 crc = (unsigned char)byte << 8; // prevent sign extension for signed char 1075 `suspend();` 1076 status = (crc | (unsigned char)byte) == sum ? MSG : ECRC; 1077 `suspend();` 1078 } // for 1079 } 1080 \end{cfa} 1081 \caption{Device driver for simple communication protocol} 1082 \end{figure} 1083 947 1084 948 1085 \subsection{Coroutine Implementation} … … 1060 1197 \end{cquote} 1061 1198 The combination of these two approaches allows an easy and concise specification to coroutining (and concurrency) for normal users, while more advanced users have tighter control on memory layout and initialization. 1199 1200 1201 \section{Concurrency} 1202 \label{s:Concurrency} 1203 1204 At its core, concurrency is based on multiple call-stacks and scheduling threads executing on these stacks. 1205 Multiple call stacks (or contexts) and a single thread of execution, called \newterm{coroutining}~\cite{Conway63,Marlin80}, does \emph{not} imply concurrency~\cite[\S~2]{Buhr05a}. 1206 In coroutining, the single thread is self-scheduling across the stacks, so execution is deterministic, \ie the execution path from input to output is fixed and predictable. 1207 A \newterm{stackless} coroutine executes on the caller's stack~\cite{Python} but this approach is restrictive, \eg preventing modularization and supporting only iterator/generator-style programming; 1208 a \newterm{stackful} coroutine executes on its own stack, allowing full generality. 1209 Only stackful coroutines are a stepping stone to concurrency. 1210 1211 The transition to concurrency, even for execution with a single thread and multiple stacks, occurs when coroutines also context switch to a \newterm{scheduling oracle}, introducing non-determinism from the coroutine perspective~\cite[\S~3]{Buhr05a}. 1212 Therefore, a minimal concurrency system is possible using coroutines (see Section \ref{coroutine}) in conjunction with a scheduler to decide where to context switch next. 1213 The resulting execution system now follows a cooperative threading-model, called \newterm{non-preemptive scheduling}. 1214 1215 Because the scheduler is special, it can either be a stackless or stackful coroutine. 1216 For stackless, the scheduler performs scheduling on the stack of the current coroutine and switches directly to the next coroutine, so there is one context switch. 1217 For stackful, the current coroutine switches to the scheduler, which performs scheduling, and it then switches to the next coroutine, so there are two context switches. 1218 A stackful scheduler is often used for simplicity and security. 1219 1220 Regardless of the approach used, a subset of concurrency related challenges start to appear. 1221 For the complete set of concurrency challenges to occur, the missing feature is \newterm{preemption}, where context switching occurs randomly between any two instructions, often based on a timer interrupt, called \newterm{preemptive scheduling}. 1222 While a scheduler introduces uncertainty in the order of execution, preemption introduces uncertainty about where context switches occur. 1223 Interestingly, uncertainty is necessary for the runtime (operating) system to give the illusion of parallelism on a single processor and increase performance on multiple processors. 1224 The reason is that only the runtime has complete knowledge about resources and how to best utilized them. 1225 However, the introduction of unrestricted non-determinism results in the need for \newterm{mutual exclusion} and \newterm{synchronization} to restrict non-determinism for correctness; 1226 otherwise, it is impossible to write meaningful programs. 1227 Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows. 1228 1229 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. 1230 As such, library support for threading is far from widespread. 1231 At the time of writing the paper, neither \protect\lstinline@gcc@ nor \protect\lstinline@clang@ support \protect\lstinline@threads.h@ in their standard libraries.}. 1232 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. 1233 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. 1234 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. 1235 Hence, concurrent programs should be written using high-level mechanisms, and only step down to lower-level mechanisms when performance bottlenecks are encountered. 1062 1236 1063 1237 -
doc/papers/concurrency/mail
r6a9d4b4 r933f32f 27 27 28 28 Software: Practice and Experience Editorial Office 29 30 31 32 Date: Wed, 3 Oct 2018 21:25:28 +0000 33 From: Richard Jones <onbehalfof@manuscriptcentral.com> 34 Reply-To: R.E.Jones@kent.ac.uk 35 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca 36 Subject: Software: Practice and Experience - Decision on Manuscript ID 37 SPE-18-0205 38 39 03-Oct-2018 40 41 Dear Dr Buhr, 42 43 Many thanks for submitting SPE-18-0205 entitled "Concurrency in C∀" to Software: Practice and Experience. 44 45 In view of the comments of the referees found at the bottom of this letter, I cannot accept your paper for publication in Software: Practice and Experience. I hope that you find the referees' very detailed comments helpful. 46 47 Thank you for considering Software: Practice and Experience for the publication of your research. I hope the outcome of this specific submission will not discourage you from submitting future manuscripts. 48 49 Yours sincerely, 50 51 52 Prof. Richard Jones 53 Editor, Software: Practice and Experience 54 R.E.Jones@kent.ac.uk 55 56 Referee(s)' Comments to Author: 57 58 Reviewing: 1 59 60 Comments to the Author 61 "Concurrency in Cforall" presents a design and implementation of a set of standard concurrency features, including coroutines, user-space and kernel-space threads, mutexes, monitors, and a scheduler, for a polymorphic derivation of C called Cforall. 62 63 Section 2 is an overview of sequential Cforall that does not materially contribute to the paper. A brief syntax explanation where necessary in examples would be plenty. 64 65 Section 3 begins with with an extensive discussion of concurrency that also does not materially contribute to the paper. A brief mention of whether a particular approach implements cooperative or preemptive scheduling would be sufficient. Section 3 also makes some unfortunate claims, such as C not having threads -- C does in fact define threads, and this is noted as being true in a footnote, immediately after claiming that it does not. The question remains why the C11 parallelism design is insufficient and in what way this paper proposes to augment it. While I am personally a proponent of parallel programming languages, backing the assertion that all modern languages must have threading with citations from 2005 ignores the massive popularity of modern non-parallel languages (Javascript, node.js, Typescript, Python, Ruby, etc.) and parallel languages that are not thread based, although the authors are clearly aware of such approaches. 66 67 Sections 3.1 and 3.2 dicusses assymetric and symmetric coroutines. This also does not seem to materially contribute to a paper that is ostensibly about concurrency in a modern systems programming language. The area of coroutines, continuations, and generators is already well explored in the context of systems languages, including compilation techniques for these constructs that are more advanced than the stack instantiation model discussed in the paper. 68 69 Section 3.3 describes threads in Cforall, briefly touching on user-space vs. kernel-space thread implementations without detailing the extensive practical differences. It is unclear how the described interface differes from C++11 threads, as the description seems to center on an RAII style approach to joining in the destructor. 70 71 Section 4 briefly touches on a collection of well known synchronisation primitives. Again, this discussion does not materially contribute to the paper. 72 73 Section 5 describes monitors, which are a well known and well researched technique. The Cforall implementation is unsurprising. The "multi-acquire semantics" described are not a contribution of this paper, as establishing a stable order for lock acquisition is a well known technique, one example of which is the C++ std::scoped_lock. 74 75 Section 6 is a discussion of scheduling that does not appear to be informed by the literature. There is no discussion of work-stealing vs. work-scheduling, static vs. dynamic priorities, priority inversion, or fairness. There is a claim in secion 6.1 for a novel technique, partial signalling, that appears to be a form of dynamic priority, but no comparison is made. In section 6.6, a very brief mention of other synchronisation techniques is made, without reference to current techniques such as array-based locks, CLH or MCS queue locks, RCU and other epoch-based mechanisms, etc. Perhaps these are considered out of scope. 76 77 Section 7 discusses parallelism, but does not materially contribute to the paper. It is claimed that preemption is necessary to implement spinning, which is not correct, since two cores can implement a spinning based approach without preemption. It is claimed that with thread pools "concurrency errors return", but no approach to removing concurrency errors with either preemptive or cooperatively scheduled user threads has been proposed in the paper that would not also apply to thread pools. 78 79 Section 8 is intended to describe the Cforall runtime structure, but does so in a way that uses terminology in an unfamiliar way. The word cluster is more usually used in distributed systems, but here refers to a process. The term virtual processor is more usually used in hardware virtualisation, but here refers to a kernel thread. The term debug kernel is more usually used in operating systems to refer to kernels that have both debug info and a method for using a debugger in kernel space, but here refers to a debug build of a user-space process. This section does not materially contribute to the paper. 80 81 Section 9 is intended to describe the Cforall runtime implementation. It makes some unusual claims, such as C libraries migrating to stack chaining (stack chaining was an experimental GCC feature that has been abandoned, much as it has been abandoned in both Go and Rust). 82 83 The performance measurements in section 10 are difficult to evaluate. While I appreciate that comparable concurrency benchmarks are very difficult to write, and the corpus of existing benchmarks primarily boils down to the parallel programs in the Computer Language Benchmark Game, the lack of detail as to what is being measured in these benchmarks (particularly when implemented in other languages) is unfortunate. For example, in table 3, the benchmark appears to measure uncontended lock access, which is not a useful micro-benchmark. 84 85 It is not clear what the contributions of this paper are intended to be. A concise listing of the intended contributions would be helpful. Currently, it appears that the paper makes neither PL contributions in terms of novel features in Cforall, nor does it make systems contributions in terms of novel features in the runtime. 86 87 88 Reviewing: 2 89 90 Comments to the Author 91 This article presents the design and rationale behind the concurrency 92 features of C-forall, a new low-level programming language. After an 93 introduction that defines a selection of standard terminology, section 94 2 gives crucial background on the design of the C-forall language. 95 Section 3 then starts the core of the article, discussing the 96 language's support for "concurrency" which in this case means 97 coroutines and threads; a very brief Section 4 builds on section 3 98 with a discussion of lower level synchronizations. Section 5 the 99 presents the main features of concurrency control in C-forall: 100 monitors and mutexes. Section 6 then extends monitors with condition 101 variables to to support scheduling, and a very brief section 7 102 discusses preemption and pooling. Section 8 discusses the runtime 103 conceptual model, section 9 gives implementation detail, and section 104 10 briefly evaluates C-forall's performance via five concurrent 105 micro benchmarks. Finally section 11 concludes the article, and then 106 section 12 presents some future work. 107 108 109 At the start of section 7, article lays out its rationale: that while 110 "historically, computer performance was about processor speeds" but 111 "Now, high-performance applications must care about parallelism, 112 which requires concurrency". The doomsayers trumpeting the death of 113 Moore's law have been proved correct at last, with CPUs sequential 114 performance increasing much more slowly than the number of cores 115 within each die. This means programmers --- especially low-level, 116 systems programmers --- must somehow manage the essential complexity 117 of writing concurrent programs to run in parallel in multiple threads 118 across multiple cores. Unfortunately, the most venerable widely used 119 systems programming language, C, supports parallelism only via an 120 e.g. the threads library. This article aims to integrate concurrent 121 programming mechanisms more closely into a novel low-level C-based 122 programming language, C-forall. The article gives an outline of much of 123 C-forall, presents a series of concurrency mechanisms, and finally 124 some microbenchmark results. The article is detailed, comprehensive, 125 and generally well written in understandable English. 126 127 My main concern about the article are indicated by the fact that the 128 best summary of the problem the design of concurrent C-forall sets 129 out to solve is buried more than halfway through the article in section 130 7, as above, and then the best overview of the proposed solution is 131 given in the 2nd, 4th and 5th sentence of the conclusion: 132 133 "The approach provides concurrency based on a preemptive M:N 134 user-level threading-system, executing in clusters, which 135 encapsulate scheduling of work on multiple kernel threads 136 providing parallelism... High-level objects (monitor/task) are the 137 core mechanism for mutual exclusion and synchronization. A novel 138 aspect is allowing multiple mutex-objects to be accessed 139 simultaneously reducing the potential for deadlock for this 140 complex scenario." 141 142 That is, in my reading of the article, it proceeds bottom up rather 143 than top down, and so my main recommendation is to essentially reverse 144 the order of the article, proceeding from the problem to be solved, 145 the high level architecture of the proposed solutions, and then going 146 down to the low-level mechanisms. My biggest problem reading the 147 article was for explanations of why a particular decision was taken, 148 or why a particular mechanism may be used --- often this description 149 is actually later in the article, but at that point it's too late for 150 the reader. I have tried to point out most of these places in the 151 detailed comments below. 152 153 My second concern is that the article makes several claims that are 154 not really justified by the design or implementation in the article. 155 These include claims that this approach meets the expectations of C 156 programmers, is minimal, is implemented in itself, etc. The article 157 doesn't generally offer evidence to support these assertions (for many 158 of them, that would require empirical studies of programmers, or at 159 least corpus studies). The solution here is to talk about motivations 160 for the design choices "we made these decisions hoping that C 161 programmers would be comfortable" rather than claims of fact "C 162 programmers are comfortable". Again I attempt to point these out below. 163 164 * abstract: needs to characterize the work top down, and not make 165 claims "features respect the expectations of C programmers" that 166 are not supported empirically. 167 168 * p1 line 14 "integrated" 169 170 * introduction needs to introduce the big ideas and scope of the 171 article, not define terms. Some of the terms / distinctions are 172 non-standard (e.g. the distinction between "concurrency" and 173 "parallelism") and can be avoided by using more specific terms 174 (mutual exclusion, synchronization, parallel execution. etc). 175 176 * to me this article introduces novel language features, not just an 177 API. Similarly, it doesn't talk about any additions "to the 178 language translator" - i.e compiler changes! - rather about language 179 features. 180 181 182 * section 2 lines 6-9 why buy this fight against object-orientation? 183 this article doesn't need to make this argument, but needs to do a 184 better job of it if it does (see other comments below) 185 186 * sec 2.1 - are these the same as C++. IF so, say so, if not, say why 187 not. 188 189 * 2.2 calling it a "with statement" was confusing, given that a with 190 clause can appear in a routine declaration with a shorthand syntax. 191 192 * 2.3 again compare with C++ and Java (as well as Ada) 193 194 * line 9 "as we will see in section 3" 195 196 * 2.4 I really quite like this syntax for operators, destructors not 197 so much. 198 199 * 2.5 and many places elsewhere. Always first describe the semantics 200 of your language constructs, then describe their properties, then 201 compare with e.g. related languages (mostly C++ & Java?). E.g in 202 this case, something like: 203 204 "C-forall includes constructors, which are called to initialize 205 newly allocated objects, and constructors, which are called when 206 objects are deallocated. Constructors and destructors are written as 207 functions returning void, under the special names "?{}" for 208 constructors and "^{}" for destructors: constructors may be 209 overridden, but destructors may not be. The semantics of C-forall's 210 constructors and destructors are essentially those of C++." 211 212 this problem repeats many times throughout the article and should be 213 fixed everywhere. 214 215 216 * 2.6 again, first describe then properties then comparison. 217 in this case, compare e.g. with C++ templates, Java/Ada generics 218 etc. 219 220 * why special case forward declarations? It's not 1970 any more. 221 222 * what are traits? structural interfaces (like Go interfaces) or 223 nominal bindings? 224 225 * section 3 - lines 2-30, also making very specific global definitions 226 as in the introduction. The article does not need to take on this 227 fight either, rather make clear that this is the conceptual model in 228 C-forall. (If the article starts at the top and works down, that may 229 well follow anyway). 230 231 * "in modern programming languages... unacceptable"; "in a 232 system-level language.. concurrent programs should be written with 233 high-level features" - again, no need to take on these fights. 234 235 * 3.1 onwards; I found all this "building" up hard to follow. 236 also it's not clear a "minimal" API must separately support 237 coroutines, threads, fibres, etc 238 239 * FIG 2B - where's the output? 240 syntax "sout | next(f1) | next(f2) | endl" nowhere explained 241 why not use C++s' << and >> 242 243 * FIG 3 be clearer, earlier about the coroutine" constructor syntax 244 245 ** ensure all figures are placed *after* their first mention in the 246 text. consider interleaving smaller snippets of text rather than 247 just referring to large figures 248 249 * sec 3.1 p7 etc,. need more context / comparison e.g. Python 250 generators etc. 251 252 * FIGURE 4 is this right? should there a constructor for Cons taking 253 a Prod? 254 255 256 * sec 3.2 order of constructors depends on the language. more 257 generally, if the article is going to make arguments against OO 258 (e.g. section 2) then the article needs to explain, in detail, why 259 e.g. coroutine, thread, etc *cannot* be classes / objects. 260 261 * "type coroutine_t must be an abstract handle.. descriptor and is 262 stack are non-copyable" - too many assumptions in here (and other 263 similar passages) that are not really spelled out in detail. 264 265 * p10 line 4 introduces "coroutine" keyword. needs to give its 266 semantics. also needs to introduce and define properties and compare 267 before all the examples using coroutines. 268 269 * p10 again, trait semantics need to be better defined 270 271 * 3.3 should be an introduction to this section. Note that section 272 titles are not part of the text of the article. 273 274 * what's the difference between "coroutines" and "user threads" (and 275 "fibres?") 276 277 * what's a "task type" or an "interface routine" or "underlying 278 thread" 279 280 * section 4 - "... meaningless". nope some semantics are possible 281 e.g. if there's a memory model. 282 283 * whatare "call/return based languages" 284 285 * p12 - what if a programmer wants to join e.g. "1st of N" or "1st 3 of N" 286 threads rather than all threads in order 287 288 * 4.1 p12 13-25, again it's not clear where this is going. presenting the model 289 top down may hopefully resolve this 290 291 * section 4 should be merged e.g. into sec 3 (or 5) 292 293 294 295 * section 5 p13 what's "routine" scope. "call/return paradigm" 296 297 * thread/ coroutine declarations, traits etc, all look pretty close to 298 inheritance. why wouldn't inheritance work? 299 300 * open/closed locks = free/acquired free locks? 301 302 * testability? 303 304 * p14 lines 14-20 I had trouble following this. e.g/. what's the 305 difference between "a type that is a monitor" and "a type that looks 306 like a monitor"? why? 307 308 * line 39 - what's an "object-oriented monitor"? Java? 309 there is no one OO model of such things. 310 311 * line 47 significant asset - how do you know? 312 313 * how could this e.g. build a reader/writer lock 314 315 * *p15 what's the "bank account transfer problem" 316 317 *p16 lines6-10 why? explain? 318 319 *p17 semantics of arrays of conditions is unclear 320 given e.g. previous comments about arrays of mutexes. 321 322 *p18 define "spurious wakeup" 323 324 *p18 line 44 - "a number of approaches were examined"? which 325 approaches? examined by whom? if this is a novel contribution, needs 326 rather more there, and more comparison with related work 327 328 * FIG 8 consider e.g. sequence diagrams rather than code to show these 329 cases 330 331 * 6.2 p19 line 5 "similarly, monitor routines can be added at any 332 time" really? I thought C-forall was compiled? there's a big 333 difference between "static" and "dynamic" inheritance. which is this 334 closer to? 335 336 * line 25 "FIgure 9 (B) shows the monitor implementation" 337 I didn't understand this, especially not as an implementation. 338 339 * section 6.6 - if the article is to make claims about completeness, 340 about supporting low and high level operations, then this must be 341 expanded to give enough detail to support that argument 342 343 * "truest realization" huh? 344 345 * section 7 should be merged into 6 or 8. 346 it's not clear if this is exploring rejected alternatives, 347 out outlining different features offered by C-forall, or what. 348 349 350 * sec 7.2 how do the other threads in sections 5 & 6 relate to the 351 user threads, fibres, etc here; 352 353 * sec 8.1 I found these sections hard to follow. how is a cluster a 354 "collection of threads and virtual processors... like a virtual 355 machine"? Where do the thread pools from 7.3 fit in? 356 357 * sec 8.3 is out of place, probably unneeded in the paper 358 359 * section 9 dives straight into details with no overview. Section 9 360 seems very detailed, and depends on assumptions or details that are 361 not in the article. 362 363 * section 10 covers only microbenchmarks. are there any moderate sized 364 macrobenchmarks that can compare across the different systems? 365 (e.g the Erlang Ring?) 366 367 * sec 11 claims that "the entire C-forall runtime system are written 368 in C-forall". The article doesn't 369 370 371 * future work should precede conclusion, not follow it 372 373 * the article should have a related work section (2-3 pages) comparing 374 the design overall with various competing designs (C++, Java, go, 375 Rust,...) 376 377 To encourage accountability, I'm signing my reviews in 2018. For the record, I am James Noble, kjx@ecs.vuw.ac.nz. 378 379 Reviewing: 3 380 381 Comments to the Author 382 This paper describes the design and implementation of coroutine- and thread-based concurrency in the C-for-all (I will write "C\/") system, a considerably extended form of the C language with many concurrency features. 383 384 It first provides an overview of the non-concurrency-related aspects of the host language (references, operator overloading, generics, etc.), then addresses several technical issues around concurrency, including the multi-monitor design, bulk acquiring of locks (including deadlock-avoiding management of acquisition order), solutions to difficult scheduling problems around these, and implementation of monitors in the presence of separate compilation. It also presents empirical data showing the execution times of several microbenchmarks in comparison with other threaded concurrency systems, in support of the claim that the implementation is competitive with them. 385 386 Overall the impression I gained is that this is a substantial system into which have gone much thought and effort. 387 388 However, the present paper is not written so as to communicate sufficiently clearly the novel practices or experiences that emerged from that effort. This manifests itself in several ways. 389 390 The system is described in general, rather than with a focus on novel insights or experiences. It was not until page 18 that I found a statement that hinted at a possible core contribution: "Supporting barging prevention as well as extending internal scheduling to multiple monitors is the main source of complexity in design and implementation of C\/ concurrency." Even then, it is unclear whether such challenges have already been surmounted in prior systems, or what other challenges the paper may also be covering. The most complete list of claims appears to be in the Conclusion (section 11; oddly not the last section), although not everything listed is a novel feature of the work (e.g. N:M threading models are an old idea). This presentation needs to be completely inverted, to focus from the outset on the claimed novel/noteworthy experiences that the work embodies. 391 392 The text describing the system's motivation is unconvincing on one point: the claim that library support for threading in C is "far from widespread" (p5, footnote A). The pthreads library API is standardised, albeit not in the C language specification but rather in POSIX -- a widespread standard indeed. (With systems languages, even if the language does not define a feature, it of course does not follow that that feature is not available -- since such languages permit extension of their own runtime and/or toolchain.) Of course, the combination of C and pthreads does not provide close to the full complement of C\/-supported features, so it is easy to make a case for C\/'s targeted "gap in the market". But again, a presentation focused on novel aspects would bring this out and enable the reader to learn from the authors' efforts much more readily. 393 394 Certain sections of the text read like a tutorial on concurrency... which is potentially valuable, but does not seem to belong here. For example, much effort is spent introducing the notions of "synchronization" and "mutual exclusion", including the whole of Section 4.2. Presently it is unclear how this content supports the findings/experiences that the paper is detailing. 395 396 Similarly, section 8 reads mostly as a basic introduction to user versus kernel threading implementations (including hybrid models such as N:M scheduling), and appears superfluous to this paper. Mixed into this are details of C\/'s specific approach. These could instead be stated directly, with references to handle the unlikely case where the reader is unfamiliar. 397 398 I also found the definitions of certain terms through the paper a bit non-standard, for unclear reasons. For example, why "condition lock" rather than the standard "condition variable" (if indeed that is what is intended)? To say that "synchronisation" is about "timing" strikes me as potentially confusing, since in truth synchronisation concerns only relative timing, i.e. ordering. (Even ordering is something of a derived concept -- since of course, most commonly, control over ordering is built atop synchronisation primitives, rather than being provided directly by them.) 399 400 The empirical data presented is a reasonable start at characterising the implementation's performance. However, it currently suffers certain flaws. 401 402 Firstly, it is not clear what is being claimed. The data cannot really be said to "verify the implementation" (section 10). Presumably the claim is that the system is competitive with other systems offering reasonably high-level concurrency constructs (Java monitors, Go channels, etc.) and/or on low-level facilities (mutexes, coroutines). A claim of this form, emphasising the latter, does eventually appear in the Conclusion, but it needs to be made explicitly during the presentation of the experiments. Shifting the focus towards higher-level features may be a better target, since this appears to be C\/'s main advance over pthreads and similar libraries. 403 404 It appears some additional or alternative competitor systems might be a better match. For example, many green-thread or N:M libraries for C exist (libdill/libmill, Marcel, even GNU Pth). It would be instructive to compare with these. 405 406 It would help greatly if the "functionally identical" benchmark code that was run on the competing systems were made available somewhere. Omitting it from the main text of the paper is understandable, since it would take too much space, but its details may still have a critical bearing on the results. 407 408 In some cases it simply wasn't clear what is being compared. In Table 3, what are "FetchAdd + FetchSub"? I'm guessing this is some open-coded mutex using C++ atomics, but (unless I'm missing something) I cannot see an explanation in the text. 409 410 The reports of variance (or, rather, standard deviation) are not always plausible. Is there really no observable variation in three of Table 3's cases? At the least, I would appreciate more detail on the measures taken to reduce run-time variance (e.g. disabling CPU throttling perhaps?). 411 412 The text habitually asserts the benefits of C\/'s design without convincing argument. For example, in 2.1, do C\/'s references really reduce "syntactic noise"? I am sympathetic to the problem here, because many design trade-offs simply cannot be evaluated without very large-scale or long-term studies. However, the authors could easily refrain from extrapolating to a grand claim that cannot be substantiated. For example, instead of saying C\/ is "expressive" or "flexible" or "natural", or (say) that fork/join concurrency is "awkward and unnecessary" (p11), it would be preferable simply to give examples of the cases are captured well in the C\/ design (ideally together with any less favourable examples that illustrate the design trade-off in question) and let them speak for themselves. 413 414 One thing I found confusing in the presentation of coroutines is that it elides the distinction between "coroutines" (i.e. their definitions) and activations thereof. It would be helpful to make this clearer, since at present this makes some claims/statements hard to understand. For example, much of 3.2 talks about "adding fields", which implies that a coroutine's activation state exists as fields in a structured object -- as, indeed, it does in C\/. This is non-obvious because in a more classical presentation of coroutines, their state would live not in "fields" but in local variables. Similarly, the text also talks about composition of "coroutines" as fields within other "coroutines", and so on, whereas if I understand correctly, these are also activations. (By later on in the text, the "C\/ style" of such constructs is clear, but not at first.) 415 416 I was expecting a reference to Adya et al's 2002 Usenix ATC paper, on the topic of "fibers" and cooperative threading generally but also for its illustrative examples of stack ripping (maybe around "linearized code is the bane of device drivers", p7, which seems to be making a similar observation). 417 418 Minor comments: 419 420 The writing is rather patchy. It has many typos, and also some cases of "not meaning what is said", unclear allusions, etc.. The following is a non-exhaustive list. 421 422 - p2 line 7: "C has a notion of objects" -- true, but this is not intended as "object" in anything like the same sense as "object-oriented", so raising it here is somewhere between confusing and meaningless. 423 424 - lots of extraneous hyphenation e.g "inheritance-relationships", "critical-section", "mutual-exclusion", "shared-state" (as a general rule, only hyphenate noun phrases when making an adjective out of them) 425 426 - p4 "impossible in most type systems" -- this is not a property of the "type system" as usually understood, merely the wider language design 427 428 - p17: "release all acquired mutex types in the parameter list" should just say "release all acquired mutexes that are designated in the parameter list" (it is not "types" that are being released or acquired); 429 430 - p19: "a class includes an exhaustive list of operations" -- except it is definitively *not* exhaustive, for the reasons given immediately afterwards. I do see the problem here, about separate compilation meaning that the space of functions using a particular type is not bounded at compile time, but that needs to be identified clearly as the problem. (Incidentally, one idea is that perhaps this mapping onto a dense space could be solved at link- or load-time, in preference to run-time indirection.) 431 432 - p22: in 6.5, the significance of this design decision ("threads... are monitors") was still not clear to me. 433 434 - p22: [user threads are] "the truest realization of concurrency" sounds like unnecessary editorializing (many systems can exist that can also encode all others, without necessarily giving one supremacy... e.g. actors can be used to encode shared-state concurrency). 435 436 - p24: on line 19, the necessary feature is not "garbage collection" but precise pointer identification (which is distinct; not all GCs have it, and it has other applications besides GC) 437 438 - p24: lines 32-39 are very dense and of unclear significance; an example, including code, would be much clearer. 439 440 - p25: "current UNIX systems" seems to mean "Linux", so please say that or give the behaviour or some other modern Unix (I believe Solaris is somewhat different, and possibly the BSDs too). Also, in the explanation of signal dynamics, it would be useful to adopt the quotation's own terminology of "process-directed" signals. Presumably the "internal" thread-directed signals were generated using tgkill()? And presumably the timer expiry signal is left unblocked only on the thread (virtual processor) running the "simulation"? (Calling it a "simulation" is a bit odd, although I realise it is borrowing the concept of a discrete event queue.) 441 -
doc/proposals/vtable.md
r6a9d4b4 r933f32f 2 2 ================================== 3 3 4 This is an adaptation of the earlier virtual proposal, updating it with new5 ideas, re-framing it and laying out more design decisions. It should6 eventually replace the earlier proposal, but not all features and syntax have7 been converted to the new design.8 9 4 The basic concept of a virtual table (vtable) is the same here as in most 10 other languages. They will mostly contain function pointers although they 11 should be able to store anything that goes into a trait. 5 other languages that use them. They will mostly contain function pointers 6 although they should be able to store anything that goes into a trait. 7 8 I also include notes on a sample implementation, which primarily exists to show 9 there is a reasonable implementation. The code samples for that are in a slight 10 pseudo-code to help avoid name mangling and keeps some CFA features while they 11 would actually be written in C. 12 12 13 13 Trait Instances … … 15 15 16 16 Currently traits are completely abstract. Data types might implement a trait 17 but traits are not themselves data types. This will change that and allow 18 instances of traits to be created from instances of data types that implement 19 the trait. 17 but traits are not themselves data types. Which is to say you cannot have an 18 instance of a trait. This proposal will change that and allow instances of 19 traits to be created from instances of data types that implement the trait. 20 21 For example: 20 22 21 23 trait combiner(otype T) { 22 void combine(T&, int);23 };24 void combine(T&, int); 25 }; 24 26 25 27 struct summation { 26 int sum;27 };28 29 void ?{}( struct summation & this ) {30 this.sum = 0;31 }28 int sum; 29 }; 30 31 void ?{}( struct summation & this ) { 32 this.sum = 0; 33 } 32 34 33 35 void combine( struct summation & this, int num ) { 34 this.sum = this.sum + num;35 }36 37 trait combiner obj = struct summation{};38 combine(obj, 5);36 this.sum = this.sum + num; 37 } 38 39 trait combiner obj = struct summation{}; 40 combine(obj, 5); 39 41 40 42 As with `struct` (and `union` and `enum`), `trait` might be optional when … … 42 44 before. 43 45 44 Internally a trait object is a pair of pointers. One to an underlying object 45 and the other to the vtable. All calls on an trait are implemented by looking 46 up the matching function pointer and passing the underlying object and the 47 remaining arguments to it. 48 49 Trait objects can be moved by moving the pointers. Almost all other operations 50 require some functions to be implemented on the underlying type. Depending on 51 what is in the virtual table a trait type could be a dtype or otype. 46 For traits to be used this way they should meet two requirements. First they 47 should only have a single polymorphic type and each assertion should use that 48 type once as a parameter. Extensions may later loosen these requirements. 49 50 Also note this applies to the final expanded list of assertions. Consider: 51 52 trait foo(otype T, otype U) { 53 ... functions that use T once ... 54 } 55 56 trait bar(otype S | foo(S, char)) { 57 ... functions that use S once ... 58 } 59 60 In this example `bar` may be used as a type but `foo` may not. 61 62 When a trait is used as a type it creates a generic object which combines 63 the base structure (an instance of `summation` in this case) and the vtable, 64 which is currently created and provided by a hidden mechanism. 65 66 The generic object type for each trait also implements that trait. This is 67 actually the only means by which it can be used. The type of these functions 68 look something like this: 69 70 void combine(trait combiner & this, int num); 71 72 The main use case for trait objects is that they can be stored. They can be 73 passed into functions, but using the trait directly is preferred in this case. 74 75 trait drawable(otype T) { 76 void draw(Surface & to, T & draw); 77 Rect(int) drawArea(T & draw); 78 }; 79 80 struct UpdatingSurface { 81 Surface * surface; 82 vector(trait drawable) drawables; 83 }; 84 85 void updateSurface(UpdatingSurface & us) { 86 for (size_t i = 0 ; i < us.drawables.size ; ++i) { 87 draw(us.surface, us.drawables[i]); 88 } 89 } 90 91 With a more complete widget trait you could, for example, construct a UI tool 92 kit that can declare containers that hold widgets without knowing about the 93 widget types. Making it reasonable to extend the tool kit. 94 95 The trait types can also be used in the types of assertions on traits as well. 96 In this usage they passed as the underlying object and vtable pair as they 97 are stored. The trait types can also be used in that trait's definition, which 98 means you can pass two instances of a trait to a single function. However the 99 look-up of the one that is not used to look up any functions, until another 100 function that uses that object in the generic/look-up location is called. 101 102 trait example(otype T) { 103 bool test(T & this, trait example & that); 104 } 105 106 ### Explanation Of Restrictions 107 108 The two restrictions on traits that can be used as trait objects are: 109 110 1. Only one generic parameter may be defined in the trait's header. 111 2. Each function assertion must have one parameter with the type of the 112 generic parameter. They may or may not return a value of that type. 113 114 Elsewhere in this proposal I suggest ways to broaden these requirements. 115 A simple example would be if a trait meets requirement 1 but not 2, then 116 the assertions that do not satisfy the exactly one parameter requirement can 117 be ignored. 118 119 However I would like to talk about why these two rules are in place in the 120 first place and the problems that any exceptions to these rules must avoid. 121 122 The problems appear when the dispatcher function which operates on the 123 generic object. 124 125 trait combiner(otype T, otype U) { 126 void combine(T&, U); 127 } 128 129 This one is so strange I don't have proper syntax for it but let us say that 130 the concrete dispatcher would be typed as 131 `void combine(combiner(T) &, combiner(U));`. Does the function that combine 132 the two underlying types exist to dispatch too? 133 134 Maybe not. If `combiner(T)` works with ints and `combiner(U)` is a char then 135 they could not be. It would have to enforce that all pairs of any types 136 that are wrapped in this way. Which would pretty much destroy any chance of 137 separate compilation. 138 139 Even then it would be more expensive as the wrappers would have to carry ids 140 that you use to look up on an <number of types>+1 dimensional table. 141 142 The second restriction has a similar issue but makes a bit more sense to 143 write out. 144 145 trait Series(otype T) { 146 ... size, iterators, getters ... 147 T join(T const &, T const &); 148 } 149 150 With the dispatcher typed as: 151 152 Series join(Series const &, Series const &); 153 154 Because these instances are generic and hide the underlying implementation we 155 do not know what that implementation is. Unfortunately this also means the 156 implementation for the two parameters might not be the same. Once we have 157 two different types involved this devolves into the first case. 158 159 We could check at run-time that the have the same underlying type, but this 160 would likely time and space overhead and there is no clear recovery path. 161 162 #### Sample Implementation 163 A simple way to implement trait objects is by a pair of pointers. One to the 164 underlying object and one to the vtable. 165 166 struct vtable_drawable { 167 void (*draw)(Surface &, void *); 168 Rect(int) (*drawArea)(void *); 169 }; 170 171 struct drawable { 172 void * object; 173 vtable_drawable * vtable; 174 }; 175 176 The functions that run on the trait object would generally be generated using 177 the following pattern: 178 179 void draw(Surface & surface, drawable & traitObj) { 180 return traitObj.vtable->draw(surface, traitObj.object); 181 } 182 183 There may have to be special cases for things like copy construction, that 184 might require a more significant wrapper. On the other hand moving could be 185 implemented by moving the pointers without any need to refer to the base 186 object. 187 188 ### Extension: Multiple Trait Parameters 189 The base proposal in effect creates another use for the trait syntax that is 190 related to the ones currently in the language but is also separate from them. 191 The current uses generic functions and generic types, this new use could be 192 described as generic objects. 193 194 A generic object is of a concrete type and has concrete functions that work on 195 it. It is generic in that it is a wrapper for an unknown type. Traits serve 196 a similar role here as in generic functions as they limit what the function 197 can be generic over. 198 199 This combines the use allowing to have a generic type that is a generic 200 object. All but one of the trait's parameters is given a concrete type, 201 conceptually currying the trait to create a trait with on generic parameter 202 that fits the original restrictions. The resulting concrete generic object 203 type is different with each set of provided parameters and their values. 204 205 Then it just becomes a question of where this is done. Again both examples use 206 a basic syntax to show the idea. 207 208 trait iterator(virtual otype T, otype Item) { 209 bool has_next(T const &); 210 Item get_next(T const *); 211 } 212 213 iterator(int) int_it = begin(container_of_ints); 214 215 The first option is to do it at the definition of the trait. One parameter 216 is selected (here with the `virtual` keyword, but other rules like "the first" 217 could also be used) and when an instance of the trait is created all the 218 other parameters must be provided. 219 220 trait iterator(otype T, otype Item) { 221 bool has_next(T const &); 222 Item get_next(T const *); 223 } 224 225 iterator(virtual, int) int_it = begin(container_of_ints); 226 227 The second option is to skip a parameter as part of the type instance 228 definition. One parameter is explicitly skipped (again with the `virtual` 229 keyword) and the others have concrete types. The skipped one is the one we 230 are generic on. 231 232 Incidentally in both examples `container_of_ints` may itself be a generic 233 object and `begin` returns a generic iterator with unknown implementation. 234 235 These options are not exclusive. Defining a default on the trait allows for 236 an object to be created as in the first example. However, whether the 237 default is provided or not, the second syntax can be used to pick a 238 parameter on instantiation. 52 239 53 240 Hierarchy 54 241 --------- 55 242 56 Virtual tables by them selves are not quite enough to implement the planned 57 hierarchy system. An addition of type ids, implemented as pointers which 58 point to your parent's type id, is required to actually create the shape of 59 the hierarchy. However vtables would allow behaviour to be carried with the 60 tree. 61 62 The hierarchy would be a tree of types, of traits and structs. Currently we do 63 not support structural extension, so traits form the internal nodes and 64 structures the leaf nodes. 65 66 The syntax is undecided but it will include a clause like `virtual (PARENT)` 67 on trait and struct definitions. It marks out all types in a hierarchy. 68 PARENT may be omitted, if it is this type is the root of a hierarchy. Otherwise 69 it is the name of the type that is this type's parent in the hierarchy. 70 71 Traits define a trait instance type that implements all assertions in this 72 trait and its parents up until the root of the hierarchy. Each trait then 73 defines a vtable type. Structures will also have a vtable type but it should 74 be the same as their parent's. 75 76 Trait objects within the tree can be statically cast to a parent type. Casts 77 from a parent type to a child type are conditional, they check to make sure 78 the underlying instance is an instance of the child type, or an instance of 79 one of its children. The type then is recoverable at run-time. 80 81 As with regular trait objects, calling a function on a trait object will cause 82 a look-up on the the virtual table. The casting rules make sure anything that 83 can be cast to a trait type will have all the function implementations for 84 that trait. 85 86 Converting from a concrete type (structures at the edge of the hierarchy) to 87 an abstract type works the same as with normal trait objects, the underlying 88 object is packaged with a virtual table pointer. Converting back to an abstract 89 type requires confirming the underlying type matches, but then simply extracts 90 the pointer to it. 91 92 ### Inline vtables 243 We would also like to implement hierarchical relations between types. 244 245 ast_node 246 |-expression_node 247 | |-operator_expression 248 | 249 |-statement_node 250 | |-goto_statement 251 | 252 |-declaration_node 253 |-using_declaration 254 |-variable_declaration 255 256 Virtual tables by themselves are not quite enough to implement this system. 257 A vtable is just a list of functions and there is no way to check at run-time 258 what these functions, we carry that knowledge with the table. 259 260 This proposal adds type ids to check for position in the hierarchy and an 261 explicate syntax for establishing a hierarchical relation between traits and 262 their implementing types. The ids should uniquely identify each type and 263 allow retrieval of the type's parent if one exists. By recursion this allows 264 the ancestor relation between any two hierarchical types can be checked. 265 266 The hierarchy is created with traits as the internal nodes and structures 267 as the leaf nodes. The structures may be used normally and the traits can 268 be used to create generic objects as in the first section (the same 269 restrictions apply). However these type objects store their type id which can 270 be recovered to figure out which type they are or at least check to see if 271 they fall into a given sub-tree at run-time. 272 273 Here is an example of part of a hierarchy. The `virtual(PARENT)` syntax is 274 just an example. But when used it give the name of the parent type or if 275 empty it shows that this type is the root of its hierarchy. 276 (Also I'm not sure where I got these casing rules.) 277 278 trait ast_node(otype T) virtual() { 279 void print(T & this, ostream & out); 280 void visit(T & this, Visitor & visitor); 281 CodeLocation const & get_code_location(T & this); 282 } 283 284 trait expression_node(otype T) virtual(ast_node) { 285 Type eval_type(T const & this); 286 } 287 288 struct operator_expression virtual(expression_node) { 289 enum operator_kind kind; 290 trait expression_node rands[2]; 291 } 292 293 trait statement_node(otype T) virtual(ast_node) { 294 vector(Label) & get_labels(T & this); 295 } 296 297 struct goto_statement virtual(statement_node) { 298 vector(Label) labels; 299 Label target; 300 } 301 302 trait declaration_node(otype T) virtual(ast_node) { 303 string name_of(T const & this); 304 Type type_of(T const & this); 305 } 306 307 struct using_declaration virtual(declaration_node) { 308 string new_type; 309 Type old_type; 310 } 311 312 struct variable_declaration virtual(declaration_node) { 313 string name; 314 Type type; 315 } 316 317 This system does not support multiple inheritance. The system could be 318 extended to support it or a limited form (ex. you may have multiple parents 319 but they may not have a common ancestor). However this proposal focuses just 320 on using hierachy as organization. Other uses for reusable/genaric code or 321 shared interfaces is left for other features of the language. 322 323 ### Extension: Structural Inheritance 324 An extension would be allow structures to be used as internal nodes on the 325 inheritance tree. Its child types would have to implement the same fields. 326 327 The weaker restriction would be to convert the fields into field assertions 328 (Not implemented yet: `U T.x` means there is a field of type you on the type 329 T. Offset unknown and passed in/stored with function pointers.) 330 A concrete child would have to declare the same set of fields with the same 331 types. This is of a more functional style. 332 333 The stronger restriction is that the fields of the parent are a prefix of the 334 child's fields. Possibly automatically inserted. This the imperative view and 335 may also have less overhead. 336 337 ### Extension: Unions and Enumerations 338 Currently there is no reason unions and enumerations, in the cases they 339 do implement the trait, could not be in the hierarchy as leaf nodes. 340 341 It does not work with structural induction, but that could just be a compile 342 time check that all ancestors are traits or do not add field assertions. 343 344 #### Sample Implementation 345 The type id may be as little as: 346 347 struct typeid { 348 struct typeid const * const parent; 349 }; 350 351 Some linker magic would have to be used to ensure exactly one copy of each 352 structure for each type exists in memory. There seem to be special once 353 sections that support this and it should be easier than generating unique 354 ids across compilation units. 355 356 The structure could be extended to contain any additional type information. 357 358 There are two general designs for vtables with type ids. The first is to put 359 the type id at the top of the vtable, this is the most compact and efficient 360 solution but only works if we have exactly 1 vtable for each type. The second 361 is to put a pointer to the type id in each vtable. This has more overhead but 362 allows multiple vtables per type. 363 364 struct <trait>_vtable { 365 struct typeid const id; 366 367 // Trait dependent list of vtable members. 368 }; 369 370 struct <trait>_vtable { 371 struct typeid const * const id; 372 373 // Trait dependent list of vtable members. 374 }; 375 376 One important restriction is that only one instance of each typeid in memory. 377 There is a ".gnu.linkonce" feature in the linker that might solve the issue. 378 379 ### Virtual Casts 380 The generic objects may be cast up and down the hierarchy. 381 382 Casting to an ancestor type always succeeds. From one generic type to another 383 is just a reinterpretation and could be implicate. Wrapping and unwrapping 384 a concrete type will probably use the same syntax as in the first section. 385 386 Casting from an ancestor to a descendent requires a check. The underlying 387 type may or may not belong to the sub-tree headed by that descendent. For this 388 we introduce a new cast operator, which returns the pointer unchanged if the 389 check succeeds and null otherwise. 390 391 trait SubType * new_value = (virtual trait SubType *)super_type; 392 393 For the following example I am using the as of yet finished exception system. 394 395 trait exception(otype T) virtual() { 396 char const * what(T & this); 397 } 398 399 trait io_error(otype T) virtual(exception) { 400 FILE * which_file(T & this); 401 } 402 403 struct eof_error(otype T) virtual(io_error) { 404 FILE * file; 405 } 406 407 char const * what(eof_error &) { 408 return "Tried to read from an empty file."; 409 } 410 411 FILE * which_file(eof_error & this) { 412 return eof_error.file; 413 } 414 415 bool handleIoError(exception * exc) { 416 io_error * error = (virtual io_error *)exc; 417 if (NULL == error) { 418 return false; 419 } 420 ... 421 return true; 422 } 423 424 ### Extension: Implicate Virtual Cast Target 425 This is a small extension, even in the example above `io_error *` is repeated 426 in the cast and the variable being assigned to. Using return type inference 427 would allow the second type to be skipped in cases it is clear what type is 428 being checked against. 429 430 The line then becomes: 431 432 io_error * error = (virtual)exc; 433 434 #### Sample Implementation 435 This cast implementation assumes a type id layout similar to the one given 436 above. Also this code is definitely in the underlying C. Functions that give 437 this functionality could exist in the standard library but these are meant to 438 be produced by code translation of the virtual cast. 439 440 bool is_in_subtree(typeid const * root, typeid const * id) { 441 if (root == id) { 442 return true 443 } else if (NULL == id->parent) { 444 return false; 445 } else { 446 return is_in_subtree(root, id->parent); 447 } 448 } 449 450 void * virtual_cast(typeid const * target, void * value) { 451 return is_in_subtree(target, *(typeid const **)value) ? value : NULL; 452 } 453 454 The virtual cast function might have to be wrapped with some casts to make it 455 compile without warning. 456 457 For the implicate target type we may be able to lean on the type resolution 458 system that already exists. If the casting to ancestor type is built into 459 the resolution then the impicate target could be decided by picking an 460 overload, generated for each hierarchial type (here io_error and its root 461 type exception). 462 463 io_error * virtual_cast(exception * value) { 464 return virtual_cast(io_error_typeid, value); 465 } 466 467 ### Extension: Inline vtables 93 468 Since the structures here are usually made to be turned into trait objects 94 it might be worth it to have fields on them to store the virtual table 95 pointer. This would have to be declared on the trait as an assertion, but if 96 it is the trait object could be a single pointer. 97 98 It is trivial to do if the field with the virtual table pointer is fixed. 99 Otherwise some trickery with pointing to the field and storing the offset in 100 the virtual table to recover the main object would have to be used. 469 it might be worth it to have fields in them to store the virtual table 470 pointer. This would have to be declared on the trait as an assertion (example: 471 `vtable;` or `T.vtable;`), but if it is the trait object could be a single 472 pointer. 473 474 There are also three options for where the pointer to the vtable. It could be 475 anywhere, a fixed location for each trait or always at the front. For the per- 476 trait solution an extension to specify what it is (example `vtable[0];`) which 477 could also be used to combine it with others. So these options can be combined 478 to allow access to all three options. 479 480 The pointer to virtual table field on structures might implicately added (the 481 types have to declare they are a child here) or created with a declaration, 482 possibly like the one used to create the assertion. 101 483 102 484 ### Virtual Tables as Types 103 Here we consider encoding plus the implementation of functions on it. Which 104 is to say in the type hierarchy structures aren't concrete types anymore, 105 instead they are parent types to vtables, which combine the encoding and 106 implementation. 485 Here we consider encoding plus the implementation of functions on it to be a 486 type. Which is to say in the type hierarchy structures aren't concrete types 487 anymore, instead they are parent types to vtables, which combine the encoding 488 and implementation. 489 490 ### Question: Wrapping Structures 491 One issue is what to do with concrete types at the base of the type tree. 492 When we are working with the concrete type generally it would like them to be 493 regular structures with direct calls. On the other hand for interactions with 494 other types in the hierarchy it is more convenent for the type already to be 495 cast. 496 497 Which of these two should we use? Should we support both and if so how do we 498 choose which one is being used at any given time. 499 500 On a related note I have been using pointers two trait types here, as that 501 is how many existing languages handle it. However the generic objects might 502 be only one or two pointers wide passing the objects as a whole would not 503 be very expensive and all operations on the generic objects probably have 504 to be defined anyways. 107 505 108 506 Resolution Scope … … 120 518 the type declaration, including the functions that satisfy the trait, are 121 519 all defined. Currently there are many points where this can happen, not all 122 of them will have the same definitions and no way to select one over the 123 other. 124 125 Some syntax would have to be added. All resolutions can be found at compile 126 time and a single vtable created for each type at compilation time. 520 of them have the same definitions and no way to select one over the other. 521 522 Some syntax would have to be added to specify the resolution point. To ensure 523 a single instance there may have to be two variants, one forward declaration 524 and one to create the instance. With some compiler magic the forward 525 declaration maybe enough. 526 527 extern trait combiner(struct summation) vtable; 528 trait combiner(struct summation) vtable; 529 530 Or (with the same variants): 531 532 vtable combiner(struct summation); 533 534 The extern variant promises that the vtable will exist while the normal one 535 is where the resolution actually happens. 127 536 128 537 ### Explicit Resolution Points: … … 141 550 vtable. 142 551 552 extern trait combiner(struct summation) vtable sum; 553 trait combiner(struct summation) vtable sum; 554 555 extern trait combiner(struct summation) vtable sum default; 556 trait combiner(struct summation) vtable sum default; 557 558 The extern difference is the same before. The name (sum in the samples) is 559 used at the binding site to say which one is picked. The default keyword can 560 be used in only some of the declarations. 561 562 trait combiner fee = (summation_instance, sum); 563 trait combiner foe = summation_instance; 564 565 (I am not really happy about this syntax, but it kind of works.) 566 The object being bound is required. The name of the vtable is optional if 567 there is exactly one vtable name marked with default. 568 569 These could also be placed inside functions. In which case both the name and 570 the default keyword might be optional. If the name is omitted in an assignment 571 the closest vtable is chosen (returning to the global default rule if no 572 appropriate local vtable is in scope). 573 143 574 ### Site Based Resolution: 144 575 Every place in code where the binding of a vtable to an object occurs has … … 165 596 Stack allocated functions interact badly with this because they are not 166 597 static. There are several ways to try to resolve this, however without a 167 general solution most can only buy time. 598 general solution most can keep vtables from making the existing thunk problem 599 worse, they don't do anything to solve it. 168 600 169 601 Filling in some fields of a static vtable could cause issues on a recursive … … 180 612 shortest lifetime of a function assigned to it. However this still limits the 181 613 lifetime "implicitly" and returns to the original problem with thunks. 614 615 Odds And Ends 616 ------------- 617 618 In addition to the main design there are a few extras that should be 619 considered. They are not part of the core design but make the new uses fully 620 featured. 621 622 ### Extension: Parent-Child Assertion 623 For hierarchy types in regular traits, generic functions or generic structures 624 we may want to be able to check parent-child relationships between two types 625 given. For this we might have to add another primitive assertion. It would 626 have the following form if declared in code: 627 628 trait is_parent_child(dtype Parent, dtype Child) { <built-in magic> } 629 630 This assertion is satified if Parent is an ancestor of Child in a hierarchy. 631 In other words Child can be statically cast to Parent. The cast from Parent 632 to child would be dynamically checked as usual. 633 634 However in this form there are two concerns. The first that Parent will 635 usually be consistent for a given use, it will not be a variable. Second is 636 that we may also need the assertion functions. To do any casting/conversions 637 anyways. 638 TODO: Talk about when we wrap a concrete type and how that leads to "may". 639 640 To this end it may be better that the parent trait combines the usual 641 assertions plus this new primitive assertion. There may or may not be use 642 cases for accessing just one half and providing easy access to them may be 643 required depending on how that turns out. 644 645 trait Parent(dtype T | interface(T)) virtual(<grand-parent?>) { } 646 647 ### Extension: sizeof Compatablity 648 Trait types are always sized, it may even be a fixed size like how pointers 649 have the same size regardless of what they point at. However their contents 650 may or may not be of a known size (if the `sized(...)` assertion is used). 651 652 Currently there is no way to access this information. If it is needed a 653 special syntax would have to be added. Here a special case of `sizeof` is 654 used. 655 656 struct line aLine; 657 trait drawable widget = aLine; 658 659 size_t x = sizeof(widget); 660 size_t y = sizeof(trait drawable); 661 662 As usual `y`, size of the type, is the size of the local storage used to put 663 the value into. The other case `x` checks the saved stored value in the 664 virtual table and returns that. -
doc/theses/aaron_moss_PhD/phd/Makefile
r6a9d4b4 r933f32f 2 2 BIBDIR = ../../../bibliography 3 3 EVALDIR = evaluation 4 FIGDIR = figures 4 5 TEXLIB = .:${BUILD}:${BIBDIR}: 5 6 … … 8 9 BIBTEX = BIBINPUTS=${TEXLIB} && export BIBINPUTS && bibtex 9 10 10 VPATH = ${EVALDIR} 11 VPATH = ${EVALDIR} ${FIGDIR} 11 12 12 13 BASE = thesis … … 22 23 background \ 23 24 generic-types \ 25 resolution-heuristics \ 24 26 type-environment \ 25 resolution-heuristics \27 experiments \ 26 28 conclusion \ 29 generic-bench \ 30 } 31 32 FIGURES = ${addsuffix .eps, \ 33 safe-conv-graph \ 34 resolution-dag \ 35 union-find-with-classes \ 36 persistent-union-find \ 27 37 } 28 38 29 39 GRAPHS = ${addsuffix .tex, \ 30 40 generic-timing \ 41 tests-completed \ 42 per-prob-histo \ 43 per-prob-depth \ 44 cfa-time \ 31 45 } 32 46 … … 47 61 dvips ${BUILD}/$< -o ${BUILD}/$@ 48 62 49 ${BASE}.dvi : Makefile ${SOURCES} ${GRAPHS} ${ BIBFILE} ${BUILD}63 ${BASE}.dvi : Makefile ${SOURCES} ${GRAPHS} ${FIGURES} ${BIBFILE} ${BUILD} 50 64 ${LATEX} ${BASE} 51 65 ${BIBTEX} ${BUILD}/${BASE} … … 53 67 ${LATEX} ${BASE} 54 68 55 ${GRAPHS}: generic-timing.gp generic-timing.dat ${BUILD}69 generic-timing.tex : generic-timing.gp generic-timing.dat ${BUILD} 56 70 gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/generic-timing.gp 71 72 tests-completed.tex : algo-summary.gp algo-summary.dat bu-summary.dat ${BUILD} 73 gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/algo-summary.gp 74 75 per-prob-histo.tex : per-prob.gp per-prob.tsv ${BUILD} 76 gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/per-prob.gp 77 78 per-prob-depth.tex : per-prob-scatter.gp ${BUILD} 79 gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/per-prob-scatter.gp 80 81 cfa-time.tex : cfa-plots.gp cfa-time.tsv cfa-mem.tsv ${BUILD} 82 gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/cfa-plots.gp 57 83 58 84 ${BUILD}: -
doc/theses/aaron_moss_PhD/phd/background.tex
r6a9d4b4 r933f32f 1 1 \chapter{\CFA{}} 2 \label{cfa-chap} 2 3 3 4 \CFA{} adds a number of features to C, some of them providing significant increases to the expressive power of the language, but all designed to maintain the existing procedural programming paradigm of C and to be as orthogonal as possible to each other. 4 5 To provide background for the contributions in subsequent chapters, this chapter provides a summary of the features of \CFA{} at the time this work was conducted. 5 6 6 The core design of \CFA{} is laid out in Glen Ditchfield's 1992 PhD thesis, \emph{Contextual Polymorphism}\cite{Ditchfield92}; in that thesis, Ditchfield presents the theoretical underpinnings of the \CFA{} polymorphism model. 7 Building on Ditchfield's design for contextual polymorphism as well as KW-C\cite{Buhr94a}, an earlier set of (largely syntactic) extensions to C, Richard Bilson\cite{Bilson03} built the first version of the \CFA{} compiler, \CFACC{}, in the early 2000's. 8 This early \CFACC{} provided basic functionality, but incorporated a number of poor algorithmic choices due to a rushed implementation time frame, and as such lacked the runtime performance required for practical use; this thesis is substantially concerned with rectifying those deficits. 9 10 The \CFA{} project was revived in 2015 with the intention of building a production-ready language and compiler; at the time of this writing, both \CFA{} and \CFACC{} have been under active development continuously since. 11 As this development has been proceeding concurrently with the work described in this thesis, the state of \CFA{} has been somewhat of a moving target; however, Moss~\etal\cite{Moss18} provides a reasonable summary of the current design. 12 Notable features added during this period include generic types (Chapter~\ref{generic-chap}), constructors and destructors\cite{Schluntz17}, improved support for tuples\cite{Schluntz17}, reference types\cite{Moss18}, first-class concurrent and parallel programming support\cite{Delisle18}, as well as numerous pieces of syntactic sugar and the start of an idiomatic standard library\cite{Moss18}. 13 14 \section{\CFA{} Features} 15 16 The selection of features presented in this chapter are chosen to elucidate the design constraints of the work presented in this thesis. 17 In some cases the interactions of multiple features make this design a significantly more complex problem than any individual feature would; in other cases a feature that does not by itself add any complexity to expression resolution triggers previously rare edge cases more frequently. 18 19 \subsection{Procedural Paradigm} 7 Glen Ditchfield laid out the core design of \CFA{} in his 1992 PhD thesis, \emph{Contextual Polymorphism} \cite{Ditchfield92}; in that thesis, Ditchfield presents the theoretical underpinnings of the \CFA{} polymorphism model. 8 Building on Ditchfield's design for contextual polymorphism as well as KW-C \cite{Buhr94a}, an earlier set of (largely syntactic) extensions to C, Richard Bilson \cite{Bilson03} built the first version of the \CFA{} compiler, \CFACC{}, in the early 2000's. 9 This early \CFACC{} provided basic functionality, but incorporated a number of algorithmic choices that have failed to scale as \CFA{} has developed, lacking the runtime performance for practical use; this thesis is substantially concerned with rectifying those deficits. 10 11 The \CFA{} project was revived in 2015 with the intention of building a production-ready language and compiler; at the time of this writing, both \CFA{} and \CFACC{} remain under active development. 12 As this development has been proceeding concurrently with the work described in this thesis, the state of \CFA{} has been somewhat of a moving target; however, Moss~\etal~\cite{Moss18} provides a reasonable summary of the current design. 13 Notable features added during this period include generic types (Chapter~\ref{generic-chap}), constructors and destructors \cite{Schluntz17}, improved support for tuples \cite{Schluntz17}, reference types \cite{Moss18}, first-class concurrent and parallel programming support \cite{Delisle18}, as well as numerous pieces of syntactic sugar and the start of an idiomatic standard library \cite{Moss18}. 14 15 This thesis is primarily concerned with the \emph{expression resolution} portion of \CFA{} type-checking; resolution is discussed in more detail in Chapter~\ref{resolution-chap}, but is essentially determining which declarations the identifiers in each expression correspond to. 16 In C, no simultaneously-visible declarations share identifiers, hence expression resolution in C is not difficult. 17 In \CFA{}, multiple added features make the resolution process significantly more complex. 18 Due to this complexity, the expression-resolution pass in \CFACC{} requires 95\% of compiler runtime on some source files, making a new, more efficient procedure for expression resolution a requirement for a performant \CFA{} compiler. 19 20 The features presented in this chapter are chosen to elucidate the design constraints of the work presented in this thesis. 21 In some cases the interactions of multiple features make this design a significantly more complex problem than any individual feature; in other cases a feature that does not by itself add any complexity to expression resolution triggers previously rare edge cases more frequently. 22 23 \section{Procedural Paradigm} 20 24 21 25 It is important to note that \CFA{} is not an object-oriented language. 22 This is a deliberate choice intended to maintain the applicability of the mental model and language idioms already possessed by C programmers. 23 This choice is in marked contrast to \CC{}, which, though it has backward-compatibility with C on the source code level, is a much larger and more complex language, and requires extensive developer re-training to write idiomatic, efficient code in \CC{}'s object-oriented paradigm. 24 25 \CFA{} does have a system of implicit type conversions derived from C's ``usual arithmetic conversions''; while these conversions may be thought of as something like an inheritance hierarchy, the underlying semantics are significantly different and such an analogy is loose at best. 26 This is a deliberate choice intended to maintain the applicability of the programming model and language idioms already possessed by C programmers. 27 This choice is in marked contrast to \CC{}, which is a much larger and more complex language, and requires extensive developer re-training to write idiomatic, efficient code in \CC{}'s object-oriented paradigm. 28 26 29 Particularly, \CFA{} has no concept of \emph{subclass}, and thus no need to integrate an inheritance-based form of polymorphism with its parametric and overloading-based polymorphism. 27 The graph structure of the \CFA{} type conversions is also markedly different than an inheritance hierarchy; it has neither a top nor a bottom type, and does not satisfy the lattice properties typical of inheritance hierarchies. 30 While \CFA{} does have a system of implicit type conversions derived from C's ``usual arithmetic conversions'' \cite[\S{}6.3.1.8]{C11} and these conversions may be thought of as something like an inheritance hierarchy, the underlying semantics are significantly different and such an analogy is loose at best. 31 The graph structure of the \CFA{} type conversions (discussed in Section~\ref{conv-cost-sec}) is also markedly different than an inheritance hierarchy; it has neither a top nor a bottom type, and does not satisfy the lattice properties typical of inheritance hierarchies. 28 32 29 33 Another aspect of \CFA{}'s procedural paradigm is that it retains C's translation-unit-based encapsulation model, rather than class-based encapsulation such as in \CC{}. 30 This choice implies that that separate compilation must be maintained to allow headers to act as an encapsulation boundary, rather than the header-only libraries used by \CC{} templates. 31 32 \subsection{Name Overloading} \label{overloading-sec} 33 34 In C, no more than one variable or function in the same scope may share the same name\footnote{Technically, C has multiple separated namespaces, one holding \lstinline{struct}, \lstinline{union}, and \lstinline{enum} tags, one holding labels, one holding \lstinline{typedef} names, variable, function, and enumerator identifiers, and one for each \lstinline{struct} and \lstinline{union} type holding the field names\cit{}.}, and variable or function declarations in inner scopes with the same name as a declaration in an outer scope hide the outer declaration. 35 This restriction makes finding the proper declaration to match to a variable expression or function application a simple matter of symbol-table lookup, which can be easily and efficiently implemented. 34 As such, any language feature that requires code to be exposed in header files (\eg{} \CC{} templates) also eliminates encapsulation in \CFA{}. 35 Given this constraint, \CFA{} is carefully designed to allow separate compilation for its added language features under the existing C usage patterns. 36 37 \section{Name Overloading} \label{overloading-sec} 38 39 In C, no more than one variable or function in the same scope may share the same name\footnote{Technically, C has multiple separated namespaces, one holding \lstinline{struct}, \lstinline{union}, and \lstinline{enum} tags, one holding labels, one holding \lstinline{typedef} names, variable, function, and enumerator identifiers, and one for each \lstinline{struct} and \lstinline{union} type holding the field names \cite[\S{}6.2.3]{C11}.}, and variable or function declarations in inner scopes with the same name as a declaration in an outer scope hide the outer declaration. 40 This restriction makes finding the proper declaration to match to a variable expression or function application a simple matter of lexically-scoped name lookup, which can be easily and efficiently implemented. 36 41 \CFA{}, on the other hand, allows overloading of variable and function names so long as the overloaded declarations do not have the same type, avoiding the multiplication of variable and function names for different types common in the C standard library, as in the following example: 37 42 … … 50 55 \end{cfa} 51 56 52 While the wisdom of giving both the maximum value of a type and the function to take the maximum of two values the same name is debatable, \eg{} some developers may prefer !MAX! for the former, the guiding philosophy of \CFA{} is ``describe, don't prescribe'' --- we prefer to trust programmers with powerful tools, and there is no technical reason to restrict overloading between variables and functions. 53 However, the expressivity of \CFA{}'s name overloading has the consequence that simple table lookup is insufficient to match identifiers to declarations, and a type-matching algorithm must be part of expression resolution. 54 55 \subsubsection{Operator Overloading} 57 The final expression in the preceding example includes a feature of \CFA{} name overloading not shared by \CC{}, the ability to disambiguate expressions based on their return type. This provides greater flexibility and power than the parameter-based overload selection of \CC{}, though at the cost of greater complexity in the resolution algorithm. 58 59 While the wisdom of giving both the maximum value of a type and the function to take the maximum of two values the same name in the example above is debatable, \eg{} some developers may prefer !MAX! for the former, the guiding philosophy of \CFA{} is ``describe, don't prescribe'' --- we prefer to trust programmers with powerful tools, and there is no technical reason to restrict overloading between variables and functions. 60 However, the expressivity of \CFA{}'s name overloading does have the consequence that simple table lookup is insufficient to match identifiers to declarations, and a type-matching algorithm must be part of expression resolution. 61 62 \subsection{Operator Overloading} 56 63 57 64 C does allow name overloading in one context: operator overloading. 58 65 From the perspective of the type system, there is nothing special about operators as opposed to other functions, nor is it desirable to restrict the clear and readable syntax of operators to only the built-in types. 59 For these reasons, \CFA{} also allows overloading of operators by writing specially-named functions where !?! stands in for the operands\footnote{This example uses \CFA{}'s reference types, described in Section~\ref{type-features-sec}}: 66 For these reasons, \CFA{}, like \CC{} and many other programming languages, allows overloading of operators by writing specially-named functions where !?! stands in for the operands. 67 This syntax is more natural than the operator overloading syntax of \CC{}, which requires ``dummy'' parameters to disambiguate overloads of similarly-named pre- and postfix operators\footnote{This example uses \CFA{}'s reference types, described in Section~\ref{type-features-sec}}: 60 68 61 69 \begin{cfa} … … 71 79 \end{cfa} 72 80 73 Together, \CFA{}'s backward-compatibility with C and the inclusion of this operator overloading feature imply that \CFA{} must select among function overloads using a method compatible with C's ``usual arithmetic conversions'' \cit{}, so as to present user programmers with only a single set of overloading rules.74 75 \subs ubsection{Special Literal Types}81 Together, \CFA{}'s backward-compatibility with C and the inclusion of this operator overloading feature imply that \CFA{} must select among function overloads using a method compatible with C's ``usual arithmetic conversions'' \cite[\S{}6.3.1.8]{C11}, so as to present user programmers with only a single set of overloading rules. 82 83 \subsection{Special Literal Types} 76 84 77 85 Literal !0! is also used polymorphically in C; it may be either integer zero or the null value of any pointer type. 78 \CFA{} provides a special type for the !0! literal, !zero_t!, so that users can define a zero value for their own types without being forced to create a conversion from an integer or pointer type (though \CFA{} also includes implicit conversions from !zero_t! to the integer and pointer types for backward compatibility). 79 80 According to the C standard\cit{}, !0! is the only false value; any value that compares equal to zero is false, while any value that does not is true. 81 By this rule, boolean contexts such as !if ( x )! can always be equivalently rewritten as \lstinline{if ( (x) != 0 )}. 82 \CFACC{} applies this rewriting in all boolean contexts, so any type !T! can be made ``truthy'' (that is, given a boolean interpretation) in \CFA{} by defining an operator overload \lstinline{int ?!=?(T, zero_t)}; unlike \CC{} prior to the addition of explicit casts in \CCeleven{}, this design does not add comparability or convertablity to arbitrary integer types. 86 \CFA{} provides a special type for the !0! literal, !zero_t!, so that users can define a zero value for their own types without being forced to create a conversion from an integer or pointer type; \CFA{} also includes implicit conversions from !zero_t! to the !int! and pointer type constructors\footnote{See Section~\ref{type-features-sec}} from !zero_t! for backward compatibility. 87 88 According to the C standard \cite[\S{}6.8.4.1]{C11}, !0! is the only false value; any value that compares equal to zero is false, while any value that does not is true. 89 By this rule, Boolean contexts such as !if ( x )! can always be equivalently rewritten as \lstinline{if ( (x) != 0 )}. 90 \CFACC{} applies this rewriting in all Boolean contexts, so any type !T! can be made ``truthy'' (that is, given a Boolean interpretation) in \CFA{} by defining an operator overload \lstinline{int ?!=?(T, zero_t)}. 91 \CC{} takes a different approach to user-defined truthy types, allowing definition of an implicit conversion operator to !bool!; prior to the introduction of the !explicit! keyword for conversion operators in \CCeleven{} this approach also allowed undesired implicit conversions to all other arithmetic types, a shortcoming not shared by the \CFA{} design. 83 92 84 93 \CFA{} also includes a special type for !1!, !one_t!; like !zero_t!, !one_t! has built-in implicit conversions to the various integral types so that !1! maintains its expected semantics in legacy code. 85 94 The addition of !one_t! allows generic algorithms to handle the unit value uniformly for types where it is meaningful; a simple example of this is that polymorphic functions\footnote{discussed in Section~\ref{poly-func-sec}} in the \CFA{} prelude define !++x! and !x++! in terms of !x += 1!, allowing users to idiomatically define all forms of increment for a type !T! by defining the single function !T& ?+=?(T&, one_t)!; analogous overloads for the decrement operators are also present, and programmers can override any of these functions for a particular type if desired. 86 95 87 \CFA{} previously allowed !0! and !1! to be the names of polymorphic variables, with separate overloads for !int 0!, !int 1!, and !forall(dtype T) T* 0!.88 As revealed in my own work on generic types (Chapter~\ref{generic-chap}), the parameteric polymorphic zero variable was not generalizable to other types; though all null pointers have the same in-memory representation, the same cannot be said of the zero values of arbitrary types.89 As such, variables that could represent !0! and !1!were phased out in favour of functions that could generate those values for a given type as appropriate.90 91 \s ubsection{Polymorphic Functions} \label{poly-func-sec}92 93 The most significant feature \CFA{} adds is parametric-polymorphic functions.96 \CFA{} previously allowed !0! and !1! to be the names of polymorphic variables, with separate overloads for !int 0!, !int 1!, and the polymorphic variable !forall(dtype T) T* 0!. 97 While designing \CFA{} generic types (see Chapter~\ref{generic-chap}), it was discovered that the parametric polymorphic zero variable is not generalizable to other types; though all null pointers have the same in-memory representation, the same cannot be said of the zero values of arbitrary types. 98 As such, polymorphic variables, and in particular variables for !0! and !1!, were phased out in favour of functions that could generate those values for a given type as appropriate. 99 100 \section{Polymorphic Functions} \label{poly-func-sec} 101 102 The most significant type-system feature \CFA{} adds is parametric-polymorphic functions. 94 103 Such functions are written using a !forall! clause (which gives the language its name): 95 104 … … 102 111 The type variable !T! is transformed into a set of additional implicit parameters to !identity!, which encode sufficient information about !T! to create and return a variable of that type. 103 112 \CFA{} passes the size and alignment of the type represented by an !otype! parameter, as well as a default constructor, copy constructor, assignment operator, and destructor. 104 Types which do not have one or more of these operators visible cannot be bound to !otype! parameters. 105 In this design, the runtime cost of polymorphism is spread over each polymorphic call, due to passing more arguments to polymorphic functions; experiments have shown this overhead to be similar to \CC{} virtual function calls. \TODO{rerun experiments, possibly look at vtable variant} 113 Types that do not have one or more of these operators visible cannot be bound to !otype! parameters, but may be bound to un-constrained !dtype! (``data type'') type variables. 114 In this design, the runtime cost of polymorphism is spread over each polymorphic call, due to passing more arguments to polymorphic functions; the experiments in Chapter~\ref{generic-chap} indicate that this overhead is comparable to that of \CC{} virtual function calls. 115 % \TODO{rerun experiments, possibly look at vtable variant} 106 116 107 117 One benefit of this design is that it allows polymorphic functions to be separately compiled. … … 109 119 The fact that there is only one implementation of each polymorphic function also reduces compile times relative to the template-expansion approach taken by \CC{}, as well as reducing binary sizes and runtime pressure on instruction cache by re-using a single version of each function. 110 120 111 \subs ubsection{Type Assertions}112 113 Since bare polymorphic types do not provide a great range of available operations, \CFA{} provides a \emph{type assertion} mechanism to provide further information about a type :121 \subsection{Type Assertions} 122 123 Since bare polymorphic types do not provide a great range of available operations, \CFA{} provides a \emph{type assertion} mechanism to provide further information about a type\footnote{This example introduces a convention used throughout this thesis of disambiguating overloaded names with subscripts; the subscripts do not appear in \CFA{} source code.}: 114 124 115 125 \begin{cfa} 116 126 forall(otype T `| { T twice(T); }`) 117 127 T four_times(T x) { return twice( twice(x) ); } 118 double twice (double d) { return d * 2.0; } $\C[2.75in]{// (1)}$128 double twice$\(_1\)$(double d) { return d * 2.0; } 119 129 120 130 double ans = four_times( 10.5 ); $\C[2.75in]{// T bound to double, ans == 42.0}$ … … 129 139 \begin{cfa} 130 140 forall(otype S | { S ?+?(S, S); }) 131 S twice(S x) { return x + x; } $\C[2.75in]{// (2)} 132 \end{cfa} 133 134 This version of !twice! works for any type !S! that has an addition operator defined for it, and it could be used to satisfy the type assertion on !four_times!. 135 \CFACC{} accomplishes this by creating a wrapper function calling !twice//(2)! with !S! bound to !double!, then providing this wrapper function to !four_times!\footnote{\lstinline{twice // (2)} could also have had a type parameter named \lstinline{T}; \CFA{} specifies renaming of the type parameters, which would avoid the name conflict with the type variable \lstinline{T} of \lstinline{four_times}}. 136 137 Finding appropriate functions to satisfy type assertions is essentially a recursive case of expression resolution, as it takes a name (that of the type assertion) and attempts to match it to a suitable declaration in the current scope. 141 S twice$\(_2\)$(S x) { return x + x; } 142 \end{cfa} 143 144 Specializing this polymorphic function with !S = double! produces a monomorphic function which can be used to satisfy the type assertion on !four_times!. 145 \CFACC{} accomplishes this by creating a wrapper function calling !twice!$_2$ with !S! bound to !double!, then providing this wrapper function to !four_times!\footnote{\lstinline{twice}$_2$ could also have had a type parameter named \lstinline{T}; \CFA{} specifies renaming of the type parameters, which would avoid the name conflict with the type variable \lstinline{T} of \lstinline{four_times}}. 146 However, !twice!$_2$ also works for any type !S! that has an addition operator defined for it. 147 148 Finding appropriate functions to satisfy type assertions is essentially a recursive case of expression resolution, as it takes a name (that of the type assertion) and attempts to match it to a suitable declaration in the current scope\footnote{\CFACC{} actually performs a type-unification computation for assertion satisfaction rather than an expression resolution computation; see Section~\ref{assn-sat-sec} for details.}. 138 149 If a polymorphic function can be used to satisfy one of its own type assertions, this recursion may not terminate, as it is possible that that function is examined as a candidate for its own assertion unboundedly repeatedly. 139 To avoid such infinite loops, \CFACC{} imposes a fixed limit on the possible depth of recursion, similar to that employed by most \CC{} compilers for template expansion; this restriction means that there are some semantically well-typed expressions that cannot be resolved by \CFACC{}. 140 \TODO{Update this with final state} One contribution made in the course of this thesis was modifying \CFACC{} to use the more flexible expression resolution algorithm for assertion matching, rather than the simpler but limited previous approach of unification on the types of the functions. 141 142 \subsubsection{Deleted Declarations} 143 144 Particular type combinations can be exempted from matching a given polymorphic function through use of a \emph{deleted function declaration}: 145 146 \begin{cfa} 147 int somefn(char) = void; 148 \end{cfa} 149 150 This feature is based on a \CCeleven{} feature typically used to make a type non-copyable by deleting its copy constructor and assignment operator\footnote{In previous versions of \CC{}, a type could be made non-copyable by declaring a private copy constructor and assignment operator, but not defining either. This idiom is well-known, but depends on some rather subtle and \CC{}-specific rules about private members and implicitly-generated functions; the deleted function form is both clearer and less verbose.} or forbidding some interpretations of a polymorphic function by specifically deleting the forbidden overloads\footnote{Specific polymorphic function overloads can also be forbidden in previous \CC{} versions through use of template metaprogramming techniques, though this advanced usage is beyond the skills of many programmers. A similar effect can be produced on an ad-hoc basis at the appropriate call sites through use of casts to determine the function type. In both cases, the deleted-function form is clearer and more concise.}. 151 Deleted function declarations are implemented in \CFACC{} by adding them to the symbol table as usual, but with a flag set that indicates that the function is deleted. 152 If this deleted declaration is selected as the unique minimal-cost interpretation of an expression than an error is produced. \TODO{Check this is implemented at print.} 153 154 \subsubsection{Traits} 155 156 \CFA{} provides \emph{traits} as a means to name a group of type assertions, as in the example below\footnote{This example uses \CFA{}'s reference types, constructors, and zero type, described in Section~\ref{type-features-sec}.}: 150 To avoid such infinite loops, \CFACC{} imposes a fixed limit on the possible depth of recursion, similar to that employed by most \CC{} compilers for template expansion; this restriction means that there are some otherwise semantically well-typed expressions that cannot be resolved by \CFACC{}. 151 152 \subsection{Traits} 153 154 \CFA{} provides \emph{traits} as a means to name a group of type assertions, as in the example below\footnote{This example uses \CFA{}'s reference types and constructors, described in Section~\ref{type-features-sec}.}: 157 155 158 156 \begin{cfa} … … 171 169 172 170 Semantically, traits are simply a named list of type assertions, but they may be used for many of the same purposes that interfaces in Java or abstract base classes in \CC{} are used for. 173 Unlike Java interfaces or \CC{} base classes, \CFA{} types do not explicitly state any inheritance relationship to traits they satisfy; this can be considered a form astructural inheritance, similar to interface implementation in Go, as opposed to the nominal inheritance model of Java and \CC{}.171 Unlike Java interfaces or \CC{} base classes, \CFA{} types do not explicitly state any inheritance relationship to traits they satisfy; this can be considered a form of structural inheritance, similar to interface implementation in Go, as opposed to the nominal inheritance model of Java and \CC{}. 174 172 Nominal inheritance can be simulated in \CFA{} using marker variables in traits: 175 173 … … 186 184 187 185 Traits, however, are significantly more powerful than nominal-inheritance interfaces; firstly, due to the scoping rules of the declarations that satisfy a trait's type assertions, a type may not satisfy a trait everywhere that that type is declared, as with !char! and the !nominal! trait above. 188 Secondly, because \CFA{} is not object-oriented and types do not have a closed set of methods, existing C library types can be extended to implement a trait simply by writing the requisite functions .186 Secondly, because \CFA{} is not object-oriented and types do not have a closed set of methods, existing C library types can be extended to implement a trait simply by writing the requisite functions\footnote{\CC{} only allows partial extension of C types, because constructors, destructors, conversions, and the assignment, indexing, and function-call operators may only be defined in a class; \CFA{} does not have any of these restrictions.}. 189 187 Finally, traits may be used to declare a relationship among multiple types, a property that may be difficult or impossible to represent in nominal-inheritance type systems\footnote{This example uses \CFA{}'s reference types, described in Section~\ref{type-features-sec}.}: 190 188 … … 206 204 \end{cfa} 207 205 208 In th eexample above, !(list_iterator, int)! satisfies !pointer_like! by the user-defined dereference function, and !(list_iterator, list)! also satisfies !pointer_like! by the built-in dereference operator for pointers.206 In this example above, !(list_iterator, int)! satisfies !pointer_like! by the user-defined dereference function, and !(list_iterator, list)! also satisfies !pointer_like! by the built-in dereference operator for pointers. 209 207 Given a declaration !list_iterator it!, !*it! can be either an !int! or a !list!, with the meaning disambiguated by context (\eg{} !int x = *it;! interprets !*it! as !int!, while !(*it).value = 42;! interprets !*it! as !list!). 210 While a nominal-inheritance system with associated types could model one of those two relationships by making !El! an associated type of !Ptr! in the !pointer_like! implementation, few such systems could model both relationships simultaneously. 208 While a nominal-inheritance system with associated types could model one of those two relationships by making !El! an associated type of !Ptr! in the !pointer_like! implementation, 209 I am unaware of any nominal-inheritance system that can model both relationships simultaneously. 210 Further comparison of \CFA{} polymorphism with other languages can be found in Section~\ref{generic-related-sec}. 211 211 212 212 The flexibility of \CFA{}'s implicit trait-satisfaction mechanism provides programmers with a great deal of power, but also blocks some optimization approaches for expression resolution. 213 The ability of types to begin or cease to satisfy traits when declarations go into or out of scope makes caching of trait satisfaction judgements difficult, and the ability of traits to take multiple type parameters can lead to a combinatorial explosion of work in any attempt to pre-compute trait satisfaction relationships. 214 215 \subsection{Implicit Conversions} \label{implicit-conv-sec} 216 217 In addition to the multiple interpretations of an expression produced by name overloading and polymorphic functions, for backward compatibility \CFA{} must support all of the implicit conversions present in C, producing further candidate interpretations for expressions. 218 As mentioned above, C does not have an inheritance hierarchy of types, but the C standard's rules for the ``usual arithmetic conversions'\cit{} define which of the built-in types are implicitly convertible to which other types, and the relative cost of any pair of such conversions from a single source type. 213 The ability of types to begin or cease to satisfy traits when declarations go into or out of scope makes caching of trait satisfaction judgments difficult, and the ability of traits to take multiple type parameters can lead to a combinatorial explosion of work in any attempt to pre-compute trait satisfaction relationships. 214 215 \subsection{Deleted Declarations} 216 217 Particular type combinations can be exempted from matching a given polymorphic function through the use of a \emph{deleted function declaration}: 218 219 \begin{cfa} 220 int somefn(char) = void; 221 \end{cfa} 222 223 This feature is based on a \CCeleven{} feature typically used to make a type non-copyable by deleting its copy constructor and assignment operator\footnote{In previous versions of \CC{}, a type could be made non-copyable by declaring a private copy constructor and assignment operator, but not defining either. This idiom is well-known, but depends on some rather subtle and \CC{}-specific rules about private members and implicitly-generated functions; the deleted function form is both clearer and less verbose.} or forbidding some interpretations of a polymorphic function by specifically deleting the forbidden overloads\footnote{Specific polymorphic function overloads can also be forbidden in previous \CC{} versions through use of template metaprogramming techniques, though this advanced usage is beyond the skills of many programmers.}. 224 Deleted function declarations are implemented in \CFACC{} by adding them to the symbol table as usual, but with a flag set that indicates that the function is deleted. 225 If this deleted declaration is selected as the unique minimal-cost interpretation of an expression then an error is produced, allowing \CFA{} programmers to guide the expression resolver away from undesirable solutions. 226 227 \section{Implicit Conversions} \label{implicit-conv-sec} 228 229 In addition to the multiple interpretations of an expression produced by name overloading and polymorphic functions, \CFA{} must support all of the implicit conversions present in C for backward compatibility, producing further candidate interpretations for expressions. 230 As mentioned above, C does not have an inheritance hierarchy of types, but the C standard's rules for the ``usual arithmetic conversions'' \cite[\S{}6.3.1.8]{C11} define which of the built-in types are implicitly convertible to which other types, as well as which implicit conversions to apply for mixed arguments to binary operators. 219 231 \CFA{} adds rules to the usual arithmetic conversions defining the cost of binding a polymorphic type variable in a function call; such bindings are cheaper than any \emph{unsafe} (narrowing) conversion, \eg{} !int! to !char!, but more expensive than any \emph{safe} (widening) conversion, \eg{} !int! to !double!. 220 One contribution of this thesis, discussed in Section \TODO{add to resolution chapter}, is a number of refinements to this cost model to more efficiently resolve polymorphic function calls.221 222 The expression resolution problem which is the focus of Chapter~\ref{resolution-chap} is to findthe unique minimal-cost interpretation of each expression in the program, where all identifiers must be matched to a declaration, and implicit conversions or polymorphic bindings of the result of an expression may increase the cost of the expression.223 While semantically valid \CFA{} code always has such a unique minimal-cost interpretation, \CFACC{} must also be able to detect and report as errors expressions whichhave either no interpretation or multiple ambiguous minimal-cost interpretations.232 One contribution of this thesis, discussed in Section~\ref{conv-cost-sec}, is a number of refinements to this cost model to more efficiently resolve polymorphic function calls. 233 234 In the context of these implicit conversions, the expression resolution problem can be restated as finding the unique minimal-cost interpretation of each expression in the program, where all identifiers must be matched to a declaration, and implicit conversions or polymorphic bindings of the result of an expression may increase the cost of the expression. 235 While semantically valid \CFA{} code always has such a unique minimal-cost interpretation, \CFACC{} must also be able to detect and report as errors expressions that have either no interpretation or multiple ambiguous minimal-cost interpretations. 224 236 Note that which subexpression interpretation is minimal-cost may require contextual information to disambiguate. 225 237 For instance, in the example in Section~\ref{overloading-sec}, !max(max, -max)! cannot be unambiguously resolved, but !int m = max(max, -max)! has a single minimal-cost resolution. 226 While the interpretation !int m = (int)max((double)max, -(double)max)! is also a valid interpretation, it is not minimal-cost due to the unsafe cast from the !double! result of !max! to !int!\footnote{The two \lstinline{double} casts function as type ascriptions selecting \lstinline{double max} rather than casts from \lstinline{int max} to \lstinline{double}, and as such are zero-cost. }.238 While the interpretation !int m = (int)max((double)max, -(double)max)! is also a valid interpretation, it is not minimal-cost due to the unsafe cast from the !double! result of !max! to !int!\footnote{The two \lstinline{double} casts function as type ascriptions selecting \lstinline{double max} rather than casts from \lstinline{int max} to \lstinline{double}, and as such are zero-cost. The \lstinline{int} to \lstinline{double} conversion could be forced if desired with two casts: \lstinline{(double)(int)max}}. 227 239 These contextual effects make the expression resolution problem for \CFA{} both theoretically and practically difficult, but the observation driving the work in Chapter~\ref{resolution-chap} is that of the many top-level expressions in a given program, most are straightforward and idiomatic so that programmers writing and maintaining the code can easily understand them; it follows that effective heuristics for common cases can bring down compiler runtime enough that a small proportion of harder-to-resolve expressions does not inordinately increase overall compiler runtime or memory usage. 228 240 229 \s ubsection{Type Features} \label{type-features-sec}230 231 The name overloading and polymorphism features of \CFA{} have the greatest effect on language design and compiler runtime, but there are a number of other features in the type system whichhave a smaller effect but are useful for code examples.241 \section{Type Features} \label{type-features-sec} 242 243 The name overloading and polymorphism features of \CFA{} have the greatest effect on language design and compiler runtime, but there are a number of other features in the type system that have a smaller effect but are useful for code examples. 232 244 These features are described here. 233 245 234 \subs ubsection{Reference Types}235 236 One of the key ergonomic improvements in \CFA{} is reference types, designed and implemented by Robert Schluntz \cite{Schluntz17}.246 \subsection{Reference Types} 247 248 One of the key ergonomic improvements in \CFA{} is reference types, designed and implemented by Robert Schluntz \cite{Schluntz17}. 237 249 Given some type !T!, a !T&! (``reference to !T!'') is essentially an automatically dereferenced pointer. 238 These types allow seamless pass-by-reference for function parameters, without the extraneous dereferencing syntax present in C; they also allow easy easy aliasing of nested values with a similarly convenient syntax. 239 A particular improvement is removing syntactic special cases for operators which take or return mutable values; for example, the use !a += b! of a compound assignment operator now matches its signature, !int& ?+=?(int&, int)!, as opposed to the previous syntactic special cases to automatically take the address of the first argument to !+=! and to mark its return value as mutable. 240 241 The C standard makes heavy use of the concept of \emph{lvalue}, an expression with a memory address; its complement, \emph{rvalue} (a non-addressable expression) is not explicitly named. 242 In \CFA{}, the distinction between lvalue and rvalue can be reframed in terms of reference and non-reference types, with the benefit of being able to express the difference in user code. 243 \CFA{} references preserve the existing qualifier-dropping implicit lvalue-to-rvalue conversion from C (\eg{} a !const volatile int&! can be implicitly copied to a bare !int!) 244 To make reference types more easily usable in legacy pass-by-value code, \CFA{} also adds an implicit rvalue-to-lvalue conversion, implemented by storing the value in a fresh compiler-generated temporary variable and passing a reference to that temporary. 245 To mitigate the ``!const! hell'' problem present in \CC{}, there is also a qualifier-dropping lvalue-to-lvalue conversion, also implemented by copying into a temporary: 250 These types allow seamless pass-by-reference for function parameters, without the extraneous dereferencing syntax present in C; they also allow easy aliasing of nested values with a similarly convenient syntax. 251 The addition of reference types also eliminated two syntactic special-cases present in previous versions of \CFA{}. 252 Consider the a call !a += b! to a compound assignment operator. 253 The previous declaration for that operator is !lvalue int ?+=?(int*, int)!. 254 To mutate the left argument, the built-in operators were special-cased to implicitly take the address of that argument, while the special !lvalue! syntax was used to mark the return type of a function as a mutable reference. 255 With references, this declaration is re-written as !int& ?+=?(int&, int)!. 256 The reference semantics generalize the implicit address-of on the left argument and allow it to be used in user-declared functions, while also subsuming the (now removed) !lvalue! syntax for function return types. 257 258 The C standard makes heavy use of the concept of \emph{lvalue}, an expression with a memory address; its complement, \emph{rvalue} (a non-addressable expression) is not explicitly named in the standard. 259 In \CFA{}, the distinction between lvalue and rvalue can be re-framed in terms of reference and non-reference types, with the benefit of being able to express the difference in user code. 260 \CFA{} references preserve the existing qualifier-dropping implicit lvalue-to-rvalue conversion from C (\eg{} a !const volatile int&! can be implicitly copied to a bare !int!). 261 To make reference types more easily usable in legacy pass-by-value code, \CFA{} also adds an implicit rvalue-to-lvalue conversion, implemented by storing the value in a compiler-generated temporary variable and passing a reference to that temporary. 262 To mitigate the ``!const! hell'' problem present in \CC{}, there is also a qualifier-dropping lvalue-to-lvalue conversion implemented by copying into a temporary: 246 263 247 264 \begin{cfa} 248 265 const int magic = 42; 249 250 266 void inc_print( int& x ) { printf("%d\n", ++x); } 251 267 252 print_inc( magic ); $\C{// legal; implicitly generated code in red below:}$268 inc_print( magic ); $\C{// legal; implicitly generated code in red below:}$ 253 269 254 270 `int tmp = magic;` $\C{// to safely strip const-qualifier}$ 255 ` print_inc( tmp );` $\C{// tmp is incremented, magic is unchanged}$271 `inc_print( tmp );` $\C{// tmp is incremented, magic is unchanged}$ 256 272 \end{cfa} 257 273 … … 259 275 The primary issue with \CC{} references is that it is impossible to extract the address of the reference variable rather than the address of the referred-to variable. 260 276 This breaks a number of the usual compositional properties of the \CC{} type system, \eg{} a reference cannot be re-bound to another variable, nor is it possible to take a pointer to, array of, or reference to a reference. 261 \CFA{} supports all of these use cases \TODO{test array}without further added syntax.277 \CFA{} supports all of these use cases without further added syntax. 262 278 The key to this syntax-free feature support is an observation made by the author that the address of a reference is a lvalue. 263 In C, the address-of operator !&x! can only be applied to lvalue expressions, and always produces an immutable rvalue; \CFA{} supports reference re-binding by assignment to the address of a reference , and pointers to references by repeating the address-of operator:279 In C, the address-of operator !&x! can only be applied to lvalue expressions, and always produces an immutable rvalue; \CFA{} supports reference re-binding by assignment to the address of a reference\footnote{The syntactic difference between reference initialization and reference assignment is unfortunate, but preserves the ability to pass function arguments by reference (a reference initialization context) without added syntax.}, and pointers to references by repeating the address-of operator: 264 280 265 281 \begin{cfa} … … 270 286 \end{cfa} 271 287 272 For better compatibility with C, the \CFA{} team has chosen not to differentiate function overloads based on top-level reference types, and as such their contribution to the difficulty of \CFA{} expression resolution is largely restricted to the implementation details of normalization conversions and adapters.273 274 \subs ubsection{Resource Management}275 276 \CFA{} also supports the RAII (``Resource Acquisition is Initialization'') idiom originated by \CC{}, thanks to the object lifetime work of Robert Schluntz \cite{Schluntz17}.288 For better compatibility with C, the \CFA{} team has chosen not to differentiate function overloads based on top-level reference types, and as such their contribution to the difficulty of \CFA{} expression resolution is largely restricted to the implementation details of matching reference to non-reference types during type-checking. 289 290 \subsection{Resource Management} \label{ctor-sec} 291 292 \CFA{} also supports the RAII (``Resource Acquisition is Initialization'') idiom originated by \CC{}, thanks to the object lifetime work of Robert Schluntz \cite{Schluntz17}. 277 293 This idiom allows a safer and more principled approach to resource management by tying acquisition of a resource to object initialization, with the corresponding resource release executed automatically at object finalization. 278 294 A wide variety of conceptual resources may be conveniently managed by this scheme, including heap memory, file handles, and software locks. … … 325 341 \end{cfa} 326 342 327 \subs ubsection{Tuple Types}343 \subsection{Tuple Types} 328 344 329 345 \CFA{} adds \emph{tuple types} to C, a syntactic facility for referring to lists of values anonymously or with a single identifier. 330 346 An identifier may name a tuple, a function may return one, and a tuple may be implicitly \emph{destructured} into its component values. 331 347 The implementation of tuples in \CFACC{}'s code generation is based on the generic types introduced in Chapter~\ref{generic-chap}, with one compiler-generated generic type for each tuple arity. 332 This allows tuples to take advantage of the same runtime optimizations available to generic types, while reducing code bloat.333 An extended presentation of the tuple features of \CFA{} can be found in \cite{Moss18}, but the following example shows the basics:334 335 \begin{cfa} 336 [char, char] x = ['!', '?']; $\C{// (1);tuple type and expression syntax}$337 int x = 2; $\C{// (2)}$348 This reuse allows tuples to take advantage of the same runtime optimizations available to generic types, while reducing code bloat. 349 An extended presentation of the tuple features of \CFA{} can be found in \cite{Moss18}, but the following example demonstrates the basic features: 350 351 \begin{cfa} 352 [char, char] x$\(_1\)$ = ['!', '?']; $\C{// tuple type and expression syntax}$ 353 int x$\(_2\)$ = 2; 338 354 339 355 forall(otype T) 340 [T, T] swap ( T a, T b ) { $\C{// (3)}$356 [T, T] swap$\(_1\)$( T a, T b ) { 341 357 return [b, a]; $\C{// one-line swap syntax}$ 342 358 } 343 359 344 x = swap( x ); $\C{// destructure [char, char] xinto two elements}$345 $\C{// cannot use int x, not enough arguments}$346 347 void swap ( int, char, char ); $\C{// (4)}$348 349 swap( x, x ); $\C{// (4) on (2), (1)}$350 $\C{// not (3) on (2), (2) due to polymorphism cost}$360 x = swap( x ); $\C{// destructure x\(_1\) into two elements}$ 361 $\C{// cannot use x\(_2\), not enough arguments}$ 362 363 void swap$\(_2\)$( int, char, char ); 364 365 swap( x, x ); $\C{// swap\(_2\)( x\(_2\), x\(_1\) )}$ 366 $\C{// not swap\(_1\)( x\(_2\), x\(_2\) ) due to polymorphism cost}$ 351 367 \end{cfa} 352 368 353 369 Tuple destructuring breaks the one-to-one relationship between identifiers and values. 354 This precludes some argument-parameter matching strategies for expression resolution, as well as cheap interpretation filters based on comparing number of parameters and arguments. 355 As an example, in the call to !swap( x, x )! above, the second !x! can be resolved starting at the second or third parameter of !swap!, depending which interpretation of !x! was chosen for the first argument. 370 Hence, some argument-parameter matching strategies for expression resolution are precluded, as well as cheap interpretation filters based on comparing number of parameters and arguments. 371 As an example, in the call to !swap( x, x )! above, the second !x! can be resolved starting at the second or third parameter of !swap!$_2$, depending which interpretation of !x! is chosen for the first argument. 372 373 \section{Conclusion} 374 375 \CFA{} adds a significant number of features to standard C, increasing the expressivity and re-usability of \CFA{} code while maintaining backwards compatibility for both code and larger language paradigms. 376 This flexibility does incur significant added compilation costs, however, the mitigation of which are the primary concern of this thesis. -
doc/theses/aaron_moss_PhD/phd/conclusion.tex
r6a9d4b4 r933f32f 1 1 \chapter{Conclusion} 2 2 3 Wrap it up --- Done, done done. 3 Decades after its first standardization, the C language remains a widely-used tool and a vital part of the software development landscape. 4 The \CFA{} language under development at the University of Waterloo represents an evolutionary modernization of C with expressive modern language features paired with strong C backwards-compatibility. 5 This thesis has contributed to these project goals in a variety of ways, including the addition of a generic-types language feature (Chapter~\ref{generic-chap}) and refinement of the \CFA{} overload selection rules to produce a more expressive and intuitive model (Section~\ref{conv-cost-sec}). 6 Based on the technical contribution of the resolver prototype system (Section~\ref{rp-features-sec}), I have also made significant improvements to \CFA{} compilation performance, including un-combined bottom-up expression traversal (Section~\ref{arg-parm-matching-sec}), deferred-cached assertion satisfaction (Section~\ref{assn-sat-sec}), and a novel persistent union-find type environment data structure (Section~\ref{env-persistent-union-find}). 7 The combination of these practical improvements and added features significantly improve the viability of \CFA{} as a practical programming language. 8 9 Further improvements to the \CFA{} type system are still possible, however. 10 One area suggested by this work is development of a scheme for user-defined conversions; to integrate properly with the \CFA{} conversion model, there would need to be a distinction between safe and unsafe conversions, and possibly a way to denote conversions as explicit-only or non-chainable. 11 Another place for ongoing effort is improvement of compilation performance; I believe the most promising direction for that effort is rebuilding the \CFA{} compiler on a different framework than Bilson's \CFACC{}. 12 The resolver prototype presented in this work has good performance and already has the basics of \CFA{} semantics implemented, as well as many of the necessary core data structures, and would be a viable candidate for a new compiler architecture. 13 An alternate approach would be to fork an existing C compiler such as Clang~\cite{Clang}, which would need to be modified to use one of the resolution algorithms discussed here, as well as various other features introduced by Bilson~\cite{Bilson03}. 14 15 More generally, the algorithmic techniques described in this thesis may be useful to implementors of other programming languages. 16 In particular, the demonstration of practical performance for polymorphic return-type inference suggests the possibility of eliding return-type-only template parameters in \CC{} function calls, though integrating such an extension into \CC{} expression resolution in a backwards-compatible manner may be challenging. 17 The \CFA{} expression resolution problem also bears some similarity to the \emph{local type inference} model put forward by Pierce \& Turner \cite{Pierce00} and Odersky \etal{} \cite{Odersky01}; compiler implementors for languages like Scala \cite{Scala}, which performs type inference based on this model, may be able to profitably adapt the algorithms and data structures presented in this thesis. -
doc/theses/aaron_moss_PhD/phd/evaluation/generic-timing.dat
r6a9d4b4 r933f32f 8 8 "clear\npair" 2840 773 748 3511 9 9 "pop\npair" 3025 5414 813 23867 10 -
doc/theses/aaron_moss_PhD/phd/frontpgs.tex
r6a9d4b4 r933f32f 62 62 \bigskip 63 63 64 % \noindent 65 % \begin{tabbing} 66 % Internal-External Member: \= \kill % using longest text to define tab length 67 % External Examiner: \> Bruce Bruce \\ 68 % \> Professor, Dept. of Philosophy of Zoology, University of Wallamaloo \\ 69 % \end{tabbing} 70 % \bigskip 64 \noindent 65 \begin{tabbing} 66 Internal-External Member: \= \kill % using longest text to define tab length 67 External Examiner: \> Doug Lea \\ 68 \> Professor, Computer Science Department, \\ 69 \> State University of New York at Oswego \\ 70 \end{tabbing} 71 \bigskip 71 72 72 73 \noindent … … 74 75 Internal-External Member: \= \kill % using longest text to define tab length 75 76 Supervisor: \> Peter Buhr \\ 76 \> Professor, School of Computer Science, University of Waterloo \\ 77 \> Associate Professor, School of Computer Science, \\ 78 \> University of Waterloo \\ 77 79 \end{tabbing} 78 80 \bigskip … … 81 83 \begin{tabbing} 82 84 Internal-External Member: \= \kill % using longest text to define tab length 83 Internal Members: \> Gregor Richards \\ 84 \> Professor, School of Computer Science, University of Waterloo \\ 85 \> Ond\v{r}ej Lhot\a'ak \\ 86 \> Professor, School of Computer Science, University of Waterloo \\ 85 Internal Members: \> Ond\v{r}ej Lhot\a'ak \\ 86 \> Associate Professor, School of Computer Science, \\ 87 \>University of Waterloo \\ 88 \\ 89 \> Gregor Richards \\ 90 \> Assistant Professor, School of Computer Science, \\ 91 \> University of Waterloo \\ 87 92 \end{tabbing} 88 % \bigskip 89 90 % \noindent 91 % \begin{tabbing} 92 % Internal-External Member: \= \kill % using longest text to define tab length 93 % Internal-External Member: \> Deepa Thotta \\ 94 % \> Professor, Dept. of Philosophy, University of Waterloo \\ 95 % \end{tabbing} 96 % \bigskip 93 \bigskip 94 95 \noindent 96 \begin{tabbing} 97 Internal-External Member: \= \kill % using longest text to define tab length 98 Internal-External Member: \> Werner Dietl \\ 99 \> Assistant Professor, Electrical and Computer Engineering, \\ 100 \> University of Waterloo \\ 101 \end{tabbing} 102 % \bigskip 97 103 98 104 % \noindent … … 124 130 \begin{center}\textbf{Abstract}\end{center} 125 131 126 This is the abstract. 132 The C programming language has been an important software development tool for decades. 133 \CFA{} is a new programming language designed with strong backwards-compatibility to take advantage of widely distributed C programming expertise and the large deployed base of C code, paired with modern language features to improve developer productivity. 134 135 This thesis presents a number of improvements to \CFA{}. 136 The author has developed one major new language feature, generic types, in a way that integrates naturally with both the existing polymorphism features of \CFA{} and the translation-unit-based encapsulation model of C. 137 This thesis also presents a number of smaller refinements to the \CFA{} overload resolution rules, each of which improves the expressivity or intuitive nature of the language. 138 139 This thesis also includes a number of practical improvements to \CFA{} compilation performance, focused on the expression resolution pass, which is the main bottleneck. 140 These include better algorithms for argument-parameter matching and type assertion satisfaction, as well as a new type-environment data-structure based on a novel variant of union-find. 141 The compilation performance improvements have all been experimentally validated with a new prototype system that encapsulates the key aspects of the \CFA{} language; this prototype is a promising basis for future research and a technical contribution of this work. 142 143 \CFA{}, extended and refined in this thesis, presents both an independently interesting combination of language features and a comprehensive approach to the modernization of C. 144 This work demonstrates the hitherto unproven compiler-implementation viability of the \CFA{} language design, and provides a number of useful tools to implementors of other languages. 127 145 128 146 \cleardoublepage … … 131 149 % ------------------------------- 132 150 133 % \begin{center}\textbf{Acknowledgements}\end{center} 134 135 % I would like to thank all the little people who made this thesis possible. 136 % \cleardoublepage 151 \begin{center}\textbf{Acknowledgements}\end{center} 152 153 Though a doctoral thesis is an individual project, I could not have completed it without the help and support of many members of my community. 154 This thesis would not exist in the form it does without the mentorship of my advisor, Peter Buhr, who has ably led the \CFA{} team while giving me both the advantage of his decades of experience and the freedom to follow my own interests. 155 156 My work on \CFA{} does not exist in a vacuum, and it has been a pleasure and a privilege to collaborate with the members of the \CFA{} team: Andrew Beach, Richard Bilson, Michael Brooks, Bryan Chan, Thierry Delisle, Glen Ditchfield, Brice Dobry, Rob Schluntz, and others. 157 I gratefully acknowledge the financial support of the National Science and Engineering Council of Canada and Huawei Ltd.\ for this project. 158 I would also like to thank of my thesis committee, Werner Dietl, Doug Lea, Ond\v{r}ej Lhot\a'ak, and Gregor Richards, for the time and effort they have invested in providing constructive feedback to refine this work. 159 I am indebted to Peter van Beek and Ian Munro for their algorithmic expertise and willingness to share their time with me. 160 I have far too many colleagues in the Programming Languages Group and School of Computer Science to name, but I deeply appreciate their camaraderie; specifically with regard to the production of this thesis, I would like to thank Nathan Fish for recommending my writing soundtrack, and Sharon Choy for her unfailing supply of encouraging rabbit animations. 161 162 Finally, to all my friends and family who have supported me and made Kitchener-Waterloo home these past seven years, thank you, I could not have done it without you; most especially, Christina Moss, you are the best of wives and best of women, your support has kept me going through the ups and downs of research, and your partnership is key to all my successes. 163 164 \cleardoublepage 137 165 138 166 % D E D I C A T I O N … … 141 169 % \begin{center}\textbf{Dedication}\end{center} 142 170 143 % This is dedicated to the one I love. 171 % To Christina, who has spent too many hours politely listening to me work out the technical minutiae of this thesis, I love you, and I won't make you read it. 172 144 173 % \cleardoublepage 145 174 -
doc/theses/aaron_moss_PhD/phd/generic-types.tex
r6a9d4b4 r933f32f 7 7 While this approach is flexible and supports integration with the C type checker and tooling, it is also tedious and error prone, especially for more complex data structures. 8 8 A second approach is to use !void*!-based polymorphism, \eg{} the C standard library functions !bsearch! and !qsort!, which allow for the reuse of common functionality. 9 However, basing all polymorphism on !void*! eliminates the type checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that is otherwise not needed.9 However, basing all polymorphism on !void*! eliminates the type checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that is otherwise unnecessary. 10 10 A third approach to generic code is to use preprocessor macros, which does allow the generated code to be both generic and type checked, but errors in such code may be difficult to locate and debug. 11 11 Furthermore, writing and using preprocessor macros is unnatural and inflexible. 12 Figure~\ref{bespoke-generic-fig} demonstrates the bespoke approach for a simple linked list with !insert! and !head! operations, while Figure~\ref{void-generic-fig} and Figure~\ref{macro-generic-fig} show the same example using !void*! -and !#define!-based polymorphism, respectively.12 Figure~\ref{bespoke-generic-fig} demonstrates the bespoke approach for a simple linked list with !insert! and !head! operations, while Figure~\ref{void-generic-fig} and Figure~\ref{macro-generic-fig} show the same example using !void*! and !#define!-based polymorphism, respectively. 13 13 14 14 \begin{figure} 15 15 \begin{cfa} 16 #include <stdlib.h> $\C{// for malloc}$ 17 #include <stdio.h> $\C{// for printf}$ 18 16 19 struct int_list { int value; struct int_list* next; }; 17 20 … … 24 27 int int_list_head( const struct int_list* ls ) { return ls->value; } 25 28 26 $\C[\textwidth]{// all code must be duplicated for every generic instantiation}$29 // all code must be duplicated for every generic instantiation 27 30 28 31 struct string_list { const char* value; struct string_list* next; }; … … 37 40 { return ls->value; } 38 41 39 $\C[\textwidth]{// use is efficient and idiomatic}$42 // use is efficient and idiomatic 40 43 41 44 int main() { … … 55 58 \begin{figure} 56 59 \begin{cfa} 60 #include <stdlib.h> $\C{// for malloc}$ 61 #include <stdio.h> $\C{// for printf}$ 62 57 63 // single code implementation 58 64 59 65 struct list { void* value; struct list* next; }; 60 66 61 $\C[\textwidth]{// internal memory management requires helper functions}$67 // internal memory management requires helper functions 62 68 63 69 void list_insert( struct list** ls, void* x, void* (*copy)(void*) ) { … … 69 75 void* list_head( const struct list* ls ) { return ls->value; } 70 76 71 $\C[\textwidth]{// helpers duplicated per type}$77 // helpers duplicated per type 72 78 73 79 void* int_copy(void* x) { … … 96 102 \begin{figure} 97 103 \begin{cfa} 98 $\C[\textwidth]{// code is nested in macros}$ 104 #include <stdlib.h> $\C{// for malloc}$ 105 #include <stdio.h> $\C{// for printf}$ 106 107 // code is nested in macros 99 108 100 109 #define list(N) N ## _list … … 118 127 define_list(string, const char*); $\C[3in]{// defines string\_list}$ 119 128 120 $\C[\textwidth]{// use is efficient, but syntactically idiosyncratic}$129 // use is efficient, but syntactically idiosyncratic 121 130 122 131 int main() { … … 134 143 \end{figure} 135 144 136 \CC{}, Java, and other languages use \emph{generic types} to produce type-safe abstract data types.137 Design and implementation of generic types for \CFA{} is the first major contribution of this thesis, a summary of which is published in \cite{Moss18} and fromwhich this chapter is closely based.145 \CC{}, Java, and other languages use \emph{generic types} (or \emph{parameterized types}) to produce type-safe abstract data types. 146 Design and implementation of generic types for \CFA{} is the first major contribution of this thesis, a summary of which is published in \cite{Moss18} and on which this chapter is closely based. 138 147 \CFA{} generic types integrate efficiently and naturally with the existing polymorphic functions in \CFA{}, while retaining backward compatibility with C in layout and support for separate compilation. 139 148 A generic type can be declared in \CFA{} by placing a !forall! specifier on a !struct! or !union! declaration, and instantiated using a parenthesized list of types after the generic name. 140 An example comparable to the C polymorphism examples in Figures~\ref{bespoke-generic-fig}, \ref{void-generic-fig}, and \ref{macro-generic-fig} can be seen in Figure~\ref{cfa-generic-fig} \TODO{test this code}.149 An example comparable to the C polymorphism examples in Figures~\ref{bespoke-generic-fig}, \ref{void-generic-fig}, and \ref{macro-generic-fig} can be seen in Figure~\ref{cfa-generic-fig}. 141 150 142 151 \begin{figure} 143 152 \begin{cfa} 153 #include <stdlib.hfa> $\C{// for alloc}$ 154 #include <stdio.h> $\C{// for printf}$ 155 144 156 forall(otype T) struct list { T value; list(T)* next; }; 145 157 146 $\C[\textwidth]{// single polymorphic implementation of each function}$147 $\C[\textwidth]{// overloading reduces need for namespace prefixes}$158 // single polymorphic implementation of each function 159 // overloading reduces need for namespace prefixes 148 160 149 161 forall(otype T) void insert( list(T)** ls, T x ) { … … 155 167 forall(otype T) T head( const list(T)* ls ) { return ls->value; } 156 168 157 $\C[\textwidth]{// use is clear and efficient}$169 // use is clear and efficient 158 170 159 171 int main() { … … 173 185 \section{Design} 174 186 175 Though a number of languages have some implementation of generic types, backward compatibility with both C and existing \CFA{} polymorphism present ed some unique design constraints for this project.176 The guiding principle was to maintain an unsurprising language model for C programmers without compromising runtime efficiency.177 A key insight for this design was that C already possesses a handful of built-in generic types (\emph{compound types} in the language of the standard\cit{}), notably pointer (!T*!) and array (!T[]!), and that user-definable generics should act similarly.178 179 \subsection{Related Work} 180 181 One approach to the design of generic types is that taken by \CC{} templates \cite{C++}.187 Though a number of languages have some implementation of generic types, backward compatibility with both C and existing \CFA{} polymorphism present some unique design constraints for \CFA{} generics. 188 The guiding principle is to maintain an unsurprising language model for C programmers without compromising runtime efficiency. 189 A key insight for this design is that C already possesses a handful of built-in generic types (\emph{derived types} in the language of the standard \cite[\S{}6.2.5]{C11}), notably pointer (!T*!) and array (!T[]!), and that user-definable generics should act similarly. 190 191 \subsection{Related Work} \label{generic-related-sec} 192 193 One approach to the design of generic types is that taken by \CC{} templates \cite{C++}. 182 194 The template approach is closely related to the macro-expansion approach to C polymorphism demonstrated in Figure~\ref{macro-generic-fig}, but where the macro-expansion syntax has been given first-class language support. 183 195 Template expansion has the benefit of generating code with near-optimal runtime efficiency, as distinct optimizations can be applied for each instantiation of the template. 184 On the other hand, template expansion can also lead to significant code bloat, exponential in the worst case \cit{}, and the costs of increased instruction cache pressure at runtime and wasted developer time when compiling cannot be discounted.196 On the other hand, template expansion can also lead to significant code bloat, exponential in the worst case \cite{Haberman16}, and the costs of increased compilation time and instruction cache pressure cannot be ignored. 185 197 The most significant restriction of the \CC{} template model is that it breaks separate compilation and C's translation-unit-based encapsulation mechanisms. 186 Because a \CC{} template is not actually code, but rather a sort of``recipe'' to generate code, template code must be visible at its call site to be used.187 Furthermore, \CC{} template code cannot be type-checked without instantiating it, a time consuming process with no hope of improvement until \CC{} concepts \cite{C++Concepts} are standardized in \CCtwenty{}.188 C code, by contrast, only needs a !struct! or function declaration to call that function or use (by-pointer) values of that type, a desirable property to maintain for\CFA{}.189 190 Java \cite{Java8} has another prominent implementation for generic types, introduced in Java~5 and based on a significantly different approach than \CC{}.198 Because a \CC{} template is not actually code, but rather a ``recipe'' to generate code, template code must be visible at its call site to be used. 199 Furthermore, \CC{} template code cannot be type-checked without instantiating it, a time consuming process with no hope of improvement until \CC{} concepts \cite{C++Concepts} are standardized in \CCtwenty{}. 200 C code, by contrast, only needs a function declaration to call that function or a !struct! declaration to use (by-pointer) values of that type, desirable properties to maintain in \CFA{}. 201 202 Java \cite{Java8} has another prominent implementation for generic types, introduced in Java~5 and based on a significantly different approach than \CC{}. 191 203 The Java approach has much more in common with the !void*!-polymorphism shown in Figure~\ref{void-generic-fig}; since in Java nearly all data is stored by reference, the Java approach to polymorphic data is to store pointers to arbitrary data and insert type-checked implicit casts at compile-time. 192 This process of \emph{type erasure} has the benefit of allowing a single instantiation of polymorphic code, but relies heavily on Java's object model and garbage collector.204 This process of \emph{type erasure} has the benefit of allowing a single instantiation of polymorphic code, but relies heavily on Java's object model. 193 205 To use this model, a more C-like language such as \CFA{} would be required to dynamically allocate internal storage for variables, track their lifetime, and properly clean them up afterward. 194 206 195 Cyclone \cite{Grossman06} is another language extending C, and also provides capabilities for polymorphic functions and existential types,similar to \CFA{}'s !forall! functions and generic types.207 Cyclone \cite{Grossman06} extends C and also provides capabilities for polymorphic functions and existential types which are similar to \CFA{}'s !forall! functions and generic types. 196 208 Cyclone existential types can include function pointers in a construct similar to a virtual function table, but these pointers must be explicitly initialized at some point in the code, which is tedious and error-prone compared to \CFA{}'s implicit assertion satisfaction. 197 209 Furthermore, Cyclone's polymorphic functions and types are restricted to abstraction over types with the same layout and calling convention as !void*!, \ie{} only pointer types and !int!. … … 200 212 201 213 Many other languages include some form of generic types. 202 As a brief survey, ML \cite{ML} was the first language to support parameteric polymorphism, but unlike \CFA{} does not support the use of assertions and traits to constrain type arguments.203 Haskell \cite{Haskell10} combines ML-style polymorphism with the notion of type classes, similar to \CFA{} traits, but requiring an explicit association with their implementing types, unlike \CFA{}.204 Objective-C \cite{obj-c-book} is an extension to C which has had some industrial success; however, it did not support type-checked generics until recently\cite{xcode7}, and it's garbage-collected, message-passing object-oriented model is a radical departure from C.205 Go \cite{Go}, and Rust\cite{Rust} are modern compiled languages with abstraction features similar to \CFA{} traits,\emph{interfaces} in Go and \emph{traits} in Rust.206 Go has implicit interface implementation and uses a ``fat pointer'' construct to pass polymorphic objects to functions, similar in principle to \CFA{}'s implicit forall param ters.214 As a brief survey, ML \cite{ML} was the first language to support parametric polymorphism, but unlike \CFA{} does not support the use of assertions and traits to constrain type arguments. 215 Haskell \cite{Haskell10} combines ML-style polymorphism with the notion of type classes, similar to \CFA{} traits, but requiring an explicit association with their implementing types, unlike \CFA{}. 216 Objective-C \cite{obj-c-book} is an extension to C which has had some industrial success; however, it did not support type-checked generics until recently \cite{xcode7}, and its garbage-collected, message-passing object-oriented model is a radical departure from C. 217 Go \cite{Go}, and Rust \cite{Rust} are modern compiled languages with abstraction features similar to \CFA{} traits: \emph{interfaces} in Go and \emph{traits} in Rust. 218 Go has implicit interface implementation and uses a ``fat pointer'' construct to pass polymorphic objects to functions, similar in principle to \CFA{}'s implicit forall parameters. 207 219 Go does not, however, allow user code to define generic types, restricting Go programmers to the small set of generic types defined by the compiler. 208 Rust has powerful abstractions for generic programming, including explicit implemen ation of traits and options for both separately-compiled virtual dispatch and template-instantiated static dispatch in functions.220 Rust has powerful abstractions for generic programming, including explicit implementation of traits and options for both separately-compiled virtual dispatch and template-instantiated static dispatch in functions. 209 221 On the other hand, the safety guarantees of Rust's \emph{lifetime} abstraction and borrow checker impose a distinctly idiosyncratic programming style and steep learning curve; \CFA{}, with its more modest safety features, allows direct ports of C code while maintaining the idiomatic style of the original source. 210 222 211 223 \subsection{\CFA{} Generics} 212 224 213 The generic types design in \CFA{} draws inspiration from both \CC{} and Java generics, capturing the betteraspects of each.214 Like \CC{} template types, generic !struct! s and !union!s in \CFA{} have macro-expanded storage layouts, but, like Java generics, \CFA{} generic types can be used with separately-compiled polymorphic functions without requiring either the type or function definition to be visible to the other.225 The generic types design in \CFA{} draws inspiration from both \CC{} and Java generics, capturing useful aspects of each. 226 Like \CC{} template types, generic !struct! and !union! types in \CFA{} have macro-expanded storage layouts, but, like Java generics, \CFA{} generic types can be used with separately-compiled polymorphic functions without requiring either the type or function definition to be visible to the other. 215 227 The fact that the storage layout of any instantiation of a \CFA{} generic type is identical to that of the monomorphic type produced by simple macro replacement of the generic type parameters is important to provide consistent and predictable runtime performance, and to not impose any undue abstraction penalty on generic code. 216 As an example, consider the following generic type and function \TODO{test this}: 217 228 As an example, consider the following generic type and function: 229 230 % TODO whatever the bug is with initializer-expressions not working, it affects this 218 231 \begin{cfa} 219 232 forall( otype R, otype S ) struct pair { R first; S second; }; 220 233 221 234 pair(const char*, int) with_len( const char* s ) { 222 return (pair(const char* ), int){ s, strlen(s) };235 return (pair(const char*, int)){ s, strlen(s) }; 223 236 } 224 237 \end{cfa} 225 238 226 239 In this example, !with_len! is defined at the same scope as !pair!, but it could be called from any context that can see the definition of !pair! and a declaration of !with_len!. 227 If its return type w as!pair(const char*, int)*!, callers of !with_len! would only need the declaration !forall(otype R, otype S) struct pair! to call it, in accordance with the usual C rules for opaque types.228 229 !with_len! is itself a monomorphic function, returning a type that is structurally identical to !struct { const char* first; int second; }!, and as such could be called from C given a n appropriate redeclarationand demangling flags.230 However, the definition of !with_len! depends on a polymorphic function call to the !pair! constructor, which only needs to be written once (in this case, implicitly by the compiler according to the usual \CFA{} constructor generation \cite{Moss18}) and can be re-used for a wide variety of !pair! instantiations.231 Since the parameters to this polymorphic constructor call are all statically known, compiler inlining can eliminate any runtime overhead of this polymorphic call.240 If its return type were !pair(const char*, int)*!, callers of !with_len! would only need the declaration !forall(otype R, otype S) struct pair! to call it, in accordance with the usual C rules for opaque types. 241 242 !with_len! is itself a monomorphic function, returning a type that is structurally identical to !struct { const char* first; int second; }!, and as such could be called from C given appropriate re-declarations and demangling flags. 243 However, the definition of !with_len! depends on a polymorphic function call to the !pair! constructor, which only needs to be written once (in this case, implicitly by the compiler according to the usual \CFA{} constructor generation \cite{Schluntz17}) and can be re-used for a wide variety of !pair! instantiations. 244 Since the parameters to this polymorphic constructor call are all statically known, compiler inlining can in principle eliminate any runtime overhead of this polymorphic call. 232 245 233 246 \CFA{} deliberately does not support \CC{}-style partial specializations of generic types. 234 A particularly infamous example in the \CC{} standard library is !vector<bool>!, which is represented as a bit string rather than the array representation of the other !vector! instantiations.247 A particularly infamous example in the \CC{} standard library is !vector<bool>!, which is represented as a bit-string rather than the array representation of the other !vector! instantiations. 235 248 Complications from this inconsistency (chiefly the fact that a single bit is not addressable, unlike an array element) make the \CC{} !vector! unpleasant to use in generic contexts due to the break in its public interface. 236 Rather than attempting to plug leaks in the template specialization abstraction with a detailed method interface, \CFA{} takes the more principledposition that two types with an unrelated data layout are in fact unrelated types, and should be handled with different code.237 Of course, to the degree that distinct types are similar enough to share an interface, the \CFA{} !trait! system allows one to be defined, and objects of types implementing that !trait! to be operated on inthe same polymorphic functions.249 Rather than attempting to plug leaks in the template specialization abstraction with a detailed method interface, \CFA{} takes the more consistent position that two types with an unrelated data layout are in fact unrelated types, and should be handled with different code. 250 Of course, to the degree that distinct types are similar enough to share an interface, the \CFA{} !trait! system allows such an interface to be defined, and objects of types implementing that !trait! to be operated on using the same polymorphic functions. 238 251 239 252 Since \CFA{} polymorphic functions can operate over polymorphic generic types, functions over such types can be partially or completely specialized using the usual overload selection rules. 240 As an example, the !with_len! function above could be an optimization of the following more general function:253 As an example, the following generalization of !with_len! is a semantically-equivalent function which works for any type that has a !len! function declared, making use of both the ad-hoc (overloading) and parametric (!forall!) polymorphism features of \CFA{}: 241 254 242 255 \begin{cfa} … … 247 260 \end{cfa} 248 261 249 \CFA{} generic types also support t he type constraints from!forall! functions.262 \CFA{} generic types also support type constraints, as in !forall! functions. 250 263 For example, the following declaration of a sorted set type ensures that the set key implements equality and relational comparison: 251 264 … … 254 267 \end{cfa} 255 268 256 These constraints are implemented by applying equivalent constraints to the compiler-generated constructors for this type.269 These constraints are enforced by applying equivalent constraints to the compiler-generated constructors for this type. 257 270 258 271 \section{Implementation} \label{generic-impl-sec} 259 272 260 The ability to use generic types in polymorphic contexts means that the \CFA{} implementation in \CFACC{} must support a mechanism for accessing fields of generic types dynamically at runtime. 261 While \CFACC{} could in principle use this same mechanism for accessing fields of all generic types, such an approach would throw away compiler knowledge of static types and impose an unnecessary runtime cost, limiting the utility of the generic type design. 262 Instead, my design for generic type support in \CFACC{} distinguishes between \emph{concrete} generic types that have a fixed memory layout regardless of type parameters and \emph{dynamic} generic types that may vary in memory layout depending on their type parameters. 273 The ability to use generic types in polymorphic contexts means that the \CFA{} implementation must support a mechanism for accessing fields of generic types dynamically. 274 While \CFACC{} could in principle use this same mechanism for accessing fields of generic types in monomorphic contexts as well, such an approach would throw away compiler knowledge of static types and impose an unnecessary runtime cost. 275 Instead, my design for generic types in \CFACC{} distinguishes between \emph{concrete} generic types that have a fixed memory layout regardless of type parameters and \emph{dynamic} generic types that may vary in memory layout depending on their type parameters. 276 263 277 A \emph{dtype-static} type has polymorphic parameters but is still concrete. 264 Polymorphic pointers are an example of dtype-static types; given some type variable !T!, Tis a polymorphic type, but !T*! has a fixed size and can therefore be represented by a !void*! in code generation.265 In particular, generic types where all parameters are un-!sized! (\ie{} they do not conform to the built-in !sized! trait because the compiler does not know their size and alignment) are always concrete, as there is no possibility for their layout to vary based on type parameters of unknown size and alignment.278 Polymorphic pointers are an example of dtype-static types; given some type variable !T!, !T! is a polymorphic type, but !T*! has a fixed size and can therefore be represented by a !void*! in code generation. 279 In particular, generic types where all parameters are un-!sized! (\ie{} they do not conform to the built-in !sized! trait, which is satisfied by all types the compiler knows the size and alignment of) are always concrete, as there is no possibility for their layout to vary based on type parameters of unknown size and alignment. 266 280 More precisely, a type is concrete if and only if all of its !sized! type parameters are concrete, and a concrete type is dtype-static if any of its type parameters are (possibly recursively) polymorphic. 267 To illustrate, the following code using the !pair! type from above \TODO{test this} has each use of !pair! commented with its class: 268 281 To illustrate, the following code using the !pair! type from above has each use of !pair! commented with its class: 282 283 % TODO constructor bugs here too 269 284 \begin{cfa} 270 285 //dynamic, layout varies based on T 271 forall(otype T) T value ( pair(const char*, T) p ) { return p.second; }286 forall(otype T) T value$\(_1\)$( pair(const char*, T) p ) { return p.second; } 272 287 273 288 // dtype-static, F* and T* are concrete but recursively polymorphic 274 forall(dtype F, otype T) T value ( pair(F*, T*) ) { return *p.second; }289 forall(dtype F, otype T) T value$\(_2\)$( pair(F*, T*) ) { return *p.second; } 275 290 276 291 pair(const char*, int) p = {"magic", 42}; $\C[2.5in]{// concrete}$ 277 292 int i = value(p); 278 pair(void*, int*) q = {0, & p.second}; $\C[2.5in]{// concrete}$293 pair(void*, int*) q = {0, &i}; $\C[2.5in]{// concrete}$ 279 294 i = value(q); 280 295 double d = 1.0; … … 285 300 \subsection{Concrete Generic Types} 286 301 287 The \CFACC{} translator template expands concrete generic types into new structure types, affording maximal inlining.302 The \CFACC{} translator template-expands concrete generic types into new structure types, affording maximal inlining. 288 303 To enable interoperation among equivalent instantiations of a generic type, \CFACC{} saves the set of instantiations currently in scope and reuses the generated structure declarations where appropriate. 289 304 In particular, tuple types are implemented as a single compiler-generated generic type definition per tuple arity, and can be instantiated and reused according to the usual rules for generic types. 290 305 A function declaration that accepts or returns a concrete generic type produces a declaration for the instantiated structure in the same scope, which all callers may reuse. 291 As an example, the concrete instantiation for !pair(const char*, int)! is\footnote{ This omits the field name mangling performed by \CFACC{} for overloading purposes.\label{mangle-foot}}306 As an example, the concrete instantiation for !pair(const char*, int)! is\footnote{Field name mangling for overloading purposes is omitted.\label{mangle-foot}}: 292 307 293 308 \begin{cfa} … … 296 311 297 312 A concrete generic type with dtype-static parameters is also expanded to a structure type, but this type is used for all matching instantiations. 298 In the example above, the !pair(F*, T*)! parameter to !value! is such a type; its expansion is below\footref{mangle-foot}, and it is used as the type of the variables !q! and !r! as well, with casts for member access where appropriate .313 In the example above, the !pair(F*, T*)! parameter to !value! is such a type; its expansion is below\footref{mangle-foot}, and it is used as the type of the variables !q! and !r! as well, with casts for member access where appropriate: 299 314 300 315 \begin{cfa} … … 308 323 The design for generic types presented here adds an \emph{offset array} containing structure-member offsets for dynamic generic !struct! types. 309 324 A dynamic generic !union! needs no such offset array, as all members are at offset 0, but size and alignment are still necessary. 310 Access to members of a dynamic structure is provided at runtime via base displacement addressingthe structure pointer and the member offset (similar to the !offsetof! macro), moving a compile-time offset calculation to runtime.311 312 the offset arrays are statically generated where possible.325 Access to members of a dynamic structure is provided at runtime via base-displacement addressing of the structure pointer and the member offset (similar to the !offsetof! macro), moving a compile-time offset calculation to runtime. 326 327 The offset arrays are statically generated where possible. 313 328 If a dynamic generic type is passed or returned by value from a polymorphic function, \CFACC{} can safely assume that the generic type is complete (\ie{} has a known layout) at any call site, and the offset array is passed from the caller; if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C !offsetof! macro. 314 As an example, the body of the second !value! function above is implemented as329 As an example, the body of !value!$_2$ above is implemented as: 315 330 316 331 \begin{cfa} … … 318 333 \end{cfa} 319 334 320 Here, !_assign_T! is passed in as an implicit parameter from !otype T! and takes two !T*! (!void*! in the generated code ), a destination and a source, and !_retval! is the pointer to a caller-allocated buffer for the return value, the usual \CFA{} method to handle dynamically-sized return types.321 !_offsetof_pair! is the offset array passed into !value!; this array is generated at the call site as335 Here, !_assign_T! is passed in as an implicit parameter from !otype T! and takes two !T*! (!void*! in the generated code\footnote{A GCC extension allows arithmetic on \lstinline{void*}, calculated as if \lstinline{sizeof(void) == 1}.}), a destination and a source, and !_retval! is the pointer to a caller-allocated buffer for the return value, the usual \CFA{} method to handle dynamically-sized return types. 336 !_offsetof_pair! is the offset array passed into !value!; this array is statically generated at the call site as: 322 337 323 338 \begin{cfa} … … 330 345 For instance, modularity is generally provided in C by including an opaque forward declaration of a structure and associated accessor and mutator functions in a header file, with the actual implementations in a separately-compiled \texttt{.c} file. 331 346 \CFA{} supports this pattern for generic types, implying that the caller of a polymorphic function may not know the actual layout or size of a dynamic generic type and only holds it by pointer. 332 \CFACC{} automatically generates \emph{layout functions} for cases where the size, alignment, and offset array of a generic struct cannot be passed into a function from that function s's caller.347 \CFACC{} automatically generates \emph{layout functions} for cases where the size, alignment, and offset array of a generic struct cannot be passed into a function from that function's caller. 333 348 These layout functions take as arguments pointers to size and alignment variables and a caller-allocated array of member offsets, as well as the size and alignment of all !sized! parameters to the generic structure. 334 Un !sized! parametersnot passed because they are forbidden from being used in a context that affects layout by C's usual rules about incomplete types.335 Similarly, the layout function can only safely be called from a context where the generic type definition is visible, because otherwise the caller willnot know how large to allocate the array of member offsets.336 337 The C standard does not specify a memory layout for structs, but the POSIX ABI for x86\cit{} does; this memory layout is common for C implementations, but is a platform-specific issue for porting \CFA{}.349 Un-!sized! parameters are not passed because they are forbidden from being used in a context that affects layout by C's usual rules about incomplete types. 350 Similarly, the layout function can only safely be called from a context where the generic type definition is visible, because otherwise the caller does not know how large to allocate the array of member offsets. 351 352 The C standard does not specify a memory layout for structs, but the System V ABI \cite{SysVABI} does; compatibility with this standard is sufficient for \CFA{}'s currently-supported architectures, though future ports may require different layout-function generation algorithms. 338 353 This algorithm, sketched below in pseudo-\CFA{}, is a straightforward mapping of consecutive fields into the first properly-aligned offset in the !struct! layout; layout functions for !union! types omit the offset array and simply calculate the maximum size and alignment over all union variants. 339 354 Since \CFACC{} generates a distinct layout function for each type, constant-folding and loop unrolling are applied. … … 342 357 forall(dtype T1, dtype T2, ... | sized(T1) | sized(T2) | ...) 343 358 void layout(size_t* size, size_t* align, size_t* offsets) { 344 // initialize values345 359 *size = 0; *align = 1; 346 360 // set up members … … 360 374 \end{cfa} 361 375 362 Results of layout function calls are cached so that they are only computed once per type per function.363 Layout functions also allow generic types to be used in a function definition without reflecting them in the function signature, an important implemen ation-hiding constraint of the design.376 Results of layout-function calls are cached so that they are only computed once per type per function. 377 Layout functions also allow generic types to be used in a function definition without reflecting them in the function signature, an important implementation-hiding constraint of the design. 364 378 For instance, a function that strips duplicate values from an unsorted !list(T)! likely has a reference to the list as its only explicit parameter, but uses some sort of !set(T)! internally to test for duplicate values. 365 379 This function could acquire the layout for !set(T)! by calling its layout function, providing as an argument the layout of !T! implicitly passed into that function. 366 380 367 Whether a type is concrete, dtype-static, or dynamic is decided solely on the basis of the type arguments and !forall! clause type param ters.368 This design allows opaque forward declarations of generic types, \eg{} !forall(otype T) struct Box;! like in C, all uses of $Box(T)$ can be separately compiled, and callers from other translation units know the proper calling conventions to use.369 In an alternate design where the definition of a structure type is included in deciding whether a generic type is dynamic or concrete, some further types may be recognized as dtype-static --- \eg{} !Box! could be defined with a body !{ T* p; }!, and would thus not depend on !T! for its layout.370 However, the existence of an !otype! parameter !T! means that !Box! \emph{could} depend on !T! for its layout if this definition is not visible, and we judged preserving separate compilation (and the associated C compatibility) in the implemented design to be an acceptable trade-off.381 Whether a type is concrete, dtype-static, or dynamic is decided solely on the basis of the type arguments and !forall! clause type parameters. 382 This design allows opaque forward declarations of generic types, \eg{} !forall(otype T) struct Box;! like in C, all uses of !Box(T)! can be separately compiled, and callers from other translation units know the proper calling conventions. 383 In an alternate design, where the definition of a structure type is included in deciding whether a generic type is dynamic or concrete, some further types may be recognized as dtype-static --- \eg{} !Box! could be defined with a body !{ T* p; }!, and would thus not depend on !T! for its layout. 384 However, the existence of an !otype! parameter !T! means that !Box! \emph{could} depend on !T! for its layout if this definition is not visible, and preserving separate compilation (and the associated C compatibility) is a more important design metric. 371 385 372 386 \subsection{Applications of Dtype-static Types} \label{dtype-static-sec} … … 387 401 Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \emph{tag structures}. 388 402 Sometimes, information is only used for type checking and can be omitted at runtime. 389 In the example below, !scalar! is a dtype-static type; hence, all uses have a single structure definition containing !unsigned long! and can share the same implementations of common functions like !?+?!.403 In the example below, !scalar! is a dtype-static type; hence, all uses have a single structure definition containing !unsigned long! and can share the same implementations of common functions, like !?+?!. 390 404 These implementations may even be separately compiled, unlike \CC{} template functions. 391 405 However, the \CFA{} type checker ensures matching types are used by all calls to !?+?!, preventing nonsensical computations like adding a length to a volume. … … 408 422 \section{Performance Experiments} \label{generic-performance-sec} 409 423 410 To validate the practicality of this generic type design I have conducted microbenchmark-based testsagainst a number of comparable code designs in C and \CC{}, first published in \cite{Moss18}.411 Since all these languages are compiled with the same compiler backend and share a subset essentially comprising standard C, maximal-performance benchmarks should show little runtime variance, differing only in length and clarity of source code.424 To validate the practicality of this generic type design, microbenchmark-based tests were conducted against a number of comparable code designs in C and \CC{}, first published in \cite{Moss18}. 425 Since these languages are all C-based and compiled with the same compiler backend, maximal-performance benchmarks should show little runtime variance, differing only in length and clarity of source code. 412 426 A more illustrative comparison measures the costs of idiomatic usage of each language's features. 413 The code below shows the \CFA{} benchmark tests for a generic stack based on a singly-linked list; the test suite is equivalent for the other other languages. 414 The experiment uses element types !int! and !pair(short, char)! and pushes $N = 40M$ elements on a generic stack, copies the stack, clears one of the stacks, and finds the maximum value in the other stack. 415 416 \begin{cfa} 427 The code below shows the \CFA{} benchmark tests for a generic stack based on a singly-linked list; the test suite is equivalent for the other languages, code for which is included in Appendix~\ref{generic-bench-app}. 428 The experiment uses element types !int! and !pair(short, char)! and pushes $N = 4M$ elements on a generic stack, copies the stack, clears one of the stacks, and finds the maximum value in the other stack. 429 430 \begin{cfa} 431 #define N 4000000 417 432 int main() { 418 433 int max = 0, val = 42; … … 435 450 \end{cfa} 436 451 437 The four versions of the benchmark implemented are C with !void*!-based polymorphism, \CFA{} with paramet eric polymorphism, \CC{} with templates, and \CC{} using only class inheritance for polymorphism, denoted \CCV{}.438 The \CCV{} variant illustrates an alternative object-oriented idiom where all objects inherit from a base !object! class, mimicking a Java-like interface; in particular, runtime checks are necessary to safely downcast objects.452 The four versions of the benchmark implemented are C with !void*!-based polymorphism, \CFA{} with parametric polymorphism, \CC{} with templates, and \CC{} using only class inheritance for polymorphism, denoted \CCV{}. 453 The \CCV{} variant illustrates an alternative object-oriented idiom where all objects inherit from a base !object! class, a language design similar to Java 4; in particular, runtime checks are necessary to safely downcast objects. 439 454 The most notable difference among the implementations is the memory layout of generic types: \CFA{} and \CC{} inline the stack and pair elements into corresponding list and pair nodes, while C and \CCV{} lack such capability and, instead, must store generic objects via pointers to separately allocated objects. 440 455 Note that the C benchmark uses unchecked casts as C has no runtime mechanism to perform such checks, whereas \CFA{} and \CC{} provide type safety statically. … … 449 464 \centering 450 465 \input{generic-timing} 451 \caption {Benchmark timing results (smaller is better)} \label{generic-eval-fig}466 \caption[Benchmark timing results]{Benchmark timing results (smaller is better)} \label{generic-eval-fig} 452 467 \end{figure} 453 468 … … 466 481 467 482 The C and \CCV{} variants are generally the slowest and have the largest memory footprint, due to their less-efficient memory layout and the pointer indirection necessary to implement generic types in those languages; this inefficiency is exacerbated by the second level of generic types in the pair benchmarks. 468 By contrast, the \CFA{} and \CC{} variants run in roughly equivalenttime for both the integer and pair because of the equivalent storage layout, with the inlined libraries (\ie{} no separate compilation) and greater maturity of the \CC{} compiler contributing to its lead.483 By contrast, the \CFA{} and \CC{} variants run in noticeably less time for both the integer and pair because of the equivalent storage layout, with the inlined libraries (\ie{} no separate compilation) and greater maturity of the \CC{} compiler contributing to its lead. 469 484 \CCV{} is slower than C largely due to the cost of runtime type checking of downcasts (implemented with !dynamic_cast!); the outlier for \CFA{}, pop !pair!, results from the complexity of the generated-C polymorphic code. 470 485 The gcc compiler is unable to optimize some dead code and condense nested calls; a compiler designed for \CFA{} could more easily perform these optimizations. 471 Finally, the binary size for \CFA{} is larger because of static linking with \CFA{} libraries.486 Finally, the binary size for \CFA{} is larger because of static linking with the \CFA{} prelude library, which includes function definitions for all the built-in operators. 472 487 473 488 \CFA{} is also competitive in terms of source code size, measured as a proxy for programmer effort. … … 475 490 Use of these standard library types has minimal impact on the performance benchmarks, but shrinks the \CFA{} and \CC{} code to 39 and 42 lines, respectively. 476 491 The difference between the \CFA{} and \CC{} line counts is primarily declaration duplication to implement separate compilation; a header-only \CFA{} library is similar in length to the \CC{} version. 477 On the other hand, due to the language shortcomings mentioned at the beginning of the chapter, C does not have a generic collections library in its standard distribution, resulting in frequent re implementation of such collection types by C programmers.492 On the other hand, due to the language shortcomings mentioned at the beginning of the chapter, C does not have a generic collections library in its standard distribution, resulting in frequent re-implementation of such collection types by C programmers. 478 493 \CCV{} does not use the \CC{} standard template library by construction, and, in fact, includes the definition of !object! and wrapper classes for !char!, !short!, and !int! in its line count, which inflates this count somewhat, as an actual object-oriented language would include these in the standard library. 479 494 I justify the given line count by noting that many object-oriented languages do not allow implementing new interfaces on library types without subclassing or wrapper types, which may be similarly verbose. … … 481 496 Line count is a fairly rough measure of code complexity; another important factor is how much type information the programmer must specify manually, especially where that information is not type-checked. 482 497 Such unchecked type information produces a heavier documentation burden and increased potential for runtime bugs and is much less common in \CFA{} than C, with its manually specified function pointer arguments and format codes, or \CCV{}, with its extensive use of un-type-checked downcasts, \eg{} !object! to !integer! when popping a stack. 483 To quantify this manual typing, the ``redundant type annotations'' line in Table~\ref{generic-eval-table} counts the number of lines on which the known type of a variable is re specified, either as a format specifier, explicit downcast, type-specific function, or by name in a !sizeof!, !struct! literal, or !new! expression.498 To quantify this manual typing, the ``redundant type annotations'' line in Table~\ref{generic-eval-table} counts the number of lines on which the known type of a variable is re-specified, either as a format specifier, explicit downcast, type-specific function, or by name in a !sizeof!, !struct! literal, or !new! expression. 484 499 The \CC{} benchmark uses two redundant type annotations to create new stack nodes, whereas the C and \CCV{} benchmarks have several such annotations spread throughout their code. 485 500 The \CFA{} benchmark is able to eliminate \emph{all} redundant type annotations through use of the return-type polymorphic !alloc! function in the \CFA{} standard library. … … 487 502 \section{Future Work} 488 503 489 The generic types design presented here isalready sufficiently expressive to implement a variety of useful library types.504 The generic types presented here are already sufficiently expressive to implement a variety of useful library types. 490 505 However, some other features based on this design could further improve \CFA{}. 491 506 492 507 The most pressing addition is the ability to have non-type generic parameters. 493 C already supports fixed-length array types, \eg{} !int[10]!; these types are essentially generic types with unsigned integer parameters, and allowing \CFA{} users the capability to build similar types is a requested feature. 494 More exotically, the ability to have these non-type parameters depend on dynamic runtime values rather than static compile-time constants opens up interesting opportunities for type-checking problematic code patterns. 495 For example, if a collection iterator was parameterized over the pointer to the collection it was drawn from, then a sufficiently powerful static analysis pass could ensure that that iterator was only used for that collection, eliminating one source of hard-to-find bugs. 496 497 The implementation mechanisms behind this generic types design can also be used to add new features to \CFA{}. 498 One such potential feature would be to add \emph{field assertions} to the existing function and variable assertions on polymorphic type variables. 508 C already supports fixed-length array types, \eg{} !int[10]!; these types are essentially generic types with unsigned integer parameters (\ie{} array dimension), and allowing \CFA{} users the capability to build similar types is a requested feature. 509 % More exotically, the ability to have these non-type parameters depend on dynamic runtime values rather than static compile-time constants opens up interesting opportunities for type-checking problematic code patterns. 510 % For example, if a collection iterator was parameterized over the pointer to the collection it was drawn from, then a sufficiently powerful static analysis pass could ensure that that iterator was only used for that collection, eliminating one source of hard-to-find bugs. 511 512 The implementation mechanisms behind generic types can also be used to add new features to \CFA{}. 513 One such potential feature is \emph{field assertions}, an addition to the existing function and variable assertions on polymorphic type variables. 514 These assertions could be specified using this proposed syntax: 515 516 \begin{cfa} 517 trait hasXY(dtype T) { 518 int T.x; $\C{// T has a field x of type int}$ 519 int T.y; $\C{// T has a field y of type int}$ 520 }; 521 \end{cfa} 522 499 523 Implementation of these field assertions would be based on the same code that supports member access by dynamic offset calculation for dynamic generic types. 500 524 Simulating field access can already be done more flexibly in \CFA{} by declaring a trait containing an accessor function to be called from polymorphic code, but these accessor functions impose some overhead both to write and call, and directly providing field access via an implicit offset parameter would be both more concise and more efficient. 501 Of course, there are language design trade-offs to such an approach, notably that providing the two similar features of field and function assertions would impose a burden of choice on programmers writing traits, with field assertions more efficient, but function assertions more general; given this open design question we have deferred a decision on field assertions until we have more experience using \CFA{}. 502 If field assertions are included in the language, a natural extension would be to provide a structural inheritance mechanism for every !struct! type that simply turns the list of !struct! fields into a list of field assertions, allowing monomorphic functions over that type to be generalized to polymorphic functions over other similar types with added or reordered fields. 503 \CFA{} could also support a packed or otherwise size-optimized representation for generic types based on a similar mechanism --- the layout function would need to be re-written, but nothing in the use of the offset arrays implies that the field offsets need be monotonically increasing. 525 Of course, there are language design trade-offs to such an approach, notably that providing the two similar features of field and function assertions would impose a burden of choice on programmers writing traits, with field assertions more efficient, but function assertions more general; given this open design question a decision on field assertions is deferred until \CFA{} is more mature. 526 527 If field assertions are included in the language, a natural extension would be to provide a structural inheritance mechanism for every !struct! type that simply turns the list of !struct! fields into a list of field assertions, allowing monomorphic functions over that type to be generalized to polymorphic functions over other similar types with added or reordered fields, for example: 528 529 \begin{cfa} 530 struct point { int x, y; }; $\C{// traitof(point) is equivalent to hasXY above}$ 531 struct coloured_point { int x, y; enum { RED, BLACK } colour }; 532 533 // works for both point and coloured_point 534 forall(dtype T | traitof(point)(T) ) 535 double hypot( T& p ) { return sqrt( p.x*p.x + p.y*p.y ); } 536 \end{cfa} 537 538 \CFA{} could also support a packed or otherwise size-optimized representation for generic types based on a similar mechanism --- nothing in the use of the offset arrays implies that the field offsets need to be monotonically increasing. 504 539 505 540 With respect to the broader \CFA{} polymorphism design, the experimental results in Section~\ref{generic-performance-sec} demonstrate that though the runtime impact of \CFA{}'s dynamic virtual dispatch is low, it is not as low as the static dispatch of \CC{} template inlining. 506 However, rather than subject all \CFA{} users to the compile-time costs of ubiquitous template expansion, we are considering more targeted mechanisms for performance-sensitive code. 507 Two promising approaches are are an !inline! annotation at polymorphic function call sites to create a template specialization of the function (provided the code is visible) or placing a different !inline! annotation on polymorphic function definitions to instantiate a specialized version of the function for some set of types. 508 These approaches are not mutually exclusive and allow performance optimizations to be applied only when necessary, without suffering global code bloat. 509 In general, the \CFA{} team believes that separate compilation works well with loaded hardware caches by producing smaller code, which may offset the benefit of larger inlined code. 541 However, rather than subject all \CFA{} users to the compile-time costs of ubiquitous template expansion, it is better to target performance-sensitive code more precisely. 542 Two promising approaches are an !inline! annotation at polymorphic function call sites to create a template specialization of the function (provided the code is visible) or placing a different !inline! annotation on polymorphic function definitions to instantiate a specialized version of the function for some set of types. 543 These approaches are complementary and allow performance optimizations to be applied only when necessary, without suffering global code bloat. -
doc/theses/aaron_moss_PhD/phd/introduction.tex
r6a9d4b4 r933f32f 1 1 \chapter{Introduction} 2 2 3 The C programming language has had a wide-ranging impact on the design of software and programming languages.4 In the 30 years since its first standardization, it has consistently been one of the most popular programming languages, with millions of lines of C code still in active use, and tens of thousands of trained programmers producing it. The TIOBE index\cite{TIOBE} tracks popularity of programming languages over time, and C has never dropped below second place:3 The C programming language~\cite{C11} has had a wide-ranging impact on the design of software and programming languages. 4 In the 30 years since its first standardization, it has consistently been one of the most popular programming languages, with billions of lines of C code still in active use, and tens of thousands of trained programmers producing it. The TIOBE index~\cite{TIOBE} tracks popularity of programming languages over time, and C has never dropped below second place: 5 5 6 6 \begin{table}[h] … … 18 18 \end{table} 19 19 20 The impact of C on programming language design is also obvious from Table~\ref{tiobe-table}; with the exception of Python, all of the top five languages use C-like syntax and proceduralcontrol structures.21 \CC{} is even a largely backwards-compatible extension of C, with development dating back nearly as far as C itself.22 Though its lasting popularity and wide impact on programming language design point to the continued relevance of C, the y also highlight the widespread desire of programmers for languages with more expressive power and programmer-friendly features; accommodating both low-impact maintenance of legacy C code and low-effortdevelopment of the software of the future is a difficult task for a single programming language.20 The impact of C on programming language design is also obvious from Table~\ref{tiobe-table}; with the exception of Python, all of the top five languages use C-like syntax and control structures. 21 \CC{}~\cite{C++} is even a largely backwards-compatible extension of C. 22 Though its lasting popularity and wide impact on programming language design point to the continued relevance of C, there is also widespread desire of programmers for languages with more expressive power and programmer-friendly features; accommodating both maintenance of legacy C code and development of the software of the future is a difficult task for a single programming language. 23 23 24 \CFA{}\footnote{Pronounced ``C-for-all'', and written \CFA{} or \CFL{}.} is an evolutionary modernization of the C programming language whichaims to fulfill both these ends well.24 \CFA{}\footnote{Pronounced ``C-for-all'', and written \CFA{} or \CFL{}.} is an evolutionary modernization of the C programming language that aims to fulfill both these ends well. 25 25 \CFA{} both fixes existing design problems and adds multiple new features to C, including name overloading, user-defined operators, parametric-polymorphic routines, and type constructors and destructors, among others. 26 26 The new features make \CFA{} more powerful and expressive than C, while maintaining strong backward-compatibility with both C code and the procedural paradigm expected by C programmers. 27 However, these new features do impose a compile-time cost, particularly in the expression resolver, which must evaluate the typing rules of a significantly more complex type-system. 27 Unlike other popular C extensions like \CC{} and Objective-C, \CFA{} adds modern features to C without imposing an object-oriented paradigm to use them. 28 However, these new features do impose a compile-time cost, particularly in the expression resolver, which must evaluate the typing rules of a significantly more complex type system. 28 29 29 30 This thesis is focused on making \CFA{} a more powerful and expressive language, both by adding new features to the \CFA{} type system and ensuring that both added and existing features can be efficiently implemented in \CFACC{}, the \CFA{} reference compiler. 30 Particular contributions of this work include design and implementation of 31 parametric-polymorphic (``generic'') types in a manner compatible with the existing polymorphism design of \CFA{} (Chapter~\ref{generic-chap}), a type environment data structure based on a novel variant of the union-find algorithm (Chapter~\ref{env-chap}), and a new expression resolution algorithm designed to quickly locate the optimal declarations for a \CFA{} expression (Chapter~\ref{resolution-chap}). 32 This expression resolution algorithm was designed with the aid of a purpose-built prototype system which encapsulates the essential aspects of the \CFA{} type system without incurring the technical debt of the existing system or the friction-inducing necessity of maintaining a working compiler; the goal of this prototype system was to discover effective heuristics to avoid performing unnecessary work in the process of locating the optimal \CFA{} expression resolution. 31 Particular contributions of this work include: 32 \begin{itemize} 33 \item design and implementation of parametric-polymorphic (``generic'') types in a manner compatible with the existing polymorphism design of \CFA{} (Chapter~\ref{generic-chap}), 34 \item a new expression resolution algorithm designed to quickly locate the optimal declarations for a \CFA{} expression (Chapter~\ref{resolution-chap}), 35 \item a type environment data structure based on a novel variant of the union-find algorithm (Chapter~\ref{env-chap}), 36 \item and as a technical contribution, a prototype system for compiler algorithm development which encapsulates the essential aspects of the \CFA{} type system without incurring the technical debt of the existing system or the friction-inducing necessity of maintaining a working compiler (Chapter~\ref{expr-chap}). 37 \end{itemize} 33 38 34 Though the direction and validation of this work was fairly narrowly focused on the \CFA{} programming language, the tools used and results obtained should be of interest to a wider compiler and programming language design community. 35 In particular, with the addition of \emph{concepts} in \CCtwenty{}, conforming \CC{} compilers must support a model of type assertions very similar to that in \CFA{}, and the algorithmic techniques used in the expression resolution algorithm presented here may prove useful. 36 Type environments are also widely modelled in compiler implementations, particularly of functional languages, though also increasingly commonly in other languages (such as Rust) which perform type inference; the type environment presented here may be useful to those language implementers. 39 The prototype system, which implements the algorithmic contributions of this thesis, is the first performant type-checker implementation for a \CFA{}-style type system. 40 As the existence of an efficient compiler is necessary for the practical viability of a programming language, the contributions of this thesis comprise a validation of the \CFA{} language design that was previously lacking. 41 42 Though the direction and experimental validation of this work is fairly narrowly focused on the \CFA{} programming language, the tools used and results obtained should be of interest to a wider compiler and programming language design community. 43 In particular, with the addition of \emph{concepts} in \CCtwenty{}~\cite{C++Concepts}, conforming \CC{} compilers must support a model of type assertions very similar to that in \CFA{}, and the algorithmic techniques used here may prove useful. 44 Much of the difficulty of type-checking \CFA{} stems from the language design choice to allow overload selection from the context of a function call based on function return type in addition to the type of the arguments to the call; this feature allows the programmer to specify fewer redundant type annotations on functions that are polymorphic in their return type. 45 As an example in \CC{}: 46 \begin{C++} 47 template<typename T> T* zero() { return new T( 0 ); } 48 49 int* z = zero<int>(); $\C{// must specify int twice}$ 50 \end{C++} 51 52 \CFA{} allows !int* z = zero()!, which elides the second !int!. 53 While the !auto! keyword in \CCeleven{} supports similar inference in a limited set of contexts (\eg{} !auto z = zero<int>()!), the demonstration of the richer inference in \CFA{} raises possibilities for similar features in future versions of \CC{}. 54 By contrast to \CC{}, Java~8~\cite{Java8} and Scala~\cite{Scala} use comparably powerful forms of type inference to \CFA{}, so the algorithmic techniques in this thesis may be effective for those languages' compiler implementors. 55 Type environments are also widely modelled in compiler implementations, particularly for functional languages, though also increasingly commonly for other languages (such as Rust~\cite{Rust}) that perform type inference; the type environment presented here may be useful to those language implementors. 56 57 One area of inquiry that is outside the scope of this thesis is formalization of the \CFA{} type system. 58 Ditchfield~\cite{Ditchfield92} defined the $F_\omega^\ni$ polymorphic lambda calculus, which is the theoretical basis for the \CFA{} type system. 59 Ditchfield did not, however, prove any soundness or completeness properties for $F_\omega^\ni$; such proofs remain future work. 60 A number of formalisms other than $F_\omega^\ni$ could potentially be adapted to model \CFA{}. 61 One promising candidate is \emph{local type inference} \cite{Pierce00,Odersky01}, which describes similar contextual propagation of type information; another is the polymorphic conformity-based model of the Emerald~\cite{Black90} programming language, which defines a subtyping relation on types that is conceptually similar to \CFA{} traits. 62 These modelling approaches could potentially be used to extend an existing formal semantics for C such as Cholera \cite{Norrish98}, CompCert \cite{Leroy09}, or Formalin \cite{Krebbers14}. -
doc/theses/aaron_moss_PhD/phd/macros.tex
r6a9d4b4 r933f32f 15 15 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\Large$^\sharp$}} % C# symbolic name 16 16 17 \newcommand{\ie}{\textit{i.e.}} 18 \newcommand{\eg}{\textit{e.g.}} 19 \newcommand{\etc}{\textit{etc.}} 20 \newcommand{\etal}{\textit{et~al.}} 17 \newcommand{\ie}{\textit{i.e.}\@} 18 \newcommand{\eg}{\textit{e.g.}\@} 19 \newcommand{\etc}{\textit{etc.}\@} 20 \newcommand{\etal}{\textit{et~al.}\@} 21 \newcommand{\vs}{\textit{vs.}\@} 21 22 22 23 \newcommand{\myset}[1]{\left\{#1\right\}} -
doc/theses/aaron_moss_PhD/phd/resolution-heuristics.tex
r6a9d4b4 r933f32f 1 \chapter{Resolution Heuristics}1 \chapter{Resolution Algorithms} 2 2 \label{resolution-chap} 3 3 4 The main task of the \CFACC{} type-checker is \emph{expression resolution}, determining which declarations the identifiers in each expression correspond to. 5 Resolution is a straightforward task in C, as each declaration has a unique identifier, but in \CFA{} the name overloading features discussed in Section~\ref{overloading-sec} generate multiple candidate declarations for each identifier. 6 I refer to a given matching between identifiers and declarations in an expression as an \emph{interpretation}; an interpretation also includes information about polymorphic type bindings and implicit casts to support the \CFA{} features discussed in Sections~\ref{poly-func-sec} and~\ref{implicit-conv-sec}, each of which increase the proportion of feasible candidate interpretations. 7 To choose between feasible interpretations, \CFA{} defines a \emph{conversion cost} to rank interpretations; the expression resolution problem is thus to find the unique minimal-cost interpretation for an expression, reporting an error if no such interpretation exists. 8 9 \section{Conversion Cost} 10 11 12 13 % Discuss changes to cost model, as promised in Ch. 2 14 15 % Mention relevance of work to C++20 concepts 4 The main task of the \CFACC{} type-checker is \emph{expression resolution}: determining which declarations the identifiers in each expression correspond to. 5 Resolution is a straightforward task in C, as no simultaneously-visible declarations share identifiers, but in \CFA{}, the name overloading features discussed in Section~\ref{overloading-sec} generate multiple candidate declarations for each identifier. 6 A given matching between identifiers and declarations in an expression is an \emph{interpretation}; an interpretation also includes information about polymorphic type bindings and implicit casts to support the \CFA{} features discussed in Sections~\ref{poly-func-sec} and~\ref{implicit-conv-sec}, each of which increase the number of valid candidate interpretations. 7 To choose among valid interpretations, a \emph{conversion cost} is used to rank interpretations. 8 This conversion cost is summed over all subexpression interpretations in the interpretation of a top-level expression. 9 Hence, the expression resolution problem is to find the unique minimal-cost interpretation for an expression, reporting an error if no such unique interpretation exists. 10 11 \section{Expression Resolution} 12 13 The expression resolution pass in \CFACC{} must traverse an input expression, match identifiers to available declarations, rank candidate interpretations according to their conversion cost, and check type assertion satisfaction for these candidates. 14 Once the set of valid interpretations for the top-level expression is found, the expression resolver selects the unique minimal-cost candidate or reports an error. 15 16 The expression resolution problem in \CFA{} is more difficult than the analogous problems in C or \CC{}. 17 As mentioned above, the lack of name overloading in C (except for built-in operators) makes its resolution problem substantially easier. 18 A comparison of the richer type systems in \CFA{} and \CC{} highlights some of the challenges in \CFA{} expression resolution. 19 The key distinction between \CFA{} and \CC{} resolution is that \CC{} uses a greedy algorithm for selection of candidate functions given their argument interpretations, whereas \CFA{} allows contextual information from superexpressions to influence the choice among candidate functions. 20 One key use of this contextual information is for type inference of polymorphic return types; \CC{} requires explicit specification of template parameters that only occur in a function's return type, while \CFA{} allows the instantiation of these type parameters to be inferred from context (and in fact does not allow explicit specification of type parameters to a function), as in the following example: 21 22 \begin{cfa} 23 forall(dtype T) T& deref(T*); $\C{// dereferences pointer}$ 24 forall(otype T) T* def(); $\C{// new heap-allocated default-initialized value}$ 25 26 int& i = deref( def() ); 27 \end{cfa} 28 29 In this example, the \CFA{} compiler infers the type arguments of !deref! and !def! from the !int&! type of !i!; \CC{}, by contrast, requires a type parameter on !def!\footnote{The type parameter of \lstinline{deref} can be inferred from its argument.}, \ie{} !deref( def<int>() )!. 30 Similarly, while both \CFA{} and \CC{} rank candidate functions based on a cost metric for implicit conversions, \CFA{} allows a suboptimal subexpression interpretation to be selected if it allows a lower-cost overall interpretation, while \CC{} requires that each subexpression interpretation have minimal cost. 31 Because of this use of contextual information, the \CFA{} expression resolver must consider multiple interpretations of each function argument, while the \CC{} compiler has only a single interpretation for each argument\footnote{With the exception of address-of operations on functions.}. 32 Additionally, until the introduction of concepts in \CCtwenty{} \cite{C++Concepts}, \CC{} expression resolution has no analogue to \CFA{} assertion satisfaction checking, a further complication for a \CFA{} compiler. 33 The precise definition of \CFA{} expression resolution in this section further expands on the challenges of this problem. 34 35 \subsection{Type Unification} 36 37 The polymorphism features of \CFA{} require binding of concrete types to polymorphic type variables. 38 Briefly, \CFACC{} keeps a mapping from type variables to the concrete types they are bound to as an auxiliary data structure during expression resolution; Chapter~\ref{env-chap} describes this \emph{environment} data structure in more detail. 39 A \emph{unification} algorithm is used to simultaneously check two types for equivalence with respect to the substitutions in an environment and update that environment. 40 Essentially, unification recursively traverses the structure of both types, checking them for equivalence, and when it encounters a type variable, it replaces it with the concrete type it is bound to; if the type variable has not yet been bound, the unification algorithm assigns the equivalent type as the bound type of the variable, after performing various consistency checks. 41 Ditchfield~\cite{Ditchfield92} and Bilson~\cite{Bilson03} describe the semantics of \CFA{} unification in more detail. 42 43 \subsection{Conversion Cost} \label{conv-cost-sec} 44 45 \CFA{}, like C, allows inexact matches between the type of function parameters and function call arguments. 46 Both languages insert \emph{implicit conversions} in these situations to produce an exact type match, and \CFA{} also uses the relative \emph{cost} of different conversions to select among overloaded function candidates. 47 C does not have an explicit cost model for implicit conversions, but the ``usual arithmetic conversions'' \cite[\S{}6.3.1.8]{C11} used to decide which arithmetic operators to apply define one implicitly. 48 The only context in which C has name overloading is the arithmetic operators, and the usual arithmetic conversions define a \emph{common type} for mixed-type arguments to binary arithmetic operators. 49 Since for backward-compatibility purposes the conversion costs of \CFA{} must produce an equivalent result to these common type rules, it is appropriate to summarize \cite[\S{}6.3.1.8]{C11} here: 50 51 \begin{itemize} 52 \item If either operand is a floating-point type, the common type is the size of the largest floating-point type. If either operand is !_Complex!, the common type is also \linebreak !_Complex!. 53 \item If both operands are of integral type, the common type has the same size\footnote{Technically, the C standard defines a notion of \emph{rank} in \cite[\S{}6.3.1.1]{C11}, a distinct value for each \lstinline{signed} and \lstinline{unsigned} pair; integral types of the same size thus may have distinct ranks. For instance, though \lstinline{int} and \lstinline{long} may have the same size, \lstinline{long} always has greater rank. The standard-defined types are declared to have greater rank than any types of the same size added as compiler extensions.} as the larger type. 54 \item If the operands have opposite signedness, the common type is !signed! if the !signed! operand is strictly larger, or !unsigned! otherwise. If the operands have the same signedness, the common type shares it. 55 \end{itemize} 56 57 Beginning with the work of Bilson~\cite{Bilson03}, \CFA{} defines a \emph{conversion cost} for each function call in a way that generalizes C's conversion rules. 58 Loosely defined, the conversion cost counts the implicit conversions utilized by an interpretation. 59 With more specificity, the cost is a lexicographically-ordered tuple, where each element corresponds to a particular kind of conversion. 60 In Bilson's design, conversion cost is a 3-tuple, $(unsafe, poly, safe)$, where $unsafe$ is the count of unsafe (narrowing) conversions, $poly$ is the count of polymorphic type bindings, and $safe$ is the sum of the degree of safe (widening) conversions. 61 Degree of safe conversion is calculated as path weight in a directed graph of safe conversions between types; Bilson's version of this graph is in Figure~\ref{bilson-conv-fig}. 62 The safe conversion graph is designed such that the common type $c$ of two types $u$ and $v$ is compatible with the C standard definitions from \cite[\S{}6.3.1.8]{C11} and can be calculated as the unique type minimizing the sum of the path weights of $\overrightarrow{uc}$ and $\overrightarrow{vc}$. 63 The following example lists the cost in the Bilson model of calling each of the following functions with two !int! parameters, where the interpretation with the minimum total cost will be selected: 64 65 \begin{cfa} 66 void f$\(_1\)$(char, long); $\C{// (1,0,1)}$ 67 void f$\(_2\)$(short, long); $\C{// (1,0,1)}$ 68 forall(otype T) void f$\(_3\)$(T, long); $\C{// (0,1,1)}$ 69 void f$\(_4\)$(long, long); $\C{// (0,0,2)}$ 70 void f$\(_5\)$(int, unsigned long); $\C{// (0,0,2)}$ 71 void f$\(_6\)$(int, long); $\C{// (0,0,1)}$ 72 \end{cfa} 73 74 Note that safe and unsafe conversions are handled differently; \CFA{} counts distance of safe conversions (\eg{} !int! to !long! is cheaper than !int! to !unsigned long!), while only counting the number of unsafe conversions (\eg{} !int! to !char! and !int! to !short! both have unsafe cost 1, as in !f!$_1$ and !f!$_2$ above). 75 These costs are summed over the parameters in a call; in the example above, the cost of the two !int! to !long! conversions for !f!$_4$ sum equal to the one !int! to !unsigned long! conversion for !f!$_5$. 76 77 \begin{figure} 78 \centering 79 \begin{subfigure}[h]{3in} 80 \includegraphics{figures/bilson-conv-graph} 81 \caption{Bilson} \label{bilson-conv-fig} 82 \end{subfigure}~\begin{subfigure}[h]{3in} 83 \includegraphics{figures/extended-conv-graph} 84 \caption{Extended} \label{extended-conv-fig} 85 \end{subfigure} 86 % \includegraphics{figures/safe-conv-graph} 87 \caption[Safe conversion graphs.]{Safe conversion graphs. In both graphs, plain arcs have cost $safe = 1, sign = 0$ while dashed sign-conversion arcs have cost $safe = 1, sign = 1$. As per \cite[\S{}6.3.1.8]{C11}, types promote to types of the same signedness with greater rank, from \lstinline{signed} to \lstinline{unsigned} with the same rank, and from \lstinline{unsigned} to \lstinline{signed} with greater size. The arc from \lstinline{unsigned long} to \lstinline{long long} (highlighted in red in \ref{bilson-conv-fig}) is deliberately omitted in \ref{extended-conv-fig}, as on the presented system \lstinline{sizeof(long) == sizeof(long long)}.} 88 \label{safe-conv-fig} 89 \end{figure} 90 91 As part of adding reference types to \CFA{} (see Section~\ref{type-features-sec}), Schluntz added a new $reference$ element to the cost tuple, which counts the number of implicit reference-to-rvalue conversions performed so that candidate interpretations can be distinguished by how closely they match the nesting of reference types; since references are meant to act almost indistinguishably from lvalues, this $reference$ element is the least significant in the lexicographic comparison of cost tuples. 92 93 I also refined the \CFA{} cost model as part of this thesis work. 94 Bilson's \CFA{} cost model includes the cost of polymorphic type bindings from a function's type assertions in the $poly$ element of the cost tuple; this has the effect of making more-constrained functions more expensive than less-constrained functions, as in the following example, based on differing iterator types: 95 96 \begin{cfa} 97 forall(dtype T | { T& ++?(T&); }) T& advance$\(_1\)$(T& i, int n); 98 forall(dtype T | { T& ++?(T&); T& ?+=?(T&, int)}) T& advance$\(_2\)$(T& i, int n); 99 \end{cfa} 100 101 In resolving a call to !advance!, the binding to the !T&! parameter in the assertions is added to the $poly$ cost in Bilson's model. 102 However, type assertions actually make a function \emph{less} polymorphic, and as such functions with more type assertions should be preferred in type resolution. 103 In the example above, if the meaning of !advance! is ``increment !i! !n! times'', !advance!$_1$ requires an !n!-iteration loop, while !advance!$_2$ can be implemented more efficiently with the !?+=?! operator; as such, !advance!$_2$ should be chosen over !advance!$_1$ whenever its added constraint can be satisfied. 104 Accordingly, a $specialization$ element is now included in the \CFA{} cost tuple, the values of which are always negative. 105 Each type assertion subtracts 1 from $specialization$, so that more-constrained functions cost less, and thus are chosen over less-constrained functions, all else being equal. 106 A more sophisticated design would define a partial order over sets of type assertions by set inclusion (\ie{} one function would only cost less than another if it had a strict superset of assertions, rather than just more total assertions), but I did not judge the added complexity of computing and testing this order to be worth the gain in specificity. 107 108 I also incorporated an unimplemented aspect of Ditchfield's earlier cost model. 109 In the example below, adapted from \cite[p.89]{Ditchfield92}, Bilson's cost model only distinguished between the first two cases by accounting extra cost for the extra set of !otype! parameters, which, as discussed above, is not a desirable solution: 110 111 \begin{cfa} 112 forall(otype T, otype U) void f$\(_1\)$(T, U); $\C[3.125in]{// polymorphic}$ 113 forall(otype T) void f$\(_2\)$(T, T); $\C[3.125in]{// less polymorphic}$ 114 forall(otype T) void f$\(_3\)$(T, int); $\C[3.125in]{// even less polymorphic}$ 115 forall(otype T) void f$\(_4\)$(T*, int); $\C[3.125in]{// least polymorphic}$ 116 \end{cfa} 117 118 The new cost model accounts for the fact that functions with more polymorphic variables are less constrained by introducing a $var$ cost element that counts the number of type variables on a candidate function. 119 In the example above, !f!$_1$ has $var = 2$, while the others have $var = 1$. 120 121 The new cost model also accounts for a nuance unhandled by Ditchfield or Bilson, in that it makes the more specific !f!$_4$ cheaper than the more generic !f!$_3$; !f!$_4$ is presumably somewhat optimized for handling pointers, but the prior \CFA{} cost model could not account for the more specific binding, as it simply counted the number of polymorphic unifications. 122 In the modified model, each level of constraint on a polymorphic type in the parameter list results in a decrement of the $specialization$ cost element, which is shared with the count of assertions due to their common nature as constraints on polymorphic type bindings. 123 Thus, all else equal, if both a binding to !T! and a binding to !T*! are available, the model chooses the more specific !T*! binding with $specialization = -1$. 124 This process is recursive, such that !T**! has $specialization = -2$. 125 This calculation works similarly for generic types, \eg{} !box(T)! also has specialization cost $-1$. 126 For multi-argument generic types, the least-specialized polymorphic parameter sets the specialization cost, \eg{} the specialization cost of !pair(T, S*)! is $-1$ (from !T!) rather than $-2$ (from !S!). 127 Specialization cost is not counted on the return type list; since $specialization$ is a property of the function declaration, a lower specialization cost prioritizes one declaration over another. 128 User programmers can choose between functions with varying parameter lists by adjusting the arguments, but the same is not true in general of varying return types\footnote{In particular, as described in Section~\ref{expr-cost-sec}, cast expressions take the cheapest valid and convertible interpretation of the argument expression, and expressions are resolved as a cast to \lstinline{void}. As a result of this, including return types in the $specialization$ cost means that a function with return type \lstinline{T*} for some polymorphic type \lstinline{T} would \emph{always} be chosen over a function with the same parameter types returning \lstinline{void}, even for \lstinline{void} contexts, an unacceptably counter-intuitive result.}, so the return types are omitted from the $specialization$ element. 129 Since both $vars$ and $specialization$ are properties of the declaration rather than any particular interpretation, they are prioritized less than the interpretation-specific conversion costs from Bilson's original 3-tuple. 130 131 A final refinement I have made to the \CFA{} cost model is with regard to choosing among arithmetic conversions. 132 The C standard \cite[\S{}6.3.1.8]{C11} states that the common type of !int! and !unsigned int! is !unsigned int! and that the common type of !int! and !long! is !long!, but does not provide guidance for making a choice among conversions. 133 Bilson's \CFACC{} uses conversion costs based off Figure~\ref{bilson-conv-fig}. 134 However, Bilson's design results in inconsistent and somewhat surprising costs, with conversion to the next-larger same-sign type generally (but not always) double the cost of conversion to the !unsigned! type of the same size. 135 In the redesign, for consistency with the approach of the usual arithmetic conversions, which select a common type primarily based on size, but secondarily on sign, arcs in the new graph are annotated with whether they represent a sign change, and such sign changes are summed in a new $sign$ cost element that lexicographically succeeds $safe$. 136 This means that sign conversions are approximately the same cost as widening conversions, but slightly more expensive (as opposed to less expensive in Bilson's graph), so maintaining the same signedness is consistently favoured. 137 This refined conversion graph is shown in Figure~\ref{extended-conv-fig}. 138 139 With these modifications, the current \CFA{} cost tuple is as follows: 140 141 \begin{equation*} 142 (unsafe, poly, safe, sign, vars, specialization, reference) 143 \end{equation*} 144 145 \subsection{Expression Cost} \label{expr-cost-sec} 146 147 The mapping from \CFA{} expressions to cost tuples is described by Bilson in \cite{Bilson03}, and remains effectively unchanged with the exception of the refinements to the cost tuple described above. 148 Nonetheless, some salient details are repeated here for the sake of completeness. 149 150 On a theoretical level, the resolver treats most expressions as if they were function calls. 151 Operators in \CFA{} (both those existing in C and added features like constructors) are all modelled as function calls. 152 In terms of the core argument-parameter matching algorithm, overloaded variables are handled the same as zero-argument function calls, aside from a different pool of candidate declarations and setup for different code generation. 153 Similarly, an aggregate member expression !a.m! can be modelled as a unary function !m! that takes one argument of the aggregate type. 154 Literals do not require sophisticated resolution, as in C the syntactic form of each implies their result types: !42! is !int!, !"hello"! is !char*!, \etc{}\footnote{Struct literals (\eg{} \lstinline|(S)\{ 1, 2, 3 \}| for some struct \lstinline{S}) are a somewhat special case, as they are known to be of type \lstinline{S}, but require resolution of the implied constructor call described in Section~\ref{ctor-sec}.}. 155 156 Since most expressions can be treated as function calls, nested function calls are the primary component of complexity in expression resolution. 157 Each function call has an \emph{identifier} that must match the name of the corresponding declaration, and a possibly-empty list of \emph{arguments}. 158 These arguments may be function call expressions themselves, producing a tree of function-call expressions to resolve, where the leaf expressions are generally nullary functions, variable expressions, or literals. 159 A single instance of expression resolution consists of matching declarations to all the identifiers in the expression tree of a top-level expression, along with inserting any conversions and satisfying all assertions necessary for that matching. 160 The cost of a function-call expression is the sum of the conversion costs of each argument type to the corresponding parameter and the total cost of each subexpression, recursively calculated. 161 \CFA{} expression resolution must produce either the unique lowest-cost interpretation of the top-level expression, or an appropriate error message if none exists. 162 The cost model of \CFA{} precludes a greedy bottom-up resolution pass, as constraints and costs introduced by calls higher in the expression tree can change the interpretation of those lower in the tree, as in the following example: 163 164 \begin{cfa} 165 void f(int); 166 double g$\(_1\)$(int); 167 int g$\(_2\)$(long); 168 169 f( g(42) ); 170 \end{cfa} 171 172 Considered independently, !g!$_1$!(42)! is the cheapest interpretation of !g(42)!, with cost $(0,0,0,0,0,0,0)$ since the argument type is an exact match. 173 However, in context, an unsafe conversion is required to downcast the return type of !g!$_1$ to an !int! suitable for !f!, for a total cost of $(1,0,0,0,0,0,0)$ for !f( g!$_1$!(42) )!. 174 If !g!$_2$ is chosen, on the other hand, there is a safe upcast from the !int! type of !42! to !long!, but no cast on the return of !g!$_2$, for a total cost of $(0,0,1,0,0,0,0)$ for !f( g!$_2$!(42) )!; as this is cheaper, !g!$_2$ is chosen. 175 Due to this design, all valid interpretations of subexpressions must in general be propagated to the top of the expression tree before any can be eliminated, a lazy form of expression resolution, as opposed to the eager expression resolution allowed by C or \CC{}, where each expression can be resolved given only the resolution of its immediate subexpressions. 176 177 If there are no valid interpretations of the top-level expression, expression resolution fails and must produce an appropriate error message. 178 If any subexpression has no valid interpretations, the process can be short-circuited and the error produced at that time. 179 If there are multiple valid interpretations of a top-level expression, ties are broken based on the conversion cost, calculated as above. 180 If there are multiple minimal-cost valid interpretations of a top-level expression, that expression is said to be \emph{ambiguous}, and an error must be produced. 181 Multiple minimal-cost interpretations of a subexpression do not necessarily imply an ambiguous top-level expression, however, as the subexpression interpretations may be disambiguated based on their return type or by selecting a more-expensive interpretation of that subexpression to reduce the overall expression cost, as in the example above. 182 183 The \CFA{} resolver uses type assertions to filter out otherwise-valid subexpression interpretations. 184 An interpretation can only be selected if all the type assertions in the !forall! clause on the corresponding declaration can be satisfied with a unique minimal-cost set of satisfying declarations. 185 Type assertion satisfaction is tested by performing type unification on the type of the assertion and the type of the declaration satisfying the assertion. 186 That is, a declaration that satisfies a type assertion must have the same name and type as the assertion after applying the substitutions in the type environment. 187 Assertion-satisfying declarations may be polymorphic functions with assertions of their own that must be satisfied recursively. 188 This recursive assertion satisfaction has the potential to introduce infinite loops into the type resolution algorithm, a situation which \CFACC{} avoids by imposing a hard limit on the depth of recursive assertion satisfaction (currently 4); this approach is also taken by \CC{} to prevent infinite recursion in template expansion, and has proven to be effective and not unduly restrictive of the expressive power of \CFA{}. 189 190 Cast expressions must be treated somewhat differently than functions for backwards compatibility purposes with C. 191 In C, cast expressions can serve two purposes, \emph{conversion} (\eg{} !(int)3.14!), which semantically converts a value to another value in a different type with a different bit representation, or \emph{coercion} (\eg{} !void* p; (int*)p;!), which assigns a different type to the same bit value. 192 C provides a set of built-in conversions and coercions, and user programmers are able to force a coercion over a conversion if desired by casting pointers. 193 The overloading features in \CFA{} introduce a third cast semantic, \emph{ascription} (\eg{} !int x; double x; (int)x;!), which selects the overload that most-closely matches the cast type. 194 However, since ascription does not exist in C due to the lack of overloadable identifiers, if a cast argument has an unambiguous interpretation as a conversion argument then it must be interpreted as such, even if the ascription interpretation would have a lower overall cost. 195 This is demonstrated in the following example, adapted from the C standard library: 196 197 \begin{cfa} 198 unsigned long long x; 199 (unsigned)(x >> 32); 200 \end{cfa} 201 202 In C semantics, this example is unambiguously upcasting !32! to !unsigned long long!, performing the shift, then downcasting the result to !unsigned!, at cost $(1,0,3,1,0,0,0)$. 203 If ascription were allowed to be a first-class interpretation of a cast expression, it would be cheaper to select the !unsigned! interpretation of !?>>?! by downcasting !x! to !unsigned! and upcasting !32! to !unsigned!, at a total cost of $(1,0,1,1,0,0,0)$. 204 However, this break from C semantics is not backwards compatible, so to maintain C compatibility, the \CFA{} resolver selects the lowest-cost interpretation of the cast argument for which a conversion or coercion to the target type exists (upcasting to !unsigned long long! in the example above, due to the lack of unsafe downcasts), using the cost of the conversion itself only as a tie-breaker. 205 For example, in !int x; double x; (int)x;!, both declarations have zero-cost interpretations as !x!, but the !int x! interpretation is cheaper to cast to !int!, and is thus selected. 206 Thus, in contrast to the lazy resolution of nested function-call expressions discussed above, where final interpretations for each subexpression are not chosen until the top-level expression is reached, cast expressions introduce eager resolution of their argument subexpressions, as if that argument was itself a top-level expression. 207 208 \section{Resolution Algorithms} 209 210 \CFA{} expression resolution is not, in general, polynomial in the size of the input expression, as shown in Section~\ref{resn-analysis-sec}. 211 While this theoretical result is daunting, its implications can be mitigated in practice. 212 \CFACC{} does not solve one instance of expression resolution in the course of compiling a program, but rather thousands; therefore, if the worst case of expression resolution is sufficiently rare, worst-case instances can be amortized by more-common easy instances for an acceptable overall runtime, as shown in Section~\ref{instance-expr-sec}. 213 Secondly, while a programmer \emph{can} deliberately generate a program designed for inefficient compilation\footnote{See for instance \cite{Haberman16}, which generates arbitrarily large \CC{} template expansions from a fixed-size source file.}, source code tends to follow common patterns. 214 Programmers generally do not want to run the full compiler algorithm in their heads, and as such keep mental shortcuts in the form of language idioms. 215 If the compiler can be tuned to handle idiomatic code more efficiently, then the reduction in runtime for idiomatic (but otherwise difficult) resolution instances can make a significant difference in total compiler runtime. 216 217 \subsection{Worst-case Analysis} \label{resn-analysis-sec} 218 219 Expression resolution has a number of components that contribute to its runtime, including argument-parameter type unification, recursive traversal of the expression tree, and satisfaction of type assertions. 220 221 If the bound type for a type variable can be looked up or mutated in constant time (as asserted in Table~\ref{env-bounds-table}), then the runtime of the unification algorithm to match an argument to a parameter is usually proportional to the complexity of the types being unified. 222 In C, complexity of type representation is bounded by the most-complex type explicitly written in a declaration, effectively a small constant; in \CFA{}, however, polymorphism can generate more-complex types: 223 224 \begin{cfa} 225 forall(otype T) pair(T) wrap(T x, T y); 226 227 wrap(wrap(wrap(1, 2), wrap(3, 4)), wrap(wrap(5, 6), wrap(7, 8))); 228 \end{cfa} 229 230 To resolve the outermost !wrap!, the resolver must check that !pair(pair(int))! unifies with itself, but at three levels of nesting, !pair(pair(int))! is more complex than either !pair(T)! or !T!, the types in the declaration of !wrap!. 231 Accordingly, the cost of a single argument-parameter unification is $O(d)$, where $d$ is the depth of the expression tree, and the cost of argument-parameter unification for a single candidate for a given function call expression is $O(pd)$, where $p$ is the number of parameters. 232 This bound does not, however, account for the higher costs of unifying two polymorphic type variables, which may in the worst case result in a recursive unification of all type variables in the expression (as discussed in Chapter~\ref{env-chap}). 233 Since this recursive unification reduces the number of type variables, it may happen at most once, for an added $O(p^d)$ cost for a top-level expression with $O(p^d)$ type variables. 234 235 Implicit conversions are also checked in argument-parameter matching, but the cost of checking for the existence of an implicit conversion is again proportional to the complexity of the type, $O(d)$. 236 Polymorphism also introduces a potential expense here; for a monomorphic function there is only one potential implicit conversion from argument type to parameter type, while if the parameter type is an unbound polymorphic type-variable then any implicit conversion from the argument type could potentially be considered a valid binding for that type variable. 237 \CFA{}, however, requires exact matches for the bound type of polymorphic parameters, removing this problem. 238 An interesting question for future work is whether loosening this requirement incurs a significant compiler runtime cost in practice; preliminary results from the prototype system described in Chapter~\ref{expr-chap} suggest it does not. 239 240 Considering the recursive traversal of the expression tree, polymorphism again greatly expands the worst-case runtime. 241 Let $i$ be the number of candidate declarations for each function call; if all of these candidates are monomorphic, then there are no more than $i$ unambiguous interpretations of the subexpression rooted at that function call. 242 Ambiguous minimal-cost subexpression interpretations may also be collapsed into a single \emph{ambiguous interpretation}, as the presence of such a subexpression interpretation in the final solution is an error condition. 243 One safe pruning operation during expression resolution is to discard all subexpression interpretations with greater-than-minimal cost for their return type, as such interpretations cannot beat the minimal-cost interpretation with their return type for the overall optimal solution. 244 As such, with no polymorphism, each declaration can generate no more than one minimal-cost interpretation with its return type, so the number of possible subexpression interpretations is $O(i)$ (note that in C, which lacks overloading, $i \leq 1$). 245 With polymorphism, however, a single declaration (like !wrap! above) can have many concrete return types after type variable substitution, and could in principle have a different concrete return type for each combination of argument interpretations. 246 Calculated recursively, the bound on the total number of candidate interpretations is $O(i^{p^d})$, each with a distinct type. 247 248 Given these calculations of number of subexpression interpretations and matching costs, the upper bound on runtime for generating candidates for a single subexpression $d$ levels up from the leaves is $O( i^{p^d} \cdot pd )$. 249 Since there are $O(p^d)$ subexpressions in a single top-level expression, the total worst-case cost of argument-parameter matching with the overloading and polymorphism features of \CFA{} is $O( i^{p^d} \cdot pd \cdot p^d )$. 250 Since the size of the expression is $O(p^d)$, letting $n = p^d$ this simplifies to $O(i^n \cdot n^2)$ 251 252 This bound does not yet account for the cost of assertion satisfaction, however. 253 \CFA{} uses type unification on the assertion type and the candidate declaration type to test assertion satisfaction; this unification calculation has cost proportional to the complexity of the declaration type after substitution of bound type variables; as discussed above, this cost is $O(d)$. 254 If there are $O(a)$ type assertions on each declaration, there are $O(i)$ candidates to satisfy each assertion, for a total of $O(ai)$ candidates to check for each declaration. 255 However, each assertion candidate may generate another $O(a)$ assertions, recursively until the assertion recursion limit $r$ is reached, for a total cost of $O((ai)^r \cdot d)$. 256 Now, $a$ and $i$ are properties of the set of declarations in scope, while $r$ is defined by the language spec, so $(ai)^r$ is essentially a constant for purposes of expression resolution, albeit a very large one. 257 It is not uncommon in \CFA{} to have functions with dozens of assertions, and common function names (\eg{} !?{}!, the constructor) can have hundreds of overloads. 258 259 It is clear that assertion satisfaction costs can be very large, and in fact a method for heuristically reducing these costs is one of the key contributions of this thesis, but it should be noted that the worst-case analysis is a particularly poor match for actual code in the case of assertions. 260 It is reasonable to assume that most code compiles without errors, as an actively-developed project is compiled many times, generally with relatively few new errors introduced between compiles. 261 However, the worst-case bound for assertion satisfaction is based on recursive assertion satisfaction calls exceeding the limit, which is an error case. 262 In practice, then, the depth of recursive assertion satisfaction should be bounded by a small constant for error-free code, which accounts for the vast majority of problem instances. 263 264 Similarly, uses of polymorphism like those that generate the $O(d)$ bound on unification or the $O(i^{p^d})$ bound on number of candidates are rare, but not completely absent. 265 This analysis points to type unification, argument-parameter matching, and assertion satisfaction as potentially costly elements of expression resolution, and thus profitable targets for algorithmic investigation. 266 Type unification is discussed in Chapter~\ref{env-chap}, while the other aspects are covered below. 267 268 \subsection{Argument-Parameter Matching} \label{arg-parm-matching-sec} 269 270 Pruning possible interpretations as early as possible is one way to reduce the real-world cost of expression resolution, provided that a sufficient proportion of interpretations are pruned to pay for the cost of the pruning algorithm. 271 One opportunity for interpretation pruning is by the argument-parameter type matching, but the literature \cite{Baker82,Bilson03,Cormack81,Ganzinger80,Pennello80,PW:overload} provides no clear answers on whether candidate functions should be chosen according to their available arguments, or whether argument resolution should be driven by the available function candidates. 272 For programming languages without implicit conversions, argument-parameter matching is essentially the entirety of the expression resolution problem, and is generally referred to as ``overload resolution'' in the literature. 273 All expression-resolution algorithms form a DAG of interpretations, some explicitly, some implicitly; in this DAG, arcs point from function-call interpretations to argument interpretations, as in Figure~\ref{res-dag-fig} 274 275 \begin{figure}[h] 276 \centering 277 \begin{subfigure}[h]{3in} 278 \begin{cfa} 279 char *p$\(_1\)$; 280 int *p$\(_2\)$; 281 282 char *f$\(_1\)$(char*, int*); 283 double *f$\(_2\)$(int*, int*); 284 285 f$\(_A\)$( f$\(_B\)$( p$\(_A\)$, p$\(_B\)$ ), p$\(_C\)$ ); 286 \end{cfa} 287 \end{subfigure}~\begin{subfigure}[h]{2.5in} 288 \includegraphics{figures/resolution-dag} 289 \end{subfigure} 290 \caption[Resolution DAG for a simple expression.]{Resolution DAG for a simple expression, annotated with explanatory subscripts. Functions that do not have a valid argument matching are covered with an \textsf{X}.} \label{res-dag-fig} 291 \end{figure} 292 293 Note that some interpretations may be part of more than one super-interpretation, as with the !p!$_2$ interpretation of !p!$_B$, while some valid subexpression interpretations, like the !f!$_2$ interpretation of !f!$_B$, are not used in any interpretation of their superexpression. 294 295 Overload resolution was first seriously considered in the development of compilers for the Ada programming language, with different algorithms making various numbers of passes over the expression DAG, these passes being either top-down or bottom-up. 296 Baker's algorithm~\cite{Baker82} takes a single pass from the leaves of the expression tree up, pre-computing argument candidates at each step. 297 For each candidate function, Baker attempts to match argument types to parameter types in sequence, failing if any parameter cannot be matched. 298 299 Bilson~\cite{Bilson03} similarly pre-computes argument-candidates in a single bottom-up pass in the original \CFACC{}, but then explicitly enumerates all possible argument combinations for a multi-parameter function. 300 These argument combinations are matched to the parameter types of the candidate function as a unit rather than individual arguments. 301 Bilson's approach is less efficient than Baker's, as the same argument may be compared to the same parameter many times, but does allow a more straightforward handling of polymorphic type-binding and tuple-typed expressions. 302 303 Unlike Baker and Bilson, Cormack's algorithm~\cite{Cormack81} requests argument candidates that match the type of each parameter of each candidate function, in a single pass from the top-level expression down; memoization of these requests is presented as an optimization. 304 As presented, this algorithm requires the parameter to have a known type, which is a poor fit for polymorphic type parameters in \CFA{}. 305 Cormack's algorithm can be modified to request argument interpretations of \emph{any} type when provided an unbound parameter type, but this eliminates any pruning gains that could be provided by the algorithm. 306 307 Ganzinger and Ripken~\cite{Ganzinger80} propose an approach (later refined by Pennello~\etal{}~\cite{Pennello80}) that uses a top-down filtering pass followed by a bottom-up filtering pass to reduce the number of candidate interpretations; they prove that a small number of such iterations is sufficient to converge to a solution for the overload resolution problem in the Ada programming language. 308 Persch~\etal{}~\cite{PW:overload} developed a similar two-pass approach where the bottom-up pass is followed by the top-down pass. 309 These approaches differ from Baker, Bilson, or Cormack in that they take multiple passes over the expression tree to yield a solution by applying filtering heuristics to all expression nodes. 310 This approach of filtering out invalid types is unsuited to \CFA{} expression resolution, however, due to the presence of polymorphic functions and implicit conversions. 311 312 Some other language designs solve the matching problem by forcing a bottom-up order. 313 \CC{}, for instance, defines its overload-selection algorithm in terms of a partial order between function overloads given a fixed list of argument candidates, implying that the arguments must be selected before the function. 314 This design choice improves worst-case expression resolution time by only propagating a single candidate for each subexpression, but type annotations must be provided for any function call that is polymorphic in its return type, and these annotations are often redundant: 315 316 \begin{C++} 317 template<typename T> T* malloc() { /* ... */ } 318 319 int* p = malloc<int>(); $\C{// T = int must be explicitly supplied}$ 320 \end{C++} 321 322 \CFA{} saves programmers from redundant annotations with its richer inference: 323 324 \begin{cfa} 325 forall(dtype T | sized(T)) T* malloc(); 326 327 int* p = malloc(); $\C{// Infers T = int from left-hand side}$ 328 \end{cfa} 329 330 Baker~\cite{Baker82} left empirical comparison of different overload resolution algorithms to future work; Bilson~\cite{Bilson03} described an extension of Baker's algorithm to handle implicit conversions and polymorphism, but did not further explore the space of algorithmic approaches to handle both overloaded names and implicit conversions. 331 This thesis closes that gap in the literature by performing performance comparisons of both top-down and bottom-up expression resolution algorithms, with results reported in Chapter~\ref{expr-chap}. 332 333 \subsection{Assertion Satisfaction} \label{assn-sat-sec} 334 335 The assertion satisfaction algorithm designed by Bilson~\cite{Bilson03} for the original \CFACC{} is the most-relevant prior work to this project. 336 Before accepting any subexpression candidate, Bilson first checks that that candidate's assertions can all be resolved; this is necessary due to Bilson's addition of assertion satisfaction costs to candidate costs (discussed in Section~\ref{conv-cost-sec}). 337 If this subexpression interpretation ends up not being used in the final resolution, then the (sometimes substantial) work of checking its assertions ends up wasted. 338 Bilson's assertion checking function recurses on two lists, !need! and !newNeed!, the current declaration's assertion set and those implied by the assertion-satisfying declarations, respectively, as detailed in the pseudo-code below (ancillary aspects of the algorithm are omitted for clarity): 339 340 \begin{cfa} 341 List(List(Declaration)) checkAssertions( 342 List(Assertion) need, List(Assertion) newNeed, List(Declaration) have, 343 Environment env ) { 344 if ( is_empty(need) ) { 345 if ( is_empty( newNeed ) ) return { have }; 346 else return checkAssertions( newNeed, {}, have, env ); 347 } 348 349 Assertion a = head(need); 350 Type adjType = substitute( a.type, env ); 351 List(Declaration) candidates = decls_matching( a.name ); 352 List(List(Declaration)) alternatives = {} 353 for ( Declaration c : candidates ) { 354 Environment newEnv = env; 355 if ( unify( adjType, c.type, newEnv ) ) { 356 append( alternatives, 357 checkAssertions( 358 tail(need), append(newNeed, c.need), append(have, c), newEnv ) ); 359 } 360 } 361 return alternatives; 362 } 363 \end{cfa} 364 365 One shortcoming of this approach is that if an earlier assertion has multiple valid candidates, later assertions may be checked many times due to the structure of the recursion. 366 Satisfying declarations for assertions are not completely independent of each other, since the unification process may produce new type bindings in the environment, and these bindings may not be compatible between independently-checked assertions. 367 Nonetheless, with the environment data-structures discussed in Chapter~\ref{env-chap}, I have found it more efficient to produce a list of possibly-satisfying declarations for each assertion once, then check their respective environments for mutual compatibility when combining lists of assertions together. 368 369 Another improvement I have made to the assertion resolution scheme in \CFACC{} is to consider all assertion-satisfying combinations at one level of recursion before attempting to recursively satisfy any !newNeed! assertions. 370 Monomorphic functions are cheaper than polymorphic functions for assertion satisfaction because they are an exact match for the environment-adjusted assertion type, whereas polymorphic functions require an extra type binding. 371 Thus, if there is any mutually-compatible set of assertion-satisfying declarations that does not include any polymorphic functions (and associated recursive assertions), then the optimal set of assertions does not require any recursive !newNeed! satisfaction. 372 More generally, due to the \CFA{} cost-model changes I introduced in Section~\ref{conv-cost-sec}, the conversion cost of an assertion-satisfying declaration is no longer dependent on the conversion cost of its own assertions. 373 As such, all sets of mutually-compatible assertion-satisfying declarations can be sorted by their summed conversion costs, and the recursive !newNeed! satisfaction pass is required only to check the feasibility of the minimal-cost sets. 374 This optimization significantly reduces wasted work relative to Bilson's approach, as well as avoiding generation of deeply-recursive assertion sets, for a significant performance improvement relative to Bilson's \CFACC{}. 375 376 Making the conversion cost of an interpretation independent of the cost of satisfying its assertions has further benefits. 377 Bilson's algorithm checks assertions for all subexpression interpretations immediately, including those that are not ultimately used; I have developed a \emph{deferred} variant of assertion checking that waits until a top-level interpretation has been generated to check any assertions. 378 If the assertions of the minimal-cost top-level interpretation cannot be satisfied then the next-most-minimal-cost interpretation's assertions are checked, and so forth until a minimal-cost satisfiable interpretation (or ambiguous set thereof) is found, or no top-level interpretations are found to have satisfiable assertions. 379 In the common case where the code actually does compile, this saves the work of checking assertions for ultimately-rejected interpretations, though it does rule out some pruning opportunities for subinterpretations with unsatisfiable assertions or which are more expensive than a minimal-cost polymorphic function with the same return type. 380 The experimental results in Chapter~\ref{expr-chap} indicate that this is a worthwhile trade-off. 381 382 Optimizing assertion satisfaction for common idioms has also proved effective in \CFA{}; the code below is an unexceptional print statement derived from the \CFA{} test suite that nonetheless is a very difficult instance of expression resolution: 383 384 \begin{cfa} 385 sout | "one" | 1 | "two" | 2 | "three" | 3 | "four" | 4 | "five" | 5 | "six" | 6 386 | "seven" | 7 | "eight" | 8 | "nine" | 9 | "ten" | 10 | "end" | nl | nl; 387 \end{cfa} 388 389 The first thing that makes this expression so difficult is that it is 23 levels deep; Section~\ref{resn-analysis-sec} indicates that the worst-case bounds on expression resolution are exponential in expression depth. 390 Secondly, the !?|?! operator is significantly overloaded in \CFA{} --- there are 74 such operators in the \CFA{} standard library, and while 9 are arithmetic operators inherited from C, the rest are polymorphic I/O operators that look similar to: 391 392 \begin{cfa} 393 forall( dtype ostype | ostream( ostype ) ) 394 ostype& ?|? ( ostype&, int ); 395 \end{cfa} 396 397 Note that !ostream! is a trait with 25 type assertions, and that the output operators for the other arithmetic types are also valid for the !int!-type parameters due to implicit conversions. 398 On this instance, deferred assertion satisfaction saves wasted work checking assertions on the wrong output operators, but does nothing about the 23 repeated checks of the 25 assertions to determine that !ofstream! (the type of !sout!) satisfies !ostream!. 399 400 To solve this problem, I have developed a \emph{cached} variant of assertion checking. 401 During the course of checking the assertions of a single top-level expression, the results are cached for each assertion checked. 402 The search key for this cache is the assertion declaration with its type variables substituted according to the type environment to distinguish satisfaction of the same assertion for different types. 403 This adjusted assertion declaration is then run through the \CFA{} name-mangling algorithm to produce an equivalent string-type key. 404 405 One superficially-promising optimization, which I did not pursue, is caching assertion-satisfaction judgments among top-level expressions. 406 This approach would be difficult to correctly implement in a \CFA{} compiler, due to the lack of a closed set of operations for a given type. 407 New declarations related to a particular type can be introduced in any lexical scope in \CFA{}, and these added declarations may cause an assertion that was previously satisfiable to fail due to an introduced ambiguity. 408 Furthermore, given the recursive nature of assertion satisfaction and the possibility of this satisfaction judgment depending on an inferred type, an added declaration may break satisfaction of an assertion with a different name and that operates on different types. 409 Given these concerns, correctly invalidating a cross-expression assertion satisfaction cache for \CFA{} is a non-trivial problem, and the overhead of such an approach may possibly outweigh any benefits from such caching. 410 411 The assertion satisfaction aspect of \CFA{} expression resolution bears some similarity to satisfiability problems from logic, and as such other languages with similar trait and assertion mechanisms make use of logic-program solvers in their compilers. 412 For instance, Matsakis~\cite{Matsakis17} and the Rust team have developed a PROLOG-based engine to check satisfaction of Rust traits. 413 The combination of the assertion satisfaction elements of the problem with the conversion-cost model of \CFA{} makes this logic-solver approach difficult to apply in \CFACC{}, however. 414 Expressing assertion resolution as a satisfiability problem ignores the cost optimization aspect, which is necessary to decide among what are often many possible satisfying assignments of declarations to assertions. 415 (MaxSAT solvers \cite{Morgado13}, which allow weights on solutions to satisfiability problems, may be a productive avenue for future investigation.) 416 On the other hand, the deeply-recursive nature of the satisfiability problem makes it difficult to adapt to optimizing solver approaches such as linear programming. 417 To maintain a well-defined programming language, any optimization algorithm used must provide an exact (rather than approximate) solution; this constraint also rules out a whole class of approximately-optimal generalized solvers. 418 As such, I opted to continue Bilson's approach of designing a bespoke solver for \CFA{} assertion satisfaction, rather than attempting to re-express the problem in some more general formalism. 419 420 \section{Conclusion \& Future Work} \label{resn-conclusion-sec} 421 422 As the results in Chapter~\ref{expr-chap} show, the algorithmic approaches I have developed for \CFA{} expression resolution are sufficient to build a practically-performant \CFA{} compiler. 423 This work may also be of use to other compiler construction projects, notably to members of the \CC{} community as they implement the new Concepts \cite{C++Concepts} standard, which includes type assertions similar to those used in \CFA{}, as well as the C-derived implicit conversion system already present in \CC{}. 424 425 I have experimented with using expression resolution rather than type unification to check assertion satisfaction; this variant of the expression resolution problem should be investigated further in future work. 426 This approach is more flexible than type unification, allowing for conversions to be applied to functions to satisfy assertions. 427 Anecdotally, this flexibility matches user-programmer expectations better, as small type differences (\eg{} the presence or absence of a reference type, or the usual conversion from !int! to !long!) no longer break assertion satisfaction. 428 Practically, the resolver prototype discussed in Chapter~\ref{expr-chap} uses this model of assertion satisfaction, with no apparent deficit in performance; the generated expressions that are resolved to satisfy the assertions are easier than the general case because they never have nested subexpressions, which eliminates much of the theoretical differences between unification and resolution. 429 The main challenge to implement this approach in \CFACC{} is applying the implicit conversions generated by the resolution process in the code-generation for the thunk functions that \CFACC{} uses to pass type assertions to their requesting functions with the proper signatures. 430 431 One \CFA{} feature that could be added to improve the ergonomics of overload selection is an \emph{ascription cast}; as discussed in Section~\ref{expr-cost-sec}, the semantics of the C cast operator are to choose the cheapest argument interpretation which is convertible to the target type, using the conversion cost as a tie-breaker. 432 An ascription cast would reverse these priorities, choosing the argument interpretation with the cheapest conversion to the target type, only using interpretation cost to break ties\footnote{A possible stricter semantics would be to select the cheapest interpretation with a zero-cost conversion to the target type, reporting a compiler error otherwise.}. 433 This would allow ascription casts to the desired return type to be used for overload selection: 434 435 \begin{cfa} 436 int f$\(_1\)$(int); 437 int f$\(_2\)$(double); 438 int g$\(_1\)$(int); 439 double g$\(_2\)$(long); 440 441 f((double)42); $\C[4.5in]{// select f\(_2\) by argument cast}$ 442 (as double)g(42); $\C[4.5in]{// select g\(_2\) by return ascription cast}$ 443 (double)g(42); $\C[4.5in]{// select g\(_1\) NOT g\(_2\) because of parameter conversion cost}$ 444 \end{cfa} 445 446 Though performance of the existing resolution algorithms is promising, some further optimizations do present themselves. 447 The refined cost model discussed in Section~\ref{conv-cost-sec} is more expressive, but requires more than twice as many fields; it may be fruitful to investigate more tightly-packed in-memory representations of the cost-tuple, as well as comparison operations that require fewer instructions than a full lexicographic comparison. 448 Integer or vector operations on a more-packed representation may prove effective, though dealing with the negative-valued $specialization$ field may require some effort. 449 450 Parallelization of various phases of expression resolution may also be useful. 451 The algorithmic variants I have introduced for both argument-parameter matching and assertion satisfaction are essentially divide-and-conquer algorithms, which solve subproblem instances for each argument or assertion, respectively, then check mutual compatibility of the solutions. 452 While the checks for mutual compatibility are naturally more serial, there may be some benefit to parallel resolution of the subproblem instances. 453 454 The resolver prototype built for this project and described in Chapter~\ref{expr-chap} would be a suitable vehicle for many of these further experiments, and thus a technical contribution of continuing utility. -
doc/theses/aaron_moss_PhD/phd/thesis.tex
r6a9d4b4 r933f32f 29 29 \usepackage{footmisc} % for double refs to the same footnote 30 30 31 \usepackage{caption} % for subfigure 32 \usepackage{subcaption} 33 31 34 % Hyperlinks make it very easy to navigate an electronic document. 32 35 % In addition, this is where you should specify the thesis title … … 34 37 % Use the "hyperref" package 35 38 % N.B. HYPERREF MUST BE THE LAST PACKAGE LOADED; ADD ADDITIONAL PKGS ABOVE 36 %\usepackage[pdftex,pagebackref=false]{hyperref} % with basic options 37 \usepackage[ pagebackref=false]{hyperref}39 %\usepackage[pdftex,pagebackref=false]{hyperref} % with basic options\ 40 \usepackage[breaklinks,pagebackref=false]{hyperref} 38 41 % N.B. pagebackref=true provides links back from the References to the body text. This can cause trouble for printing. 39 42 … … 129 132 \input{resolution-heuristics} 130 133 \input{type-environment} 134 \input{experiments} 131 135 \input{conclusion} 132 136 … … 156 160 % \nocite{*} 157 161 162 % APPENDICIES 163 % ----------- 164 \appendix 165 \input{generic-bench} 166 158 167 \end{document} -
doc/theses/aaron_moss_PhD/phd/type-environment.tex
r6a9d4b4 r933f32f 4 4 One key data structure for expression resolution is the \emph{type environment}. 5 5 As discussed in Chapter~\ref{resolution-chap}, being able to efficiently determine which type variables are bound to which concrete types or whether two type environments are compatible is a core requirement of the resolution algorithm. 6 Furthermore, expression resolution involves a search through many related possible solutions, so being able to re-use shared subsets of type environment data and to switch between environments quickly is desirable for performance. 7 In this chapter I discuss and empirically compare a number of type environment data structure variants, including some novel variations on the union-find\cite{Galler64} data structure introduced in this thesis. 6 Furthermore, expression resolution involves a search through many related possible solutions, so the ability to re-use shared subsets of type-environment data and to switch between environments quickly is desirable for performance. 7 In this chapter, I discuss a number of type-environment data-structure variants, including some novel variations on the union-find \cite{Galler64} data structure introduced in this thesis. 8 Chapter~\ref{expr-chap} contains empirical comparisons of the performance of these data structures when integrated into the resolution algorithm. 8 9 9 10 \section{Definitions} \label{env-defn-sec} 10 11 11 12 For purposes of this chapter, a \emph{type environment} $T$ is a set of \emph{type classes} $\myset{T_1, T_2, \cdots, T_{|T|}}$. 12 Each type class $T_i$ contains a set of \emph{type variables} $\myset{v_{i,1}, v_{i,2}, \cdots, v_{i,|T_i|}}$; note that the sets of variables contained in two distinct classes in the same environment must be disjoint. 13 Each individual type class $T_i$ may also be associated with a \emph{bound}, $b_i$; this bound contains the \emph{bound type} which the variables in the type class are replaced with, but also includes other information in \CFACC{}, including whether type conversions are permissible on the bound type and what sort of type variables are contained in the class (data types, function types, or variadic tuples). 13 Each type class $T_i$ contains a set of \emph{type variables} $\myset{v_{i,1}, v_{i,2}, \cdots, v_{i,|T_i|}}$. 14 Since the type classes represent an equivalence relation over the type variables the sets of variables contained in two distinct classes in the same environment must be \emph{disjoint}. 15 Each individual type class $T_i$ may also be associated with a \emph{bound}, $b_i$; this bound contains the \emph{bound type} that the variables in the type class are replaced with, but also includes other information in \CFACC{}, including whether type conversions are permissible on the bound type and what sort of type variables are contained in the class (data types, function types, or variadic tuples). 16 17 The following example demonstrates the use of a type environment for unification: 18 19 \begin{cfa} 20 forall(otype F) F f(F, F); 21 forall(otype G) G g(G); 22 23 f( g(10), g(20) ); 24 \end{cfa} 25 26 Expression resolution starts from an empty type environment; from this empty environment, the calls to !g! can be independently resolved. 27 These resolutions result in two new type environments, $T = \{ \myset{\mathsf{G}_1} \rightarrow$ !int!$\}$ and $T' = \{ \myset{\mathsf{G}_2} \rightarrow$ !int!$\}$; the calls to !g! have generated distinct type variables !G!$_1$ and !G!$_2$, each bound to !int! by unification with the type of its argument (!10! and !20!, both !int!). 28 To complete resolution of the call to !f!, both environments must be combined; resolving the first argument to !f! produces a new type environment $T'' = \{ \myset{\mathsf{G}_1, \mathsf{F}_1} \rightarrow$ !int!$\}$: the new type variable !F!$_1$ has been introduced and unified with !G!$_1$ (the return type of !g(10)!), and consequently bound to !int!. 29 To resolve the second argument to !f!, $T''$ must be checked for compatibility with $T'$; since !F!$_1$ unifies with !G!$_2$, their type classes must be merged. 30 Since both !F!$_1$ and !G!$_2$ are bound to !int!, this merge succeeds, producing the final environment $T'' = \{ \myset{\mathsf{G}_1, \mathsf{F}_1, \mathsf{G}_2} \rightarrow$ !int!$\}$. 14 31 15 32 \begin{table} … … 18 35 \centering 19 36 \begin{tabular}{r@{\hskip 0.25em}ll} 20 $find(T, v_{i,j})$ & $\rightarrow T_i | \bot$ & Locate class for variable \\ 37 \hline 38 $find(T, v_{i,j})$ & $\rightarrow T_i~|~\mathsf{fail}$ & Locate class for variable \\ 21 39 $report(T_i)$ & $\rightarrow \{ v_{i,j} \cdots \}$ & List variables for class \\ 22 $bound(T_i)$ & $\rightarrow b_i | \bot$ & Get bound for class \\23 $insert( v_{i,1})$ && New single-variable class \\40 $bound(T_i)$ & $\rightarrow b_i~|~\mathsf{fail}$ & Get bound for class \\ 41 $insert(T, v_{i,1})$ & & New single-variable class \\ 24 42 $add(T_i, v_{i,j})$ & & Add variable to class \\ 25 43 $bind(T_i, b_i)$ & & Set or update class bound \\ 26 $unify(T, T_i, T_j)$ & $\rightarrow \top | \bot$ & Combine two type classes \\ 44 \hline 45 $unify(T, T_i, T_j)$ & $\rightarrow \mathsf{pass}~|~\mathsf{fail}$ & Combine two type classes \\ 27 46 $split(T, T_i)$ & $\rightarrow T'$ & Revert the last $unify$ operation on $T_i$ \\ 28 $combine(T, T')$ & $\rightarrow \ top | \bot$ & Merge two environments \\47 $combine(T, T')$ & $\rightarrow \mathsf{pass}~|~\mathsf{fail}$ & Merge two environments \\ 29 48 $save(T)$ & $\rightarrow H$ & Get handle for current state \\ 30 $backtrack(T, H)$ & & Return to handle state 49 $backtrack(T, H)$ & & Return to handle state \\ 50 \hline 31 51 \end{tabular} 32 52 \end{table} 33 53 34 Given this basic structure, type environments in \CFACC{} need to support eleven basic operations, summarized in Table~\ref{env-op-table}.35 The first s evenoperations are straightforward queries and updates on these data structures:36 The lookup operation $find(T, v_{i,j})$ produces $T_i$, the type class in $T$ whichcontains variable $v_{i,j}$, or an invalid sentinel value for no such class.54 Type environments in \CFACC{} need to support eleven basic operations, summarized in Table~\ref{env-op-table}. 55 The first six operations are straightforward queries and updates on these data structures: 56 The lookup operation $find(T, v_{i,j})$ produces $T_i$, the type class in $T$ that contains variable $v_{i,j}$, or an invalid sentinel value for no such class. 37 57 The other two query operations act on type classes, where $report(T_i)$ produces the set $\myset{v_{i,1}, v_{i,2}, \cdots, v_{i,|T_i|}}$ of all type variables in a class $T_i$ and $bound(T_i)$ produces the bound $b_i$ of that class, or a sentinel indicating no bound is set. 38 58 39 The update operation $insert(T, v_{i,1})$ creates a new type class $T_i$ in $T$ that contains only the variable $v_{i,1}$ and no bound; due to the disjointness property $v_{i,1}$ cannot belong to any other type class in $T$.59 The update operation $insert(T, v_{i,1})$ creates a new type class $T_i$ in $T$ that contains only the variable $v_{i,1}$ and no bound; due to the disjointness property, $v_{i,1}$ must not belong to any other type class in $T$. 40 60 The $add(T_i, v_{i,j})$ operation adds a new type variable $v_{i,j}$ to class $T_i$; again, $v_{i,j}$ cannot exist elsewhere in $T$. 41 61 $bind(T_i, b_i)$ mutates the bound for a type class, setting or updating the current bound. 42 62 43 The $unify$ operation is the fundamental non-trivial operation a type environment datastructure must support.63 The $unify$ operation is the fundamental non-trivial operation a type-environment data-structure must support. 44 64 $unify(T, T_i, T_j)$ merges a type class $T_j$ into another $T_i$, producing a failure result and leaving $T$ in an invalid state if this merge fails. 45 65 It is always possible to unify the type variables of both classes by simply taking the union of both sets; given the disjointness property, no checks for set containment are required, and the variable sets can simply be concatenated if supported by the underlying data structure. 46 $unify$ depends on an internal $unifyBound$ operation which may fail.47 In \CFACC{}, $unifyBound(b_i, b_j) \rightarrow b'_i |\bot$ checks that the type classes contain the same sort of variable, takes the tighter of the two conversion permissions, and checks if the bound types can be unified.66 $unify$ depends on an internal $unifyBound$ operation, which may fail. 67 In \CFACC{}, $unifyBound(b_i, b_j) \rightarrow b'_i~|~\mathsf{fail}$ checks that the type classes contain the same sort of variable, takes the tighter of the two conversion permissions, and checks if the bound types can be unified. 48 68 If the bound types cannot be unified (\eg{} !struct A! with !int*!), then $unifyBound$ fails, while other combinations of bound types may result in recursive calls. 49 For instance, unifying !R*! with !S*! for type variables !R! and !S! will result in a call to $unify(T, find($!R!$), find($!S!$))$, while unifying !R*! with !int*! will resultin a call to $unifyBound$ on !int! and the bound type of the class containing !R!.69 For instance, unifying !R*! with !S*! for type variables !R! and !S! results in a call to $unify(T, find($!R!$), find($!S!$))$, while unifying !R*! with !int*! results in a call to $unifyBound$ on !int! and the bound type of the class containing !R!. 50 70 As such, a call to $unify(T, T_i, T_j)$ may touch every type class in $T$, not just $T_i$ and $T_j$, collapsing the entirety of $T$ into a single type class in extreme cases. 51 71 For more information on \CFA{} unification, see \cite{Bilson03}. 52 The inverse of $unify$ is $split(T, T_i)$, which produces a new environment $T'$ whichis the same as $T$ except that $T_i$ has been replaced by two classes corresponding to the arguments to the previous call to $unify$ on $T_i$.53 If there has been nocall to $unify$ on $T_i$ (\ie{} $T_i$ is a single-element class) $T_i$ is absent in $T'$.54 55 Given the nature of the expression resolution problem as backtracking search, caching and concurrency are both useful tools to decrease runtime.72 The inverse of $unify$ is $split(T, T_i)$, which produces a new environment $T'$ that is the same as $T$ except that $T_i$ has been replaced by two classes corresponding to the arguments to the previous call to $unify$ on $T_i$. 73 If there is no prior call to $unify$ on $T_i$ (\ie{} $T_i$ is a single-element class) $T_i$ is absent in $T'$. 74 75 Given the nature of the expression resolution problem as a backtracking search, caching and concurrency are both useful tools to decrease runtime. 56 76 However, both of these approaches may produce multiple distinct descendants of the same initial type environment, which have possibly been mutated in incompatible ways. 57 As such, to effectively employ either c oncurrency or caching, the type environment data structure must support an efficient method to check if two type environments are compatible and merge them if so.58 $combine(T,T')$ attempts to merge an environment $T'$ into another environment $T$, producing $\ top$ if successful or leaving $T$ in an invalid state and producing $\bot$ otherwise.59 The invalid state of $T$ on failure is not important, given that a combination failure will resultin the resolution algorithm backtracking to a different environment.77 As such, to effectively employ either caching or concurrency, the type environment data structure must support an efficient method to check if two type environments are compatible and merge them if so. 78 $combine(T,T')$ attempts to merge an environment $T'$ into another environment $T$, producing $\mathsf{pass}$ if successful or leaving $T$ in an invalid state and producing $\mathsf{fail}$ otherwise. 79 The invalid state of $T$ on failure is not important, given that a combination failure results in the resolution algorithm backtracking to a different environment. 60 80 $combine$ proceeds by calls to $insert$, $add$, and $unify$ as needed, and can be roughly thought of as calling $unify$ on every pair of classes in $T$ that have variables $v'_{i,j}$ and $v'_{i,k}$ in the same class $T'_i$ in $T'$. 61 81 Like $unify$, $combine$ can always find a mutually-consistent partition of type variables into classes (in the extreme case, all type variables from $T$ and $T'$ in a single type class), but may fail due to inconsistent bounds on merged type classes. … … 64 84 The set of mutations to a type environment across the execution of the resolution algorithm produce an implicit tree of related environments, and the backtracking search typically focuses only on one leaf of the tree at once, or at most a small number of closely-related nodes as arguments to $combine$. 65 85 As such, the ability to save and restore particular type environment states is useful, and supported by the $save(T) \rightarrow H$ and $backtrack(T, H)$ operations, which produce a handle for the current environment state and mutate an environment back to a previous state, respectively. 66 These operations can be naively implemented by a deep copy of $T$ into $H$ and vice versa, but have more efficient implementations in persistency-aware data structures .67 68 \section{Approaches} 69 70 \subsection{Na\"{\i}ve} 71 72 The type environment data structure used in Bilson's \cite{Bilson03} original implementation of \CFACC{} is a straightforwardtranslation of the definitions in Section~\ref{env-defn-sec} to \CC{} code; a !TypeEnvironment! contains a list of !EqvClass! type equivalence classes, each of which contains the type bound information and a tree-based sorted set of type variables.86 These operations can be naively implemented by a deep copy of $T$ into $H$ and vice versa, but have more efficient implementations in persistency-aware data structures such as the persistent union-find introduced in Section~\ref{env-persistent-union-find}. 87 88 \section{Approaches} \label{env-approaches-sec} 89 90 \subsection{Na\"{\i}ve} \label{naive-env-sec} 91 92 The type environment data structure used in Bilson's~\cite{Bilson03} original implementation of \CFACC{} is a simple translation of the definitions in Section~\ref{env-defn-sec} to \CC{} code; a !TypeEnvironment! contains a list of !EqvClass! type equivalence classes, each of which contains the type bound information and a tree-based sorted set of type variables. 73 93 This approach has the benefit of being easy to understand and not imposing life-cycle or inheritance constraints on its use, but, as can be seen in Table~\ref{env-bounds-table}, does not support many of the desired operations with any particular efficiency. 74 Some variations on this structure may improve performance somewhat; for instance, replacing the !EqvClass! variable storage with a hash-based set would reduce search and update times from $O(\log n)$ to amortized $O(1)$, while adding an index for the type variables in the entire environment would removethe need to check each type class individually to maintain the disjointness property.94 Some variations on this structure may improve performance somewhat; for instance, replacing the !EqvClass! variable storage with a hash-based set reduces search and update times from $O(\log n)$ to amortized $O(1)$, while adding an index for the type variables in the entire environment removes the need to check each type class individually to maintain the disjointness property. 75 95 These improvements do not change the fundamental issues with this data structure, however. 76 96 77 \subsection{Incremental Inheritance} 78 79 One more invasive modification to this data structure which I investigated is to support swifter combinations of closely-related environments in the backtracking tree by storing a reference to a \emph{parent} environment within each environment, and having that environment only store type classes whichhave been modified with respect to the parent.97 \subsection{Incremental Inheritance} \label{inc-env-sec} 98 99 One more invasive modification to this data structure that I investigated is to support swifter combinations of closely-related environments in the backtracking tree by storing a reference to a \emph{parent} environment within each environment, and having that environment only store type classes that have been modified with respect to the parent. 80 100 This approach provides constant-time copying of environments, as a new environment simply consists of an empty list of type classes and a reference to its (logically identical) parent; since many type environments are no different than their parent, this speeds backtracking in this common case. 81 Since all mutations made to a child environment are by definition compatible with the parent environment, two descendants of a common ancestor environment can be combined by iteratively combining the changes made in one environment then that environment's parentuntil the common ancestor is reached, again re-using storage and reducing computation in many cases.82 83 For this environment I also employed a lazily-generated index of type variables to their containing class, which could be in either the current environment or an ancestor.84 Any mutation of a type class in an ancestor environment would cause that class to be copied into the current environment before mutation, as well as added to the index, ensuring thatall local changes to the type environment are listed in its index.101 Since all mutations made to a child environment are by definition compatible with the parent environment, two descendants of a common ancestor environment can be combined by iteratively combining the changes made in one environment, then that environment's parent, until the common ancestor is reached, again re-using storage and reducing computation in many cases. 102 103 For this environment, I also employed a lazily-generated index of type variables to their containing class, which could be in either the current environment or an ancestor. 104 Any mutation of a type class in an ancestor environment causes that class to be copied into the current environment before mutation, as well as added to the index, ensuring all local changes to the type environment are listed in its index. 85 105 However, not adding type variables to the index until lookup or mutation preserves the constant-time environment copy operation in the common case in which the copy is not mutated from its parent during its life-cycle. 86 106 87 This approach imposes some performance penalty on $combine$ if related environments are not properly linked together, as the entire environment needs to be combined rather than just the diff , but is correct as long as the ``null parent'' basecase is properly handled.107 This approach imposes some performance penalty on $combine$ if related environments are not properly linked together, as the entire environment needs to be combined rather than just the difference, but is correct as long as the ``null parent'' base-case is properly handled. 88 108 The life-cycle issues are somewhat more complex, as many environments may descend from a common parent, and all of these need their parent to stay alive for purposes of lookup. 89 These issues can be solved by ``flattening'' parent nodes into their children before the parent s leave scope, but given the tree structure of the inheritance graph it is more straightforward to store the parent nodes in reference-counted or otherwise automatically garbage-collected heap storage.109 These issues can be solved by ``flattening'' parent nodes into their children before the parent's scope ends, but given the tree structure of the inheritance graph it is more straightforward to store the parent nodes in reference-counted or otherwise automatically garbage-collected heap storage. 90 110 91 111 \subsection{Union-Find} \label{env-union-find-approach} 92 112 93 Given the nature of the classes of type variables as disjoint sets, another natural approach to implementing a type environment is the union-find disjoint set data structure\cite{Galler64}.113 Given the nature of the classes of type variables as disjoint sets, another natural approach to implementing a type environment is the union-find disjoint-set data-structure~\cite{Galler64}. 94 114 Union-find efficiently implements two operations over a partition of a collection of elements into disjoint sets; $find(x)$ locates the \emph{representative} of $x$, the element which canonically names its set, while $union(r, s)$ merges two sets represented by $r$ and $s$, respectively. 95 115 The union-find data structure is based on providing each element with a reference to its parent element, such that the root of a tree of elements is the representative of the set of elements contained in the tree. 96 116 $find$ is then implemented by a search up to the parent, generally combined with a \emph{path compression} step that links nodes more directly to their ancestors to speed up subsequent searches. 97 117 $union$ involves making the representative of one set a child of the representative of the other, generally employing a rank- or size-based heuristic to ensure that the tree remains somewhat balanced. 98 If both path compression and a balancing heuristic are employed, both $union$ and $find$ run in amortized $O(\alpha(n))$ worst-case time; this bound by the inverse Ackermann function is a small constant for all practical values of $n$.118 If both path compression and a balancing heuristic are employed, both $union$ and $find$ run in amortized $O(\alpha(n))$ worst-case time; this inverse Ackermann bound is a small constant for all practical values of $n$ \cite{Tarjan75}. 99 119 100 120 The union-find $find$ and $union$ operations have obvious applicability to the $find$ and $unify$ type environment operations in Table~\ref{env-op-table}, but the union-find data structure must be augmented to fully implement the type environment operations. 101 In particular, the type class bound cannot be easily included in the union-find data structure, as the requirement to make it the class representative breaks the balancing properties of $union$, and requires too-close integration of the type environment $unifyBound$ internal operation.102 This issue can be solved by including a side map from class representatives to the type class bound.103 If placeholder values are inserted in this map for type classes without bounds th an this also has the useful property that the key set of the map provides an easily obtainable list of all the class representatives, a list which cannot be derived from the union-find data structure without a linear search for class representatives through all elements.121 In particular, the type-class bound cannot be easily included in the union-find data structure, as the requirement to make it the class representative breaks the balancing properties of $union$, and requires too-close integration of the type environment $unifyBound$ internal operation. 122 This issue can be solved by including a side map from class representatives to the type-class bound. 123 If placeholder values are inserted in this map for type classes without bounds then this also has the useful property that the key set of the map provides an easily obtainable list of all the class representatives, a list which cannot be derived from the union-find data structure without a linear search for class representatives through all elements. 104 124 105 125 \subsection{Union-Find with Classes} \label{env-union-find-classes-approach} … … 107 127 Another type environment operation not supported directly by the union-find data structure is $report$, which lists the type variables in a given class, and similarly $split$, which reverts a $unify$ operation. 108 128 Since the union-find data structure stores only links from children to parents and not vice-versa, there is no way to reconstruct a class from one of its elements without a linear search over the entire data structure, with $find$ called on each element to check its membership in the class. 109 The situation is even worse for the $split$ operation, which would require extra information to maintain the order that each child was added to its parent node. 110 Unfortunately, the literature\cite{Tarjan84,Galil91,Patwary10} on union-find does not present a way to keep references to children without breaking the asymptotic time bounds of the algorithm; I have discovered a method to do so which, despite its simplicity, seems to be novel. 111 112 \TODO{port figure from slideshow} 129 The situation is even worse for the $split$ operation, which requires extra information to maintain the order that each child is added to its parent node. 130 Unfortunately, the literature \cite{Tarjan84,Galil91,Patwary10} on union-find does not present a way to keep references to children without breaking the asymptotic time bounds of the algorithm; I have discovered a method to do so, which, despite its simplicity, seems to be novel. 113 131 114 132 The core idea of this ``union-find with classes'' data structure and algorithm is to keep the members of each class stored in a circularly-linked list. … … 117 135 In my version, the list data structure does not affect the layout of the union-find tree, maintaining the same asymptotic bounds as union-find. 118 136 In more detail, each element is given a !next! pointer to another element in the same class; this !next! pointer initially points to the element itself. 119 When two classes are unified, the !next! pointers of the representatives of those classes are swapped, splicing the two circularly-linked lists together .137 When two classes are unified, the !next! pointers of the representatives of those classes are swapped, splicing the two circularly-linked lists together as illustrated in Figure~\ref{union-find-classes-fig}. 120 138 Importantly, though this approach requires an extra pointer per element, it does maintain the linear space bound of union-find, and because it only requires updating the two root nodes in $union$ it does not asymptotically increase runtime either. 121 139 The basic approach is compatible with all path-compression techniques, and allows the members of any class to be retrieved in time linear in the size of the class simply by following the !next! pointers from any element. 140 141 \begin{figure} 142 \centering 143 \includegraphics{figures/union-find-with-classes} 144 \caption[Union operation for union-find with classes.]{Union operation for union-find with classes. Solid lines indicate parent pointers, dashed lines are \lstinline{next} pointers.} 145 \label{union-find-classes-fig} 146 \end{figure} 122 147 123 148 If the path-compression optimization is abandoned, union-find with classes also encodes a reversible history of all the $union$ operations applied to a given class. … … 127 152 128 153 \begin{theorem} \label{env-reverse-thm} 129 The !next! pointer of a class representative in the union-find with classes algorithm without path compressionpoints to a leaf from the most-recently-added subtree.154 The !next! pointer of a class representative in the union-find with classes algorithm, without path compression, points to a leaf from the most-recently-added subtree. 130 155 \end{theorem} 131 156 … … 133 158 By induction on the height of the tree. \\ 134 159 \emph{Base case:} A height 1 tree by definition includes only a single item. In such a case, the representative's !next! pointer points to itself by construction, and the representative is the most-recently-added (and only) leaf in the tree. \\ 135 \emph{Inductive case:} By construction, a tree $T$ of height greater than 1 has children of the root (representative) node that were representative nodes of classes merged by $union$. By definition, the most-recently-added subtree $T'$ has a smaller height than $T$, thus by the inductive hypothesis before the most-recent $union$ operation the !next! pointer of the root of $T'$ pointed to one of the leaf nodes of $T'$; by construction the !next! pointer of the root of $T$ points to this leaf after the $union$ operation.160 \emph{Inductive case:} By construction, a tree $T$ of height greater than 1 has children of the root (representative) node that were representative nodes of classes merged by $union$. By definition, the most-recently-added subtree $T'$ has a smaller height than $T$, thus by the inductive hypothesis before the most-recent $union$ operation, the !next! pointer of the root of $T'$ pointed to one of the leaf nodes of $T'$; by construction the !next! pointer of the root of $T$ points to this leaf after the $union$ operation. 136 161 \end{proof} 137 162 … … 139 164 140 165 \subsection{Persistent Union-Find} 141 142 Given the backtracking nature of the resolution algorithm discussed in Section~\ref{env-defn-sec}, the abilities to quickly switch between related versions of a type environment and to de-duplicate shared data between environments are both assets to performance. 166 \label{env-persistent-union-find} 167 168 Given the backtracking nature of the resolution algorithm discussed in Section~\ref{env-defn-sec}, the abilities to quickly switch between related versions of a type environment and to de-duplicate shared data among environments are both assets to performance. 143 169 Conchon and Filli\^{a}tre~\cite{Conchon07} present a persistent union-find data structure based on the persistent array of Baker~\cite{Baker78,Baker91}. 144 170 145 \TODO{port figure from slideshow} 146 147 In Baker's persistent array, an array reference contains either a pointer to the array or a pointer to an \emph{edit node}; these edit nodes contain an array index, the value in that index, and another array reference pointing either to the array or a different edit node. 148 In this manner, a tree of edits is formed, rooted at the actual array. 149 Read from the actual array at the root can be performed in constant time, as with a non-persistent array. 171 In Baker's persistent array, an \emph{array reference} contains either a pointer to the array or a pointer to an \emph{edit node}; these edit nodes contain an array index, the value in that index, and another array reference pointing either to the array or a different edit node. 172 By construction, these array references always point to a node more like the actual array, forming a tree of edits rooted at the actual array. 173 Reads from the actual array at the root can be performed in constant time, as with a non-persistent array. 150 174 The persistent array can be mutated in constant time by directly modifying the underlying array, then replacing its array reference with an edit node containing the mutated index, the previous value at that index, and a reference to the mutated array. If the current array reference is not the root, mutation consists simply of constructing a new edit node encoding the change and referring to the current array reference. 151 The mutation algorithm at the root is in some sense a special case of the key operation on persistent arrays, $reroot$. 152 175 176 The mutation algorithm at the root is a special case of the key operation on persistent arrays, $reroot$. 153 177 A rerooting operation takes any array reference and makes it the root node of the array. 154 This is accomplished by tracing the path from some edit node to the root node of the array (always the underlying array), recursively applying the edits to the underlying array and replacing each edit node's successor with the inverse edit.178 This operation is accomplished by tracing the path from some edit node to actual array at the root node, recursively applying the edits to the underlying array and replacing each edit node's successor with the inverse edit. 155 179 In this way, any previous state of the persistent array can be restored in time proportional to the number of edits to the current state of the array. 156 While $reroot$ does maintain the same value mapping in every version of the persistent array, the internal mutations it performs means that it is not thread-safe, andmust be used behind a lock in a concurrent context.180 While $reroot$ does maintain the same value mapping in every version of the persistent array, the internal mutations it performs break thread-safety, and thus it must be used behind a lock in a concurrent context. 157 181 Also, the root node with the actual array may in principle be anywhere in the tree, and does not provide information to report its leaf nodes, so some form of automatic garbage collection is generally required for the data structure. 158 182 Since the graph of edit nodes is tree-structured, reference counting approaches suffice for garbage collection; Conchon and Filli\^{a}tre~\cite{Conchon07} also observe that if the only $reroot$ operations are for backtracking then the tail of inverse edit nodes may be elided, suggesting the possibility of stack-based memory management. 159 183 160 184 While Conchon and Filli\^{a}tre~\cite{Conchon07} implement their persistent union-find data structure over a universe of integer elements in the fixed range $[1,N]$, the type environment problem needs more flexibility. 161 In particular, an arbitrary number of type variables m ustbe added to the environment.162 As such, a persistent hash table is a more suitable structure than a persistent array, providing the same expected asymptotic time bounds while allowing a dynamic number of elements.163 Besides replacing the underlying array with a hash table, the other major change in this approach is to replace the two types of array references, !Array! and !Edit!, with four node types, !Table!, !Edit!, !Add!, and !Remove!, where !Add! adds a new key-value pair, !Remove! removes a key , and !Edit! mutates an existing key-value pair.164 In this variant of \CFACC{}, this persistent hash table is used as the side map discussed in Section~\ref{env-union-find-approach} for class bounds.185 In particular, an arbitrary number of type variables may be added to the environment. 186 As such, a persistent hash table is a more suitable structure than a persistent array, providing the same expected asymptotic time bounds, while allowing a dynamic number of elements. 187 Besides replacing the underlying array with a hash table, the other major change in this approach is to replace the two types of array references, !Array! and !Edit!, with four node types, !Table!, !Edit!, !Add!, and !Remove!, where !Add! adds a new key-value pair, !Remove! removes a key-value pair, and !Edit! mutates an existing key-value pair. 188 In this variant of \CFACC{}, this persistent hash-table is used as the side map discussed in Section~\ref{env-union-find-approach} for class bounds. 165 189 The actual union-find data structure is slightly modified from this approach, with a !Base! node containing the root union-find data structure, !Add! nodes adding new elements, !AddTo! nodes defining the union of two type classes, and !Remove! and !RemoveFrom! nodes as inverses of the previous two elements, for purposes of maintaining the edit list. 166 Making !AddTo! and !RemoveFrom! single nodes shortens the edit path for improved performance, while also providing semantic information missing from the raw array updates in Conchon and Filli\^{a}tre's data structure. 167 The single-node approach, does, however, break under most path-compression algorithms; !RemoveFrom! can be applied to the underlying data structure using the ``leaf of last union'' approach discussed in in Section~\ref{env-union-find-classes-approach}; this was judged an acceptable trade-off for the added semantic information and shortened paths. 168 169 Maintaining explicit information on $union$ operations in the persistent union-find edit tree in the form of !AddTo! and !RemoveFrom! nodes exposes a new option for combining type environments. 190 Figure~\ref{persistent-union-find-fig} demonstrates the structure of a simple example. 191 Making !AddTo! and !RemoveFrom! single nodes provides semantic information missing from the raw array updates in Conchon and Filli\^{a}tre's data structure. 192 !RemoveFrom! is implemented using the ``leaf of last union'' approach discussed in Section~\ref{env-union-find-classes-approach}; this does, however, preclude the use of path-compression algorithms in this persistent union-find data structure. 193 194 \begin{figure} 195 \centering 196 \includegraphics{figures/persistent-union-find} 197 \caption[Persistent union-find data structure.]{Persistent union-find data structure. Shows the edit nodes to reverse back to an empty structure.} 198 \label{persistent-union-find-fig} 199 \end{figure} 200 201 This added semantic information on $union$ operations in the persistent union-find edit tree exposes a new option for combining type environments. 170 202 If the type environments are part of the same edit tree, one environment $T'$ can be combined with another $T$ by only testing the edits on the path from $T'$ to $T$ in both the persistent union-find data structure describing the classes and the persistent hash table containing the class bounds. 171 This is generally more efficient than testing the compatibility of all type classes in $T'$, as only those that are actually different than those in $T$ must be considered. 203 This approach is generally more efficient than testing the compatibility of all type classes in $T'$, as only those that are actually different than those in $T$ must be considered. 204 However, the improved performance comes at the cost of some flexibility, as the edit-tree link must be maintained between any two environments to be combined under this algorithm. 172 205 173 206 The procedure for $combine(T, T')$ based on edit paths is as follows: 174 207 The shared edit trees for classes and bindings are rerooted at $T$, and the path from $T'$ to $T$ is followed to create a list of actual edits. 175 208 By tracking the state of each element, redundant changes such as an !Edit! followed by an !Edit! can be reduced to their form in $T'$ by dropping the later (more like $T$) !Edit! for the same key; !Add! and !Remove! cancel similarly. 176 This procedure is repeated for both the class edit tree and the binding edit tree. 177 When the list of net changes to the environment has been produced, the additive changes are applied to $T$. 178 For example, if a type class exists in $T'$ but not $T$, the corresponding !Add! edit will be applied to $T$, but in the reverse situation the !Remove! edit will not be applied to $T$, as the intention is to produce a new environment representing the union of the two sets of type classes; similarly, !AddTo! edits are applied to unify type-classes in $T$ that are united in $T'$, but !RemoveFrom! edits that split type classes are not. 179 The new environment, $T''$ can always be constructed with a consistent partitioning of type variables; in the extreme case, all variables from both $T$ and $T'$ will be united in a single type class in $T''$. 180 Where $combine$ can fail is in unifying the bound types; if any class in $T'$ has a class bound which does not unify with the merged class in $T''$ than $combine$ fails. 181 182 \section{Analysis} 183 184 In this section I present asymptotic analyses of the various approaches to a type environment data structure discussed in the previous section. 209 This procedure is repeated for both the class edit-tree and the binding edit-tree. 210 When the list of net changes to the environment is produced, the additive changes are applied to $T$. 211 For example, if a type class exists in $T'$ but not $T$, the corresponding !Add! edit is applied to $T$, but in the reverse situation the !Remove! edit is not applied to $T$, as the intention is to produce a new environment representing the union of the two sets of type classes; similarly, !AddTo! edits are applied to unify type-classes in $T$ that are united in $T'$, but !RemoveFrom! edits that split type classes are not. 212 A new environment, $T''$, can always be constructed with a consistent partitioning of type variables; in the extreme case, all variables from both $T$ and $T'$ are united in a single type class in $T''$. 213 $combine$ can fail to unify the bound types; if any class in $T'$ has a class bound that does not unify with the merged class in $T''$, then $combine$ fails. 214 215 \section{Analysis} \label{env-analysis-sec} 216 217 In this section, I present asymptotic analyses of the various approaches to the type environment data structure discussed in the previous section. 218 My results are summarized in Table~\ref{env-bounds-table}; in all cases, $n$ is the number of type classes, $m$ is the maximum size of a type class, and $p$ the number of edits between two environments or one environment and the empty environment. 219 $u(n)$ captures the recursive cost of class unification, which is kept separate so that the $O(n)$ number of recursive class unifications can be distinguished from the direct cost of each recursive step. 185 220 186 221 \begin{table} … … 190 225 \begin{tabular}{rllll} 191 226 \hline 192 & \textbf{Na\"{\i}ve} & \textbf{Incremental} & \textbf{Union-Find} & \textbf{U-F with Classes} \\ 193 \hline 194 $find$ & $O(n)$ & $O(p)$ & $O(\alpha(m))$ & $O(\log m)$ \\ 195 $report$ & $O(m)$ & $O(m)$ & $O(n \log m)$ & $O(m)$ \\ 196 $bound$ & $O(1)$ & $O(1)$ & $O(1)$ & $O(1)$ \\ 197 $insert$ & $O(1)$ & $O(1)$ & $O(1)$ & $O(1)$ \\ 198 $add$ & $O(1)$ & $O(1)$ & $O(1)$ & $O(1)$ \\ 199 $bind$ & $O(1)$ & $O(1)$ & $O(1)$ & $O(1)$ \\ 200 $unify$ & $O(m + u(n))$ & $O(m + u(n))$ & $O(\log m + u(n))$ & $O(\log m + u(n))$ \\ 201 $split$ & --- & --- & --- & $O(\log m)$ \\ 202 $combine$ & $O(nm \cdot u(n))$ & $O(pm \cdot u(n))$ & $O(n \log m \cdot u(n))$ & $O(p \log m \cdot u(n))$ \\ 203 $save$ & $O(nm)$ & $O(1)$ & $O(nm)$ & $O(1)$ \\ 204 $backtrack$ & $O(nm)$ & $O(pm)$ & $O(nm)$ & $O(p)$ \\ 227 & \textbf{Na\"{\i}ve} & \textbf{Incremental} & \textbf{Union-Find} & \textbf{Persistent U-F} \\ 228 \hline 229 $find$ & $O(n)$ & $O(p)$ & $O(\alpha(m))$ & $O(\log m)$ \\ 230 $report$ & $O(m)$ & $O(m)$ & $O(nm\alpha(m))$ & $O(m)$ \\ 231 $bound$ & $O(1)$ & $O(1)$ & $O(1)$ & $O(1)$ \\ 232 $insert$ & $O(1)$ & $O(1)$ & $O(1)$ & $O(1)$ \\ 233 $add$ & $O(1)$ & $O(m)$ & $O(1)$ & $O(1)$ \\ 234 $bind$ & $O(1)$ & $O(1)$ & $O(1)$ & $O(1)$ \\ 235 $unify$ & $O(m + u(n))$ & $O(m + u(n))$ & $O(1 + u(n))$ & $O(1 + u(n))$ \\ 236 $split$ & --- & --- & --- & $O(\log m)$ \\ 237 $combine$ & $O(n^2m $ & $O(p^2m $ & $O(nm\alpha(m) $ & $O(p \log m $ \\ 238 & $~~~+ nu(n))$ & $~~~+ pu(n))$ & $~~~+ nu(n))$ & $~~~+ pu(n))$ \\ 239 $save$ & $O(nm)$ & $O(1)$ & $O(nm)$ & $O(1)$ \\ 240 $backtrack$ & $O(nm)$ & $O(pm)$ & $O(nm)$ & $O(p)$ \\ 205 241 \hline 206 242 \end{tabular} 207 243 \end{table} 208 244 209 % Future work: design multi-threaded version of C&F persistent map --- core idea is some sort of thread-boundary edit node 245 \subsection{Na\"{\i}ve and Incremental} 246 \label{naive-incremental-analysis} 247 248 The na\"{\i}ve type environment data structure does not have an environment-wide index for type variables, but does have an index for each type class, assumed to be hash-based here. 249 As a result, every class's index must be consulted for a $find$ operation, at an overall cost of $O(n)$. 250 The incremental variant builds an overall hash-based index as it is queried, but may need to recursively check its parent environments if its local index does not contain a type variable, and may have as many parents as times it has been modified, for cost $O(p)$. 251 It should be noted that subsequent queries for the same variable execute in constant time. 252 253 Since both na\"{\i}ve and incremental variants store complete type classes, the cost of a $report$ operation is simply the time needed to output the contained variables, $O(m)$. 254 Since the type classes store their bounds, $bound$ and $bind$ are both $O(1)$ given a type class. 255 Once a $find$ operation has already been performed to verify that a type variable does not exist in the environment, the data structures for both these variants support adding new type classes (the $insert$ operation) in $O(1)$. 256 Adding a variable to a type class (the $add$ operation) can be done in $O(1)$ for the na\"{\i}ve implementation, but the incremental implementation may need to copy the edited type class from a parent at cost $O(m)$. 257 258 The linear storage of type classes in both variants also leads to $O(m)$ time for the variable-merging step in $unify$, plus the usual $u(n)$ recursion term for $unifyBound$. 259 The na\"{\i}ve $combine$ operation must traverse each of the classes of one environment, merging in any class of the other environment that shares a type variable. 260 Since there are at most $n$ classes to unify, the unification cost is $O(nm + nu(n))$, while traversal and $find$ costs to locate classes to merge total $O(n^2m)$, for an overall cost of $O(n^2m + nu(n))$. 261 The incremental $combine$ operation works similarly, but only needs to consider classes modified in either environment with respect to the common ancestor of both environments, allowing the $n$ cost terms to be substituted for $p$, for an overall cost of $O(p^2m + pu(n))$. 262 Neither variant supports the $split$ operation to undo a $unify$. 263 264 The na\"{\i}ve environment does nothing to support $save$ and $backtrack$, so these operations must be implemented by making a deep copy of the environment on $save$, then a destructive overwrite on $backtrack$, each at a cost of $O(nm)$. 265 The incremental environment supports $O(1)$ $save$ by simply setting aside a reference to the current environment, then proceeding with a new, empty environment with the former environment as a parent. 266 $backtrack$ to a parent environment may involve destroying all the intermediate environments if this backtrack removes the last reference to the backtracked-from environment; this cost is $O(pm)$. 267 268 \subsection{Union-Find} 269 270 The union-find data structure is designed to support $find$ efficiently, and thus for any variant, the cost is simply the distance up the tree to the representative element. 271 For basic union-find, this is amortized to the inverse Ackermann function, $O(\alpha(m))$, essentially a small constant, though the loss of path compression in persistent union-find raises this cost to $O(\log m)$. 272 Basic union-find is not designed to support the $report$ operation, however, so it must be simulated by checking the representative of every type variable, at cost $O(nm\alpha(m))$. 273 Persistent union-find, on the other hand, uses the ``with classes'' extension to union-find described in Section~\ref{env-union-find-classes-approach} to run $report$ in $O(m)$ time. 274 275 All union-find environment variants described here use a secondary hash table to map from class representatives to bindings, and as such can perform $bound$ and $bind$ in $O(1)$, given the representative. 276 $insert$ is also a $O(1)$ operation for both basic and persistent union-find. 277 Since $add$ simply involves attaching a new child to the class root, it is also a $O(1)$ operation for all union-find environment variants. 278 279 Union-find is also designed to support $unify$ in constant time, and as such, given class representatives, the variable-merging cost of $unify$ for both variants is $O(1)$ to make one representative the child of the other, plus the $O(u(n))$ term for $unifyBound$. 280 Basic union-find does not support $split$, but persistent union-find can accomplish it using the mechanism described in Section~\ref{env-union-find-classes-approach} in $O(\log m)$, the cost of traversing up to the root of a class from a leaf without path compression. 281 $combine$ on the basic union-find data structure works similarly to the data structures discussed above in Section~\ref{naive-incremental-analysis}, with a $O(nu(n))$ term for the $O(n)$ underlying $unify$ operations, and a $O(n\alpha(m))$ term to find the classes which need unification by checking the class representatives of each corresponding type variable in both environments for equality. 282 Persistent union-find uses a different approach for $combine$, discussed in Section~\ref{env-persistent-union-find}. 283 Discounting recursive $unify$ operations included in the $u(n)$ $unifyBound$ term, there may be at most $O(p)$ $unify$ operations performed, at cost $O(pu(n))$. 284 Each of the $O(p)$ steps on the edit path can be processed in the $O(\log m)$ time it takes to find the current representative of the modified type class, for a total runtime of $O(p \log m + pu(n))$. 285 286 In terms of backtracking operations, the basic union-find data structure only supports deep copies, for $O(nm)$ cost for both $save$ and $backtrack$. 287 Persistent union-find, as the name suggests, is more optimized, with $O(1)$ cost to $save$ a backtrack-capable reference to the current environment state, and $O(p)$ cost to revert to that state (possibly destroying no-longer-used edit nodes along the path). 288 289 \section{Conclusion \& Future Work} 290 291 This chapter presents the type environment abstract data type, some type-environment data-structures optimized for workloads encountered in the expression resolution problem, and asymptotic analysis of each data structure. 292 Chapter~\ref{expr-chap} provides experimental performance results for a representative set of these approaches. 293 One contribution of this thesis is the union-find with classes data structure for efficient retrieval of union-find class members, along with a related algorithm for reversing the history of $union$ operations in this data structure. 294 This reversible history contributes to the second novel contribution of this chapter, a type environment data structure based off the persistent union-find data structure of Conchon and Filli\^{a}tre~\cite{Conchon07}. 295 This persistent union-find environment uses the $split$ operation introduced in union-find with classes and the edit history of the persistent data structure to support an environment-combining algorithm that only considers the edits between the environments to be merged. 296 297 This persistent union-find data structure is efficient, but not thread-safe; as suggested in Section~\ref{resn-conclusion-sec}, it may be valuable to parallelize the \CFA{} expression resolver. 298 However, allowing multiple threads concurrent access to the persistent data structure is likely to result in ``reroot thrashing'', as different threads reroot the data structure to their own versions of interest. 299 This contention could be mitigated by partitioning the data structure into separate subtrees for each thread, with each subtree having its own root node, and the boundaries among them implemented with a lock-equipped !ThreadBoundary! edit node. 300 Alternatively, the concurrent hash trie of Prokopec \etal{} \cite{Prokopec11,Prokopec12} may be a useful hash-table replacement. -
doc/user/user.tex
r6a9d4b4 r933f32f 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Tue Dec 11 23:19:26 201814 %% Update Count : 34 0013 %% Last Modified On : Sun May 5 18:24:50 2019 14 %% Update Count : 3489 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 193 193 \end{center} 194 194 While the \CFA I/O looks similar to the \Index*[C++]{\CC{}} output style, there are important differences, such as automatic spacing between variables as in \Index*{Python} (see~\VRef{s:IOLibrary}). 195 195 196 196 197 \subsection{Background} … … 432 433 which conditionally includes the correct header file, if the program is compiled using \Indexc{gcc} or \Indexc{cfa}. 433 434 435 The \CFA translator has multiple steps. 436 The following flags control how the tranlator works, the stages run, and printing within a stage. 437 The majority of these flags are used by \CFA developers, but some are occasionally useful to programmers. 438 \begin{description}[topsep=5pt,itemsep=0pt,parsep=0pt] 439 \item 440 \Indexc{-h}\index{translator option!-h@{©-h©}}, \Indexc{--help}\index{translator option!--help@{©--help©}} \, print help message 441 \item 442 \Indexc{-l}\index{translator option!-l@{©-l©}}, \Indexc{--libcfa}\index{translator option!--libcfa@{©--libcfa©}} \, generate libcfa.c 443 \item 444 \Indexc{-L}\index{translator option!-L@{©-L©}}, \Indexc{--linemarks}\index{translator option!--linemarks@{©--linemarks©}} \, generate line marks 445 \item 446 \Indexc{-m}\index{translator option!-m@{©-m©}}, \Indexc{--no-main}\index{translator option!--no-main@{©--no-main©}} \, do not replace main 447 \item 448 \Indexc{-N}\index{translator option!-N@{©-N©}}, \Indexc{--no-linemarks}\index{translator option!--no-linemarks@{©--no-linemarks©}} \, do not generate line marks 449 \item 450 \Indexc{-n}\index{translator option!-n@{©-n©}}, \Indexc{--no-prelude}\index{translator option!--no-prelude@{©--no-prelude©}} \, do not read prelude 451 \item 452 \Indexc{-p}\index{translator option!-p@{©-p©}}, \Indexc{--prototypes}\index{translator option!--prototypes@{©--prototypes©}} \, generate prototypes for prelude functions 453 \item 454 \Indexc{-P}\index{translator option!-P@{©-P©}}, \Indexc{--print}\index{translator option!--print@{©--print©}} \, one of: 455 \begin{description}[topsep=0pt,itemsep=0pt,parsep=0pt] 456 \item 457 \Indexc{altexpr}\index{translator option!-P@{©-P©}!©altexpr©}\index{translator option!--print@{©-print©}!©altexpr©} \, alternatives for expressions 458 \item 459 \Indexc{ascodegen}\index{translator option!-P@{©-P©}!©ascodegen©}\index{translator option!--print@{©-print©}!©ascodegen©} \, as codegen rather than AST 460 \item 461 \Indexc{ast}\index{translator option!-P@{©-P©}!©ast©}\index{translator option!--print@{©-print©}!©ast©} \, AST after parsing 462 \item 463 \Indexc{astdecl}\index{translator option!-P@{©-P©}!©astdecl©}\index{translator option!--print@{©-print©}!©astdecl©} \, AST after declaration validation pass 464 \item 465 \Indexc{asterr}\index{translator option!-P@{©-P©}!©asterr©}\index{translator option!--print@{©-print©}!©asterr©} \, AST on error 466 \item 467 \Indexc{astexpr}\index{translator option!-P@{©-P©}!©astexpr©}\index{translator option!--print@{©-print©}!©altexpr©} \, AST after expression analysis 468 \item 469 \Indexc{astgen}\index{translator option!-P@{©-P©}!©astgen©}\index{translator option!--print@{©-print©}!©astgen©} \, AST after instantiate generics 470 \item 471 \Indexc{box}\index{translator option!-P@{©-P©}!©box©}\index{translator option!--print@{©-print©}!©box©} \, before box step 472 \item 473 \Indexc{ctordtor}\index{translator option!-P@{©-P©}!©ctordtor©}\index{translator option!--print@{©-print©}!©ctordtor©} \, after ctor/dtor are replaced 474 \item 475 \Indexc{codegen}\index{translator option!-P@{©-P©}!©codegen©}\index{translator option!--print@{©-print©}!©codegen©} \, before code generation 476 \item 477 \Indexc{declstats}\index{translator option!-P@{©-P©}!©declstats©}\index{translator option!--print@{©-print©}!©declstats©} \, code property statistics 478 \item 479 \Indexc{parse}\index{translator option!-P@{©-P©}!©parse©}\index{translator option!--print@{©-print©}!©parse©} \, yacc (parsing) debug information 480 \item 481 \Indexc{pretty}\index{translator option!-P@{©-P©}!©pretty©}\index{translator option!--print@{©-print©}!©pretty©} \, prettyprint for ascodegen flag 482 \item 483 \Indexc{resolver}\index{translator option!-P@{©-P©}!©resolver©}\index{translator option!--print@{©-print©}!©resolver©} \, before resolver step 484 \item 485 \Indexc{rproto}\index{translator option!-P@{©-P©}!©rproto©}\index{translator option!--print@{©-print©}!©rproto©} \, resolver-proto instance 486 \item 487 \Indexc{rsteps}\index{translator option!-P@{©-P©}!©rsteps©}\index{translator option!--print@{©-print©}!©rsteps©} \, resolver steps 488 \item 489 \Indexc{symevt}\index{translator option!-P@{©-P©}!©symevt©}\index{translator option!--print@{©-print©}!©symevt©} \, symbol table events 490 \item 491 \Indexc{tree}\index{translator option!-P@{©-P©}!©tree©}\index{translator option!--print@{©-print©}!©tree©} \, parse tree 492 \item 493 \Indexc{tuple}\index{translator option!-P@{©-P©}!©tuple©}\index{translator option!--print@{©-print©}!©tuple©} \, after tuple expansion 494 \end{description} 495 \item 496 \Indexc{--prelude-dir} <directory> \, prelude directory for debug/nodebug 497 \item 498 \Indexc{-S}\index{translator option!-S@{©-S©}!©counters,heap,time,all,none©}, \Indexc{--statistics}\index{translator option!--statistics@{©--statistics©}!©counters,heap,time,all,none©} <option-list> \, enable profiling information: 499 \begin{description}[topsep=0pt,itemsep=0pt,parsep=0pt] 500 \item 501 \Indexc{counters,heap,time,all,none} 502 \end{description} 503 \item 504 \Indexc{-t}\index{translator option!-t@{©-t©}}, \Indexc{--tree}\index{translator option!--tree@{©--tree©}} build in tree 505 \end{description} 506 434 507 435 508 \section{Backquote Identifiers} … … 508 581 509 582 As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types. 510 Unsigned integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the base is 2). 511 Signed integral exponentiation\index{exponentiation!signed integral} is performed with repeated multiplication (or shifting if the base is 2), but yields a floating result because $x^{-y}=1/x^y$. 512 Hence, it is important to designate exponent integral-constants as unsigned or signed: ©3 \ 3u© return an integral result, while ©3 \ 3© returns a floating result. 513 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the base cannot be negative. 514 \begin{cfa} 515 sout | 2 ®\® 8u | 4 ®\® 3u | -4 ®\® 3u | 4 ®\® -3 | -4 ®\® -3 | 4.0 ®\® 2.1 | (1.0f+2.0fi) ®\® (3.0f+2.0fi); 516 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i 517 \end{cfa} 583 Integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the exponent is 2). 584 Overflow from large exponents or negative exponents return zero. 585 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative. 586 \begin{cfa} 587 sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\® 2.1 588 | (1.0f+2.0fi) ®\® (3.0f+2.0fi); 589 1 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i 590 \end{cfa} 591 Note, ©5 ®\® 32© and ©5L ®\® 64© overflow, and ©-4 ®\® -3© is a fraction but stored in an integer so all three computations generate an integral zero. 518 592 Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©. 519 The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation versions are available. 520 For returning an integral value, the user type ©T© must define multiplication, ©*©, and one, ©1©; 521 for returning a floating value, an additional divide of type ©T© into a ©double© returning a ©double© (©double ?/?( double, T )©) is necessary for negative exponents. 593 The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation version is available. 594 \begin{cfa} 595 forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) 596 OT ?®\®?( OT ep, unsigned int y ); 597 forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) 598 OT ?®\®?( OT ep, unsigned long int y ); 599 \end{cfa} 600 The user type ©T© must define multiplication, one, ©1©, and, ©*©. 522 601 523 602 … … 549 628 \subsection{Loop Control} 550 629 551 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges. 630 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}). 631 \begin{itemize} 632 \item 552 633 An empty conditional implies ©1©. 553 The up-to range ©~©\index{~@©~©} means exclusive range [M,N); 554 the up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N]. 555 The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M); 556 the down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M]. 634 \item 635 The up-to range ©~©\index{~@©~©} means exclusive range [M,N). 636 \item 637 The up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N]. 638 \item 639 The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M). 640 \item 641 The down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M]. 642 \item 643 ©@© means put nothing in this field. 644 \item 557 645 ©0© is the implicit start value; 646 \item 558 647 ©1© is the implicit increment value. 648 \item 559 649 The up-to range uses ©+=© for increment; 560 the down-to range uses ©-=© for decrement. 650 \item 651 The down-to range uses ©-=© for decrement. 652 \item 561 653 The loop index is polymorphic in the type of the start value or comparison value when start is implicitly ©0©. 654 \end{itemize} 655 656 \begin{figure} 562 657 \begin{cquote} 563 \begin{tabular}{@{}l l|l@{}}564 \multicolumn{ 2}{c|}{loop control} & \multicolumn{1}{c}{output} \\658 \begin{tabular}{@{}l|l@{}} 659 \multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\ 565 660 \hline 566 661 \begin{cfa} 567 while ®()® { sout | "empty"; break; } 568 do { sout | "empty"; break; } while ®()®; 569 for ®()® { sout | "empty"; break; } 570 for ( ®0® ) { sout | "A"; } 571 for ( ®1® ) { sout | "A"; } 572 for ( ®10® ) { sout | "A"; } 573 for ( ®1 ~= 10 ~ 2® ) { sout | "B"; } 574 for ( ®10 -~= 1 ~ 2® ) { sout | "C"; } 575 for ( ®0.5 ~ 5.5® ) { sout | "D"; } 576 for ( ®5.5 -~ 0.5® ) { sout | "E"; } 577 for ( ®i; 10® ) { sout | i; } 578 for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; } 579 for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; } 580 for ( ®i; 0.5 ~ 5.5® ) { sout | i; } 581 for ( ®i; 5.5 -~ 0.5® ) { sout | i; } 582 for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; } 583 for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; } 662 sout | nlOff; 663 while ®()® { sout | "empty"; break; } sout | nl; 664 do { sout | "empty"; break; } while ®()®; sout | nl; 665 for ®()® { sout | "empty"; break; } sout | nl; 666 for ( ®0® ) { sout | "A"; } sout | "zero" | nl; 667 for ( ®1® ) { sout | "A"; } sout | nl; 668 for ( ®10® ) { sout | "A"; } sout | nl; 669 for ( ®1 ~= 10 ~ 2® ) { sout | "B"; } sout | nl; 670 for ( ®10 -~= 1 ~ 2® ) { sout | "C"; } sout | nl; 671 for ( ®0.5 ~ 5.5® ) { sout | "D"; } sout | nl; 672 for ( ®5.5 -~ 0.5® ) { sout | "E"; } sout | nl; 673 for ( ®i; 10® ) { sout | i; } sout | nl; 674 for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; } sout | nl; 675 for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; } sout | nl; 676 for ( ®i; 0.5 ~ 5.5® ) { sout | i; } sout | nl; 677 for ( ®i; 5.5 -~ 0.5® ) { sout | i; } sout | nl; 678 for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; } sout | nl; 679 for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; } sout | nl; 584 680 enum { N = 10 }; 585 for ( ®N® ) { sout | "N"; } 586 for ( ®i; N® ) { sout | i; } 587 for ( ®i; N -~ 0® ) { sout | i; } 681 for ( ®N® ) { sout | "N"; } sout | nl; 682 for ( ®i; N® ) { sout | i; } sout | nl; 683 for ( ®i; N -~ 0® ) { sout | i; } sout | nl; 588 684 const int start = 3, comp = 10, inc = 2; 589 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } 685 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } sout | nl; 686 for ( ®i; 1 ~ @® ) { if ( i > 10 ) break; 687 sout | i; } sout | nl; 688 for ( ®i; 10 -~ @® ) { if ( i < 0 ) break; 689 sout | i; } sout | nl; 690 for ( ®i; 2 ~ @ ~ 2® ) { if ( i > 10 ) break; 691 sout | i; } sout | nl; 692 for ( ®i; 2.1 ~ @ ~ @® ) { if ( i > 10.5 ) break; 693 sout | i; i += 1.7; } sout | nl; 694 for ( ®i; 10 -~ @ ~ 2® ) { if ( i < 0 ) break; 695 sout | i; } sout | nl; 696 for ( ®i; 12.1 ~ @ ~ @® ) { if ( i < 2.5 ) break; 697 sout | i; i -= 1.7; } sout | nl; 698 for ( ®i; 5 : j; -5 ~ @® ) { sout | i | j; } sout | nl; 699 for ( ®i; 5 : j; -5 -~ @® ) { sout | i | j; } sout | nl; 700 for ( ®i; 5 : j; -5 ~ @ ~ 2® ) { sout | i | j; } sout | nl; 701 for ( ®i; 5 : j; -5 -~ @ ~ 2® ) { sout | i | j; } sout | nl; 702 for ( ®j; -5 ~ @ : i; 5® ) { sout | i | j; } sout | nl; 703 for ( ®j; -5 -~ @ : i; 5® ) { sout | i | j; } sout | nl; 704 for ( ®j; -5 ~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl; 705 for ( ®j; -5 -~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl; 706 for ( ®j; -5 -~ @ ~ 2 : i; 5 : k; 1.5 ~ @® ) { 707 sout | i | j | k; } sout | nl; 708 for ( ®j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 5® ) { 709 sout | i | j | k; } sout | nl; 710 for ( ®k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 5® ) { 711 sout | i | j | k; } sout | nl; 590 712 \end{cfa} 591 713 & 592 714 \begin{cfa} 593 sout | nl; 594 sout | nl; 595 sout | nl; 596 sout | "zero" | nl; 597 sout | nl; 598 sout | nl; 599 sout | nl; 600 sout | nl; 601 sout | nl; 602 sout | nl; 603 sout | nl; 604 sout | nl; 605 sout | nl; 606 sout | nl; 607 sout | nl; 608 sout | nl; 609 sout | nl | nl; 610 611 sout | nl; 612 sout | nl; 613 sout | nl | nl; 614 615 sout | nl; 616 \end{cfa} 617 & 618 \begin{cfa} 715 619 716 empty 620 717 empty … … 640 737 641 738 3 6 9 739 740 1 2 3 4 5 6 7 8 9 10 741 742 10 9 8 7 6 5 4 3 2 1 0 743 744 2 4 6 8 10 745 746 2.1 3.8 5.5 7.2 8.9 747 748 10 8 6 4 2 0 749 750 12.1 10.4 8.7 7 5.3 3.6 751 0 -5 1 -4 2 -3 3 -2 4 -1 752 0 -5 1 -6 2 -7 3 -8 4 -9 753 0 -5 1 -3 2 -1 3 1 4 3 754 0 -5 1 -7 2 -9 3 -11 4 -13 755 0 -5 1 -4 2 -3 3 -2 4 -1 756 0 -5 1 -6 2 -7 3 -8 4 -9 757 0 -5 1 -3 2 -1 3 1 4 3 758 0 -5 1 -7 2 -9 3 -11 4 -13 759 760 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 761 762 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 763 764 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 642 765 \end{cfa} 643 766 \end{tabular} 644 767 \end{cquote} 768 \caption{Loop Control Examples} 769 \label{f:LoopControlExamples} 770 \end{figure} 645 771 646 772 … … 1320 1446 \end{cfa} 1321 1447 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}). 1322 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice. 1448 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise: 1449 \begin{quote} 1450 In spite of its difficulties, I believe that the C's approach to declarations remains plausible, and am comfortable with it; it is a useful unifying principle.~\cite[p.~12]{Ritchie93} 1451 \end{quote} 1323 1452 1324 1453 \CFA provides its own type, variable and routine declarations, using a different syntax. -
driver/Makefile.am
r6a9d4b4 r933f32f 19 19 20 20 # applies to both programs 21 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src 21 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src -I${abs_top_srcdir}/src/include 22 22 23 23 # don't install cfa directly -
driver/Makefile.in
r6a9d4b4 r933f32f 187 187 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 188 188 ACLOCAL = @ACLOCAL@ 189 ALLOCA = @ALLOCA@190 189 AMTAR = @AMTAR@ 191 190 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 335 334 336 335 # applies to both programs 337 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src 336 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src -I${abs_top_srcdir}/src/include 338 337 cfa_SOURCES = cfa.cc 339 338 -
driver/cfa.cc
r6a9d4b4 r933f32f 10 10 // Created On : Tue Aug 20 13:44:49 2002 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jan 15 20:56:03201913 // Update Count : 28 012 // Last Modified On : Sun Feb 10 08:28:09 2019 13 // Update Count : 281 14 14 // 15 15 … … 107 107 bool link = true; // linking as well as compiling 108 108 bool verbose = false; // -v flag 109 bool quiet = false; // -quiet flag 110 bool debug = true; // -debug flag 111 bool help = false; // -help flag 109 bool quiet = false; // -quiet flag 110 bool debug = true; // -debug flag 111 bool nolib = false; // -nolib flag 112 bool help = false; // -help flag 112 113 bool CFA_flag = false; // -CFA flag 113 114 bool cpp_flag = false; // -E or -M flag, preprocessor only … … 162 163 debug = true; // strip the debug flag 163 164 } else if ( arg == "-nodebug" ) { 164 debug = false; // strip the nodebug flag 165 debug = false; // strip the debug flag 166 } else if ( arg == "-nolib" ) { 167 nolib = true; // strip the nodebug flag 165 168 } else if ( arg == "-quiet" ) { 166 169 quiet = true; // strip the quiet flag … … 366 369 } // if 367 370 } // if 368 const char * config = debug ? "debug": "nodebug";371 const char * config = nolib ? "nolib" : (debug ? "debug": "nodebug"); 369 372 string libdir = libbase + arch + "-" + config; 370 373 371 if ( ! dirExists( libdir ) ) {374 if ( ! nolib && ! dirExists( libdir ) ) { 372 375 cerr << argv[0] << " internal error, configuration " << config << " not installed." << endl; 373 376 cerr << "Was looking for " << libdir << endl; … … 495 498 args[nargs] = "-Wno-deprecated"; 496 499 nargs += 1; 500 #ifdef HAVE_CAST_FUNCTION_TYPE 501 args[nargs] = "-Wno-cast-function-type"; 502 nargs += 1; 503 #endif // HAVE_CAST_FUNCTION_TYPE 497 504 if ( ! std_flag ) { // default c11, if none specified 498 505 args[nargs] = "-std=gnu11"; -
libcfa/configure
r6a9d4b4 r933f32f 2382 2382 2383 2383 2384 # http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m4 2385 2384 2386 2385 2387 am__api_version='1.15' … … 2957 2959 case $CONFIGURATION in 2958 2960 "debug" ) 2959 CONFIG_CFLAGS="-O 0-g"2961 CONFIG_CFLAGS="-Og -g" 2960 2962 CONFIG_CFAFLAGS="-debug" 2961 2963 CONFIG_BUILDLIB="yes" 2962 2964 ;; 2963 2965 "nodebug" ) 2964 CONFIG_CFLAGS="-O 2-s"2966 CONFIG_CFLAGS="-O3 -s" 2965 2967 CONFIG_CFAFLAGS="-nodebug" 2966 2968 CONFIG_BUILDLIB="yes" 2967 2969 ;; 2968 2970 "nolib" ) 2969 CONFIG_CFLAGS="-O2 -s" 2971 CONFIG_CFLAGS="-O3 -s" 2972 CONFIG_CFAFLAGS="-nolib" 2973 CONFIG_BUILDLIB="no" 2974 ;; 2975 "profile" ) 2976 CONFIG_CFLAGS="-O3 -g -fno-omit-frame-pointer" 2970 2977 CONFIG_CFAFLAGS="-nodebug" 2971 CONFIG_BUILDLIB=" no"2978 CONFIG_BUILDLIB="yes" 2972 2979 ;; 2973 2980 *) … … 2975 2982 ;; 2976 2983 esac 2984 2985 CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}" 2977 2986 2978 2987 -
libcfa/configure.ac
r6a9d4b4 r933f32f 45 45 case $CONFIGURATION in 46 46 "debug" ) 47 CONFIG_CFLAGS="-O 0-g"47 CONFIG_CFLAGS="-Og -g" 48 48 CONFIG_CFAFLAGS="-debug" 49 49 CONFIG_BUILDLIB="yes" 50 50 ;; 51 51 "nodebug" ) 52 CONFIG_CFLAGS="-O 2-s"52 CONFIG_CFLAGS="-O3 -s" 53 53 CONFIG_CFAFLAGS="-nodebug" 54 54 CONFIG_BUILDLIB="yes" 55 55 ;; 56 56 "nolib" ) 57 CONFIG_CFLAGS="-O2 -s" 57 CONFIG_CFLAGS="-O3 -s" 58 CONFIG_CFAFLAGS="-nolib" 59 CONFIG_BUILDLIB="no" 60 ;; 61 "profile" ) 62 CONFIG_CFLAGS="-O3 -g -fno-omit-frame-pointer" 58 63 CONFIG_CFAFLAGS="-nodebug" 59 CONFIG_BUILDLIB=" no"64 CONFIG_BUILDLIB="yes" 60 65 ;; 61 66 *) … … 63 68 ;; 64 69 esac 70 71 CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}" 65 72 66 73 AC_SUBST(CONFIG_CFLAGS) -
libcfa/prelude/builtins.c
r6a9d4b4 r933f32f 10 10 // Created On : Fri Jul 21 16:21:03 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Aug 5 21:40:38 201813 // Update Count : 2012 // Last Modified On : Tue Mar 26 23:10:36 2019 13 // Update Count : 95 14 14 // 15 15 … … 42 42 typedef unsigned long long __cfaabi_abi_exception_type_t; 43 43 44 #include <limits.h> // CHAR_BIT 44 45 #include "../src/virtual.h" 45 46 #include "../src/exception.h" … … 50 51 // increment/decrement unification 51 52 52 static inline forall( dtype T | { T& ?+=?( T&, one_t ); } ) 53 T& ++? ( T& x ) { return x += 1; } 53 static inline { 54 forall( dtype DT | { DT & ?+=?( DT &, one_t ); } ) 55 DT & ++?( DT & x ) { return x += 1; } 54 56 55 static inline forall( dtype T | sized(T) | { void ?{}( T&, T ); void ^?{}( T& ); T& ?+=?( T&, one_t ); } )56 T& ?++ ( T& x ) {T tmp = x; x += 1; return tmp; }57 forall( dtype DT | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?+=?( DT &, one_t ); } ) 58 DT & ?++( DT & x ) { DT tmp = x; x += 1; return tmp; } 57 59 58 static inline forall( dtype T | { T& ?-=?( T&, one_t ); } )59 T& --? ( T& x ) { return x -= 1; }60 forall( dtype DT | { DT & ?-=?( DT &, one_t ); } ) 61 DT & --?( DT & x ) { return x -= 1; } 60 62 61 static inline forall( dtype T | sized(T) | { void ?{}( T&, T ); void ^?{}( T& ); T& ?-=?( T&, one_t ); } ) 62 T& ?-- ( T& x ) { T tmp = x; x -= 1; return tmp; } 63 forall( dtype DT | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?-=?( DT &, one_t ); } ) 64 DT & ?--( DT & x ) { DT tmp = x; x -= 1; return tmp; } 65 } // distribution 66 67 // universal typed pointer constant 68 // Compiler issue: there is a problem with anonymous types that do not have a size. 69 static inline forall( dtype DT | sized(DT) ) DT * intptr( uintptr_t addr ) { return (DT *)addr; } 63 70 64 71 // exponentiation operator implementation … … 73 80 } // extern "C" 74 81 75 static inline float ?\?( float x, float y ) { return powf( x, y ); } 76 static inline double ?\?( double x, double y ) { return pow( x, y ); } 77 static inline long double ?\?( long double x, long double y ) { return powl( x, y ); } 78 static inline float _Complex ?\?( float _Complex x, _Complex float y ) { return cpowf(x, y ); } 79 static inline double _Complex ?\?( double _Complex x, _Complex double y ) { return cpow( x, y ); } 80 static inline long double _Complex ?\?( long double _Complex x, _Complex long double y ) { return cpowl( x, y ); } 82 static inline { 83 float ?\?( float x, float y ) { return powf( x, y ); } 84 double ?\?( double x, double y ) { return pow( x, y ); } 85 long double ?\?( long double x, long double y ) { return powl( x, y ); } 86 float _Complex ?\?( float _Complex x, _Complex float y ) { return cpowf(x, y ); } 87 double _Complex ?\?( double _Complex x, _Complex double y ) { return cpow( x, y ); } 88 long double _Complex ?\?( long double _Complex x, _Complex long double y ) { return cpowl( x, y ); } 89 } // distribution 81 90 82 static inline long int ?\?( long int ep, unsigned long int y ) { // disallow negative exponent 83 if ( y == 0 ) return 1; // base case 84 if ( ep == 2 ) return ep << (y - 1); // special case, positive shifting only 85 typeof( ep ) op = 1; // accumulate odd product 86 for ( ; y > 1; y >>= 1 ) { // squaring exponentiation, O(log2 y) 87 if ( (y & 1) == 1 ) op *= ep; // odd ? 88 ep *= ep; 89 } // for 90 return ep * op; 91 } // ?\? 91 #define __CFA_BASE_COMP_1__() if ( ep == 1 ) return 1 92 #define __CFA_BASE_COMP_2__() if ( ep == 2 ) return ep << (y - 1) 93 #define __CFA_EXP_OVERFLOW__() if ( y >= sizeof(y) * CHAR_BIT ) return 0 92 94 93 static inline forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } ) 94 T ?\?( T ep, unsigned long int y ) { 95 if ( y == 0 ) return 1; 96 T op = 1; 97 for ( ; y > 1; y >>= 1 ) { // squaring exponentiation, O(log2 y) 98 if ( (y & 1) == 1 ) op = op * ep; // odd ? 99 ep = ep * ep; 100 } // for 101 return ep * op; 102 } // ?\? 95 #define __CFA_EXP__() \ 96 if ( y == 0 ) return 1; /* convention */ \ 97 __CFA_BASE_COMP_1__(); /* base case */ \ 98 __CFA_BASE_COMP_2__(); /* special case, positive shifting for integral types */ \ 99 __CFA_EXP_OVERFLOW__(); /* immediate overflow, negative exponent > 2^size-1 */ \ 100 typeof(ep) op = 1; /* accumulate odd product */ \ 101 for ( ; y > 1; y >>= 1 ) { /* squaring exponentiation, O(log2 y) */ \ 102 if ( (y & 1) == 1 ) op = op * ep; /* odd ? */ \ 103 ep = ep * ep; \ 104 } \ 105 return ep * op 103 106 104 // unsigned computation may be faster and larger 105 static inline unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { // disallow negative exponent 106 if ( y == 0 ) return 1; // base case 107 if ( ep == 2 ) return ep << (y - 1); // special case, positive shifting only 108 typeof( ep ) op = 1; // accumulate odd product 109 for ( ; y > 1; y >>= 1 ) { // squaring exponentiation, O(log2 y) 110 if ( (y & 1) == 1 ) op *= ep; // odd ? 111 ep *= ep; 112 } // for 113 return ep * op; 114 } // ?\? 107 static inline { 108 long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); } 109 long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); } 110 // unsigned computation may be faster and larger 111 unsigned long int ?\?( unsigned int ep, unsigned int y ) { __CFA_EXP__(); } 112 unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { __CFA_EXP__(); } 113 } // distribution 115 114 116 static inline double ?\?( long int x, signed long int y ) { // allow negative exponent 117 if ( y >= 0 ) return (double)(x \ (unsigned long int)y); 118 else return 1.0 / x \ (unsigned int)(-y); 119 } // ?\? 115 #undef __CFA_BASE_COMP_1__ 116 #undef __CFA_BASE_COMP_2__ 117 #undef __CFA_EXP_OVERFLOW__ 118 #define __CFA_BASE_COMP_1__() 119 #define __CFA_BASE_COMP_2__() 120 #define __CFA_EXP_OVERFLOW__() 120 121 121 // FIXME (x \ (unsigned long int)y) relies on X ?\?(T, unsigned long) a function that is neither 122 // defined, nor passed as an assertion parameter. Without user-defined conversions, cannot specify 123 // X as a type that casts to double, yet it doesn't make sense to write functions with that type 124 // signature where X is double. 122 static inline forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) { 123 OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); } 124 OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); } 125 } // distribution 125 126 126 // static inline forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); double ?/?( double, T ); } ) 127 // double ?\?( T x, signed long int y ) { 128 // if ( y >= 0 ) return (double)(x \ (unsigned long int)y); 129 // else return 1.0 / x \ (unsigned long int)(-y); 130 // } // ?\? 127 #undef __CFA_BASE_COMP_1__ 128 #undef __CFA_BASE_COMP_2__ 129 #undef __CFA_EXP_OVERFLOW__ 131 130 132 static inline long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; } 133 static inline unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; } 134 static inline int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; } 135 static inline unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; } 131 static inline { 132 long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; } 133 unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; } 134 int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; } 135 unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; } 136 } // distribution 136 137 137 138 // Local Variables: // -
libcfa/prelude/extras.c
r6a9d4b4 r933f32f 1 #include <stddef.h> // size_t, ptrdiff_t 1 #include <stddef.h> // size_t, ptrdiff_t, intptr_t, uintptr_t 2 2 #include <stdint.h> // intX_t, uintX_t, where X is 8, 16, 32, 64 3 3 #include <uchar.h> // char16_t, char32_t -
libcfa/prelude/extras.regx
r6a9d4b4 r933f32f 1 1 typedef.* size_t; 2 2 typedef.* ptrdiff_t; 3 typedef.* intptr_t; 4 typedef.* uintptr_t; 3 5 typedef.* __int8_t; 4 6 typedef.* __int16_t; -
libcfa/prelude/prelude-gen.cc
r6a9d4b4 r933f32f 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo 3 // 4 // The contents of this file are covered under the licence agreement in the 5 // file "LICENCE" distributed with Cforall. 6 // 7 // prelude-gen.cc -- 8 // 9 // Author : Rob Schluntz and Thierry Delisle 10 // Created On : Sat Feb 16 08:44:58 2019 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 2 17:18:24 2019 13 // Update Count : 37 14 // 15 1 16 #include <algorithm> 2 17 #include <array> … … 11 26 bool hasComparison; 12 27 } basicTypes[] = { 13 //{ "char" , false, true , },14 //{ "signed char" , false, true , },15 //{ "unsigned char" , false, true , },28 { "char" , false, true , }, 29 { "signed char" , false, true , }, 30 { "unsigned char" , false, true , }, 16 31 { "signed short" , false, true , }, 17 32 { "unsigned short" , false, true , }, … … 34 49 #if defined(__i386__) || defined(__ia64__) || defined(__x86_64__) 35 50 { "__float80" , true , true , }, 36 { "_ Float128", true , true , },51 { "__float128" , true , true , }, 37 52 #endif 38 53 }; … … 103 118 { "?!=?", false, "signed int", Normal, "" }, 104 119 { "?=?", true, "", Normal, "" }, // void * LHS, zero_t RHS ??? 105 { "*?", false, "&", Normal, " | sized(DT)" }, // & ??? 120 // { "*?", false, "&", Normal, " | sized(DT)" }, // & ??? 121 { "*?", false, "&", Normal, "" }, // & ??? 106 122 107 123 { "?-?", false, "ptrdiff_t", Normal, " | sized(DT)" }, … … 150 166 cout << endl; 151 167 152 cout << "signed int ?==?( zero_t, zero_t ), ?!=?( zero_t, zero_t );" << endl;153 cout << "signed int ?==?( one_t, one_t ), ?!=?( one_t, one_t );" << endl;154 cout << "signed int ?==?( _Bool, _Bool ), ?!=?( _Bool, _Bool );" << endl;155 cout << "signed int !?( _Bool );" << endl;168 cout << "signed int ?==?( zero_t, zero_t ), ?!=?( zero_t, zero_t );" << endl; 169 cout << "signed int ?==?( one_t, one_t ), ?!=?( one_t, one_t );" << endl; 170 cout << "signed int ?==?( _Bool, _Bool ), ?!=?( _Bool, _Bool );" << endl; 171 cout << "signed int !?( _Bool );" << endl; 156 172 157 173 for (auto op : arithmeticOperators) { … … 188 204 cout << "// Arithmetic Constructors //" << endl; 189 205 cout << "/////////////////////////////" << endl; 206 cout << endl; 207 190 208 auto otype = [](const std::string & type, bool do_volatile = false) { 191 cout << "void \t?{} ( " << type << " &);" << endl;192 cout << "void \t?{} ( " << type << " &, " << type << ");" << endl;193 cout << type << " \t?=? ( " << type << " &, " << type << ")";194 if ( do_volatile ) {195 cout << ", \t?=?( volatile " << type << " &, " << type << ")";209 cout << "void ?{} (" << type << " &);" << endl; 210 cout << "void ?{} (" << type << " &, " << type << ");" << endl; 211 cout << type << " ?=? (" << type << " &, " << type << ")"; 212 if ( do_volatile ) { 213 cout << ", ?=?(volatile " << type << " &, " << type << ")"; 196 214 } 197 215 cout << ";" << endl; 198 cout << "void \t^?{}( " << type << " & );" << endl;216 cout << "void ^?{}( " << type << " & );" << endl; 199 217 }; 200 218 201 219 otype("zero_t"); 220 cout << endl; 202 221 otype("one_t"); 222 cout << endl; 203 223 otype("_Bool", true); 204 otype("char", true); 205 otype("signed char", true); 206 otype("unsigned char", true); 224 cout << endl; 207 225 208 226 for (auto type : basicTypes) { 209 cout << "void ?{}(" << type.name << " &);" << endl; 210 cout << "void ?{}(" << type.name << " &, " << type.name << ");" << endl; 227 cout << "void ?{}(" << type.name << " &);" << endl; 228 cout << "void ?{}(" << type.name << " &, " << type.name << ");" << endl; 229 cout << "void ?{}(" << type.name << " &, zero_t);" << endl; 230 cout << "void ?{}(" << type.name << " &, one_t);" << endl; 211 231 cout << "void ^?{}(" << type.name << " &);" << endl; 212 232 cout << endl; … … 217 237 cout << "// Pointer Constructors //" << endl; 218 238 cout << "//////////////////////////" << endl; 219 cout << "forall(ftype FT) void ?{}( FT *&, FT * );" << endl; 220 cout << "forall(ftype FT) void ?{}( FT * volatile &, FT * );" << endl; 239 cout << endl; 240 241 cout << "forall(ftype FT) void ?{}( FT *&, FT * );" << endl; 242 cout << "forall(ftype FT) void ?{}( FT * volatile &, FT * );" << endl; 221 243 222 244 // generate qualifiers … … 242 264 for (auto cvq : qualifiersPair) { 243 265 for (auto is_vol : { " ", "volatile" }) { 244 cout << "forall(dtype DT) void ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl;266 cout << "forall(dtype DT) void ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl; 245 267 } 246 268 } 247 269 for (auto cvq : qualifiersSingle) { 248 270 for (auto is_vol : { " ", "volatile" }) { 249 cout << "forall(dtype DT) void ?{}(" << cvq << type << " * " << is_vol << " &);" << endl;271 cout << "forall(dtype DT) void ?{}(" << cvq << type << " * " << is_vol << " &);" << endl; 250 272 } 251 273 for (auto is_vol : { " ", "volatile" }) { … … 269 291 cout << "forall(ftype FT) FT * ?=?( FT * &, zero_t );" << endl; 270 292 cout << "forall(ftype FT) FT * ?=?( FT * volatile &, zero_t );" << endl; 271 cout << "forall( ftype FT) void ?{}( FT * & );" << endl;272 cout << "forall( ftype FT) void ^?{}( FT * & );" << endl;293 cout << "forall(ftype FT) void ?{}( FT * & );" << endl; 294 cout << "forall(ftype FT) void ^?{}( FT * & );" << endl; 273 295 cout << endl; 274 296 … … 277 299 cout << "///////////////////////" << endl; 278 300 279 cout << "forall( ftype FT ) FT * ?=?( FT *&, FT * );" << endl; 280 cout << "forall( ftype FT ) FT * ?=?( FT * volatile &, FT * );" << endl; 281 cout << "forall( ftype FT ) int !?( FT * );" << endl; 282 cout << "forall( ftype FT ) signed int ?==?( FT *, FT * );" << endl; 283 cout << "forall( ftype FT ) signed int ?!=?( FT *, FT * );" << endl; 284 cout << "forall( ftype FT ) FT & *?( FT * );" << endl; 285 301 cout << "forall(ftype FT) FT * ?=?( FT *&, FT * );" << endl; 302 cout << "forall(ftype FT) FT * ?=?( FT * volatile &, FT * );" << endl; 303 cout << "forall(ftype FT) int !?( FT * );" << endl; 304 cout << "forall(ftype FT) signed int ?==?( FT *, FT * );" << endl; 305 cout << "forall(ftype FT) signed int ?!=?( FT *, FT * );" << endl; 306 cout << "forall(ftype FT) FT & *?( FT * );" << endl; 286 307 287 308 for (auto op : pointerOperators) { … … 387 408 } 388 409 410 // Local Variables: // 411 // tab-width: 4 // 412 // End: // -
libcfa/prelude/sync-builtins.cf
r6a9d4b4 r933f32f 323 323 _Bool __sync_bool_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...); 324 324 #endif 325 forall(dtype T) _Bool __sync_bool_compare_and_swap(T * volatile *, T *, T*, ...); 325 326 326 327 char __sync_val_compare_and_swap(volatile char *, char, char,...); … … 348 349 unsigned __int128 __sync_val_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...); 349 350 #endif 351 forall(dtype T) T * __sync_val_compare_and_swap(T * volatile *, T *, T*,...); 350 352 351 353 char __sync_lock_test_and_set(volatile char *, char,...); … … 434 436 #endif 435 437 436 char __atomic_exchange_n(volatile char *, volatile char *, int);438 char __atomic_exchange_n(volatile char *, char, int); 437 439 char __atomic_exchange_1(volatile char *, char, int); 438 440 void __atomic_exchange(volatile char *, volatile char *, volatile char *, int); 439 signed char __atomic_exchange_n(volatile signed char *, volatile signed char *, int);441 signed char __atomic_exchange_n(volatile signed char *, signed char, int); 440 442 signed char __atomic_exchange_1(volatile signed char *, signed char, int); 441 443 void __atomic_exchange(volatile signed char *, volatile signed char *, volatile signed char *, int); 442 unsigned char __atomic_exchange_n(volatile unsigned char *, volatile unsigned char *, int);444 unsigned char __atomic_exchange_n(volatile unsigned char *, unsigned char, int); 443 445 unsigned char __atomic_exchange_1(volatile unsigned char *, unsigned char, int); 444 446 void __atomic_exchange(volatile unsigned char *, volatile unsigned char *, volatile unsigned char *, int); 445 signed short __atomic_exchange_n(volatile signed short *, volatile signed short *, int);447 signed short __atomic_exchange_n(volatile signed short *, signed short, int); 446 448 signed short __atomic_exchange_2(volatile signed short *, signed short, int); 447 449 void __atomic_exchange(volatile signed short *, volatile signed short *, volatile signed short *, int); 448 unsigned short __atomic_exchange_n(volatile unsigned short *, volatile unsigned short *, int);450 unsigned short __atomic_exchange_n(volatile unsigned short *, unsigned short, int); 449 451 unsigned short __atomic_exchange_2(volatile unsigned short *, unsigned short, int); 450 452 void __atomic_exchange(volatile unsigned short *, volatile unsigned short *, volatile unsigned short *, int); 451 signed int __atomic_exchange_n(volatile signed int *, volatile signed int *, int);453 signed int __atomic_exchange_n(volatile signed int *, signed int, int); 452 454 signed int __atomic_exchange_4(volatile signed int *, signed int, int); 453 455 void __atomic_exchange(volatile signed int *, volatile signed int *, volatile signed int *, int); 454 unsigned int __atomic_exchange_n(volatile unsigned int *, volatile unsigned int *, int);456 unsigned int __atomic_exchange_n(volatile unsigned int *, unsigned int, int); 455 457 unsigned int __atomic_exchange_4(volatile unsigned int *, unsigned int, int); 456 458 void __atomic_exchange(volatile unsigned int *, volatile unsigned int *, volatile unsigned int *, int); 457 signed long long int __atomic_exchange_n(volatile signed long long int *, volatile signed long long int *, int);459 signed long long int __atomic_exchange_n(volatile signed long long int *, signed long long int, int); 458 460 signed long long int __atomic_exchange_8(volatile signed long long int *, signed long long int, int); 459 461 void __atomic_exchange(volatile signed long long int *, volatile signed long long int *, volatile signed long long int *, int); 460 unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, volatile unsigned long long int *, int);462 unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, unsigned long long int, int); 461 463 unsigned long long int __atomic_exchange_8(volatile unsigned long long int *, unsigned long long int, int); 462 464 void __atomic_exchange(volatile unsigned long long int *, volatile unsigned long long int *, volatile unsigned long long int *, int); 463 465 #if defined(__SIZEOF_INT128__) 464 signed __int128 __atomic_exchange_n(volatile signed __int128 *, volatile signed __int128 *, int);466 signed __int128 __atomic_exchange_n(volatile signed __int128 *, signed __int128, int); 465 467 signed __int128 __atomic_exchange_16(volatile signed __int128 *, signed __int128, int); 466 468 void __atomic_exchange(volatile signed __int128 *, volatile signed __int128 *, volatile signed __int128 *, int); 467 unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, volatile unsigned __int128 *, int);469 unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, unsigned __int128, int); 468 470 unsigned __int128 __atomic_exchange_16(volatile unsigned __int128 *, unsigned __int128, int); 469 471 void __atomic_exchange(volatile unsigned __int128 *, volatile unsigned __int128 *, volatile unsigned __int128 *, int); 470 472 #endif 473 forall(dtype T) T * __atomic_exchange_n(T * volatile *, T *, int); 474 forall(dtype T) void __atomic_exchange(T * volatile *, T * volatile *, T * volatile *, int); 471 475 472 476 _Bool __atomic_load_n(const volatile _Bool *, int); … … 507 511 void __atomic_load(const volatile unsigned __int128 *, volatile unsigned __int128 *, int); 508 512 #endif 513 forall(dtype T) T * __atomic_load_n(T * const volatile *, int); 514 forall(dtype T) void __atomic_load(T * const volatile *, T **, int); 509 515 510 516 _Bool __atomic_compare_exchange_n(volatile char *, char *, char, _Bool, int, int); … … 543 549 _Bool __atomic_compare_exchange (volatile unsigned __int128 *, unsigned __int128 *, unsigned __int128 *, _Bool, int, int); 544 550 #endif 551 forall(dtype T) _Bool __atomic_compare_exchange_n (T * volatile *, T **, T*, _Bool, int, int); 552 forall(dtype T) _Bool __atomic_compare_exchange (T * volatile *, T **, T**, _Bool, int, int); 545 553 546 554 void __atomic_store_n(volatile _Bool *, _Bool, int); … … 581 589 void __atomic_store(volatile unsigned __int128 *, unsigned __int128 *, int); 582 590 #endif 591 forall(dtype T) void __atomic_store_n(T * volatile *, T *, int); 592 forall(dtype T) void __atomic_store(T * volatile *, T **, int); 583 593 584 594 char __atomic_add_fetch (volatile char *, char, int); -
libcfa/src/Makefile.am
r6a9d4b4 r933f32f 74 74 75 75 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 76 ${AM_V_GEN} @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@-XCFA -l ${<} -c -o ${@}76 ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@} 77 77 78 78 prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 79 79 ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \ 80 @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@-XCFA -l ${<} -c -o ${@}80 $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@} 81 81 82 82 -
libcfa/src/Makefile.in
r6a9d4b4 r933f32f 926 926 927 927 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 928 ${AM_V_GEN} @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@-XCFA -l ${<} -c -o ${@}928 ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@} 929 929 930 930 prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 931 931 ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \ 932 @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@-XCFA -l ${<} -c -o ${@}932 $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@} 933 933 934 934 #---------------------------------------------------------------------------------------------------------------- -
libcfa/src/bits/containers.hfa
r6a9d4b4 r933f32f 186 186 187 187 forall(dtype T | is_node(T)) 188 static inline bool ?!=?( __queue(T) & this, zero_t zero ) {188 static inline bool ?!=?( __queue(T) & this, __attribute__((unused)) zero_t zero ) { 189 189 return this.head != 0; 190 190 } … … 196 196 //----------------------------------------------------------------------------- 197 197 #ifdef __cforall 198 forall(dtype TYPE | sized(TYPE))198 forall(dtype TYPE) 199 199 #define T TYPE 200 200 #define __getter_t * [T * & next, T * & prev] ( T & ) … … 268 268 269 269 forall(dtype T | sized(T)) 270 static inline bool ?!=?( __dllist(T) & this, zero_t zero ) {270 static inline bool ?!=?( __dllist(T) & this, __attribute__((unused)) zero_t zero ) { 271 271 return this.head != 0; 272 272 } -
libcfa/src/concurrency/CtxSwitch-i386.S
r6a9d4b4 r933f32f 41 41 #define PC_OFFSET ( 2 * PTR_BYTE ) 42 42 43 .text43 .text 44 44 .align 2 45 .globl CtxSwitch 45 .globl CtxSwitch 46 .type CtxSwitch, @function 46 47 CtxSwitch: 47 48 … … 50 51 51 52 movl 4(%esp),%eax 52 53 // Save floating & SSE control words on the stack.54 55 sub $8,%esp56 stmxcsr 0(%esp) // 4 bytes57 fnstcw 4(%esp) // 2 bytes58 53 59 54 // Save volatile registers on the stack. … … 67 62 movl %esp,SP_OFFSET(%eax) 68 63 movl %ebp,FP_OFFSET(%eax) 69 // movl 4(%ebp),%ebx // save previous eip for debugger70 // movl %ebx,PC_OFFSET(%eax)71 64 72 65 // Copy the "to" context argument from the stack to register eax … … 74 67 // argument is now at 8 + 12 = 20(%esp) 75 68 76 movl 2 8(%esp),%eax69 movl 20(%esp),%eax 77 70 78 71 // Load new context from the "to" area. … … 87 80 popl %ebx 88 81 89 // Load floating & SSE control words from the stack.90 91 fldcw 4(%esp)92 ldmxcsr 0(%esp)93 add $8,%esp94 95 82 // Return to thread. 96 83 97 84 ret 85 .size CtxSwitch, .-CtxSwitch 98 86 99 87 // Local Variables: // -
libcfa/src/concurrency/CtxSwitch-x86_64.S
r6a9d4b4 r933f32f 39 39 #define SP_OFFSET ( 0 * PTR_BYTE ) 40 40 #define FP_OFFSET ( 1 * PTR_BYTE ) 41 #define PC_OFFSET ( 2 * PTR_BYTE )42 41 43 .text 42 //----------------------------------------------------------------------------- 43 // Regular context switch routine which enables switching from one context to anouther 44 .text 44 45 .align 2 45 .globl CtxSwitch 46 .globl CtxSwitch 47 .type CtxSwitch, @function 46 48 CtxSwitch: 47 48 // Save floating & SSE control words on the stack.49 50 subq $8,%rsp51 stmxcsr 0(%rsp) // 4 bytes52 fnstcw 4(%rsp) // 2 bytes53 49 54 50 // Save volatile registers on the stack. … … 78 74 popq %r15 79 75 80 // Load floating & SSE control words from the stack.81 82 fldcw 4(%rsp)83 ldmxcsr 0(%rsp)84 addq $8,%rsp85 86 76 // Return to thread. 87 77 88 78 ret 79 .size CtxSwitch, .-CtxSwitch 89 80 90 .text 81 //----------------------------------------------------------------------------- 82 // Stub used to create new stacks which are ready to be context switched to 83 .text 91 84 .align 2 92 .globl CtxInvokeStub 85 .globl CtxInvokeStub 86 .type CtxInvokeStub, @function 93 87 CtxInvokeStub: 94 88 movq %rbx, %rdi 95 89 jmp *%r12 90 .size CtxInvokeStub, .-CtxInvokeStub 96 91 97 92 // Local Variables: // -
libcfa/src/concurrency/coroutine.cfa
r6a9d4b4 r933f32f 35 35 36 36 extern "C" { 37 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) __attribute__ ((__noreturn__)); 38 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__)); 39 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) { 40 abort(); 41 } 37 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__)); 38 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__)); 39 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) { 40 abort(); 41 } 42 43 extern void CtxRet( struct __stack_context_t * to ) asm ("CtxRet") __attribute__ ((__noreturn__)); 42 44 } 43 45 … … 47 49 // minimum feasible stack size in bytes 48 50 #define MinStackSize 1000 49 static size_t pageSize = 0; // architecture pagesize HACK, should go in proper runtime singleton 51 extern size_t __page_size; // architecture pagesize HACK, should go in proper runtime singleton 52 53 void __stack_prepare( __stack_info_t * this, size_t create_size ); 50 54 51 55 //----------------------------------------------------------------------------- 52 56 // Coroutine ctors and dtors 53 void ?{}( coStack_t & this, void * storage, size_t storageSize ) with( this ) { 54 size = storageSize == 0 ? 65000 : storageSize; // size of stack 55 this.storage = storage; // pointer to stack 56 limit = NULL; // stack grows towards stack limit 57 base = NULL; // base of stack 58 context = NULL; // address of cfa_context_t 59 top = NULL; // address of top of storage 60 userStack = storage != NULL; 61 } 62 63 void ^?{}(coStack_t & this) { 64 if ( ! this.userStack && this.storage ) { 65 __cfaabi_dbg_debug_do( 66 if ( mprotect( this.storage, pageSize, PROT_READ | PROT_WRITE ) == -1 ) { 67 abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) ); 68 } 69 ); 70 free( this.storage ); 71 } 57 void ?{}( __stack_info_t & this, void * storage, size_t storageSize ) { 58 this.storage = (__stack_t *)storage; 59 60 // Did we get a piece of storage ? 61 if (this.storage || storageSize != 0) { 62 // We either got a piece of storage or the user asked for a specific size 63 // Immediately create the stack 64 // (This is slightly unintuitive that non-default sized coroutines create are eagerly created 65 // but it avoids that all coroutines carry an unnecessary size) 66 verify( storageSize != 0 ); 67 __stack_prepare( &this, storageSize ); 68 } 69 } 70 71 void ^?{}(__stack_info_t & this) { 72 bool userStack = ((intptr_t)this.storage & 0x1) != 0; 73 if ( ! userStack && this.storage ) { 74 __attribute__((may_alias)) intptr_t * istorage = (intptr_t *)&this.storage; 75 *istorage &= (intptr_t)-1; 76 77 void * storage = this.storage->limit; 78 __cfaabi_dbg_debug_do( 79 storage = (char*)(storage) - __page_size; 80 if ( mprotect( storage, __page_size, PROT_READ | PROT_WRITE ) == -1 ) { 81 abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) ); 82 } 83 ); 84 __cfaabi_dbg_print_safe("Kernel : Deleting stack %p\n", storage); 85 free( storage ); 86 } 72 87 } 73 88 74 89 void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) { 75 (this.stack){storage, storageSize};76 this.name = name;77 errno_ = 0;78 state = Start;79 starter = NULL;80 last = NULL;81 cancellation = NULL;90 (this.context){NULL, NULL}; 91 (this.stack){storage, storageSize}; 92 this.name = name; 93 state = Start; 94 starter = NULL; 95 last = NULL; 96 cancellation = NULL; 82 97 } 83 98 84 99 void ^?{}(coroutine_desc& this) { 85 if(this.state != Halted && this.state != Start) {86 coroutine_desc * src = TL_GET( this_coroutine );87 coroutine_desc * dst = &this;88 89 struct _Unwind_Exception storage;90 storage.exception_class = -1;91 storage.exception_cleanup = _CtxCoroutine_UnwindCleanup;92 this.cancellation = &storage;93 this.last = src;94 95 // not resuming self ?96 if ( src == dst ) {97 abort( "Attempt by coroutine %.256s (%p) to terminate itself.\n", src->name, src );98 }99 100 CoroutineCtxSwitch( src, dst );101 }100 if(this.state != Halted && this.state != Start) { 101 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 102 coroutine_desc * dst = &this; 103 104 struct _Unwind_Exception storage; 105 storage.exception_class = -1; 106 storage.exception_cleanup = _CtxCoroutine_UnwindCleanup; 107 this.cancellation = &storage; 108 this.last = src; 109 110 // not resuming self ? 111 if ( src == dst ) { 112 abort( "Attempt by coroutine %.256s (%p) to terminate itself.\n", src->name, src ); 113 } 114 115 CoroutineCtxSwitch( src, dst ); 116 } 102 117 } 103 118 … … 106 121 forall(dtype T | is_coroutine(T)) 107 122 void prime(T& cor) { 108 coroutine_desc* this = get_coroutine(cor); 109 assert(this->state == Start); 110 111 this->state = Primed; 112 resume(cor); 113 } 114 115 // Wrapper for co 116 void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 117 // Safety note : This could cause some false positives due to preemption 118 verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate ); 119 disable_interrupts(); 120 121 // set state of current coroutine to inactive 122 src->state = src->state == Halted ? Halted : Inactive; 123 124 // set new coroutine that task is executing 125 kernelTLS.this_coroutine = dst; 126 127 // context switch to specified coroutine 128 assert( src->stack.context ); 129 CtxSwitch( src->stack.context, dst->stack.context ); 130 // when CtxSwitch returns we are back in the src coroutine 131 132 // set state of new coroutine to active 133 src->state = Active; 134 135 enable_interrupts( __cfaabi_dbg_ctx ); 136 // Safety note : This could cause some false positives due to preemption 137 verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate ); 138 139 if( unlikely(src->cancellation != NULL) ) { 140 _CtxCoroutine_Unwind(src->cancellation); 141 } 142 } //ctxSwitchDirect 143 144 void create_stack( coStack_t* this, unsigned int storageSize ) with( *this ) { 145 //TEMP HACK do this on proper kernel startup 146 if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE ); 147 148 size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment 149 150 if ( !storage ) { 151 __cfaabi_dbg_print_safe("Kernel : Creating stack of size %zu for stack obj %p\n", cxtSize + size + 8, this); 152 153 userStack = false; 154 size = libCeiling( storageSize, 16 ); 155 // use malloc/memalign because "new" raises an exception for out-of-memory 156 157 // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment 158 __cfaabi_dbg_debug_do( storage = memalign( pageSize, cxtSize + size + pageSize ) ); 159 __cfaabi_dbg_no_debug_do( storage = malloc( cxtSize + size + 8 ) ); 160 161 __cfaabi_dbg_debug_do( 162 if ( mprotect( storage, pageSize, PROT_NONE ) == -1 ) { 163 abort( "(uMachContext &)%p.createContext() : internal error, mprotect failure, error(%d) %s.", this, (int)errno, strerror( (int)errno ) ); 164 } // if 165 ); 166 167 if ( (intptr_t)storage == 0 ) { 168 abort( "Attempt to allocate %zd bytes of storage for coroutine or task execution-state but insufficient memory available.", size ); 169 } // if 170 171 __cfaabi_dbg_debug_do( limit = (char *)storage + pageSize ); 172 __cfaabi_dbg_no_debug_do( limit = (char *)libCeiling( (unsigned long)storage, 16 ) ); // minimum alignment 173 174 } else { 175 __cfaabi_dbg_print_safe("Kernel : stack obj %p using user stack %p(%u bytes)\n", this, storage, storageSize); 176 177 assertf( ((size_t)storage & (libAlign() - 1)) == 0ul, "Stack storage %p for task/coroutine must be aligned on %d byte boundary.", storage, (int)libAlign() ); 178 userStack = true; 179 size = storageSize - cxtSize; 180 181 if ( size % 16 != 0u ) size -= 8; 182 183 limit = (char *)libCeiling( (unsigned long)storage, 16 ); // minimum alignment 184 } // if 185 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize ); 186 187 base = (char *)limit + size; 188 context = base; 189 top = (char *)context + cxtSize; 123 coroutine_desc* this = get_coroutine(cor); 124 assert(this->state == Start); 125 126 this->state = Primed; 127 resume(cor); 128 } 129 130 [void *, size_t] __stack_alloc( size_t storageSize ) { 131 static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment 132 assert(__page_size != 0l); 133 size_t size = libCeiling( storageSize, 16 ) + stack_data_size; 134 135 // If we are running debug, we also need to allocate a guardpage to catch stack overflows. 136 void * storage; 137 __cfaabi_dbg_debug_do( 138 storage = memalign( __page_size, size + __page_size ); 139 ); 140 __cfaabi_dbg_no_debug_do( 141 storage = (void*)malloc(size); 142 ); 143 144 __cfaabi_dbg_print_safe("Kernel : Created stack %p of size %zu\n", storage, size); 145 __cfaabi_dbg_debug_do( 146 if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) { 147 abort( "__stack_alloc : internal error, mprotect failure, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 148 } 149 storage = (void *)(((intptr_t)storage) + __page_size); 150 ); 151 152 verify( ((intptr_t)storage & (libAlign() - 1)) == 0ul ); 153 return [storage, size]; 154 } 155 156 void __stack_prepare( __stack_info_t * this, size_t create_size ) { 157 static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment 158 bool userStack; 159 void * storage; 160 size_t size; 161 if ( !this->storage ) { 162 userStack = false; 163 [storage, size] = __stack_alloc( create_size ); 164 } else { 165 userStack = true; 166 __cfaabi_dbg_print_safe("Kernel : stack obj %p using user stack %p(%zd bytes)\n", this, this->storage, (intptr_t)this->storage->limit - (intptr_t)this->storage->base); 167 168 // The stack must be aligned, advance the pointer to the next align data 169 storage = (void*)libCeiling( (intptr_t)this->storage, libAlign()); 170 171 // The size needs to be shrinked to fit all the extra data structure and be aligned 172 ptrdiff_t diff = (intptr_t)storage - (intptr_t)this->storage; 173 size = libFloor(create_size - stack_data_size - diff, libAlign()); 174 } // if 175 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize ); 176 177 this->storage = (__stack_t *)((intptr_t)storage + size); 178 this->storage->limit = storage; 179 this->storage->base = (void*)((intptr_t)storage + size); 180 __attribute__((may_alias)) intptr_t * istorage = (intptr_t*)&this->storage; 181 *istorage |= userStack ? 0x1 : 0x0; 190 182 } 191 183 … … 193 185 // is not inline (We can't inline Cforall in C) 194 186 extern "C" { 195 void __suspend_internal(void) { 196 suspend(); 197 } 198 199 void __leave_coroutine() { 200 coroutine_desc * src = TL_GET( this_coroutine ); // optimization 201 coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter; 202 203 src->state = Halted; 204 205 assertf( starter != 0, 206 "Attempt to suspend/leave coroutine \"%.256s\" (%p) that has never been resumed.\n" 207 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.", 208 src->name, src ); 209 assertf( starter->state != Halted, 210 "Attempt by coroutine \"%.256s\" (%p) to suspend/leave back to terminated coroutine \"%.256s\" (%p).\n" 211 "Possible cause is terminated coroutine's main routine has already returned.", 212 src->name, src, starter->name, starter ); 213 214 CoroutineCtxSwitch( src, starter ); 215 } 187 void __suspend_internal(void) { 188 suspend(); 189 } 190 191 void __leave_coroutine( coroutine_desc * src ) { 192 coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter; 193 194 src->state = Halted; 195 196 assertf( starter != 0, 197 "Attempt to suspend/leave coroutine \"%.256s\" (%p) that has never been resumed.\n" 198 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.", 199 src->name, src ); 200 assertf( starter->state != Halted, 201 "Attempt by coroutine \"%.256s\" (%p) to suspend/leave back to terminated coroutine \"%.256s\" (%p).\n" 202 "Possible cause is terminated coroutine's main routine has already returned.", 203 src->name, src, starter->name, starter ); 204 205 CoroutineCtxSwitch( src, starter ); 206 } 216 207 } 217 208 -
libcfa/src/concurrency/coroutine.hfa
r6a9d4b4 r933f32f 46 46 //----------------------------------------------------------------------------- 47 47 // Public coroutine API 48 static inline void suspend( );48 static inline void suspend(void); 49 49 50 50 forall(dtype T | is_coroutine(T)) 51 static inline voidresume(T & cor);51 static inline T & resume(T & cor); 52 52 53 53 forall(dtype T | is_coroutine(T)) … … 64 64 forall(dtype T | is_coroutine(T)) 65 65 void CtxStart(T * this, void ( *invoke)(T *)); 66 67 extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__)); 68 69 extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch"); 66 70 } 67 71 68 72 // Private wrappers for context switch and stack creation 69 extern void CoroutineCtxSwitch(coroutine_desc * src, coroutine_desc * dst); 70 extern void create_stack( coStack_t * this, unsigned int storageSize ); 73 // Wrapper for co 74 static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 75 // set state of current coroutine to inactive 76 src->state = src->state == Halted ? Halted : Inactive; 77 78 // set new coroutine that task is executing 79 TL_GET( this_thread )->curr_cor = dst; 80 81 // context switch to specified coroutine 82 verify( dst->context.SP ); 83 CtxSwitch( &src->context, &dst->context ); 84 // when CtxSwitch returns we are back in the src coroutine 85 86 // set state of new coroutine to active 87 src->state = Active; 88 89 if( unlikely(src->cancellation != NULL) ) { 90 _CtxCoroutine_Unwind(src->cancellation, src); 91 } 92 } 93 94 extern void __stack_prepare ( __stack_info_t * this, size_t size /* ignored if storage already allocated */); 71 95 72 96 // Suspend implementation inlined for performance 73 static inline void suspend( ) {97 static inline void suspend(void) { 74 98 // optimization : read TLS once and reuse it 75 99 // Safety note: this is preemption safe since if … … 77 101 // will also migrate which means this value will 78 102 // stay in syn with the TLS 79 coroutine_desc * src = TL_GET( this_ coroutine );103 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 80 104 81 105 assertf( src->last != 0, … … 93 117 // Resume implementation inlined for performance 94 118 forall(dtype T | is_coroutine(T)) 95 static inline voidresume(T & cor) {119 static inline T & resume(T & cor) { 96 120 // optimization : read TLS once and reuse it 97 121 // Safety note: this is preemption safe since if … … 99 123 // will also migrate which means this value will 100 124 // stay in syn with the TLS 101 coroutine_desc * src = TL_GET( this_ coroutine );125 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 102 126 coroutine_desc * dst = get_coroutine(cor); 103 127 104 if( unlikely( !dst->stack.base) ) {105 create_stack(&dst->stack, dst->stack.size);128 if( unlikely(dst->context.SP == NULL) ) { 129 __stack_prepare(&dst->stack, 65000); 106 130 CtxStart(&cor, CtxInvokeCoroutine); 107 131 } … … 121 145 // always done for performance testing 122 146 CoroutineCtxSwitch( src, dst ); 147 148 return cor; 123 149 } 124 150 … … 129 155 // will also migrate which means this value will 130 156 // stay in syn with the TLS 131 coroutine_desc * src = TL_GET( this_ coroutine );157 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 132 158 133 159 // not resuming self ? -
libcfa/src/concurrency/invoke.c
r6a9d4b4 r933f32f 28 28 29 29 extern void __suspend_internal(void); 30 extern void __leave_coroutine( void);31 extern void __finish_creation( void);30 extern void __leave_coroutine( struct coroutine_desc * ); 31 extern void __finish_creation( struct thread_desc * ); 32 32 extern void __leave_thread_monitor( struct thread_desc * this ); 33 33 extern void disable_interrupts(); … … 47 47 cor->state = Active; 48 48 49 enable_interrupts( __cfaabi_dbg_ctx );50 51 49 main( this ); 52 50 53 51 //Final suspend, should never return 54 __leave_coroutine( );52 __leave_coroutine( cor ); 55 53 __cabi_abort( "Resumed dead coroutine" ); 56 54 } … … 62 60 __attribute((__unused__)) struct _Unwind_Exception * unwind_exception, 63 61 __attribute((__unused__)) struct _Unwind_Context * context, 64 __attribute((__unused__))void * param62 void * param 65 63 ) { 66 64 if( actions & _UA_END_OF_STACK ) { 67 65 // We finished unwinding the coroutine, 68 66 // leave it 69 __leave_coroutine( );67 __leave_coroutine( param ); 70 68 __cabi_abort( "Resumed dead coroutine" ); 71 69 } … … 75 73 } 76 74 77 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage ) __attribute__ ((__noreturn__));78 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage ) {79 _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, NULL);75 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) __attribute__ ((__noreturn__)); 76 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) { 77 _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, cor ); 80 78 printf("UNWIND ERROR %d after force unwind\n", ret); 81 79 abort(); … … 88 86 void *this 89 87 ) { 88 // Fetch the thread handle from the user defined thread structure 89 struct thread_desc* thrd = get_thread( this ); 90 90 91 // First suspend, once the thread arrives here, 91 92 // the function pointer to main can be invalidated without risk 92 __finish_creation(); 93 94 // Fetch the thread handle from the user defined thread structure 95 struct thread_desc* thrd = get_thread( this ); 96 thrd->self_cor.last = NULL; 93 __finish_creation( thrd ); 97 94 98 95 // Officially start the thread by enabling preemption … … 120 117 void (*invoke)(void *) 121 118 ) { 122 struct coStack_t* stack = &get_coroutine( this )->stack; 119 struct coroutine_desc * cor = get_coroutine( this ); 120 struct __stack_t * stack = cor->stack.storage; 123 121 124 122 #if defined( __i386 ) 125 123 126 124 struct FakeStack { 127 void *fixedRegisters[3]; // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant) 128 uint32_t mxcr; // SSE Status and Control bits (control bits are preserved across function calls) 129 uint16_t fcw; // X97 FPU control word (preserved across function calls) 125 void *fixedRegisters[3]; // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant) 130 126 void *rturn; // where to go on return from uSwitch 131 void *dummyReturn; // fake return compiler would have pushed on call to uInvoke132 void *argument[3]; // for 16-byte ABI, 16-byte alignment starts here133 void *padding; // padding to force 16-byte alignment, as "base" is 16-byte aligned127 void *dummyReturn; // fake return compiler would have pushed on call to uInvoke 128 void *argument[3]; // for 16-byte ABI, 16-byte alignment starts here 129 void *padding; // padding to force 16-byte alignment, as "base" is 16-byte aligned 134 130 }; 135 131 136 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );137 ((struct machine_context_t *)stack->context)->FP = NULL; // terminate stack with NULL fp132 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack ); 133 cor->context.FP = NULL; // terminate stack with NULL fp 138 134 139 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL;140 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument[0] = this; // argument to invoke 141 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = invoke;142 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520143 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7135 struct FakeStack *fs = (struct FakeStack *)cor->context.SP; 136 137 fs->dummyReturn = NULL; 138 fs->argument[0] = this; // argument to invoke 139 fs->rturn = invoke; 144 140 145 141 #elif defined( __x86_64 ) … … 147 143 struct FakeStack { 148 144 void *fixedRegisters[5]; // fixed registers rbx, r12, r13, r14, r15 149 uint32_t mxcr; // SSE Status and Control bits (control bits are preserved across function calls)150 uint16_t fcw; // X97 FPU control word (preserved across function calls)151 145 void *rturn; // where to go on return from uSwitch 152 146 void *dummyReturn; // NULL return address to provide proper alignment 153 147 }; 154 148 155 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );156 ((struct machine_context_t *)stack->context)->FP = NULL; // terminate stack with NULL fp149 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack ); 150 cor->context.FP = NULL; // terminate stack with NULL fp 157 151 158 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL;159 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = CtxInvokeStub; 160 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[0] = this;161 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = invoke;162 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520163 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7152 struct FakeStack *fs = (struct FakeStack *)cor->context.SP; 153 154 fs->dummyReturn = NULL; 155 fs->rturn = CtxInvokeStub; 156 fs->fixedRegisters[0] = this; 157 fs->fixedRegisters[1] = invoke; 164 158 165 159 #elif defined( __ARM_ARCH ) … … 171 165 }; 172 166 173 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );174 ((struct machine_context_t *)stack->context)->FP = NULL;167 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack ); 168 cor->context.FP = NULL; 175 169 176 struct FakeStack *fs = (struct FakeStack *) ((struct machine_context_t *)stack->context)->SP;170 struct FakeStack *fs = (struct FakeStack *)cor->context.SP; 177 171 178 172 fs->intRegs[8] = CtxInvokeStub; -
libcfa/src/concurrency/invoke.h
r6a9d4b4 r933f32f 50 50 51 51 extern thread_local struct KernelThreadData { 52 struct coroutine_desc * volatile this_coroutine;53 52 struct thread_desc * volatile this_thread; 54 53 struct processor * volatile this_processor; … … 61 60 } kernelTLS __attribute__ ((tls_model ( "initial-exec" ))); 62 61 } 63 64 static inline struct coroutine_desc * volatile active_coroutine() { return TL_GET( this_coroutine ); }65 static inline struct thread_desc * volatile active_thread () { return TL_GET( this_thread ); }66 static inline struct processor * volatile active_processor() { return TL_GET( this_processor ); } // UNSAFE67 62 #endif 68 63 69 struct coStack_t { 70 size_t size; // size of stack 71 void * storage; // pointer to stack 72 void * limit; // stack grows towards stack limit 73 void * base; // base of stack 74 void * context; // address of cfa_context_t 75 void * top; // address of top of storage 76 bool userStack; // whether or not the user allocated the stack 64 struct __stack_context_t { 65 void * SP; 66 void * FP; 67 }; 68 69 // low adresses : +----------------------+ <- start of allocation 70 // | optional guard page | 71 // +----------------------+ <- __stack_t.limit 72 // | | 73 // | /\ /\ /\ | 74 // | || || || | 75 // | | 76 // | program stack | 77 // | | 78 // __stack_info_t.storage -> +----------------------+ <- __stack_t.base 79 // | __stack_t | 80 // high adresses : +----------------------+ <- end of allocation 81 82 struct __stack_t { 83 // stack grows towards stack limit 84 void * limit; 85 86 // base of stack 87 void * base; 88 }; 89 90 struct __stack_info_t { 91 // pointer to stack 92 struct __stack_t * storage; 77 93 }; 78 94 … … 80 96 81 97 struct coroutine_desc { 98 // context that is switch during a CtxSwitch 99 struct __stack_context_t context; 100 82 101 // stack information of the coroutine 83 struct coStack_t stack;84 85 // textual name for coroutine/task , initialized by uC++ generated code102 struct __stack_info_t stack; 103 104 // textual name for coroutine/task 86 105 const char * name; 87 88 // copy of global UNIX variable errno89 int errno_;90 106 91 107 // current execution status for coroutine 92 108 enum coroutine_state state; 109 93 110 // first coroutine to resume this one 94 111 struct coroutine_desc * starter; … … 144 161 struct thread_desc { 145 162 // Core threading fields 163 // context that is switch during a CtxSwitch 164 struct __stack_context_t context; 165 166 // current execution status for coroutine 167 enum coroutine_state state; 168 169 //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it 170 146 171 // coroutine body used to store context 147 172 struct coroutine_desc self_cor; … … 170 195 struct thread_desc * prev; 171 196 } node; 172 }; 173 174 #ifdef __cforall 175 extern "Cforall" { 197 }; 198 199 #ifdef __cforall 200 extern "Cforall" { 201 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; } 202 static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); } 203 static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE 204 176 205 static inline thread_desc * & get_next( thread_desc & this ) { 177 206 return this.next; … … 231 260 // assembler routines that performs the context switch 232 261 extern void CtxInvokeStub( void ); 233 void CtxSwitch( void * from, void * to ) asm ("CtxSwitch"); 234 235 #if defined( __i386 ) 236 #define CtxGet( ctx ) __asm__ ( \ 237 "movl %%esp,%0\n" \ 238 "movl %%ebp,%1\n" \ 239 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 240 #elif defined( __x86_64 ) 241 #define CtxGet( ctx ) __asm__ ( \ 242 "movq %%rsp,%0\n" \ 243 "movq %%rbp,%1\n" \ 244 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 245 #elif defined( __ARM_ARCH ) 246 #define CtxGet( ctx ) __asm__ ( \ 247 "mov %0,%%sp\n" \ 248 "mov %1,%%r11\n" \ 249 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 250 #else 251 #error unknown hardware architecture 252 #endif 262 extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch"); 263 // void CtxStore ( void * this ) asm ("CtxStore"); 264 // void CtxRet ( void * dst ) asm ("CtxRet"); 253 265 254 266 #endif //_INVOKE_PRIVATE_H_ -
libcfa/src/concurrency/kernel.cfa
r6a9d4b4 r933f32f 36 36 #include "invoke.h" 37 37 38 //----------------------------------------------------------------------------- 39 // Some assembly required 40 #if defined( __i386 ) 41 #define CtxGet( ctx ) \ 42 __asm__ volatile ( \ 43 "movl %%esp,%0\n"\ 44 "movl %%ebp,%1\n"\ 45 : "=rm" (ctx.SP),\ 46 "=rm" (ctx.FP) \ 47 ) 48 49 // mxcr : SSE Status and Control bits (control bits are preserved across function calls) 50 // fcw : X87 FPU control word (preserved across function calls) 51 #define __x87_store \ 52 uint32_t __mxcr; \ 53 uint16_t __fcw; \ 54 __asm__ volatile ( \ 55 "stmxcsr %0\n" \ 56 "fnstcw %1\n" \ 57 : "=m" (__mxcr),\ 58 "=m" (__fcw) \ 59 ) 60 61 #define __x87_load \ 62 __asm__ volatile ( \ 63 "fldcw %1\n" \ 64 "ldmxcsr %0\n" \ 65 ::"m" (__mxcr),\ 66 "m" (__fcw) \ 67 ) 68 69 #elif defined( __x86_64 ) 70 #define CtxGet( ctx ) \ 71 __asm__ volatile ( \ 72 "movq %%rsp,%0\n"\ 73 "movq %%rbp,%1\n"\ 74 : "=rm" (ctx.SP),\ 75 "=rm" (ctx.FP) \ 76 ) 77 78 #define __x87_store \ 79 uint32_t __mxcr; \ 80 uint16_t __fcw; \ 81 __asm__ volatile ( \ 82 "stmxcsr %0\n" \ 83 "fnstcw %1\n" \ 84 : "=m" (__mxcr),\ 85 "=m" (__fcw) \ 86 ) 87 88 #define __x87_load \ 89 __asm__ volatile ( \ 90 "fldcw %1\n" \ 91 "ldmxcsr %0\n" \ 92 :: "m" (__mxcr),\ 93 "m" (__fcw) \ 94 ) 95 96 97 #elif defined( __ARM_ARCH ) 98 #define CtxGet( ctx ) __asm__ ( \ 99 "mov %0,%%sp\n" \ 100 "mov %1,%%r11\n" \ 101 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 102 #else 103 #error unknown hardware architecture 104 #endif 105 106 //----------------------------------------------------------------------------- 38 107 //Start and stop routine for the kernel, declared first to make sure they run first 39 108 static void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); … … 42 111 //----------------------------------------------------------------------------- 43 112 // Kernel storage 44 KERNEL_STORAGE(cluster, mainCluster);45 KERNEL_STORAGE(processor, mainProcessor);46 KERNEL_STORAGE(thread_desc, mainThread);47 KERNEL_STORAGE( machine_context_t,mainThreadCtx);113 KERNEL_STORAGE(cluster, mainCluster); 114 KERNEL_STORAGE(processor, mainProcessor); 115 KERNEL_STORAGE(thread_desc, mainThread); 116 KERNEL_STORAGE(__stack_t, mainThreadCtx); 48 117 49 118 cluster * mainCluster; … … 54 123 struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters; 55 124 } 125 126 size_t __page_size = 0; 56 127 57 128 //----------------------------------------------------------------------------- … … 60 131 NULL, 61 132 NULL, 62 NULL,63 133 { 1, false, false } 64 134 }; … … 67 137 // Struct to steal stack 68 138 struct current_stack_info_t { 69 machine_context_t ctx; 70 unsigned int size; // size of stack 139 __stack_t * storage; // pointer to stack object 71 140 void *base; // base of stack 72 void *storage; // pointer to stack73 141 void *limit; // stack grows towards stack limit 74 142 void *context; // address of cfa_context_t 75 void *top; // address of top of storage76 143 }; 77 144 78 145 void ?{}( current_stack_info_t & this ) { 79 CtxGet( this.ctx );80 this.base = this.ctx.FP;81 this. storage = this.ctx.SP;146 __stack_context_t ctx; 147 CtxGet( ctx ); 148 this.base = ctx.FP; 82 149 83 150 rlimit r; 84 151 getrlimit( RLIMIT_STACK, &r); 85 this.size = r.rlim_cur;86 87 this.limit = (void *)(((intptr_t)this.base) - this.size);152 size_t size = r.rlim_cur; 153 154 this.limit = (void *)(((intptr_t)this.base) - size); 88 155 this.context = &storage_mainThreadCtx; 89 this.top = this.base;90 156 } 91 157 92 158 //----------------------------------------------------------------------------- 93 159 // Main thread construction 94 void ?{}( coStack_t & this, current_stack_info_t * info) with( this ) {95 size = info->size;96 storage = info->storage;97 limit = info->limit;98 base = info->base;99 context = info->context;100 top = info->top;101 userStack = true;102 }103 160 104 161 void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) { 105 stack{ info }; 162 stack.storage = info->storage; 163 with(*stack.storage) { 164 limit = info->limit; 165 base = info->base; 166 } 167 __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage; 168 *istorage |= 0x1; 106 169 name = "Main Thread"; 107 errno_ = 0;108 170 state = Start; 109 171 starter = NULL; 172 last = NULL; 173 cancellation = NULL; 110 174 } 111 175 112 176 void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) { 177 state = Start; 113 178 self_cor{ info }; 114 179 curr_cor = &self_cor; … … 241 306 } 242 307 308 static int * __volatile_errno() __attribute__((noinline)); 309 static int * __volatile_errno() { asm(""); return &errno; } 310 243 311 // KERNEL ONLY 244 312 // runThread runs a thread by context switching 245 313 // from the processor coroutine to the target thread 246 static void runThread(processor * this, thread_desc * dst) { 247 assert(dst->curr_cor); 314 static void runThread(processor * this, thread_desc * thrd_dst) { 248 315 coroutine_desc * proc_cor = get_coroutine(this->runner); 249 coroutine_desc * thrd_cor = dst->curr_cor;250 316 251 317 // Reset the terminating actions here … … 253 319 254 320 // Update global state 255 kernelTLS.this_thread = dst; 256 257 // Context Switch to the thread 258 ThreadCtxSwitch(proc_cor, thrd_cor); 259 // when ThreadCtxSwitch returns we are back in the processor coroutine 321 kernelTLS.this_thread = thrd_dst; 322 323 // set state of processor coroutine to inactive and the thread to active 324 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 325 thrd_dst->state = Active; 326 327 // set context switch to the thread that the processor is executing 328 verify( thrd_dst->context.SP ); 329 CtxSwitch( &proc_cor->context, &thrd_dst->context ); 330 // when CtxSwitch returns we are back in the processor coroutine 331 332 // set state of processor coroutine to active and the thread to inactive 333 thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive; 334 proc_cor->state = Active; 260 335 } 261 336 … … 263 338 static void returnToKernel() { 264 339 coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner); 265 coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine; 266 ThreadCtxSwitch(thrd_cor, proc_cor); 340 thread_desc * thrd_src = kernelTLS.this_thread; 341 342 // set state of current coroutine to inactive 343 thrd_src->state = thrd_src->state == Halted ? Halted : Inactive; 344 proc_cor->state = Active; 345 int local_errno = *__volatile_errno(); 346 #if defined( __i386 ) || defined( __x86_64 ) 347 __x87_store; 348 #endif 349 350 // set new coroutine that the processor is executing 351 // and context switch to it 352 verify( proc_cor->context.SP ); 353 CtxSwitch( &thrd_src->context, &proc_cor->context ); 354 355 // set state of new coroutine to active 356 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 357 thrd_src->state = Active; 358 359 #if defined( __i386 ) || defined( __x86_64 ) 360 __x87_load; 361 #endif 362 *__volatile_errno() = local_errno; 267 363 } 268 364 … … 307 403 processor * proc = (processor *) arg; 308 404 kernelTLS.this_processor = proc; 309 kernelTLS.this_coroutine = NULL;310 405 kernelTLS.this_thread = NULL; 311 406 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1]; … … 314 409 // to waste the perfectly valid stack create by pthread. 315 410 current_stack_info_t info; 316 machine_context_t ctx;317 info. context= &ctx;411 __stack_t ctx; 412 info.storage = &ctx; 318 413 (proc->runner){ proc, &info }; 319 414 320 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack. base);415 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage); 321 416 322 417 //Set global state 323 kernelTLS.this_coroutine = get_coroutine(proc->runner);324 418 kernelTLS.this_thread = NULL; 325 419 … … 350 444 351 445 // KERNEL_ONLY 352 void kernel_first_resume( processor * this) {353 coroutine_desc * src = kernelTLS.this_coroutine;446 void kernel_first_resume( processor * this ) { 447 thread_desc * src = mainThread; 354 448 coroutine_desc * dst = get_coroutine(this->runner); 355 449 356 450 verify( ! kernelTLS.preemption_state.enabled ); 357 451 358 create_stack(&dst->stack, dst->stack.size);452 __stack_prepare( &dst->stack, 65000 ); 359 453 CtxStart(&this->runner, CtxInvokeCoroutine); 360 454 361 455 verify( ! kernelTLS.preemption_state.enabled ); 362 456 363 dst->last = src;364 dst->starter = dst->starter ? dst->starter : src;457 dst->last = &src->self_cor; 458 dst->starter = dst->starter ? dst->starter : &src->self_cor; 365 459 366 460 // set state of current coroutine to inactive 367 461 src->state = src->state == Halted ? Halted : Inactive; 368 462 369 // set new coroutine that task is executing370 kernelTLS.this_coroutine = dst;371 372 // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch.373 // Therefore, when first creating a coroutine, interrupts are enable before calling the main.374 // This is consistent with thread creation. However, when creating the main processor coroutine,375 // we wan't interrupts to be disabled. Therefore, we double-disable interrupts here so they will376 // stay disabled.377 disable_interrupts();378 379 463 // context switch to specified coroutine 380 assert( src->stack.context);381 CtxSwitch( src->stack.context, dst->stack.context );464 verify( dst->context.SP ); 465 CtxSwitch( &src->context, &dst->context ); 382 466 // when CtxSwitch returns we are back in the src coroutine 383 467 … … 386 470 387 471 verify( ! kernelTLS.preemption_state.enabled ); 472 } 473 474 // KERNEL_ONLY 475 void kernel_last_resume( processor * this ) { 476 coroutine_desc * src = &mainThread->self_cor; 477 coroutine_desc * dst = get_coroutine(this->runner); 478 479 verify( ! kernelTLS.preemption_state.enabled ); 480 verify( dst->starter == src ); 481 verify( dst->context.SP ); 482 483 // context switch to the processor 484 CtxSwitch( &src->context, &dst->context ); 388 485 } 389 486 … … 394 491 void ScheduleThread( thread_desc * thrd ) { 395 492 verify( thrd ); 396 verify( thrd->s elf_cor.state != Halted );493 verify( thrd->state != Halted ); 397 494 398 495 verify( ! kernelTLS.preemption_state.enabled ); … … 551 648 __cfaabi_dbg_print_safe("Kernel : Starting\n"); 552 649 650 __page_size = sysconf( _SC_PAGESIZE ); 651 553 652 __cfa_dbg_global_clusters.list{ __get }; 554 653 __cfa_dbg_global_clusters.lock{}; … … 565 664 mainThread = (thread_desc *)&storage_mainThread; 566 665 current_stack_info_t info; 666 info.storage = (__stack_t*)&storage_mainThreadCtx; 567 667 (*mainThread){ &info }; 568 668 … … 599 699 kernelTLS.this_processor = mainProcessor; 600 700 kernelTLS.this_thread = mainThread; 601 kernelTLS.this_coroutine = &mainThread->self_cor;602 701 603 702 // Enable preemption … … 634 733 // which is currently here 635 734 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 636 returnToKernel();735 kernel_last_resume( kernelTLS.this_processor ); 637 736 mainThread->self_cor.state = Halted; 638 737 … … 720 819 __cfaabi_dbg_bits_write( abort_text, len ); 721 820 722 if ( get_coroutine(thrd) != kernelTLS.this_coroutine) {723 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", kernelTLS.this_coroutine->name, kernelTLS.this_coroutine);821 if ( &thrd->self_cor != thrd->curr_cor ) { 822 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor ); 724 823 __cfaabi_dbg_bits_write( abort_text, len ); 725 824 } -
libcfa/src/concurrency/thread.cfa
r6a9d4b4 r933f32f 31 31 // Thread ctors and dtors 32 32 void ?{}(thread_desc & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) { 33 context{ NULL, NULL }; 33 34 self_cor{ name, storage, storageSize }; 34 verify(&self_cor);35 state = Start; 35 36 curr_cor = &self_cor; 36 37 self_mon.owner = &this; … … 73 74 forall( dtype T | is_thread(T) ) 74 75 void __thrd_start( T& this ) { 75 coroutine_desc* thrd_c = get_coroutine(this); 76 thread_desc * thrd_h = get_thread (this); 77 thrd_c->last = TL_GET( this_coroutine ); 78 79 // __cfaabi_dbg_print_safe("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h); 76 thread_desc * this_thrd = get_thread(this); 77 thread_desc * curr_thrd = TL_GET( this_thread ); 80 78 81 79 disable_interrupts(); 82 create_stack(&thrd_c->stack, thrd_c->stack.size);83 kernelTLS.this_coroutine = thrd_c;84 80 CtxStart(&this, CtxInvokeThread); 85 assert( thrd_c->last->stack.context ); 86 CtxSwitch( thrd_c->last->stack.context, thrd_c->stack.context ); 81 this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP]; 82 verify( this_thrd->context.SP ); 83 CtxSwitch( &curr_thrd->context, &this_thrd->context ); 87 84 88 ScheduleThread(th rd_h);85 ScheduleThread(this_thrd); 89 86 enable_interrupts( __cfaabi_dbg_ctx ); 90 87 } … … 92 89 extern "C" { 93 90 // KERNEL ONLY 94 void __finish_creation(void) { 95 coroutine_desc* thrd_c = kernelTLS.this_coroutine; 96 ThreadCtxSwitch( thrd_c, thrd_c->last ); 91 void __finish_creation(thread_desc * this) { 92 // set new coroutine that the processor is executing 93 // and context switch to it 94 verify( kernelTLS.this_thread != this ); 95 verify( kernelTLS.this_thread->context.SP ); 96 CtxSwitch( &this->context, &kernelTLS.this_thread->context ); 97 97 } 98 98 } … … 112 112 } 113 113 114 // KERNEL ONLY115 void ThreadCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {116 // set state of current coroutine to inactive117 src->state = src->state == Halted ? Halted : Inactive;118 dst->state = Active;119 120 // set new coroutine that the processor is executing121 // and context switch to it122 kernelTLS.this_coroutine = dst;123 assert( src->stack.context );124 CtxSwitch( src->stack.context, dst->stack.context );125 kernelTLS.this_coroutine = src;126 127 // set state of new coroutine to active128 dst->state = dst->state == Halted ? Halted : Inactive;129 src->state = Active;130 }131 132 114 // Local Variables: // 133 115 // mode: c // -
libcfa/src/concurrency/thread.hfa
r6a9d4b4 r933f32f 61 61 void ^?{}(thread_desc & this); 62 62 63 static inline void ?{}(thread_desc & this) { this{ "Anonymous Thread", *mainCluster, NULL, 0 }; }63 static inline void ?{}(thread_desc & this) { this{ "Anonymous Thread", *mainCluster, NULL, 65000 }; } 64 64 static inline void ?{}(thread_desc & this, size_t stackSize ) { this{ "Anonymous Thread", *mainCluster, NULL, stackSize }; } 65 65 static inline void ?{}(thread_desc & this, void * storage, size_t storageSize ) { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; } 66 static inline void ?{}(thread_desc & this, struct cluster & cl ) { this{ "Anonymous Thread", cl, NULL, 0 }; }67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize ) { this{ "Anonymous Thread", cl, 0, stackSize }; }66 static inline void ?{}(thread_desc & this, struct cluster & cl ) { this{ "Anonymous Thread", cl, NULL, 65000 }; } 67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize ) { this{ "Anonymous Thread", cl, NULL, stackSize }; } 68 68 static inline void ?{}(thread_desc & this, struct cluster & cl, void * storage, size_t storageSize ) { this{ "Anonymous Thread", cl, storage, storageSize }; } 69 static inline void ?{}(thread_desc & this, const char * const name) { this{ name, *mainCluster, NULL, 0 }; }70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl ) { this{ name, cl, NULL, 0 }; }69 static inline void ?{}(thread_desc & this, const char * const name) { this{ name, *mainCluster, NULL, 65000 }; } 70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl ) { this{ name, cl, NULL, 65000 }; } 71 71 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, NULL, stackSize }; } 72 72 -
libcfa/src/containers/maybe.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed May 24 15:40:00 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 20 15:23:50 201713 // Update Count : 212 // Last Modified On : Sun Feb 17 11:22:03 2019 13 // Update Count : 3 14 14 // 15 15 … … 39 39 forall(otype T) 40 40 maybe(T) ?=?(maybe(T) & this, maybe(T) that) { 41 if (this.has_value & that.has_value) {41 if (this.has_value && that.has_value) { 42 42 this.value = that.value; 43 43 } else if (this.has_value) { -
libcfa/src/containers/result.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed May 24 15:40:00 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 20 15:23:58 201713 // Update Count : 212 // Last Modified On : Sun Feb 17 11:24:04 2019 13 // Update Count : 3 14 14 // 15 15 … … 48 48 forall(otype T, otype E) 49 49 result(T, E) ?=?(result(T, E) & this, result(T, E) that) { 50 if (this.has_value & that.has_value) {50 if (this.has_value && that.has_value) { 51 51 this.value = that.value; 52 52 } else if (this.has_value) { -
libcfa/src/fstream.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Dec 24 18:33:38 201813 // Update Count : 3 0412 // Last Modified On : Thu May 16 08:33:28 2019 13 // Update Count : 328 14 14 // 15 15 … … 23 23 #include <complex.h> // creal, cimag 24 24 #include <assert.h> 25 #include <errno.h> // errno 25 26 26 27 #define IO_MSG "I/O error: " 27 28 28 void ?{}( ofstream & os, void * file , bool sepDefault, bool sepOnOff, bool nlOnOff, bool prt, const char * separator, const char * tupleSeparator) {29 void ?{}( ofstream & os, void * file ) { 29 30 os.file = file; 30 os.sepDefault = sepDefault; 31 os.sepOnOff = sepOnOff; 32 os.nlOnOff = nlOnOff; 33 os.prt = prt; 34 sepSet( os, separator ); 31 os.sepDefault = true; 32 os.sepOnOff = false; 33 os.nlOnOff = true; 34 os.prt = false; 35 os.sawNL = false; 36 sepSet( os, " " ); 35 37 sepSetCur( os, sepGet( os ) ); 36 sepSetTuple( os, tupleSeparator);38 sepSetTuple( os, ", " ); 37 39 } 38 40 … … 102 104 103 105 void open( ofstream & os, const char * name, const char * mode ) { 104 FILE * file = fopen( name, mode );106 FILE * file = fopen( name, mode ); 105 107 #ifdef __CFA_DEBUG__ 106 108 if ( file == 0 ) { 107 fprintf( stderr, IO_MSG "open output file \"%s\", ", name ); 108 perror( 0 ); 109 exit( EXIT_FAILURE ); 109 abort( IO_MSG "open output file \"%s\", %s", name, strerror( errno ) ); 110 110 } // if 111 111 #endif // __CFA_DEBUG__ 112 (os){ file , true, false, true, false, " ", ", "};112 (os){ file }; 113 113 } // open 114 114 … … 121 121 122 122 if ( fclose( (FILE *)(os.file) ) == EOF ) { 123 perror( IO_MSG "close output");123 abort( IO_MSG "close output %s", strerror( errno ) ); 124 124 } // if 125 125 } // close … … 127 127 ofstream & write( ofstream & os, const char * data, size_t size ) { 128 128 if ( fail( os ) ) { 129 fprintf( stderr, "attempt write I/O on failed stream\n" ); 130 exit( EXIT_FAILURE ); 129 abort( "attempt write I/O on failed stream\n" ); 131 130 } // if 132 131 133 132 if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) { 134 perror( IO_MSG "write" ); 135 exit( EXIT_FAILURE ); 133 abort( IO_MSG "write %s", strerror( errno ) ); 136 134 } // if 137 135 return os; … … 144 142 if ( len == EOF ) { 145 143 if ( ferror( (FILE *)(os.file) ) ) { 146 fprintf( stderr, "invalid write\n" ); 147 exit( EXIT_FAILURE ); 144 abort( "invalid write\n" ); 148 145 } // if 149 146 } // if … … 155 152 } // fmt 156 153 157 static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_) , true, false, true, false, " ", ", "};154 static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_) }; 158 155 ofstream & sout = soutFile; 159 static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_) , true, false, true, false, " ", ", "};156 static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_) }; 160 157 ofstream & serr = serrFile; 161 158 159 // static ofstream sexitFile = { (FILE *)(&_IO_2_1_stdout_) }; 160 // ofstream & sexit = sexitFile; 161 // static ofstream sabortFile = { (FILE *)(&_IO_2_1_stderr_) }; 162 // ofstream & sabort = sabortFile; 163 164 void nl( ofstream & os ) { 165 if ( getANL( os ) ) (ofstream &)(nl( os )); // implementation only 166 else setPrt( os, false ); // turn off 167 } 162 168 163 169 //--------------------------------------- … … 166 172 void ?{}( ifstream & is, void * file ) { 167 173 is.file = file; 174 is.nlOnOff = false; 168 175 } 169 176 … … 177 184 open( is, name, "r" ); 178 185 } 186 187 void nlOn( ifstream & os ) { os.nlOnOff = true; } 188 void nlOff( ifstream & os ) { os.nlOnOff = false; } 189 bool getANL( ifstream & os ) { return os.nlOnOff; } 179 190 180 191 int fail( ifstream & is ) { … … 187 198 188 199 void open( ifstream & is, const char * name, const char * mode ) { 189 FILE * file = fopen( name, mode );200 FILE * file = fopen( name, mode ); 190 201 #ifdef __CFA_DEBUG__ 191 202 if ( file == 0 ) { 192 fprintf( stderr, IO_MSG "open input file \"%s\", ", name ); 193 perror( 0 ); 194 exit( EXIT_FAILURE ); 203 abort( IO_MSG "open input file \"%s\", %s\n", name, strerror( errno ) ); 195 204 } // if 196 205 #endif // __CFA_DEBUG__ … … 206 215 207 216 if ( fclose( (FILE *)(is.file) ) == EOF ) { 208 perror( IO_MSG "close input");217 abort( IO_MSG "close input %s", strerror( errno ) ); 209 218 } // if 210 219 } // close … … 212 221 ifstream & read( ifstream & is, char * data, size_t size ) { 213 222 if ( fail( is ) ) { 214 fprintf( stderr, "attempt read I/O on failed stream\n" ); 215 exit( EXIT_FAILURE ); 223 abort( "attempt read I/O on failed stream\n" ); 216 224 } // if 217 225 218 226 if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) { 219 perror( IO_MSG "read" ); 220 exit( EXIT_FAILURE ); 227 abort( IO_MSG "read %s", strerror( errno ) ); 221 228 } // if 222 229 return is; … … 225 232 ifstream &ungetc( ifstream & is, char c ) { 226 233 if ( fail( is ) ) { 227 fprintf( stderr, "attempt ungetc I/O on failed stream\n" ); 228 exit( EXIT_FAILURE ); 234 abort( "attempt ungetc I/O on failed stream\n" ); 229 235 } // if 230 236 231 237 if ( ungetc( c, (FILE *)(is.file) ) == EOF ) { 232 perror( IO_MSG "ungetc" ); 233 exit( EXIT_FAILURE ); 238 abort( IO_MSG "ungetc %s", strerror( errno ) ); 234 239 } // if 235 240 return is; … … 243 248 if ( len == EOF ) { 244 249 if ( ferror( (FILE *)(is.file) ) ) { 245 fprintf( stderr, "invalid read\n" ); 246 exit( EXIT_FAILURE ); 250 abort( "invalid read\n" ); 247 251 } // if 248 252 } // if -
libcfa/src/fstream.hfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Dec 24 18:33:41 201813 // Update Count : 1 4912 // Last Modified On : Thu May 16 08:34:10 2019 13 // Update Count : 157 14 14 // 15 15 … … 70 70 extern ofstream & sout, & serr; 71 71 72 // extern ofstream & sout, & serr, & sexit, & sabort; 73 // void nl( ofstream & os ); 74 72 75 73 76 struct ifstream { 74 77 void * file; 78 bool nlOnOff; 75 79 }; // ifstream 76 80 77 81 // public 82 void nlOn( ifstream & ); 83 void nlOff( ifstream & ); 84 bool getANL( ifstream & ); 78 85 int fail( ifstream & is ); 79 86 int eof( ifstream & is ); -
libcfa/src/gmp.hfa
r6a9d4b4 r933f32f 10 10 // Created On : Tue Apr 19 08:43:43 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 4 23:25:51 201813 // Update Count : 2 212 // Last Modified On : Sat Apr 20 09:01:52 2019 13 // Update Count : 24 14 14 // 15 15 … … 271 271 272 272 void ?|?( ostype & os, Int mp ) { 273 (ostype)(os | mp); if ( getANL( os ) )nl( os );273 (ostype)(os | mp); nl( os ); 274 274 } // ?|? 275 275 } // distribution -
libcfa/src/heap.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Sep 6 09:01:30 201813 // Update Count : 51 312 // Last Modified On : Thu May 9 16:29:12 2019 13 // Update Count : 516 14 14 // 15 15 … … 220 220 StackLF<Storage> freeList; 221 221 #else 222 #error undefined lock type for bucket lock222 #error undefined lock type for bucket lock 223 223 #endif // SPINLOCK 224 224 size_t blockSize; // size of allocations on this list … … 234 234 }; // HeapManager 235 235 236 236 237 static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; } 238 237 239 // statically allocated variables => zero filled. 238 239 240 240 static size_t pageSize; // architecture pagesize 241 241 static size_t heapExpand; // sbrk advance … … 306 306 sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment 307 307 heapBegin = heapEnd = sbrk( 0 ); // get new start point 308 } // HeapManager308 } // HeapManager 309 309 310 310 … … 316 316 // } // if 317 317 #endif // __STATISTICS__ 318 } // ~HeapManager318 } // ~HeapManager 319 319 320 320 … … 533 533 534 534 static inline void * doMalloc( size_t size ) with ( heapManager ) { 535 HeapManager.Storage * block; 535 HeapManager.Storage * block; // pointer to new block of storage 536 536 537 537 // Look up size in the size list. Make sure the user request includes space for the header that must be allocated … … 656 656 __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST ); 657 657 if ( traceHeap() ) { 658 char helpText[64]; 658 enum { BufferSize = 64 }; 659 char helpText[BufferSize]; 659 660 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size ); 660 661 __cfaabi_dbg_bits_write( helpText, len ); … … 853 854 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero. 854 855 if ( ! mapped ) 855 #endif // __CFA_DEBUG__856 #endif // __CFA_DEBUG__ 856 857 memset( (char *)area + usize, '\0', asize - ( (char *)area - (char *)header ) - usize ); // zero-fill back part 857 858 header->kind.real.blockSize |= 2; // mark new request as zero fill … … 1034 1035 // Local Variables: // 1035 1036 // tab-width: 4 // 1036 // compile-command: "cfa -nodebug -O2 heap.c " //1037 // compile-command: "cfa -nodebug -O2 heap.cfa" // 1037 1038 // End: // -
libcfa/src/iostream.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Dec 24 18:33:40 201813 // Update Count : 58912 // Last Modified On : Sun May 19 10:48:27 2019 13 // Update Count : 654 14 14 // 15 15 … … 23 23 extern size_t strlen (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1))); 24 24 #include <float.h> // DBL_DIG, LDBL_DIG 25 #include <math.h> // isfinite 25 26 #include <complex.h> // creal, cimag 26 27 } 27 28 28 29 forall( dtype ostype | ostream( ostype ) ) { 30 ostype & ?|?( ostype & os, zero_t ) { 31 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 32 fmt( os, "%d", 0n ); 33 return os; 34 } // ?|? 35 void ?|?( ostype & os, zero_t z ) { 36 (ostype &)(os | z); nl( os ); 37 } // ?|? 38 39 ostype & ?|?( ostype & os, one_t ) { 40 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 41 fmt( os, "%d", 1n ); 42 return os; 43 } // ?|? 44 void ?|?( ostype & os, one_t o ) { 45 (ostype &)(os | o); nl( os ); 46 } // ?|? 47 29 48 ostype & ?|?( ostype & os, bool b ) { 30 49 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); … … 135 154 } // ?|? 136 155 156 static void checkDecPt( ostype & os, const char * buf, int len ) { 157 for ( int i = 0;; i += 1 ) { 158 if ( i == len ) { fmt( os, "." ); break; } 159 if ( buf[i] == '.' ) break; 160 } // for 161 } // checkDecPt 162 137 163 ostype & ?|?( ostype & os, float f ) { 138 164 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 139 fmt( os, "%g", f ); 165 char buf[48]; 166 int len = snprintf( buf, 48, "%g", f ); 167 fmt( os, "%s", buf ); 168 if ( isfinite( f ) ) checkDecPt( os, buf, len ); // always print decimal point 140 169 return os; 141 170 } // ?|? … … 146 175 ostype & ?|?( ostype & os, double d ) { 147 176 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 148 fmt( os, "%.*lg", DBL_DIG, d ); 177 char buf[48]; 178 int len = snprintf( buf, 48, "%.*lg", DBL_DIG, d ); 179 fmt( os, "%s", buf ); 180 if ( isfinite( d ) ) checkDecPt( os, buf, len ); // always print decimal point 149 181 return os; 150 182 } // ?|? … … 155 187 ostype & ?|?( ostype & os, long double ld ) { 156 188 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 157 fmt( os, "%.*Lg", LDBL_DIG, ld ); 189 char buf[48]; 190 int len = snprintf( buf, 48, "%.*Lg", LDBL_DIG, ld ); 191 fmt( os, "%s", buf ); 192 if ( isfinite( ld ) ) checkDecPt( os, buf, len ); // always print decimal point 158 193 return os; 159 194 } // ?|? … … 164 199 ostype & ?|?( ostype & os, float _Complex fc ) { 165 200 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 166 fmt( os, "%g%+gi", crealf( fc ), cimagf( fc ) ); 201 // os | crealf( fc ) | nonl; 202 float f = crealf( fc ); 203 char buf[48]; 204 int len = snprintf( buf, 48, "%g", f ); 205 fmt( os, "%s", buf ); 206 if ( isfinite( f ) ) checkDecPt( os, buf, len ); // always print decimal point 207 f = cimagf( fc ); 208 len = snprintf( buf, 48, "%+g", f ); 209 fmt( os, "%s", buf ); 210 if ( isfinite( f ) ) checkDecPt( os, buf, len ); // always print decimal point 211 fmt( os, "i" ); 167 212 return os; 168 213 } // ?|? … … 173 218 ostype & ?|?( ostype & os, double _Complex dc ) { 174 219 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 175 fmt( os, "%.*lg%+.*lgi", DBL_DIG, creal( dc ), DBL_DIG, cimag( dc ) ); 220 // os | creal( dc ) | nonl; 221 double d = creal( dc ); 222 char buf[48]; 223 int len = snprintf( buf, 48, "%.*lg", DBL_DIG, d ); 224 fmt( os, "%s", buf ); 225 if ( isfinite( d ) ) checkDecPt( os, buf, len ); // always print decimal point 226 d = cimag( dc ); 227 len = snprintf( buf, 48, "%+.*lg", DBL_DIG, d ); 228 fmt( os, "%s", buf ); 229 if ( isfinite( d ) ) checkDecPt( os, buf, len ); // always print decimal point 230 fmt( os, "i" ); 176 231 return os; 177 232 } // ?|? … … 182 237 ostype & ?|?( ostype & os, long double _Complex ldc ) { 183 238 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 184 fmt( os, "%.*Lg%+.*Lgi", LDBL_DIG, creall( ldc ), LDBL_DIG, cimagl( ldc ) ); 239 // os | creall( ldc ) || nonl; 240 long double ld = creall( ldc ); 241 char buf[48]; 242 int len = snprintf( buf, 48, "%.*Lg", LDBL_DIG, ld ); 243 fmt( os, "%s", buf ); 244 if ( isfinite( ld ) ) checkDecPt( os, buf, len ); // always print decimal point 245 ld = cimagl( ldc ); 246 len = snprintf( buf, 48, "%+.*Lg", LDBL_DIG, ld ); 247 fmt( os, "%s", buf ); 248 if ( isfinite( ld ) ) checkDecPt( os, buf, len ); // always print decimal point 249 fmt( os, "i" ); 185 250 return os; 186 251 } // ?|? … … 378 443 379 444 istype & ?|?( istype & is, char & c ) { 380 fmt( is, "%c", &c ); // must pass pointer through varg to fmt 445 char temp; 446 for () { 447 fmt( is, "%c", &temp ); // must pass pointer through varg to fmt 448 // do not overwrite parameter with newline unless appropriate 449 if ( temp != '\n' || getANL( is ) ) { c = temp; break; } 450 if ( eof( is ) ) break; 451 } // for 381 452 return is; 382 453 } // ?|? … … 470 541 } // ?|? 471 542 472 473 543 // manipulators 474 544 istype & ?|?( istype & is, istype & (* manip)( istype & ) ) { … … 477 547 478 548 istype & nl( istype & is ) { 479 fmt( is, "%*[ \t\f\n\r\v]" ); // ignore whitespace549 fmt( is, "%*[^\n]" ); // ignore characters to newline 480 550 return is; 481 551 } // nl 552 553 istype & nlOn( istype & is ) { 554 nlOn( is ); // call void returning 555 return is; 556 } // nlOn 557 558 istype & nlOff( istype & is ) { 559 nlOff( is ); // call void returning 560 return is; 561 } // nlOff 482 562 } // distribution 483 563 -
libcfa/src/iostream.hfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Dec 24 18:33:40 201813 // Update Count : 2 2012 // Last Modified On : Sat May 11 10:31:27 2019 13 // Update Count : 232 14 14 // 15 15 … … 48 48 void close( ostype & os ); 49 49 ostype & write( ostype &, const char *, size_t ); 50 int fmt( ostype &, const char format[], ... ) ;50 int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) )); 51 51 }; // ostream 52 52 … … 62 62 63 63 forall( dtype ostype | ostream( ostype ) ) { 64 ostype & ?|?( ostype &, zero_t ); 65 void ?|?( ostype &, zero_t ); 66 ostype & ?|?( ostype &, one_t ); 67 void ?|?( ostype &, one_t ); 68 64 69 ostype & ?|?( ostype &, bool ); 65 70 void ?|?( ostype &, bool ); … … 144 149 145 150 trait istream( dtype istype ) { 151 void nlOn( istype & ); // read newline 152 void nlOff( istype & ); // scan newline 153 bool getANL( istype & ); // get scan newline (on/off) 146 154 int fail( istype & ); 147 155 int eof( istype & ); … … 150 158 istype & read( istype &, char *, size_t ); 151 159 istype & ungetc( istype &, char ); 152 int fmt( istype &, const char format[], ... ) ;160 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 153 161 }; // istream 154 162 … … 184 192 istype & ?|?( istype &, istype & (*)( istype & ) ); 185 193 istype & nl( istype & is ); 194 istype & nlOn( istype & ); 195 istype & nlOff( istype & ); 186 196 } // distribution 187 197 … … 205 215 206 216 // Local Variables: // 207 // mode: c //208 217 // tab-width: 4 // 209 218 // End: // -
libcfa/src/rational.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed Apr 6 17:54:28 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Dec 23 22:56:49 201813 // Update Count : 1 7012 // Last Modified On : Thu Mar 28 17:33:03 2019 13 // Update Count : 181 14 14 // 15 15 … … 35 35 static RationalImpl simplify( RationalImpl & n, RationalImpl & d ) { 36 36 if ( d == (RationalImpl){0} ) { 37 serr | "Invalid rational number construction: denominator cannot be equal to 0."; 38 exit( EXIT_FAILURE ); 37 abort( "Invalid rational number construction: denominator cannot be equal to 0.\n" ); 39 38 } // exit 40 39 if ( d < (RationalImpl){0} ) { d = -d; n = -n; } // move sign to numerator … … 54 53 void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ) { 55 54 RationalImpl t = simplify( n, d ); // simplify 56 r.numerator = n / t; 57 r.denominator = d / t; 55 r.[numerator, denominator] = [n / t, d / t]; 58 56 } // rational 59 57 … … 78 76 RationalImpl prev = r.numerator; 79 77 RationalImpl t = gcd( abs( n ), r.denominator ); // simplify 80 r.numerator = n / t; 81 r.denominator = r.denominator / t; 78 r.[numerator, denominator] = [n / t, r.denominator / t]; 82 79 return prev; 83 80 } // numerator … … 86 83 RationalImpl prev = r.denominator; 87 84 RationalImpl t = simplify( r.numerator, d ); // simplify 88 r.numerator = r.numerator / t; 89 r.denominator = d / t; 85 r.[numerator, denominator] = [r.numerator / t, d / t]; 90 86 return prev; 91 87 } // denominator … … 120 116 121 117 Rational(RationalImpl) +?( Rational(RationalImpl) r ) { 122 Rational(RationalImpl) t = { r.numerator, r.denominator }; 123 return t; 118 return (Rational(RationalImpl)){ r.numerator, r.denominator }; 124 119 } // +? 125 120 126 121 Rational(RationalImpl) -?( Rational(RationalImpl) r ) { 127 Rational(RationalImpl) t = { -r.numerator, r.denominator }; 128 return t; 122 return (Rational(RationalImpl)){ -r.numerator, r.denominator }; 129 123 } // -? 130 124 131 125 Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 132 126 if ( l.denominator == r.denominator ) { // special case 133 Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator }; 134 return t; 127 return (Rational(RationalImpl)){ l.numerator + r.numerator, l.denominator }; 135 128 } else { 136 Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; 137 return t; 129 return (Rational(RationalImpl)){ l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; 138 130 } // if 139 131 } // ?+? … … 141 133 Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 142 134 if ( l.denominator == r.denominator ) { // special case 143 Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator }; 144 return t; 135 return (Rational(RationalImpl)){ l.numerator - r.numerator, l.denominator }; 145 136 } else { 146 Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; 147 return t; 137 return (Rational(RationalImpl)){ l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; 148 138 } // if 149 139 } // ?-? 150 140 151 141 Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 152 Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator }; 153 return t; 142 return (Rational(RationalImpl)){ l.numerator * r.numerator, l.denominator * r.denominator }; 154 143 } // ?*? 155 144 156 145 Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 157 146 if ( r.numerator < (RationalImpl){0} ) { 158 r.numerator = -r.numerator; 159 r.denominator = -r.denominator; 147 r.[numerator, denominator] = [-r.numerator, -r.denominator]; 160 148 } // if 161 Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator }; 162 return t; 149 return (Rational(RationalImpl)){ l.numerator * r.denominator, l.denominator * r.numerator }; 163 150 } // ?/? 164 151 … … 167 154 forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } ) 168 155 istype & ?|?( istype & is, Rational(RationalImpl) & r ) { 169 RationalImpl t;170 156 is | r.numerator | r.denominator; 171 t = simplify( r.numerator, r.denominator );157 RationalImpl t = simplify( r.numerator, r.denominator ); 172 158 r.numerator /= t; 173 159 r.denominator /= t; … … 185 171 } // distribution 186 172 } // distribution 173 174 forall( otype RationalImpl | arithmetic( RationalImpl ) | { RationalImpl ?\?( RationalImpl, unsigned long ); } ) 175 Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y ) { 176 if ( y < 0 ) { 177 return (Rational(RationalImpl)){ x.denominator \ -y, x.numerator \ -y }; 178 } else { 179 return (Rational(RationalImpl)){ x.numerator \ y, x.denominator \ y }; 180 } // if 181 } 187 182 188 183 // conversion -
libcfa/src/rational.hfa
r6a9d4b4 r933f32f 12 12 // Created On : Wed Apr 6 17:56:25 2016 13 13 // Last Modified By : Peter A. Buhr 14 // Last Modified On : Tue Dec 4 23:07:46 201815 // Update Count : 10 614 // Last Modified On : Tue Mar 26 23:16:10 2019 15 // Update Count : 109 16 16 // 17 17 … … 98 98 } // distribution 99 99 100 forall( otype RationalImpl | arithmetic( RationalImpl ) |{RationalImpl ?\?( RationalImpl, unsigned long );} ) 101 Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y ); 102 100 103 // conversion 101 104 forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); } ) -
libcfa/src/stdhdr/stdbool.h
r6a9d4b4 r933f32f 10 10 // Created On : Mon Jul 4 23:25:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jul 5 20:39:51 201613 // Update Count : 1 212 // Last Modified On : Mon Mar 25 08:00:08 2019 13 // Update Count : 15 14 14 // 15 15 16 16 extern "C" { 17 17 #include_next <stdbool.h> // has internal check for multiple expansion 18 19 // allows printing as true/false 20 #if defined( true ) 21 #undef true 22 #define true ((_Bool)1) 23 #endif // true 24 25 #if defined( false ) 26 #undef false 27 #define false ((_Bool)0) 28 #endif // false 18 29 } // extern "C" 19 30 -
libcfa/src/stdlib.hfa
r6a9d4b4 r933f32f 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Dec 17 15:37:45 201813 // Update Count : 3 4612 // Last Modified On : Wed Apr 24 17:35:43 2019 13 // Update Count : 352 14 14 // 15 15 … … 40 40 } // malloc 41 41 42 // T & malloc( void ) {43 // int & p = *(T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc44 // printf( "& malloc %p\n", &p );45 // return p;46 // // return (T &)*(T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc47 // } // malloc48 49 42 T * calloc( size_t dim ) { 50 43 return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc … … 76 69 T * alloc( char fill ) { 77 70 T * ptr = (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc 78 return (T *)memset( ptr, (int)fill, sizeof(T) ); // initialwith fill value71 return (T *)memset( ptr, (int)fill, sizeof(T) ); // initialize with fill value 79 72 } // alloc 80 73 … … 84 77 85 78 T * alloc( size_t dim, char fill ) { 86 T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C malloc87 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); // initialwith fill value79 T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C calloc 80 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); // initialize with fill value 88 81 } // alloc 89 82 -
libcfa/src/time.hfa
r6a9d4b4 r933f32f 30 30 31 31 static inline { 32 Duration ?=?( Duration & dur, zero_t ) { return dur{ 0 }; }32 Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; } 33 33 34 34 Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tv }; } … … 59 59 bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tv >= rhs.tv; } 60 60 61 bool ?==?( Duration lhs, zero_t ) { return lhs.tv == 0; }62 bool ?!=?( Duration lhs, zero_t ) { return lhs.tv != 0; }63 bool ?<? ( Duration lhs, zero_t ) { return lhs.tv < 0; }64 bool ?<=?( Duration lhs, zero_t ) { return lhs.tv <= 0; }65 bool ?>? ( Duration lhs, zero_t ) { return lhs.tv > 0; }66 bool ?>=?( Duration lhs, zero_t ) { return lhs.tv >= 0; }61 bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv == 0; } 62 bool ?!=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv != 0; } 63 bool ?<? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv < 0; } 64 bool ?<=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv <= 0; } 65 bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv > 0; } 66 bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv >= 0; } 67 67 68 68 Duration abs( Duration rhs ) { return rhs.tv >= 0 ? rhs : -rhs; } … … 101 101 void ?{}( timeval & t, time_t sec, suseconds_t usec ) { t.tv_sec = sec; t.tv_usec = usec; } 102 102 void ?{}( timeval & t, time_t sec ) { t{ sec, 0 }; } 103 void ?{}( timeval & t, zero_t ) { t{ 0, 0 }; }104 105 timeval ?=?( timeval & t, zero_t ) { return t{ 0 }; }103 void ?{}( timeval & t, __attribute__((unused)) zero_t ) { t{ 0, 0 }; } 104 105 timeval ?=?( timeval & t, __attribute__((unused)) zero_t ) { return t{ 0 }; } 106 106 timeval ?+?( timeval lhs, timeval rhs ) { return (timeval)@{ lhs.tv_sec + rhs.tv_sec, lhs.tv_usec + rhs.tv_usec }; } 107 107 timeval ?-?( timeval lhs, timeval rhs ) { return (timeval)@{ lhs.tv_sec - rhs.tv_sec, lhs.tv_usec - rhs.tv_usec }; } … … 116 116 void ?{}( timespec & t, time_t sec, __syscall_slong_t nsec ) { t.tv_sec = sec; t.tv_nsec = nsec; } 117 117 void ?{}( timespec & t, time_t sec ) { t{ sec, 0}; } 118 void ?{}( timespec & t, zero_t ) { t{ 0, 0 }; }119 120 timespec ?=?( timespec & t, zero_t ) { return t{ 0 }; }118 void ?{}( timespec & t, __attribute__((unused)) zero_t ) { t{ 0, 0 }; } 119 120 timespec ?=?( timespec & t, __attribute__((unused)) zero_t ) { return t{ 0 }; } 121 121 timespec ?+?( timespec lhs, timespec rhs ) { return (timespec)@{ lhs.tv_sec + rhs.tv_sec, lhs.tv_nsec + rhs.tv_nsec }; } 122 122 timespec ?-?( timespec lhs, timespec rhs ) { return (timespec)@{ lhs.tv_sec - rhs.tv_sec, lhs.tv_nsec - rhs.tv_nsec }; } … … 145 145 void ?{}( Time & time, int year, int month = 0, int day = 0, int hour = 0, int min = 0, int sec = 0, int nsec = 0 ); 146 146 static inline { 147 Time ?=?( Time & time, zero_t ) { return time{ 0 }; }147 Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; } 148 148 149 149 void ?{}( Time & time, timeval t ) with( time ) { tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; } -
libcfa/src/time_t.hfa
r6a9d4b4 r933f32f 24 24 25 25 static inline void ?{}( Duration & dur ) with( dur ) { tv = 0; } 26 static inline void ?{}( Duration & dur, zero_t ) with( dur ) { tv = 0; }26 static inline void ?{}( Duration & dur, __attribute__((unused)) zero_t ) with( dur ) { tv = 0; } 27 27 28 28 … … 34 34 35 35 static inline void ?{}( Time & time ) with( time ) { tv = 0; } 36 static inline void ?{}( Time & time, zero_t ) with( time ) { tv = 0; }36 static inline void ?{}( Time & time, __attribute__((unused)) zero_t ) with( time ) { tv = 0; } 37 37 38 38 // Local Variables: // -
longrun_tests/Makefile.in
r6a9d4b4 r933f32f 91 91 build_triplet = @build@ 92 92 host_triplet = @host@ 93 subdir = tests/preempt_longrun93 subdir = longrun_tests 94 94 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 95 95 am__aclocal_m4_deps = $(top_srcdir)/automake/libtool.m4 \ … … 331 331 $(TEST_LOG_FLAGS) 332 332 am__DIST_COMMON = $(srcdir)/Makefile.in \ 333 $(top_srcdir)/automake/test-driver 333 $(top_srcdir)/automake/test-driver $(top_srcdir)/src/cfa.make 334 334 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 335 335 ACLOCAL = @ACLOCAL@ 336 ALLOCA = @ALLOCA@337 336 AMTAR = @AMTAR@ 338 337 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 343 342 AWK = @AWK@ 344 343 BUILD_IN_TREE_FLAGS = @BUILD_IN_TREE_FLAGS@ 345 CC = @C FACC@344 CC = @CC@ 346 345 CCAS = @CCAS@ 347 346 CCASDEPMODE = @CCASDEPMODE@ … … 357 356 CFA_NAME = @CFA_NAME@ 358 357 CFA_PREFIX = @CFA_PREFIX@ 359 CFLAGS = ${BUILD_FLAGS}358 CFLAGS = @CFLAGS@ 360 359 CPP = @CPP@ 361 360 CPPFLAGS = @CPPFLAGS@ … … 480 479 AUTOMAKE_OPTIONS = foreign # do not require all the GNU file names 481 480 ACLOCAL_AMFLAGS = -I automake 481 CFACOMPILE = $(CFACC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) $(AM_CFLAGS) $(CFLAGS) 482 LTCFACOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ 483 $(LIBTOOLFLAGS) --mode=compile $(CFACC) $(DEFS) \ 484 $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) \ 485 $(AM_CFLAGS) $(CFLAGS) 486 487 AM_V_CFA = $(am__v_CFA_@AM_V@) 488 am__v_CFA_ = $(am__v_CFA_@AM_DEFAULT_V@) 489 am__v_CFA_0 = @echo " CFA " $@; 490 am__v_CFA_1 = 491 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@) 492 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@) 493 am__v_JAVAC_0 = @echo " JAVAC " $@; 494 am__v_JAVAC_1 = 495 AM_V_GOC = $(am__v_GOC_@AM_V@) 496 am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@) 497 am__v_GOC_0 = @echo " GOC " $@; 498 am__v_GOC_1 = 499 UPPCC = u++ 500 UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS) 501 AM_V_UPP = $(am__v_UPP_@AM_V@) 502 am__v_UPP_ = $(am__v_UPP_@AM_DEFAULT_V@) 503 am__v_UPP_0 = @echo " UPP " $@; 504 am__v_UPP_1 = 482 505 repeats = 10 483 506 max_time = 600 … … 485 508 debug = -debug 486 509 type = LONG 487 REPEAT = $ {abs_top_srcdir}/tools/repeat488 WATCHDOG = $ {abs_top_srcdir}/tools/watchdog510 REPEAT = $(abs_top_builddir)/tools/repeat 511 WATCHDOG = $(abs_top_builddir)/tools/watchdog 489 512 TIME = /usr/bin/time -f "%E" 490 491 # $(shell ./update-type $(type)) 492 # ./update-type $(type) 493 UPDATED_TYPE = $(shell ./update-type $(type)) 494 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) 513 UPDATED_TYPE = $(shell $(srcdir)/update-type $(type)) 514 BUILD_FLAGS = 515 AM_CFAFLAGS = \ 516 -g \ 517 -Wall \ 518 -Wno-unused-function \ 519 -quiet \ 520 -O2 \ 521 -DPREEMPTION_RATE=$(preempt) \ 522 -I$(abs_top_srcdir)/tests \ 523 -I$(srcdir) \ 524 -DTEST_$(shell cat .type | tr a-z A-Z) \ 525 -in-tree 526 495 527 TESTS = block coroutine create disjoint enter enter3 processor stack wait yield 496 528 all: all-am 497 529 498 530 .SUFFIXES: 499 .SUFFIXES: . log.test .test$(EXEEXT) .trs500 $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)531 .SUFFIXES: .cfa .lo .log .o .test .test$(EXEEXT) .trs 532 $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/src/cfa.make $(am__configure_deps) 501 533 @for dep in $?; do \ 502 534 case '$(am__configure_deps)' in \ … … 507 539 esac; \ 508 540 done; \ 509 echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/preempt_longrun/Makefile'; \541 echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign longrun_tests/Makefile'; \ 510 542 $(am__cd) $(top_srcdir) && \ 511 $(AUTOMAKE) --foreign tests/preempt_longrun/Makefile543 $(AUTOMAKE) --foreign longrun_tests/Makefile 512 544 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 513 545 @case '$?' in \ … … 518 550 cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ 519 551 esac; 552 $(top_srcdir)/src/cfa.make $(am__empty): 520 553 521 554 $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) … … 918 951 919 952 920 # .INTERMEDIATE: ${TESTS} 921 922 all-local: ${TESTS:=.run} 923 924 runall : ${TESTS:=.run} 953 .cfa.o: 954 $(AM_V_CFA)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ 955 $(CFACOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ 956 $(am__mv) $$depbase.Tpo $$depbase.Po 957 958 .cfa.lo: 959 $(AM_V_CFA)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ 960 $(LTCFACOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ 961 $(am__mv) $$depbase.Tpo $$depbase.Plo 962 963 # .INTERMEDIATE: $(TESTS) 964 965 all-local: $(TESTS:=.run) 966 967 runall : $(TESTS:=.run) 925 968 @ echo "All programs terminated normally" 926 969 927 watchall : $ {TESTS:=.watch}970 watchall : $(TESTS:=.watch) 928 971 @ echo "All programs terminated normally" 929 972 930 compileall : $ {TESTS}973 compileall : $(TESTS) 931 974 @ echo "Compiled" 932 975 933 976 clean-local: 934 rm -f $ {TESTS}core* out.log .type935 936 % : %.c ${CC} ${UPDATED_TYPE}937 $ {AM_V_GEN}${CC} ${CFLAGS} ${<} $(debug) -o ${@}938 939 %.run : % $ {REPEAT}940 @ time $ {REPEAT} -r out.log -i -s $(repeats) timeout ${max_time} ./${<}941 @ rm $ {<}942 @ echo -e "$ {<}: SUCCESS\n"943 944 %.watch : % $ {WATCHDOG}945 @ time $ {WATCHDOG} ./${<}946 @ rm $ {<}947 @ echo -e "$ {<}: SUCCESS\n"948 949 %.time : % $ {REPEAT}950 @ $ {REPEAT} -i -s -- $(repeats) $(TIME) -a -o times.log ./${<}951 @ rm $ {<}952 @ echo -e "$ {<}: SUCCESS\n"953 954 $ {REPEAT}: ${abs_top_srcdir}/tools/Makefile955 @+make -C $ {abs_top_srcdir}/tools/956 957 $ {WATCHDOG}: ${abs_top_srcdir}/tools/Makefile958 @+make -C $ {abs_top_srcdir}/tools/977 rm -f $(TESTS) core* out.log .type 978 979 % : %.cfa $(CFACC) $(UPDATED_TYPE) 980 $(AM_V_CFA)$(CFACOMPILE) $(<) $(debug) -o $(@) 981 982 %.run : % $(REPEAT) 983 @ time $(REPEAT) -r out.log -i -s $(repeats) timeout $(max_time) ./$(<) 984 @ rm $(<) 985 @ echo -e "$(<): SUCCESS\n" 986 987 %.watch : % $(WATCHDOG) 988 @ time $(WATCHDOG} ./$(<) 989 @ rm $(<) 990 @ echo -e "$(<): SUCCESS\n" 991 992 %.time : % $(REPEAT) 993 @ $(REPEAT) -i -s -- $(repeats) $(TIME) -a -o times.log ./$(<) 994 @ rm $(<) 995 @ echo -e "$(<): SUCCESS\n" 996 997 $(REPEAT): $(abs_top_builddir)/tools/Makefile 998 @+make -C $(abs_top_builddir)/tools/ 999 1000 $(WATCHDOG): $(abs_top_builddir)/tools/Makefile 1001 @+make -C $(abs_top_builddir)/tools/ 959 1002 960 1003 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
longrun_tests/enter.cfa
r6a9d4b4 r933f32f 5 5 6 6 #define __kick_rate 75000ul 7 #include "long_tests.h "7 #include "long_tests.hfa" 8 8 9 9 #ifndef PREEMPTION_RATE -
longrun_tests/stack.cfa
r6a9d4b4 r933f32f 5 5 6 6 #define __kick_rate 5000000ul 7 #include "long_tests.h "7 #include "long_tests.hfa" 8 8 9 9 #ifndef PREEMPTION_RATE -
src/CodeGen/CodeGenerator.cc
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat May 5 09:08:32 201813 // Update Count : 49 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr May 2 10:47:00 2019 13 // Update Count : 497 14 14 // 15 15 #include "CodeGenerator.h" … … 83 83 void CodeGenerator::updateLocation( CodeLocation const & to ) { 84 84 // skip if linemarks shouldn't appear or if codelocation is unset 85 if ( ! lineMarks || to.isUnset() ) return;85 if ( !options.lineMarks || to.isUnset() ) return; 86 86 87 87 if ( currentLocation.followedBy( to, 0 ) ) { … … 116 116 } 117 117 118 CodeGenerator::CodeGenerator( std::ostream & os, bool pretty, bool genC, bool lineMarks, bool printExprTypes ) : indent( CodeGenerator::tabsize ), output( os ), printLabels( *this ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ), printExprTypes( printExprTypes ), endl( *this ) {} 118 CodeGenerator::CodeGenerator( std::ostream & os, bool pretty, bool genC, bool lineMarks, bool printExprTypes ) : indent( CodeGenerator::tabsize ), output( os ), printLabels( *this ), options( pretty, genC, lineMarks, printExprTypes ), endl( *this ) {} 119 CodeGenerator::CodeGenerator( std::ostream & os, const Options &options ) : indent( CodeGenerator::tabsize ), output( os ), printLabels( *this ), options(options), endl( *this ) {} 119 120 120 121 string CodeGenerator::mangleName( DeclarationWithType * decl ) { 121 122 // GCC builtins should always be printed unmangled 122 if ( pretty || decl->linkage.is_gcc_builtin ) return decl->name;123 if ( options.pretty || decl->linkage.is_gcc_builtin ) return decl->name; 123 124 if ( decl->mangleName != "" ) { 124 125 // need to incorporate scope level in order to differentiate names for destructors … … 164 165 previsit( (BaseSyntaxNode *)node ); 165 166 GuardAction( [this, node](){ 166 if ( printExprTypes && node->result ) {167 output << " /* " << genType( node->result, "", pretty, genC) << " */ ";167 if ( options.printExprTypes && node->result ) { 168 output << " /* " << genType( node->result, "", options ) << " */ "; 168 169 } 169 170 } ); … … 173 174 void CodeGenerator::postvisit( FunctionDecl * functionDecl ) { 174 175 // deleted decls should never be used, so don't print them 175 if ( functionDecl->isDeleted && genC ) return;176 if ( functionDecl->isDeleted && options.genC ) return; 176 177 extension( functionDecl ); 177 178 genAttributes( functionDecl->get_attributes() ); … … 180 181 functionDecl->get_funcSpec().print( output ); 181 182 182 output << genType( functionDecl->get_functionType(), mangleName( functionDecl ), pretty, genC ); 183 Options subOptions = options; 184 subOptions.anonymousUnused = functionDecl->has_body(); 185 output << genType( functionDecl->get_functionType(), mangleName( functionDecl ), subOptions ); 183 186 184 187 asmName( functionDecl ); … … 194 197 void CodeGenerator::postvisit( ObjectDecl * objectDecl ) { 195 198 // deleted decls should never be used, so don't print them 196 if ( objectDecl->isDeleted && genC ) return;197 if (objectDecl->get_name().empty() && genC ) {199 if ( objectDecl->isDeleted && options.genC ) return; 200 if (objectDecl->get_name().empty() && options.genC ) { 198 201 // only generate an anonymous name when generating C code, otherwise it clutters the output too much 199 202 static UniqueName name = { "__anonymous_object" }; 200 203 objectDecl->set_name( name.newName() ); 204 // Stops unused parameter warnings. 205 if ( options.anonymousUnused ) { 206 objectDecl->attributes.push_back( new Attribute( "unused" ) ); 207 } 201 208 } 202 209 … … 205 212 206 213 handleStorageClass( objectDecl ); 207 output << genType( objectDecl->get_type(), mangleName( objectDecl ), pretty,genC );214 output << genType( objectDecl->get_type(), mangleName( objectDecl ), options.pretty, options.genC ); 208 215 209 216 asmName( objectDecl ); … … 224 231 225 232 void CodeGenerator::handleAggregate( AggregateDecl * aggDecl, const std::string & kind ) { 226 if( ! aggDecl->parameters.empty() && ! genC ) {233 if( ! aggDecl->parameters.empty() && ! options.genC ) { 227 234 // assertf( ! genC, "Aggregate type parameters should not reach code generation." ); 228 235 output << "forall("; … … 294 301 295 302 void CodeGenerator::postvisit( TraitDecl * traitDecl ) { 296 assertf( ! genC, "TraitDecls should not reach code generation." );303 assertf( ! options.genC, "TraitDecls should not reach code generation." ); 297 304 extension( traitDecl ); 298 305 handleAggregate( traitDecl, "trait " ); … … 300 307 301 308 void CodeGenerator::postvisit( TypedefDecl * typeDecl ) { 302 assertf( ! genC, "Typedefs are removed and substituted in earlier passes." );309 assertf( ! options.genC, "Typedefs are removed and substituted in earlier passes." ); 303 310 output << "typedef "; 304 output << genType( typeDecl->get_base(), typeDecl->get_name(), pretty, genC) << endl;311 output << genType( typeDecl->get_base(), typeDecl->get_name(), options ) << endl; 305 312 } 306 313 307 314 void CodeGenerator::postvisit( TypeDecl * typeDecl ) { 308 assertf( ! genC, "TypeDecls should not reach code generation." );315 assertf( ! options.genC, "TypeDecls should not reach code generation." ); 309 316 output << typeDecl->genTypeString() << " " << typeDecl->name; 310 317 if ( typeDecl->sized ) { … … 371 378 372 379 void CodeGenerator::postvisit( ConstructorInit * init ){ 373 assertf( ! genC, "ConstructorInit nodes should not reach code generation." );380 assertf( ! options.genC, "ConstructorInit nodes should not reach code generation." ); 374 381 // pseudo-output for constructor/destructor pairs 375 382 output << "<ctorinit>{" << endl << ++indent << "ctor: "; … … 507 514 } else { 508 515 // no constructors with 0 or more than 2 parameters 509 assertf( ! genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );516 assertf( ! options.genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." ); 510 517 output << "("; 511 518 (*arg++)->accept( *visitor ); … … 604 611 // an lvalue cast, this has been taken out. 605 612 output << "("; 606 output << genType( castExpr->get_result(), "", pretty, genC);613 output << genType( castExpr->get_result(), "", options ); 607 614 output << ")"; 608 615 } // if … … 612 619 613 620 void CodeGenerator::postvisit( KeywordCastExpr * castExpr ) { 614 assertf( ! genC, "KeywordCast should not reach code generation." );621 assertf( ! options.genC, "KeywordCast should not reach code generation." ); 615 622 extension( castExpr ); 616 623 output << "((" << castExpr->targetString() << " &)"; … … 620 627 621 628 void CodeGenerator::postvisit( VirtualCastExpr * castExpr ) { 622 assertf( ! genC, "VirtualCastExpr should not reach code generation." );629 assertf( ! options.genC, "VirtualCastExpr should not reach code generation." ); 623 630 extension( castExpr ); 624 631 output << "(virtual "; … … 628 635 629 636 void CodeGenerator::postvisit( UntypedMemberExpr * memberExpr ) { 630 assertf( ! genC, "UntypedMemberExpr should not reach code generation." );637 assertf( ! options.genC, "UntypedMemberExpr should not reach code generation." ); 631 638 extension( memberExpr ); 632 639 memberExpr->get_aggregate()->accept( *visitor ); … … 661 668 output << "sizeof("; 662 669 if ( sizeofExpr->get_isType() ) { 663 output << genType( sizeofExpr->get_type(), "", pretty, genC);670 output << genType( sizeofExpr->get_type(), "", options ); 664 671 } else { 665 672 sizeofExpr->get_expr()->accept( *visitor ); … … 673 680 output << "__alignof__("; 674 681 if ( alignofExpr->get_isType() ) { 675 output << genType( alignofExpr->get_type(), "", pretty, genC);682 output << genType( alignofExpr->get_type(), "", options ); 676 683 } else { 677 684 alignofExpr->get_expr()->accept( *visitor ); … … 681 688 682 689 void CodeGenerator::postvisit( UntypedOffsetofExpr * offsetofExpr ) { 683 assertf( ! genC, "UntypedOffsetofExpr should not reach code generation." );690 assertf( ! options.genC, "UntypedOffsetofExpr should not reach code generation." ); 684 691 output << "offsetof("; 685 output << genType( offsetofExpr->get_type(), "", pretty, genC);692 output << genType( offsetofExpr->get_type(), "", options ); 686 693 output << ", " << offsetofExpr->get_member(); 687 694 output << ")"; … … 691 698 // use GCC builtin 692 699 output << "__builtin_offsetof("; 693 output << genType( offsetofExpr->get_type(), "", pretty, genC);700 output << genType( offsetofExpr->get_type(), "", options ); 694 701 output << ", " << mangleName( offsetofExpr->get_member() ); 695 702 output << ")"; … … 697 704 698 705 void CodeGenerator::postvisit( OffsetPackExpr * offsetPackExpr ) { 699 assertf( ! genC, "OffsetPackExpr should not reach code generation." );700 output << "__CFA_offsetpack(" << genType( offsetPackExpr->get_type(), "", pretty, genC) << ")";706 assertf( ! options.genC, "OffsetPackExpr should not reach code generation." ); 707 output << "__CFA_offsetpack(" << genType( offsetPackExpr->get_type(), "", options ) << ")"; 701 708 } 702 709 … … 728 735 extension( commaExpr ); 729 736 output << "("; 730 if ( genC ) {737 if ( options.genC ) { 731 738 // arg1 of a CommaExpr is never used, so it can be safely cast to void to reduce gcc warnings. 732 739 commaExpr->set_arg1( new CastExpr( commaExpr->get_arg1() ) ); … … 739 746 740 747 void CodeGenerator::postvisit( TupleAssignExpr * tupleExpr ) { 741 assertf( ! genC, "TupleAssignExpr should not reach code generation." );748 assertf( ! options.genC, "TupleAssignExpr should not reach code generation." ); 742 749 tupleExpr->stmtExpr->accept( *visitor ); 743 750 } 744 751 745 752 void CodeGenerator::postvisit( UntypedTupleExpr * tupleExpr ) { 746 assertf( ! genC, "UntypedTupleExpr should not reach code generation." );753 assertf( ! options.genC, "UntypedTupleExpr should not reach code generation." ); 747 754 extension( tupleExpr ); 748 755 output << "["; … … 752 759 753 760 void CodeGenerator::postvisit( TupleExpr * tupleExpr ) { 754 assertf( ! genC, "TupleExpr should not reach code generation." );761 assertf( ! options.genC, "TupleExpr should not reach code generation." ); 755 762 extension( tupleExpr ); 756 763 output << "["; … … 760 767 761 768 void CodeGenerator::postvisit( TupleIndexExpr * tupleExpr ) { 762 assertf( ! genC, "TupleIndexExpr should not reach code generation." );769 assertf( ! options.genC, "TupleIndexExpr should not reach code generation." ); 763 770 extension( tupleExpr ); 764 771 tupleExpr->get_tuple()->accept( *visitor ); … … 767 774 768 775 void CodeGenerator::postvisit( TypeExpr * typeExpr ) { 769 // if ( genC ) std::cerr << "typeexpr still exists: " << typeExpr << std::endl;770 // assertf( ! genC, "TypeExpr should not reach code generation." );771 if ( ! genC ) {772 output << genType( typeExpr->get_type(), "", pretty, genC);776 // if ( options.genC ) std::cerr << "typeexpr still exists: " << typeExpr << std::endl; 777 // assertf( ! options.genC, "TypeExpr should not reach code generation." ); 778 if ( ! options.genC ) { 779 output << genType( typeExpr->get_type(), "", options ); 773 780 } 774 781 } … … 788 795 void CodeGenerator::postvisit( CompoundLiteralExpr *compLitExpr ) { 789 796 assert( compLitExpr->get_result() && dynamic_cast< ListInit * > ( compLitExpr->get_initializer() ) ); 790 output << "(" << genType( compLitExpr->get_result(), "", pretty, genC) << ")";797 output << "(" << genType( compLitExpr->get_result(), "", options ) << ")"; 791 798 compLitExpr->get_initializer()->accept( *visitor ); 792 799 } 793 800 794 801 void CodeGenerator::postvisit( UniqueExpr * unqExpr ) { 795 assertf( ! genC, "Unique expressions should not reach code generation." );802 assertf( ! options.genC, "Unique expressions should not reach code generation." ); 796 803 output << "unq<" << unqExpr->get_id() << ">{ "; 797 804 unqExpr->get_expr()->accept( *visitor ); … … 829 836 830 837 void CodeGenerator::postvisit( ConstructorExpr * expr ) { 831 assertf( ! genC, "Unique expressions should not reach code generation." );838 assertf( ! options.genC, "Unique expressions should not reach code generation." ); 832 839 expr->callExpr->accept( *visitor ); 833 840 } 834 841 835 842 void CodeGenerator::postvisit( DeletedExpr * expr ) { 836 assertf( ! genC, "Deleted expressions should not reach code generation." );843 assertf( ! options.genC, "Deleted expressions should not reach code generation." ); 837 844 expr->expr->accept( *visitor ); 838 845 } 839 846 840 847 void CodeGenerator::postvisit( DefaultArgExpr * arg ) { 841 assertf( ! genC, "Default argument expressions should not reach code generation." );848 assertf( ! options.genC, "Default argument expressions should not reach code generation." ); 842 849 arg->expr->accept( *visitor ); 843 850 } 844 851 845 852 void CodeGenerator::postvisit( GenericExpr * expr ) { 846 assertf( ! genC, "C11 _Generic expressions should not reach code generation." );853 assertf( ! options.genC, "C11 _Generic expressions should not reach code generation." ); 847 854 output << "_Generic("; 848 855 expr->control->accept( *visitor ); … … 854 861 output << "default: "; 855 862 } else { 856 output << genType( assoc.type, "", pretty, genC) << ": ";863 output << genType( assoc.type, "", options ) << ": "; 857 864 } 858 865 assoc.expr->accept( *visitor ); … … 889 896 void CodeGenerator::postvisit( ExprStmt * exprStmt ) { 890 897 assert( exprStmt ); 891 if ( genC ) {898 if ( options.genC ) { 892 899 // cast the top-level expression to void to reduce gcc warnings. 893 900 exprStmt->set_expr( new CastExpr( exprStmt->get_expr() ) ); … … 999 1006 case BranchStmt::FallThrough: 1000 1007 case BranchStmt::FallThroughDefault: 1001 assertf( ! genC, "fallthru should not reach code generation." );1008 assertf( ! options.genC, "fallthru should not reach code generation." ); 1002 1009 output << "fallthru"; 1003 1010 break; 1004 1011 } // switch 1005 1012 // print branch target for labelled break/continue/fallthru in debug mode 1006 if ( ! genC && branchStmt->get_type() != BranchStmt::Goto ) {1013 if ( ! options.genC && branchStmt->get_type() != BranchStmt::Goto ) { 1007 1014 if ( ! branchStmt->get_target().empty() ) { 1008 1015 output << " " << branchStmt->get_target(); … … 1021 1028 1022 1029 void CodeGenerator::postvisit( ThrowStmt * throwStmt ) { 1023 assertf( ! genC, "Throw statements should not reach code generation." );1030 assertf( ! options.genC, "Throw statements should not reach code generation." ); 1024 1031 1025 1032 output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ? … … 1036 1043 } 1037 1044 void CodeGenerator::postvisit( CatchStmt * stmt ) { 1038 assertf( ! genC, "Catch statements should not reach code generation." );1045 assertf( ! options.genC, "Catch statements should not reach code generation." ); 1039 1046 1040 1047 output << ((stmt->get_kind() == CatchStmt::Terminate) ? … … 1053 1060 1054 1061 void CodeGenerator::postvisit( WaitForStmt * stmt ) { 1055 assertf( ! genC, "Waitfor statements should not reach code generation." );1062 assertf( ! options.genC, "Waitfor statements should not reach code generation." ); 1056 1063 1057 1064 bool first = true; … … 1099 1106 1100 1107 void CodeGenerator::postvisit( WithStmt * with ) { 1101 if ( ! genC ) {1108 if ( ! options.genC ) { 1102 1109 output << "with ( "; 1103 1110 genCommaList( with->exprs.begin(), with->exprs.end() ); … … 1165 1172 1166 1173 void CodeGenerator::postvisit( ImplicitCtorDtorStmt * stmt ) { 1167 assertf( ! genC, "ImplicitCtorDtorStmts should not reach code generation." );1174 assertf( ! options.genC, "ImplicitCtorDtorStmts should not reach code generation." ); 1168 1175 stmt->callStmt->accept( *visitor ); 1169 1176 } -
src/CodeGen/CodeGenerator.h
r6a9d4b4 r933f32f 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Aug 18 15:40:00 201713 // Update Count : 5 612 // Last Modified On : Tue Apr 30 12:01:00 2019 13 // Update Count : 57 14 14 // 15 15 … … 20 20 #include <string> // for string 21 21 22 #include "CodeGen/Options.h" // for Options 22 23 #include "Common/Indenter.h" // for Indenter 23 24 #include "Common/PassVisitor.h" // for PassVisitor … … 31 32 32 33 CodeGenerator( std::ostream &os, bool pretty = false, bool genC = false, bool lineMarks = false, bool printExprTypes = false ); 34 CodeGenerator( std::ostream &os, const Options &options ); 33 35 34 36 //*** Turn off visit_children for all nodes … … 144 146 std::ostream & output; 145 147 LabelPrinter printLabels; 146 bool pretty = false; // pretty print 147 bool genC = false; // true if output has to be C code 148 bool lineMarks = false; 149 bool printExprTypes = false; 148 Options options; 150 149 public: 151 150 LineEnder endl; -
src/CodeGen/GenType.cc
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Mar 17 09:02:28 201713 // Update Count : 2 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed May 1 15:24:00 2019 13 // Update Count : 23 14 14 // 15 15 #include "GenType.h" … … 28 28 struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting { 29 29 std::string typeString; 30 GenType( const std::string &typeString, bool pretty, bool genC, bool lineMarks );30 GenType( const std::string &typeString, const Options &options ); 31 31 32 32 void previsit( BaseSyntaxNode * ); … … 57 57 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic ); 58 58 59 bool pretty = false; // pretty print 60 bool genC = false; // generating C code? 61 bool lineMarks = false; // lineMarks on for CodeGenerator? 59 Options options; 62 60 }; 63 61 64 std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {65 PassVisitor<GenType> gt( baseString, pretty, genC, lineMarks );62 std::string genType( Type *type, const std::string &baseString, const Options &options ) { 63 PassVisitor<GenType> gt( baseString, options ); 66 64 std::ostringstream os; 67 65 68 66 if ( ! type->get_attributes().empty() ) { 69 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );67 PassVisitor<CodeGenerator> cg( os, options ); 70 68 cg.pass.genAttributes( type->get_attributes() ); 71 69 } // if … … 75 73 } 76 74 77 std::string genPrettyType( Type * type, const std::string & baseString ) { 78 return genType( type, baseString, true, false ); 79 } 80 81 GenType::GenType( const std::string &typeString, bool pretty, bool genC, bool lineMarks ) : typeString( typeString ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ) {} 75 std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) { 76 return genType( type, baseString, Options(pretty, genC, lineMarks, false ) ); 77 } 78 79 std::string genPrettyType( Type * type, const std::string & baseString ) { 80 return genType( type, baseString, true, false ); 81 } 82 83 GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {} 82 84 83 85 // *** BaseSyntaxNode … … 133 135 } // if 134 136 if ( dimension != 0 ) { 135 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );137 PassVisitor<CodeGenerator> cg( os, options ); 136 138 dimension->accept( cg ); 137 139 } else if ( isVarLen ) { … … 167 169 void GenType::postvisit( ReferenceType * refType ) { 168 170 assert( refType->base != 0); 169 assertf( ! genC, "Reference types should not reach code generation." );171 assertf( ! options.genC, "Reference types should not reach code generation." ); 170 172 handleQualifiers( refType ); 171 173 typeString = "&" + typeString; … … 195 197 } // if 196 198 } else { 197 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );199 PassVisitor<CodeGenerator> cg( os, options ); 198 200 os << "(" ; 199 201 … … 215 217 216 218 // add forall 217 if( ! funcType->forall.empty() && ! genC ) {219 if( ! funcType->forall.empty() && ! options.genC ) { 218 220 // assertf( ! genC, "Aggregate type parameters should not reach code generation." ); 219 221 std::ostringstream os; 220 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );222 PassVisitor<CodeGenerator> cg( os, options ); 221 223 os << "forall("; 222 224 cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() ); … … 229 231 if ( ! refType->parameters.empty() ) { 230 232 std::ostringstream os; 231 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );233 PassVisitor<CodeGenerator> cg( os, options ); 232 234 os << "("; 233 235 cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() ); … … 240 242 void GenType::postvisit( StructInstType * structInst ) { 241 243 typeString = structInst->name + handleGeneric( structInst ) + " " + typeString; 242 if ( genC ) typeString = "struct " + typeString;244 if ( options.genC ) typeString = "struct " + typeString; 243 245 handleQualifiers( structInst ); 244 246 } … … 246 248 void GenType::postvisit( UnionInstType * unionInst ) { 247 249 typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString; 248 if ( genC ) typeString = "union " + typeString;250 if ( options.genC ) typeString = "union " + typeString; 249 251 handleQualifiers( unionInst ); 250 252 } … … 252 254 void GenType::postvisit( EnumInstType * enumInst ) { 253 255 typeString = enumInst->name + " " + typeString; 254 if ( genC ) typeString = "enum " + typeString;256 if ( options.genC ) typeString = "enum " + typeString; 255 257 handleQualifiers( enumInst ); 256 258 } … … 262 264 263 265 void GenType::postvisit( TupleType * tupleType ) { 264 assertf( ! genC, "Tuple types should not reach code generation." );266 assertf( ! options.genC, "Tuple types should not reach code generation." ); 265 267 unsigned int i = 0; 266 268 std::ostringstream os; … … 268 270 for ( Type * t : *tupleType ) { 269 271 i++; 270 os << genType( t, "", pretty, genC, lineMarks ) << (i == tupleType->size() ? "" : ", ");272 os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", "); 271 273 } 272 274 os << "] "; … … 281 283 void GenType::postvisit( ZeroType * zeroType ) { 282 284 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 283 typeString = ( pretty ? "zero_t " : "long int ") + typeString;285 typeString = (options.pretty ? "zero_t " : "long int ") + typeString; 284 286 handleQualifiers( zeroType ); 285 287 } … … 287 289 void GenType::postvisit( OneType * oneType ) { 288 290 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 289 typeString = ( pretty ? "one_t " : "long int ") + typeString;291 typeString = (options.pretty ? "one_t " : "long int ") + typeString; 290 292 handleQualifiers( oneType ); 291 293 } 292 294 293 295 void GenType::postvisit( GlobalScopeType * globalType ) { 294 assertf( ! genC, "Global scope type should not reach code generation." );296 assertf( ! options.genC, "Global scope type should not reach code generation." ); 295 297 handleQualifiers( globalType ); 296 298 } 297 299 298 300 void GenType::postvisit( TraitInstType * inst ) { 299 assertf( ! genC, "Trait types should not reach code generation." );301 assertf( ! options.genC, "Trait types should not reach code generation." ); 300 302 typeString = inst->name + " " + typeString; 301 303 handleQualifiers( inst ); … … 304 306 void GenType::postvisit( TypeofType * typeof ) { 305 307 std::ostringstream os; 306 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );308 PassVisitor<CodeGenerator> cg( os, options ); 307 309 os << "typeof("; 308 310 typeof->expr->accept( cg ); … … 313 315 314 316 void GenType::postvisit( QualifiedType * qualType ) { 315 assertf( ! genC, "Qualified types should not reach code generation." );316 std::ostringstream os; 317 os << genType( qualType->parent, "", pretty, genC, lineMarks ) << "." << genType( qualType->child, "", pretty, genC, lineMarks ) << typeString;317 assertf( ! options.genC, "Qualified types should not reach code generation." ); 318 std::ostringstream os; 319 os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString; 318 320 typeString = os.str(); 319 321 handleQualifiers( qualType ); … … 333 335 typeString = "_Atomic " + typeString; 334 336 } // if 335 if ( type->get_lvalue() && ! genC ) {337 if ( type->get_lvalue() && ! options.genC ) { 336 338 // when not generating C code, print lvalue for debugging. 337 339 typeString = "lvalue " + typeString; -
src/CodeGen/GenType.h
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Jul 21 22:17:23 201713 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Apr 30 11:47:00 2019 13 // Update Count : 3 14 14 // 15 15 … … 18 18 #include <string> // for string 19 19 20 #include "CodeGen/Options.h" // for Options 21 20 22 class Type; 21 23 22 24 namespace CodeGen { 25 std::string genType( Type *type, const std::string &baseString, const Options &options ); 23 26 std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false ); 24 27 std::string genPrettyType( Type * type, const std::string & baseString ); -
src/CodeGen/module.mk
r6a9d4b4 r933f32f 18 18 # ArgTweak/Mutate.cc 19 19 20 SRC += CodeGen/Generate.cc\20 SRC_CODEGEN = \ 21 21 CodeGen/CodeGenerator.cc \ 22 CodeGen/FixMain.cc \ 22 23 CodeGen/GenType.cc \ 23 CodeGen/FixNames.cc \24 CodeGen/FixMain.cc \25 24 CodeGen/OperatorTable.cc 25 26 27 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/FixNames.cc 28 SRCDEMANGLE += $(SRC_CODEGEN) -
src/Common/Assert.cc
r6a9d4b4 r933f32f 39 39 } 40 40 41 void abort(const char *fmt, ... ) noexcept __attribute__((noreturn, format(printf, 1, 2))); 42 void abort(const char *fmt, ... ) noexcept { 43 va_list args; 44 va_start( args, fmt ); 45 vfprintf( stderr, fmt, args ); 46 va_end( args ); 47 fprintf( stderr, "\n" ); 48 abort(); 49 } 50 41 51 // Local Variables: // 42 52 // tab-width: 4 // -
src/Common/PassVisitor.h
r6a9d4b4 r933f32f 4 4 5 5 #include <stack> 6 6 #include <type_traits> 7 8 #include "Common/Stats.h" 7 9 #include "Common/utility.h" 8 10 … … 153 155 virtual void visit( ConstructorInit * ctorInit ) override final; 154 156 155 virtual void visit( Subrange * subrange ) override final;156 157 157 virtual void visit( Constant * constant ) override final; 158 158 … … 255 255 virtual Initializer * mutate( ConstructorInit * ctorInit ) override final; 256 256 257 virtual Subrange * mutate( Subrange * subrange ) override final;258 259 257 virtual Constant * mutate( Constant * constant ) override final; 260 258 … … 300 298 301 299 302 TypeSubstitution ** get_env_ptr () { return env_impl( pass, 0); }300 auto get_env_ptr () -> decltype(env_impl( pass, 0)) { return env_impl( pass, 0); } 303 301 std::list< Statement* > * get_beforeStmts() { return stmtsToAddBefore_impl( pass, 0); } 304 302 std::list< Statement* > * get_afterStmts () { return stmtsToAddAfter_impl ( pass, 0); } … … 347 345 }; 348 346 347 class WithConstTypeSubstitution { 348 protected: 349 WithConstTypeSubstitution() = default; 350 ~WithConstTypeSubstitution() = default; 351 352 public: 353 const TypeSubstitution * env = nullptr; 354 }; 355 349 356 class WithStmtsToAdd { 350 357 protected: … … 426 433 }; 427 434 435 #include "Common/Stats.h" 436 437 extern struct PassVisitorStats { 438 size_t depth = 0; 439 Stats::Counters::MaxCounter<double> * max = nullptr; 440 Stats::Counters::AverageCounter<double> * avg = nullptr; 441 } pass_visitor_stats; 442 428 443 #include "SynTree/TypeSubstitution.h" 429 444 #include "PassVisitor.impl.h" -
src/Common/PassVisitor.impl.h
r6a9d4b4 r933f32f 20 20 21 21 #define MUTATE_END( type, node ) \ 22 return call_postmutate< type * >( node ); \ 22 auto __return = call_postmutate< type * >( node ); \ 23 assert( __return ); \ 24 return __return; 23 25 24 26 … … 67 69 SemanticErrorException errors; 68 70 71 pass_visitor_stats.depth++; 72 pass_visitor_stats.max->push(pass_visitor_stats.depth); 73 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 69 74 for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) { 75 76 70 77 // splice in new declarations after previous decl 71 78 if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); } … … 83 90 if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); } 84 91 } 92 pass_visitor_stats.depth--; 85 93 if ( ! errors.isEmpty() ) { 86 94 throw errors; … … 94 102 SemanticErrorException errors; 95 103 104 pass_visitor_stats.depth++; 105 pass_visitor_stats.max->push(pass_visitor_stats.depth); 106 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 96 107 for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) { 97 108 // splice in new declarations after previous decl … … 109 120 if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); } 110 121 } 122 pass_visitor_stats.depth--; 111 123 if ( ! errors.isEmpty() ) { 112 124 throw errors; … … 126 138 if ( ! visitor.get_visit_children() ) return; 127 139 SemanticErrorException errors; 140 141 pass_visitor_stats.depth++; 142 pass_visitor_stats.max->push(pass_visitor_stats.depth); 143 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 128 144 for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) { 129 145 try { … … 135 151 } 136 152 } 153 pass_visitor_stats.depth--; 137 154 if ( ! errors.isEmpty() ) { 138 155 throw errors; … … 151 168 template< typename Container, typename pass_type > 152 169 inline void maybeMutate_impl( Container & container, PassVisitor< pass_type > & mutator ) { 170 153 171 if ( ! mutator.get_visit_children() ) return; 154 172 SemanticErrorException errors; 173 174 pass_visitor_stats.depth++; 175 pass_visitor_stats.max->push(pass_visitor_stats.depth); 176 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 155 177 for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) { 156 178 try { … … 163 185 } // try 164 186 } // for 187 pass_visitor_stats.depth--; 165 188 if ( ! errors.isEmpty() ) { 166 189 throw errors; … … 185 208 DeclList_t* afterDecls = get_afterDecls(); 186 209 210 pass_visitor_stats.depth++; 211 pass_visitor_stats.max->push(pass_visitor_stats.depth); 212 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 187 213 for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) { 188 214 … … 192 218 try { 193 219 func( *i ); 220 assert( *i ); 194 221 assert(( empty( beforeStmts ) && empty( afterStmts )) 195 222 || ( empty( beforeDecls ) && empty( afterDecls )) ); … … 202 229 if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); } 203 230 } 231 pass_visitor_stats.depth--; 204 232 205 233 if ( !empty( afterDecls ) ) { splice( std::back_inserter( statements ), afterDecls); } … … 229 257 230 258 // don't want statements from outer CompoundStmts to be added to this CompoundStmt 231 ValueGuardPtr< TypeSubstitution * > oldEnv ( get_env_ptr() );259 ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type > oldEnv( get_env_ptr() ); 232 260 ValueGuardPtr< DeclList_t > oldBeforeDecls( get_beforeDecls() ); 233 261 ValueGuardPtr< DeclList_t > oldAfterDecls ( get_afterDecls () ); … … 1965 1993 1966 1994 // don't want statements from outer CompoundStmts to be added to this StmtExpr 1967 ValueGuardPtr< TypeSubstitution * > oldEnv( get_env_ptr() );1995 ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type > oldEnv( get_env_ptr() ); 1968 1996 ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() ); 1969 1997 ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () ); … … 1982 2010 1983 2011 // don't want statements from outer CompoundStmts to be added to this StmtExpr 1984 ValueGuardPtr< TypeSubstitution * > oldEnv( get_env_ptr() );2012 ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type > oldEnv( get_env_ptr() ); 1985 2013 ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() ); 1986 2014 ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () ); … … 2678 2706 2679 2707 //-------------------------------------------------------------------------- 2680 // Subrange2681 template< typename pass_type >2682 void PassVisitor< pass_type >::visit( Subrange * node ) {2683 VISIT_START( node );2684 2685 VISIT_END( node );2686 }2687 2688 template< typename pass_type >2689 Subrange * PassVisitor< pass_type >::mutate( Subrange * node ) {2690 MUTATE_START( node );2691 2692 MUTATE_END( Subrange, node );2693 }2694 2695 //--------------------------------------------------------------------------2696 2708 // Attribute 2697 2709 template< typename pass_type > -
src/Common/PassVisitor.proto.h
r6a9d4b4 r933f32f 165 165 static inline type * name##_impl( __attribute__((unused)) pass_type& pass, __attribute__((unused)) long unused ) { return nullptr;} \ 166 166 167 FIELD_PTR( TypeSubstitution *, env )167 FIELD_PTR( const TypeSubstitution *, env ) 168 168 FIELD_PTR( std::list< Statement* >, stmtsToAddBefore ) 169 169 FIELD_PTR( std::list< Statement* >, stmtsToAddAfter ) … … 174 174 FIELD_PTR( PassVisitor<pass_type> * const, visitor ) 175 175 176 #undef FIELD_PTR 177 176 178 //--------------------------------------------------------- 177 179 // Indexer … … 220 222 INDEXER_FUNC2( addWith , std::list< Expression * > &, BaseSyntaxNode * ); 221 223 224 #undef INDEXER_FUNC1 225 #undef INDEXER_FUNC2 222 226 223 227 template<typename pass_type> -
src/Common/SemanticError.h
r6a9d4b4 r933f32f 17 17 18 18 #include "ErrorObjects.h" 19 #include "AST/Node.hpp" 19 20 #include <cstring> 20 21 -
src/Common/Stats/Heap.h
r6a9d4b4 r933f32f 16 16 #pragma once 17 17 18 namespace HeapStats { 19 void newPass( const char * const name ); 20 void printStats(); 18 namespace Stats { 19 namespace Heap { 20 void newPass( const char * const name ); 21 void print(); 22 } 21 23 } -
src/Common/module.mk
r6a9d4b4 r933f32f 15 15 ############################################################################### 16 16 17 SRC += Common/SemanticError.cc \ 18 Common/UniqueName.cc \ 19 Common/DebugMalloc.cc \ 20 Common/Assert.cc \ 21 Common/Heap.cc \ 22 Common/Eval.cc 17 SRC_COMMON = \ 18 Common/Assert.cc \ 19 Common/Eval.cc \ 20 Common/PassVisitor.cc \ 21 Common/SemanticError.cc \ 22 Common/Stats/Counter.cc \ 23 Common/Stats/Heap.cc \ 24 Common/Stats/Stats.cc \ 25 Common/Stats/Time.cc \ 26 Common/UniqueName.cc 27 28 SRC += $(SRC_COMMON) Common/DebugMalloc.cc 29 SRCDEMANGLE += $(SRC_COMMON) -
src/Common/utility.h
r6a9d4b4 r933f32f 463 463 std::pair<long long int, bool> eval(Expression * expr); 464 464 465 // ----------------------------------------------------------------------------- 466 /// Reorders the input range in-place so that the minimal-value elements according to the 467 /// comparator are in front; 465 namespace ast { 466 class Expr; 467 } 468 469 std::pair<long long int, bool> eval(const ast::Expr * expr); 470 471 // ----------------------------------------------------------------------------- 472 /// Reorders the input range in-place so that the minimal-value elements according to the 473 /// comparator are in front; 468 474 /// returns the iterator after the last minimal-value element. 469 475 template<typename Iter, typename Compare> 470 476 Iter sort_mins( Iter begin, Iter end, Compare& lt ) { 471 477 if ( begin == end ) return end; 472 478 473 479 Iter min_pos = begin; 474 480 for ( Iter i = begin + 1; i != end; ++i ) { -
src/CompilationState.cc
r6a9d4b4 r933f32f 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon Ju1 30 10:47:01 2018 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Mon Ju1 30 10:46:25 201813 // Update Count : 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri May 3 13:45:23 2019 13 // Update Count : 4 14 14 // 15 15 16 bool 16 int 17 17 astp = false, 18 18 bresolvep = false, … … 26 26 libcfap = false, 27 27 nopreludep = false, 28 noprotop= false,28 genproto = false, 29 29 nomainp = false, 30 30 parsep = false, -
src/CompilationState.h
r6a9d4b4 r933f32f 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon Ju1 30 10:47:01 2018 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Mon Ju1 30 10:46:25 201813 // Update Count : 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri May 3 13:43:21 2019 13 // Update Count : 4 14 14 // 15 15 16 16 extern int yydebug; // set for -g flag (Grammar) 17 extern bool17 extern int 18 18 astp, 19 19 bresolvep, … … 27 27 libcfap, 28 28 nopreludep, 29 noprotop,29 genproto, 30 30 nomainp, 31 31 parsep, -
src/Concurrency/Waitfor.cc
r6a9d4b4 r933f32f 11 11 // Last Modified By : 12 12 // Last Modified On : 13 // Update Count : 513 // Update Count : 7 14 14 // 15 15 -
src/Concurrency/module.mk
r6a9d4b4 r933f32f 15 15 ############################################################################### 16 16 17 SRC += Concurrency/Keywords.cc \18 Concurrency/Waitfor.cc17 SRC += Concurrency/Keywords.cc Concurrency/Waitfor.cc 18 SRCDEMANGLE += Concurrency/Keywords.cc 19 19 -
src/ControlStruct/ExceptTranslate.cc
r6a9d4b4 r933f32f 9 9 // Author : Andrew Beach 10 10 // Created On : Wed Jun 14 16:49:00 2017 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thr Aug 17 17:19:00 201713 // Update Count : 911 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 13 18:15:29 2019 13 // Update Count : 11 14 14 // 15 15 … … 617 617 return create_terminate_rethrow( throwStmt ); 618 618 } else { 619 a ssertf(false,"Invalid throw in %s at %i\n",619 abort("Invalid throw in %s at %i\n", 620 620 throwStmt->location.filename.c_str(), 621 621 throwStmt->location.first_line); 622 return nullptr;623 622 } 624 623 } else { … … 628 627 return create_resume_rethrow( throwStmt ); 629 628 } else { 630 a ssertf(false,"Invalid throwResume in %s at %i\n",629 abort("Invalid throwResume in %s at %i\n", 631 630 throwStmt->location.filename.c_str(), 632 631 throwStmt->location.first_line); 633 return nullptr;634 632 } 635 633 } -
src/ControlStruct/ForExprMutator.cc
r6a9d4b4 r933f32f 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Aug 18 10:22:00 201713 // Update Count : 1 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 11 22:26:52 2019 13 // Update Count : 14 14 14 // 15 15 … … 21 21 22 22 namespace ControlStruct { 23 Statement * hoist( Statement *originalStmt, std::list<Statement *> &init ) {23 Statement * hoist( Statement * originalStmt, std::list<Statement *> & init ) { 24 24 // If no hoisting is needed, skip: 25 25 if ( 0 == init.size() ) { … … 29 29 // Create compound statement, move initializers outside, 30 30 // the resut of the original stays as is. 31 CompoundStmt * block = new CompoundStmt();32 std::list<Statement *> & stmts = block->get_kids();31 CompoundStmt * block = new CompoundStmt(); 32 std::list<Statement *> & stmts = block->get_kids(); 33 33 stmts.splice( stmts.end(), init ); 34 34 … … 38 38 } 39 39 40 Statement * ForExprMutator::postmutate( IfStmt *ifStmt ) {40 Statement * ForExprMutator::postmutate( IfStmt * ifStmt ) { 41 41 return hoist( ifStmt, ifStmt->initialization ); 42 42 } 43 Statement * ForExprMutator::postmutate( ForStmt *forStmt ) {43 Statement * ForExprMutator::postmutate( ForStmt * forStmt ) { 44 44 // hoist any initializer declarations to make them C89 (rather than C99) 45 45 return hoist( forStmt, forStmt->initialization ); 46 46 } 47 Statement * ForExprMutator::postmutate( WhileStmt *whileStmt ) {47 Statement * ForExprMutator::postmutate( WhileStmt * whileStmt ) { 48 48 return hoist( whileStmt, whileStmt->initialization ); 49 49 } -
src/ControlStruct/LabelFixer.cc
r6a9d4b4 r933f32f 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Tue Jul 28 13:32:43 201513 // Update Count : 15 611 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 11 22:26:02 2019 13 // Update Count : 159 14 14 // 15 15 … … 32 32 } 33 33 34 LabelFixer::LabelFixer( LabelGenerator * gen ) : generator ( gen ) {34 LabelFixer::LabelFixer( LabelGenerator * gen ) : generator ( gen ) { 35 35 if ( generator == 0 ) 36 36 generator = LabelGenerator::getGenerator(); … … 49 49 50 50 // prune to at most one label definition for each statement 51 void LabelFixer::previsit( Statement * stmt ) {51 void LabelFixer::previsit( Statement * stmt ) { 52 52 std::list< Label > &labels = stmt->get_labels(); 53 53 … … 58 58 } 59 59 60 void LabelFixer::previsit( BranchStmt * branchStmt ) {60 void LabelFixer::previsit( BranchStmt * branchStmt ) { 61 61 previsit( ( Statement *)branchStmt ); 62 62 … … 75 75 76 76 77 // sets the definition of the labelTable entry to be the provided 78 // statement for every label in the listparameter. Happens for every kind of statement79 Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement *definition ) {77 // sets the definition of the labelTable entry to be the provided statement for every label in the list 78 // parameter. Happens for every kind of statement 79 Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement * definition ) { 80 80 assert( definition != 0 ); 81 81 assert( llabel.size() > 0 ); … … 100 100 } // for 101 101 102 // produce one of the labels attached to this statement to be 103 // temporarily used as the canonical label 102 // produce one of the labels attached to this statement to be temporarily used as the canonical label 104 103 return labelTable[ llabel.front() ]->get_label(); 105 104 } … … 117 116 118 117 // Builds a table that maps a label to its defining statement. 119 std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {118 std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) { 120 119 std::map< Label, Statement * > *ret = new std::map< Label, Statement * >(); 121 120 for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) { -
src/ControlStruct/LabelGenerator.cc
r6a9d4b4 r933f32f 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thr Aug 14 14:14:00 201513 // Update Count : 1 411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 11 22:23:20 2019 13 // Update Count : 15 14 14 // 15 15 … … 24 24 25 25 namespace ControlStruct { 26 LabelGenerator * LabelGenerator::labelGenerator = 0;26 LabelGenerator * LabelGenerator::labelGenerator = 0; 27 27 28 LabelGenerator * LabelGenerator::getGenerator() {28 LabelGenerator * LabelGenerator::getGenerator() { 29 29 if ( LabelGenerator::labelGenerator == 0 ) 30 30 LabelGenerator::labelGenerator = new LabelGenerator(); 31 32 31 return labelGenerator; 33 32 } … … 38 37 if ( stmt && ! stmt->get_labels().empty() ) { 39 38 os << "_" << stmt->get_labels().front() << "__"; 40 } 39 } // if 41 40 std::string ret = os.str(); 42 41 Label l( ret ); -
src/ControlStruct/module.mk
r6a9d4b4 r933f32f 15 15 ############################################################################### 16 16 17 SRC += ControlStruct/LabelGenerator.cc \ 17 SRC_CONTROLSTRUCT = \ 18 ControlStruct/ForExprMutator.cc \ 18 19 ControlStruct/LabelFixer.cc \ 20 ControlStruct/LabelGenerator.cc \ 19 21 ControlStruct/MLEMutator.cc \ 20 ControlStruct/Mutate.cc \ 21 ControlStruct/ForExprMutator.cc \ 22 ControlStruct/ExceptTranslate.cc 22 ControlStruct/Mutate.cc 23 24 SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc 25 SRCDEMANGLE += $(SRC_CONTROLSTRUCT) 26 -
src/GenPoly/Box.cc
r6a9d4b4 r933f32f 76 76 77 77 /// Replaces polymorphic return types with out-parameters, replaces calls to polymorphic functions with adapter calls as needed, and adds appropriate type variables to the function call 78 class Pass1 final : public BoxPass, public With TypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting {78 class Pass1 final : public BoxPass, public WithConstTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting { 79 79 public: 80 80 Pass1(); … … 150 150 /// * Calculates polymorphic offsetof expressions from offset array 151 151 /// * Inserts dynamic calculation of polymorphic type layouts where needed 152 class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public With TypeSubstitution {152 class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithConstTypeSubstitution { 153 153 public: 154 154 PolyGenericCalculator(); -
src/GenPoly/GenPoly.cc
r6a9d4b4 r933f32f 440 440 } 441 441 442 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, TypeSubstitution * env ) {442 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) { 443 443 // is parameter is not polymorphic, don't need to box 444 444 if ( ! isPolyType( param, exprTyVars ) ) return false; … … 450 450 } 451 451 452 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, TypeSubstitution * env ) {452 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) { 453 453 FunctionType * function = getFunctionType( appExpr->function->result ); 454 454 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() ); -
src/GenPoly/GenPoly.h
r6a9d4b4 r933f32f 81 81 82 82 /// true if arg requires boxing given exprTyVars 83 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, TypeSubstitution * env );83 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ); 84 84 85 85 /// true if arg requires boxing in the call to appExpr 86 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, TypeSubstitution * env );86 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ); 87 87 88 88 /// Adds the type variable `tyVar` to `tyVarMap` -
src/GenPoly/InstantiateGeneric.cc
r6a9d4b4 r933f32f 168 168 169 169 /// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately 170 struct GenericInstantiator final : public With TypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards {170 struct GenericInstantiator final : public WithConstTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards { 171 171 /// Map of (generic type, parameter list) pairs to concrete type instantiations 172 172 InstantiationMap< AggregateDecl, AggregateDecl > instantiations; -
src/GenPoly/Specialize.cc
r6a9d4b4 r933f32f 42 42 43 43 namespace GenPoly { 44 struct Specialize final : public With TypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {44 struct Specialize final : public WithConstTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> { 45 45 Expression * postmutate( ApplicationExpr *applicationExpr ); 46 46 Expression * postmutate( CastExpr *castExpr ); … … 54 54 55 55 /// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type. 56 bool needsPolySpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {56 bool needsPolySpecialization( Type *formalType, Type *actualType, const TypeSubstitution *env ) { 57 57 if ( env ) { 58 58 using namespace ResolvExpr; … … 145 145 } 146 146 147 bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {147 bool needsSpecialization( Type *formalType, Type *actualType, const TypeSubstitution *env ) { 148 148 return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType ); 149 149 } -
src/GenPoly/module.mk
r6a9d4b4 r933f32f 22 22 GenPoly/FindFunction.cc \ 23 23 GenPoly/InstantiateGeneric.cc 24 25 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/Lvalue.cc 26 -
src/InitTweak/FixInit.cc
r6a9d4b4 r933f32f 10 10 // Created On : Wed Jan 13 16:29:30 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jun 21 17:35:05 201713 // Update Count : 7 412 // Last Modified On : Wed Feb 13 18:15:56 2019 13 // Update Count : 76 14 14 // 15 15 #include "FixInit.h" … … 72 72 }; 73 73 74 struct InsertImplicitCalls : public With TypeSubstitution {74 struct InsertImplicitCalls : public WithConstTypeSubstitution { 75 75 /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which 76 76 /// function calls need their parameters to be copy constructed -
src/InitTweak/InitTweak.cc
r6a9d4b4 r933f32f 5 5 #include <memory> // for __shared_ptr 6 6 7 #include "AST/Expr.hpp" 8 #include "AST/Stmt.hpp" 9 #include "AST/Type.hpp" 7 10 #include "Common/PassVisitor.h" 8 11 #include "Common/SemanticError.h" // for SemanticError … … 26 29 #include "Tuples/Tuples.h" // for Tuples::isTtype 27 30 28 class UntypedValofExpr;29 30 31 namespace InitTweak { 31 32 namespace { … … 432 433 assert( false ); 433 434 } 435 436 // template<typename CallExpr> 437 // const ast::Expr * callArg( const CallExpr * call, unsigned int pos ) { 438 // if( pos >= call->args.size() ) { 439 // assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", 440 // pos, toString( call ).c_str() ); 441 // } 442 // for ( const ast::Expr * arg : call->args ) { 443 // if ( pos == 0 ) return arg; 444 // --pos; 445 // } 446 // assert( false ); 447 // } 434 448 } 435 449 … … 451 465 assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() ); 452 466 } 467 } 468 const ast::Expr * getCallArg( const ast::Expr * call, unsigned pos ) { 469 (void)call; 470 (void)pos; 471 #warning unimplemented; needs to build AST/Expr.cpp 472 assertf(false, "unimplemented; needs to build AST/Expr.cpp"); 473 // if ( auto app = dynamic_cast< const ast::ApplicationExpr * >( call ) ) { 474 // return callArg( app, pos ); 475 // } else if ( auto untyped = dynamic_cast< const ast::UntypedExpr * >( call ) ) { 476 // return callArg( untyped, pos ); 477 // } else if ( auto tupleAssn = dynamic_cast< const ast::TupleAssignExpr * >( call ) ) { 478 // const std::list<ast::ptr<ast::Stmt>>& stmts = tupleAssn->stmtExpr->stmts->kids; 479 // assertf( ! stmts.empty(), "TupleAssignExpr missing statements." ); 480 // const ExprStmt * stmt = strict_dynamic_cast< const ast::ExprStmt * >( stmts.back() ); 481 // const TupleExpr * tuple = strict_dynamic_cast< const ast::TupleExpr * >( stmt->expr ); 482 // assertf( ! tuple->exprs.empty(), "TupleAssignExpr has empty tuple expr."); 483 // return getCallArg( tuple->exprs.front(), pos ); 484 // } else if ( auto ctor = dynamic_cast< const ast::ImplicitCopyCtorExpr * >( call ) ) { 485 // return getCallArg( ctor->callExpr, pos ); 486 // } else { 487 // assertf( false, "Unexpected expression type passed to getCallArg: %s", 488 // toString( call ).c_str() ); 489 // } 453 490 } 454 491 … … 513 550 } 514 551 } 552 const ast::Type* getPointerBase( const ast::Type* t ) { 553 (void)t; 554 #warning needs to build Type.cpp before inclusion 555 assertf(false, "needs to build Type.cpp before inclusion"); 556 // if ( const auto * p = dynamic_cast< const ast::PointerType * >( t ) ) { 557 // return p->base; 558 // } else if ( const auto * a = dynamic_cast< const ast::ArrayType * >( t ) ) { 559 // return a->base; 560 // } else if ( const auto * r = dynamic_cast< const ast::ReferenceType * >( t ) ) { 561 // return r->base; 562 // } else return nullptr; 563 } 515 564 516 565 Type * isPointerType( Type * type ) { -
src/InitTweak/InitTweak.h
r6a9d4b4 r933f32f 20 20 #include <string> // for string, allocator 21 21 22 #include "AST/Fwd.hpp" // for AST nodes 22 23 #include "SynTree/SynTree.h" // for Visitor Nodes 23 24 … … 80 81 /// returns the argument to a call expression in position N indexed from 0 81 82 Expression *& getCallArg( Expression * callExpr, unsigned int pos ); 83 const ast::Expr * getCallArg( const ast::Expr * call, unsigned pos ); 82 84 83 85 /// returns the base type of a PointerType or ArrayType, else returns NULL 84 86 Type * getPointerBase( Type * ); 87 const ast::Type* getPointerBase( const ast::Type* ); 85 88 86 89 /// returns the argument if it is a PointerType or ArrayType, else returns NULL -
src/InitTweak/module.mk
r6a9d4b4 r933f32f 20 20 InitTweak/InitTweak.cc 21 21 22 SRCDEMANGLE += InitTweak/GenInit.cc \ 23 InitTweak/InitTweak.cc 24 -
src/MakeLibCfa.cc
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sat May 16 10:33:33 2015 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Fri Apr 22 13:54:15 201613 // Update Count : 4 011 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 17 21:08:09 2019 13 // Update Count : 41 14 14 // 15 15 … … 146 146 } // namespace 147 147 } // namespace LibCfa 148 149 // Local Variables: // 150 // tab-width: 4 // 151 // End: // -
src/Makefile.am
r6a9d4b4 r933f32f 10 10 ## Author : Peter A. Buhr 11 11 ## Created On : Sun May 31 08:51:46 2015 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Tus Jul 25 10:34:00 201714 ## Update Count : 7612 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Fri Feb 15 09:44:09 2019 14 ## Update Count : 97 15 15 ############################################################################### 16 16 … … 20 20 21 21 SRC = main.cc \ 22 MakeLibCfa.cc \ 23 CompilationState.cc 22 MakeLibCfa.cc \ 23 CompilationState.cc 24 25 SRCDEMANGLE = CompilationState.cc 24 26 25 27 MAINTAINERCLEANFILES = 26 MOSTLYCLEANFILES = Parser/gcc-flags.h28 MOSTLYCLEANFILES = 27 29 28 Parser/gcc-flags.h : 29 ${AM_V_GEN}$(CC) -dM -E - < /dev/null | sed 's/define /define __GCC__/' > $(@) 30 if WITH_LIBPROFILER 31 LIBPROFILER = -lprofiler 32 endif 30 33 31 Parser/lex.ll : Parser/gcc-flags.h 34 if WITH_LIBTCMALLOC 35 LIBTCMALLOC = -ltcmalloc 36 TCMALLOCFLAG = -DTCMALLOC 37 endif 32 38 33 39 include CodeGen/module.mk … … 46 52 include Virtual/module.mk 47 53 54 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h 55 56 $(srcdir)/SynTree/Type.h : BasicTypes-gen.cc 57 ${AM_V_GEN}${CXXCOMPILE} $< -o BasicTypes-gen -Wall -Wextra 58 @./BasicTypes-gen 59 @rm BasicTypes-gen 60 48 61 # put into lib for now 49 62 cfa_cpplibdir = $(CFA_LIBDIR) 50 63 cfa_cpplib_PROGRAMS = ../driver/cfa-cpp demangler 51 64 ___driver_cfa_cpp_SOURCES = $(SRC) 52 ___driver_cfa_cpp_LDADD = -ldl # yywrap65 ___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC) 53 66 54 AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O 2 -g -std=c++1467 AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O3 -g -std=c++14 $(TCMALLOCFLAG) 55 68 AM_LDFLAGS = @HOST_FLAGS@ -Xlinker -export-dynamic 56 69 ARFLAGS = cr … … 58 71 demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete 59 72 60 demangler_LDADD = libdemangle.a # yywrap73 demangler_LDADD = libdemangle.a -ldl # yywrap 61 74 62 75 noinst_LIBRARIES = libdemangle.a 63 libdemangle_a_SOURCES = \ 64 SymTab/Demangle.cc \ 65 SymTab/ManglerCommon.cc \ 66 SynTree/Type.cc \ 67 SynTree/VoidType.cc \ 68 SynTree/BasicType.cc \ 69 SynTree/PointerType.cc \ 70 SynTree/ArrayType.cc \ 71 SynTree/ReferenceType.cc \ 72 SynTree/FunctionType.cc \ 73 SynTree/ReferenceToType.cc \ 74 SynTree/TupleType.cc \ 75 SynTree/TypeofType.cc \ 76 SynTree/AttrType.cc \ 77 SynTree/VarArgsType.cc \ 78 SynTree/ZeroOneType.cc \ 79 SynTree/Constant.cc \ 80 SynTree/Expression.cc \ 81 SynTree/TupleExpr.cc \ 82 SynTree/CommaExpr.cc \ 83 SynTree/TypeExpr.cc \ 84 SynTree/ApplicationExpr.cc \ 85 SynTree/AddressExpr.cc \ 86 SynTree/Statement.cc \ 87 SynTree/CompoundStmt.cc \ 88 SynTree/DeclStmt.cc \ 89 SynTree/Declaration.cc \ 90 SynTree/DeclarationWithType.cc \ 91 SynTree/ObjectDecl.cc \ 92 SynTree/FunctionDecl.cc \ 93 SynTree/AggregateDecl.cc \ 94 SynTree/NamedTypeDecl.cc \ 95 SynTree/TypeDecl.cc \ 96 SynTree/Initializer.cc \ 97 SynTree/TypeSubstitution.cc \ 98 SynTree/Attribute.cc \ 99 SynTree/DeclReplacer.cc \ 100 CompilationState.cc \ 101 CodeGen/CodeGenerator.cc \ 102 CodeGen/FixMain.cc \ 103 CodeGen/Generate.cc \ 104 CodeGen/GenType.cc \ 105 CodeGen/OperatorTable.cc \ 106 Common/Assert.cc \ 107 Common/Eval.cc \ 108 Common/SemanticError.cc \ 109 Common/UniqueName.cc \ 110 Concurrency/Keywords.cc \ 111 ControlStruct/ForExprMutator.cc \ 112 ControlStruct/LabelFixer.cc \ 113 ControlStruct/LabelGenerator.cc \ 114 ControlStruct/MLEMutator.cc \ 115 ControlStruct/Mutate.cc \ 116 GenPoly/GenPoly.cc \ 117 GenPoly/Lvalue.cc \ 118 InitTweak/GenInit.cc \ 119 InitTweak/InitTweak.cc \ 120 Parser/LinkageSpec.cc \ 121 ResolvExpr/AdjustExprType.cc \ 122 ResolvExpr/Alternative.cc \ 123 ResolvExpr/AlternativeFinder.cc \ 124 ResolvExpr/ExplodedActual.cc \ 125 ResolvExpr/CastCost.cc \ 126 ResolvExpr/CommonType.cc \ 127 ResolvExpr/ConversionCost.cc \ 128 ResolvExpr/CurrentObject.cc \ 129 ResolvExpr/FindOpenVars.cc \ 130 ResolvExpr/Occurs.cc \ 131 ResolvExpr/PolyCost.cc \ 132 ResolvExpr/PtrsAssignable.cc \ 133 ResolvExpr/PtrsCastable.cc \ 134 ResolvExpr/RenameVars.cc \ 135 ResolvExpr/ResolveAssertions.cc \ 136 ResolvExpr/Resolver.cc \ 137 ResolvExpr/ResolveTypeof.cc \ 138 ResolvExpr/SpecCost.cc \ 139 ResolvExpr/TypeEnvironment.cc \ 140 ResolvExpr/Unify.cc \ 141 SymTab/Autogen.cc \ 142 SymTab/FixFunction.cc \ 143 SymTab/Indexer.cc \ 144 SymTab/Mangler.cc \ 145 SymTab/Validate.cc \ 146 Tuples/Explode.cc \ 147 Tuples/TupleAssignment.cc \ 148 Tuples/TupleExpansion.cc \ 149 Validate/HandleAttributes.cc \ 150 Validate/FindSpecialDecls.cc 151 76 libdemangle_a_SOURCES = $(SRCDEMANGLE) 152 77 153 78 MAINTAINERCLEANFILES += ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}} -
src/Makefile.in
r6a9d4b4 r933f32f 162 162 libdemangle_a_LIBADD = 163 163 am__dirstamp = $(am__leading_dot)dirstamp 164 am_libdemangle_a_OBJECTS = SymTab/Demangle.$(OBJEXT) \ 165 SymTab/ManglerCommon.$(OBJEXT) SynTree/Type.$(OBJEXT) \ 166 SynTree/VoidType.$(OBJEXT) SynTree/BasicType.$(OBJEXT) \ 167 SynTree/PointerType.$(OBJEXT) SynTree/ArrayType.$(OBJEXT) \ 168 SynTree/ReferenceType.$(OBJEXT) SynTree/FunctionType.$(OBJEXT) \ 169 SynTree/ReferenceToType.$(OBJEXT) SynTree/TupleType.$(OBJEXT) \ 170 SynTree/TypeofType.$(OBJEXT) SynTree/AttrType.$(OBJEXT) \ 171 SynTree/VarArgsType.$(OBJEXT) SynTree/ZeroOneType.$(OBJEXT) \ 172 SynTree/Constant.$(OBJEXT) SynTree/Expression.$(OBJEXT) \ 173 SynTree/TupleExpr.$(OBJEXT) SynTree/CommaExpr.$(OBJEXT) \ 174 SynTree/TypeExpr.$(OBJEXT) SynTree/ApplicationExpr.$(OBJEXT) \ 175 SynTree/AddressExpr.$(OBJEXT) SynTree/Statement.$(OBJEXT) \ 176 SynTree/CompoundStmt.$(OBJEXT) SynTree/DeclStmt.$(OBJEXT) \ 177 SynTree/Declaration.$(OBJEXT) \ 178 SynTree/DeclarationWithType.$(OBJEXT) \ 179 SynTree/ObjectDecl.$(OBJEXT) SynTree/FunctionDecl.$(OBJEXT) \ 180 SynTree/AggregateDecl.$(OBJEXT) \ 181 SynTree/NamedTypeDecl.$(OBJEXT) SynTree/TypeDecl.$(OBJEXT) \ 182 SynTree/Initializer.$(OBJEXT) \ 183 SynTree/TypeSubstitution.$(OBJEXT) SynTree/Attribute.$(OBJEXT) \ 184 SynTree/DeclReplacer.$(OBJEXT) CompilationState.$(OBJEXT) \ 185 CodeGen/CodeGenerator.$(OBJEXT) CodeGen/FixMain.$(OBJEXT) \ 186 CodeGen/Generate.$(OBJEXT) CodeGen/GenType.$(OBJEXT) \ 187 CodeGen/OperatorTable.$(OBJEXT) Common/Assert.$(OBJEXT) \ 188 Common/Eval.$(OBJEXT) Common/SemanticError.$(OBJEXT) \ 189 Common/UniqueName.$(OBJEXT) Concurrency/Keywords.$(OBJEXT) \ 190 ControlStruct/ForExprMutator.$(OBJEXT) \ 164 am__objects_1 = CodeGen/CodeGenerator.$(OBJEXT) \ 165 CodeGen/FixMain.$(OBJEXT) CodeGen/GenType.$(OBJEXT) \ 166 CodeGen/OperatorTable.$(OBJEXT) 167 am__objects_2 = Common/Assert.$(OBJEXT) Common/Eval.$(OBJEXT) \ 168 Common/PassVisitor.$(OBJEXT) Common/SemanticError.$(OBJEXT) \ 169 Common/Stats/Counter.$(OBJEXT) Common/Stats/Heap.$(OBJEXT) \ 170 Common/Stats/Stats.$(OBJEXT) Common/Stats/Time.$(OBJEXT) \ 171 Common/UniqueName.$(OBJEXT) 172 am__objects_3 = ControlStruct/ForExprMutator.$(OBJEXT) \ 191 173 ControlStruct/LabelFixer.$(OBJEXT) \ 192 174 ControlStruct/LabelGenerator.$(OBJEXT) \ 193 175 ControlStruct/MLEMutator.$(OBJEXT) \ 194 ControlStruct/Mutate.$(OBJEXT) GenPoly/GenPoly.$(OBJEXT) \ 195 GenPoly/Lvalue.$(OBJEXT) InitTweak/GenInit.$(OBJEXT) \ 196 InitTweak/InitTweak.$(OBJEXT) Parser/LinkageSpec.$(OBJEXT) \ 197 ResolvExpr/AdjustExprType.$(OBJEXT) \ 176 ControlStruct/Mutate.$(OBJEXT) 177 am__objects_4 = ResolvExpr/AdjustExprType.$(OBJEXT) \ 198 178 ResolvExpr/Alternative.$(OBJEXT) \ 199 179 ResolvExpr/AlternativeFinder.$(OBJEXT) \ 200 ResolvExpr/ExplodedActual.$(OBJEXT) \201 180 ResolvExpr/CastCost.$(OBJEXT) ResolvExpr/CommonType.$(OBJEXT) \ 202 181 ResolvExpr/ConversionCost.$(OBJEXT) \ 203 182 ResolvExpr/CurrentObject.$(OBJEXT) \ 183 ResolvExpr/ExplodedActual.$(OBJEXT) \ 204 184 ResolvExpr/FindOpenVars.$(OBJEXT) ResolvExpr/Occurs.$(OBJEXT) \ 205 185 ResolvExpr/PolyCost.$(OBJEXT) \ … … 212 192 ResolvExpr/SpecCost.$(OBJEXT) \ 213 193 ResolvExpr/TypeEnvironment.$(OBJEXT) \ 214 ResolvExpr/Unify.$(OBJEXT) SymTab/Autogen.$(OBJEXT) \ 215 SymTab/FixFunction.$(OBJEXT) SymTab/Indexer.$(OBJEXT) \ 216 SymTab/Mangler.$(OBJEXT) SymTab/Validate.$(OBJEXT) \ 217 Tuples/Explode.$(OBJEXT) Tuples/TupleAssignment.$(OBJEXT) \ 218 Tuples/TupleExpansion.$(OBJEXT) \ 219 Validate/HandleAttributes.$(OBJEXT) \ 220 Validate/FindSpecialDecls.$(OBJEXT) 221 libdemangle_a_OBJECTS = $(am_libdemangle_a_OBJECTS) 222 am__installdirs = "$(DESTDIR)$(cfa_cpplibdir)" 223 PROGRAMS = $(cfa_cpplib_PROGRAMS) 224 am__objects_1 = main.$(OBJEXT) MakeLibCfa.$(OBJEXT) \ 225 CompilationState.$(OBJEXT) CodeGen/Generate.$(OBJEXT) \ 226 CodeGen/CodeGenerator.$(OBJEXT) CodeGen/GenType.$(OBJEXT) \ 227 CodeGen/FixNames.$(OBJEXT) CodeGen/FixMain.$(OBJEXT) \ 228 CodeGen/OperatorTable.$(OBJEXT) CodeTools/DeclStats.$(OBJEXT) \ 229 CodeTools/ResolvProtoDump.$(OBJEXT) \ 230 CodeTools/TrackLoc.$(OBJEXT) Concurrency/Keywords.$(OBJEXT) \ 231 Concurrency/Waitfor.$(OBJEXT) Common/SemanticError.$(OBJEXT) \ 232 Common/UniqueName.$(OBJEXT) Common/DebugMalloc.$(OBJEXT) \ 233 Common/Assert.$(OBJEXT) Common/Heap.$(OBJEXT) \ 234 Common/Eval.$(OBJEXT) ControlStruct/LabelGenerator.$(OBJEXT) \ 235 ControlStruct/LabelFixer.$(OBJEXT) \ 236 ControlStruct/MLEMutator.$(OBJEXT) \ 237 ControlStruct/Mutate.$(OBJEXT) \ 238 ControlStruct/ForExprMutator.$(OBJEXT) \ 239 ControlStruct/ExceptTranslate.$(OBJEXT) GenPoly/Box.$(OBJEXT) \ 240 GenPoly/GenPoly.$(OBJEXT) GenPoly/ScrubTyVars.$(OBJEXT) \ 241 GenPoly/Lvalue.$(OBJEXT) GenPoly/Specialize.$(OBJEXT) \ 242 GenPoly/FindFunction.$(OBJEXT) \ 243 GenPoly/InstantiateGeneric.$(OBJEXT) \ 244 InitTweak/GenInit.$(OBJEXT) InitTweak/FixInit.$(OBJEXT) \ 245 InitTweak/FixGlobalInit.$(OBJEXT) \ 246 InitTweak/InitTweak.$(OBJEXT) Parser/parser.$(OBJEXT) \ 247 Parser/lex.$(OBJEXT) Parser/TypedefTable.$(OBJEXT) \ 248 Parser/ParseNode.$(OBJEXT) Parser/DeclarationNode.$(OBJEXT) \ 249 Parser/ExpressionNode.$(OBJEXT) Parser/StatementNode.$(OBJEXT) \ 250 Parser/InitializerNode.$(OBJEXT) Parser/TypeData.$(OBJEXT) \ 251 Parser/LinkageSpec.$(OBJEXT) Parser/parserutility.$(OBJEXT) \ 252 ResolvExpr/AlternativeFinder.$(OBJEXT) \ 253 ResolvExpr/Alternative.$(OBJEXT) ResolvExpr/Unify.$(OBJEXT) \ 254 ResolvExpr/PtrsAssignable.$(OBJEXT) \ 255 ResolvExpr/CommonType.$(OBJEXT) \ 256 ResolvExpr/ConversionCost.$(OBJEXT) \ 257 ResolvExpr/CastCost.$(OBJEXT) \ 258 ResolvExpr/PtrsCastable.$(OBJEXT) \ 259 ResolvExpr/AdjustExprType.$(OBJEXT) \ 260 ResolvExpr/AlternativePrinter.$(OBJEXT) \ 261 ResolvExpr/Resolver.$(OBJEXT) \ 262 ResolvExpr/ResolveTypeof.$(OBJEXT) \ 263 ResolvExpr/RenameVars.$(OBJEXT) \ 264 ResolvExpr/FindOpenVars.$(OBJEXT) \ 265 ResolvExpr/PolyCost.$(OBJEXT) ResolvExpr/Occurs.$(OBJEXT) \ 266 ResolvExpr/TypeEnvironment.$(OBJEXT) \ 267 ResolvExpr/CurrentObject.$(OBJEXT) \ 268 ResolvExpr/ExplodedActual.$(OBJEXT) \ 269 ResolvExpr/SpecCost.$(OBJEXT) \ 270 ResolvExpr/ResolveAssertions.$(OBJEXT) \ 194 ResolvExpr/Unify.$(OBJEXT) 195 am__objects_5 = SymTab/Autogen.$(OBJEXT) SymTab/FixFunction.$(OBJEXT) \ 271 196 SymTab/Indexer.$(OBJEXT) SymTab/Mangler.$(OBJEXT) \ 272 SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT) \ 273 SymTab/FixFunction.$(OBJEXT) SymTab/Autogen.$(OBJEXT) \ 274 SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \ 197 SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT) 198 am__objects_6 = SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \ 275 199 SynTree/BasicType.$(OBJEXT) SynTree/PointerType.$(OBJEXT) \ 276 200 SynTree/ArrayType.$(OBJEXT) SynTree/ReferenceType.$(OBJEXT) \ … … 291 215 SynTree/Initializer.$(OBJEXT) \ 292 216 SynTree/TypeSubstitution.$(OBJEXT) SynTree/Attribute.$(OBJEXT) \ 293 SynTree/DeclReplacer.$(OBJEXT) \ 217 SynTree/DeclReplacer.$(OBJEXT) 218 am__objects_7 = CompilationState.$(OBJEXT) $(am__objects_1) \ 219 Concurrency/Keywords.$(OBJEXT) $(am__objects_2) \ 220 $(am__objects_3) GenPoly/GenPoly.$(OBJEXT) \ 221 GenPoly/Lvalue.$(OBJEXT) InitTweak/GenInit.$(OBJEXT) \ 222 InitTweak/InitTweak.$(OBJEXT) Parser/LinkageSpec.$(OBJEXT) \ 223 $(am__objects_4) $(am__objects_5) SymTab/Demangle.$(OBJEXT) \ 224 $(am__objects_6) Tuples/TupleAssignment.$(OBJEXT) \ 225 Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \ 226 Validate/HandleAttributes.$(OBJEXT) \ 227 Validate/FindSpecialDecls.$(OBJEXT) 228 am_libdemangle_a_OBJECTS = $(am__objects_7) 229 libdemangle_a_OBJECTS = $(am_libdemangle_a_OBJECTS) 230 am__installdirs = "$(DESTDIR)$(cfa_cpplibdir)" 231 PROGRAMS = $(cfa_cpplib_PROGRAMS) 232 am__objects_8 = main.$(OBJEXT) MakeLibCfa.$(OBJEXT) \ 233 CompilationState.$(OBJEXT) $(am__objects_1) \ 234 CodeGen/Generate.$(OBJEXT) CodeGen/FixNames.$(OBJEXT) \ 235 CodeTools/DeclStats.$(OBJEXT) \ 236 CodeTools/ResolvProtoDump.$(OBJEXT) \ 237 CodeTools/TrackLoc.$(OBJEXT) Concurrency/Keywords.$(OBJEXT) \ 238 Concurrency/Waitfor.$(OBJEXT) $(am__objects_2) \ 239 Common/DebugMalloc.$(OBJEXT) $(am__objects_3) \ 240 ControlStruct/ExceptTranslate.$(OBJEXT) GenPoly/Box.$(OBJEXT) \ 241 GenPoly/GenPoly.$(OBJEXT) GenPoly/ScrubTyVars.$(OBJEXT) \ 242 GenPoly/Lvalue.$(OBJEXT) GenPoly/Specialize.$(OBJEXT) \ 243 GenPoly/FindFunction.$(OBJEXT) \ 244 GenPoly/InstantiateGeneric.$(OBJEXT) \ 245 InitTweak/GenInit.$(OBJEXT) InitTweak/FixInit.$(OBJEXT) \ 246 InitTweak/FixGlobalInit.$(OBJEXT) \ 247 InitTweak/InitTweak.$(OBJEXT) Parser/parser.$(OBJEXT) \ 248 Parser/lex.$(OBJEXT) Parser/TypedefTable.$(OBJEXT) \ 249 Parser/ParseNode.$(OBJEXT) Parser/DeclarationNode.$(OBJEXT) \ 250 Parser/ExpressionNode.$(OBJEXT) Parser/StatementNode.$(OBJEXT) \ 251 Parser/InitializerNode.$(OBJEXT) Parser/TypeData.$(OBJEXT) \ 252 Parser/LinkageSpec.$(OBJEXT) Parser/parserutility.$(OBJEXT) \ 253 $(am__objects_4) ResolvExpr/AlternativePrinter.$(OBJEXT) \ 254 $(am__objects_5) $(am__objects_6) \ 294 255 Tuples/TupleAssignment.$(OBJEXT) \ 295 256 Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \ … … 297 258 Validate/FindSpecialDecls.$(OBJEXT) \ 298 259 Virtual/ExpandCasts.$(OBJEXT) 299 am____driver_cfa_cpp_OBJECTS = $(am__objects_ 1)260 am____driver_cfa_cpp_OBJECTS = $(am__objects_8) 300 261 ___driver_cfa_cpp_OBJECTS = $(am____driver_cfa_cpp_OBJECTS) 301 ___driver_cfa_cpp_DEPENDENCIES = 262 am__DEPENDENCIES_1 = 263 ___driver_cfa_cpp_DEPENDENCIES = $(am__DEPENDENCIES_1) \ 264 $(am__DEPENDENCIES_1) 302 265 AM_V_lt = $(am__v_lt_@AM_V@) 303 266 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) … … 418 381 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 419 382 ACLOCAL = @ACLOCAL@ 420 ALLOCA = @ALLOCA@421 383 AMTAR = @AMTAR@ 422 384 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 566 528 AUTOMAKE_OPTIONS = foreign subdir-objects 567 529 ACLOCAL_AMFLAGS = -I automake 568 SRC = main.cc MakeLibCfa.cc CompilationState.cc CodeGen/Generate.cc \ 569 CodeGen/CodeGenerator.cc CodeGen/GenType.cc \ 570 CodeGen/FixNames.cc CodeGen/FixMain.cc \ 571 CodeGen/OperatorTable.cc CodeTools/DeclStats.cc \ 530 SRC = main.cc MakeLibCfa.cc CompilationState.cc $(SRC_CODEGEN) \ 531 CodeGen/Generate.cc CodeGen/FixNames.cc CodeTools/DeclStats.cc \ 572 532 CodeTools/ResolvProtoDump.cc CodeTools/TrackLoc.cc \ 573 Concurrency/Keywords.cc Concurrency/Waitfor.cc \ 574 Common/SemanticError.cc Common/UniqueName.cc \ 575 Common/DebugMalloc.cc Common/Assert.cc Common/Heap.cc \ 576 Common/Eval.cc ControlStruct/LabelGenerator.cc \ 577 ControlStruct/LabelFixer.cc ControlStruct/MLEMutator.cc \ 578 ControlStruct/Mutate.cc ControlStruct/ForExprMutator.cc \ 533 Concurrency/Keywords.cc Concurrency/Waitfor.cc $(SRC_COMMON) \ 534 Common/DebugMalloc.cc $(SRC_CONTROLSTRUCT) \ 579 535 ControlStruct/ExceptTranslate.cc GenPoly/Box.cc \ 580 536 GenPoly/GenPoly.cc GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc \ … … 587 543 Parser/StatementNode.cc Parser/InitializerNode.cc \ 588 544 Parser/TypeData.cc Parser/LinkageSpec.cc \ 589 Parser/parserutility.cc ResolvExpr/AlternativeFinder.cc \ 590 ResolvExpr/Alternative.cc ResolvExpr/Unify.cc \ 591 ResolvExpr/PtrsAssignable.cc ResolvExpr/CommonType.cc \ 592 ResolvExpr/ConversionCost.cc ResolvExpr/CastCost.cc \ 593 ResolvExpr/PtrsCastable.cc ResolvExpr/AdjustExprType.cc \ 594 ResolvExpr/AlternativePrinter.cc ResolvExpr/Resolver.cc \ 595 ResolvExpr/ResolveTypeof.cc ResolvExpr/RenameVars.cc \ 596 ResolvExpr/FindOpenVars.cc ResolvExpr/PolyCost.cc \ 597 ResolvExpr/Occurs.cc ResolvExpr/TypeEnvironment.cc \ 598 ResolvExpr/CurrentObject.cc ResolvExpr/ExplodedActual.cc \ 599 ResolvExpr/SpecCost.cc ResolvExpr/ResolveAssertions.cc \ 600 SymTab/Indexer.cc SymTab/Mangler.cc SymTab/ManglerCommon.cc \ 601 SymTab/Validate.cc SymTab/FixFunction.cc SymTab/Autogen.cc \ 602 SynTree/Type.cc SynTree/VoidType.cc SynTree/BasicType.cc \ 603 SynTree/PointerType.cc SynTree/ArrayType.cc \ 604 SynTree/ReferenceType.cc SynTree/FunctionType.cc \ 605 SynTree/ReferenceToType.cc SynTree/TupleType.cc \ 606 SynTree/TypeofType.cc SynTree/AttrType.cc \ 607 SynTree/VarArgsType.cc SynTree/ZeroOneType.cc \ 608 SynTree/Constant.cc SynTree/Expression.cc SynTree/TupleExpr.cc \ 609 SynTree/CommaExpr.cc SynTree/TypeExpr.cc \ 610 SynTree/ApplicationExpr.cc SynTree/AddressExpr.cc \ 611 SynTree/Statement.cc SynTree/CompoundStmt.cc \ 612 SynTree/DeclStmt.cc SynTree/Declaration.cc \ 613 SynTree/DeclarationWithType.cc SynTree/ObjectDecl.cc \ 614 SynTree/FunctionDecl.cc SynTree/AggregateDecl.cc \ 615 SynTree/NamedTypeDecl.cc SynTree/TypeDecl.cc \ 616 SynTree/Initializer.cc SynTree/TypeSubstitution.cc \ 617 SynTree/Attribute.cc SynTree/DeclReplacer.cc \ 545 Parser/parserutility.cc $(SRC_RESOLVEXPR) \ 546 ResolvExpr/AlternativePrinter.cc $(SRC_SYMTAB) $(SRC_SYNTREE) \ 618 547 Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \ 619 548 Tuples/Explode.cc Validate/HandleAttributes.cc \ 620 549 Validate/FindSpecialDecls.cc Virtual/ExpandCasts.cc 550 SRCDEMANGLE = CompilationState.cc $(SRC_CODEGEN) \ 551 Concurrency/Keywords.cc $(SRC_COMMON) $(SRC_CONTROLSTRUCT) \ 552 GenPoly/GenPoly.cc GenPoly/Lvalue.cc InitTweak/GenInit.cc \ 553 InitTweak/InitTweak.cc Parser/LinkageSpec.cc $(SRC_RESOLVEXPR) \ 554 $(SRC_SYMTAB) SymTab/Demangle.cc $(SRC_SYNTREE) \ 555 Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \ 556 Tuples/Explode.cc Validate/HandleAttributes.cc \ 557 Validate/FindSpecialDecls.cc 621 558 MAINTAINERCLEANFILES = ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}} 622 MOSTLYCLEANFILES = Parser/gcc-flags.h Parser/lex.cc Parser/parser.cc \ 623 Parser/parser.hh Parser/parser.output 624 BUILT_SOURCES = Parser/parser.hh 625 AM_YFLAGS = -d -t -v 626 627 # put into lib for now 628 cfa_cpplibdir = $(CFA_LIBDIR) 629 ___driver_cfa_cpp_SOURCES = $(SRC) 630 ___driver_cfa_cpp_LDADD = -ldl # yywrap 631 AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O2 -g -std=c++14 632 AM_LDFLAGS = @HOST_FLAGS@ -Xlinker -export-dynamic 633 ARFLAGS = cr 634 demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete 635 demangler_LDADD = libdemangle.a # yywrap 636 noinst_LIBRARIES = libdemangle.a 637 libdemangle_a_SOURCES = \ 638 SymTab/Demangle.cc \ 639 SymTab/ManglerCommon.cc \ 640 SynTree/Type.cc \ 641 SynTree/VoidType.cc \ 642 SynTree/BasicType.cc \ 643 SynTree/PointerType.cc \ 644 SynTree/ArrayType.cc \ 645 SynTree/ReferenceType.cc \ 646 SynTree/FunctionType.cc \ 647 SynTree/ReferenceToType.cc \ 648 SynTree/TupleType.cc \ 649 SynTree/TypeofType.cc \ 650 SynTree/AttrType.cc \ 651 SynTree/VarArgsType.cc \ 652 SynTree/ZeroOneType.cc \ 653 SynTree/Constant.cc \ 654 SynTree/Expression.cc \ 655 SynTree/TupleExpr.cc \ 656 SynTree/CommaExpr.cc \ 657 SynTree/TypeExpr.cc \ 658 SynTree/ApplicationExpr.cc \ 659 SynTree/AddressExpr.cc \ 660 SynTree/Statement.cc \ 661 SynTree/CompoundStmt.cc \ 662 SynTree/DeclStmt.cc \ 663 SynTree/Declaration.cc \ 664 SynTree/DeclarationWithType.cc \ 665 SynTree/ObjectDecl.cc \ 666 SynTree/FunctionDecl.cc \ 667 SynTree/AggregateDecl.cc \ 668 SynTree/NamedTypeDecl.cc \ 669 SynTree/TypeDecl.cc \ 670 SynTree/Initializer.cc \ 671 SynTree/TypeSubstitution.cc \ 672 SynTree/Attribute.cc \ 673 SynTree/DeclReplacer.cc \ 674 CompilationState.cc \ 559 MOSTLYCLEANFILES = Parser/lex.cc Parser/parser.cc Parser/parser.hh \ 560 Parser/parser.output 561 @WITH_LIBPROFILER_TRUE@LIBPROFILER = -lprofiler 562 @WITH_LIBTCMALLOC_TRUE@LIBTCMALLOC = -ltcmalloc 563 @WITH_LIBTCMALLOC_TRUE@TCMALLOCFLAG = -DTCMALLOC 564 SRC_CODEGEN = \ 675 565 CodeGen/CodeGenerator.cc \ 676 566 CodeGen/FixMain.cc \ 677 CodeGen/Generate.cc \678 567 CodeGen/GenType.cc \ 679 CodeGen/OperatorTable.cc \ 680 Common/Assert.cc \ 681 Common/Eval.cc \ 682 Common/SemanticError.cc \ 683 Common/UniqueName.cc \ 684 Concurrency/Keywords.cc \ 568 CodeGen/OperatorTable.cc 569 570 SRC_COMMON = \ 571 Common/Assert.cc \ 572 Common/Eval.cc \ 573 Common/PassVisitor.cc \ 574 Common/SemanticError.cc \ 575 Common/Stats/Counter.cc \ 576 Common/Stats/Heap.cc \ 577 Common/Stats/Stats.cc \ 578 Common/Stats/Time.cc \ 579 Common/UniqueName.cc 580 581 SRC_CONTROLSTRUCT = \ 685 582 ControlStruct/ForExprMutator.cc \ 686 583 ControlStruct/LabelFixer.cc \ 687 584 ControlStruct/LabelGenerator.cc \ 688 585 ControlStruct/MLEMutator.cc \ 689 ControlStruct/Mutate.cc \ 690 GenPoly/GenPoly.cc \ 691 GenPoly/Lvalue.cc \ 692 InitTweak/GenInit.cc \ 693 InitTweak/InitTweak.cc \ 694 Parser/LinkageSpec.cc \ 695 ResolvExpr/AdjustExprType.cc \ 696 ResolvExpr/Alternative.cc \ 697 ResolvExpr/AlternativeFinder.cc \ 698 ResolvExpr/ExplodedActual.cc \ 699 ResolvExpr/CastCost.cc \ 700 ResolvExpr/CommonType.cc \ 701 ResolvExpr/ConversionCost.cc \ 702 ResolvExpr/CurrentObject.cc \ 703 ResolvExpr/FindOpenVars.cc \ 704 ResolvExpr/Occurs.cc \ 705 ResolvExpr/PolyCost.cc \ 706 ResolvExpr/PtrsAssignable.cc \ 707 ResolvExpr/PtrsCastable.cc \ 708 ResolvExpr/RenameVars.cc \ 709 ResolvExpr/ResolveAssertions.cc \ 710 ResolvExpr/Resolver.cc \ 711 ResolvExpr/ResolveTypeof.cc \ 712 ResolvExpr/SpecCost.cc \ 713 ResolvExpr/TypeEnvironment.cc \ 714 ResolvExpr/Unify.cc \ 715 SymTab/Autogen.cc \ 716 SymTab/FixFunction.cc \ 717 SymTab/Indexer.cc \ 718 SymTab/Mangler.cc \ 719 SymTab/Validate.cc \ 720 Tuples/Explode.cc \ 721 Tuples/TupleAssignment.cc \ 722 Tuples/TupleExpansion.cc \ 723 Validate/HandleAttributes.cc \ 724 Validate/FindSpecialDecls.cc 725 586 ControlStruct/Mutate.cc 587 588 BUILT_SOURCES = Parser/parser.hh 589 AM_YFLAGS = -d -t -v 590 SRC_RESOLVEXPR = \ 591 ResolvExpr/AdjustExprType.cc \ 592 ResolvExpr/Alternative.cc \ 593 ResolvExpr/AlternativeFinder.cc \ 594 ResolvExpr/CastCost.cc \ 595 ResolvExpr/CommonType.cc \ 596 ResolvExpr/ConversionCost.cc \ 597 ResolvExpr/CurrentObject.cc \ 598 ResolvExpr/ExplodedActual.cc \ 599 ResolvExpr/FindOpenVars.cc \ 600 ResolvExpr/Occurs.cc \ 601 ResolvExpr/PolyCost.cc \ 602 ResolvExpr/PtrsAssignable.cc \ 603 ResolvExpr/PtrsCastable.cc \ 604 ResolvExpr/RenameVars.cc \ 605 ResolvExpr/ResolveAssertions.cc \ 606 ResolvExpr/Resolver.cc \ 607 ResolvExpr/ResolveTypeof.cc \ 608 ResolvExpr/SpecCost.cc \ 609 ResolvExpr/TypeEnvironment.cc \ 610 ResolvExpr/Unify.cc 611 612 SRC_SYMTAB = \ 613 SymTab/Autogen.cc \ 614 SymTab/FixFunction.cc \ 615 SymTab/Indexer.cc \ 616 SymTab/Mangler.cc \ 617 SymTab/ManglerCommon.cc \ 618 SymTab/Validate.cc 619 620 SRC_SYNTREE = \ 621 SynTree/Type.cc \ 622 SynTree/VoidType.cc \ 623 SynTree/BasicType.cc \ 624 SynTree/PointerType.cc \ 625 SynTree/ArrayType.cc \ 626 SynTree/ReferenceType.cc \ 627 SynTree/FunctionType.cc \ 628 SynTree/ReferenceToType.cc \ 629 SynTree/TupleType.cc \ 630 SynTree/TypeofType.cc \ 631 SynTree/AttrType.cc \ 632 SynTree/VarArgsType.cc \ 633 SynTree/ZeroOneType.cc \ 634 SynTree/Constant.cc \ 635 SynTree/Expression.cc \ 636 SynTree/TupleExpr.cc \ 637 SynTree/CommaExpr.cc \ 638 SynTree/TypeExpr.cc \ 639 SynTree/ApplicationExpr.cc \ 640 SynTree/AddressExpr.cc \ 641 SynTree/Statement.cc \ 642 SynTree/CompoundStmt.cc \ 643 SynTree/DeclStmt.cc \ 644 SynTree/Declaration.cc \ 645 SynTree/DeclarationWithType.cc \ 646 SynTree/ObjectDecl.cc \ 647 SynTree/FunctionDecl.cc \ 648 SynTree/AggregateDecl.cc \ 649 SynTree/NamedTypeDecl.cc \ 650 SynTree/TypeDecl.cc \ 651 SynTree/Initializer.cc \ 652 SynTree/TypeSubstitution.cc \ 653 SynTree/Attribute.cc \ 654 SynTree/DeclReplacer.cc 655 656 657 # put into lib for now 658 cfa_cpplibdir = $(CFA_LIBDIR) 659 ___driver_cfa_cpp_SOURCES = $(SRC) 660 ___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC) 661 AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O3 -g -std=c++14 $(TCMALLOCFLAG) 662 AM_LDFLAGS = @HOST_FLAGS@ -Xlinker -export-dynamic 663 ARFLAGS = cr 664 demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete 665 demangler_LDADD = libdemangle.a -ldl # yywrap 666 noinst_LIBRARIES = libdemangle.a 667 libdemangle_a_SOURCES = $(SRCDEMANGLE) 726 668 all: $(BUILT_SOURCES) 727 669 $(MAKE) $(AM_MAKEFLAGS) all-am … … 762 704 clean-noinstLIBRARIES: 763 705 -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) 764 SymTab/$(am__dirstamp):765 @$(MKDIR_P) SymTab766 @: > SymTab/$(am__dirstamp)767 SymTab/$(DEPDIR)/$(am__dirstamp):768 @$(MKDIR_P) SymTab/$(DEPDIR)769 @: > SymTab/$(DEPDIR)/$(am__dirstamp)770 SymTab/Demangle.$(OBJEXT): SymTab/$(am__dirstamp) \771 SymTab/$(DEPDIR)/$(am__dirstamp)772 SymTab/ManglerCommon.$(OBJEXT): SymTab/$(am__dirstamp) \773 SymTab/$(DEPDIR)/$(am__dirstamp)774 SynTree/$(am__dirstamp):775 @$(MKDIR_P) SynTree776 @: > SynTree/$(am__dirstamp)777 SynTree/$(DEPDIR)/$(am__dirstamp):778 @$(MKDIR_P) SynTree/$(DEPDIR)779 @: > SynTree/$(DEPDIR)/$(am__dirstamp)780 SynTree/Type.$(OBJEXT): SynTree/$(am__dirstamp) \781 SynTree/$(DEPDIR)/$(am__dirstamp)782 SynTree/VoidType.$(OBJEXT): SynTree/$(am__dirstamp) \783 SynTree/$(DEPDIR)/$(am__dirstamp)784 SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \785 SynTree/$(DEPDIR)/$(am__dirstamp)786 SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \787 SynTree/$(DEPDIR)/$(am__dirstamp)788 SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \789 SynTree/$(DEPDIR)/$(am__dirstamp)790 SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \791 SynTree/$(DEPDIR)/$(am__dirstamp)792 SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \793 SynTree/$(DEPDIR)/$(am__dirstamp)794 SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \795 SynTree/$(DEPDIR)/$(am__dirstamp)796 SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \797 SynTree/$(DEPDIR)/$(am__dirstamp)798 SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \799 SynTree/$(DEPDIR)/$(am__dirstamp)800 SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \801 SynTree/$(DEPDIR)/$(am__dirstamp)802 SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \803 SynTree/$(DEPDIR)/$(am__dirstamp)804 SynTree/ZeroOneType.$(OBJEXT): SynTree/$(am__dirstamp) \805 SynTree/$(DEPDIR)/$(am__dirstamp)806 SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \807 SynTree/$(DEPDIR)/$(am__dirstamp)808 SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \809 SynTree/$(DEPDIR)/$(am__dirstamp)810 SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \811 SynTree/$(DEPDIR)/$(am__dirstamp)812 SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \813 SynTree/$(DEPDIR)/$(am__dirstamp)814 SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \815 SynTree/$(DEPDIR)/$(am__dirstamp)816 SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \817 SynTree/$(DEPDIR)/$(am__dirstamp)818 SynTree/AddressExpr.$(OBJEXT): SynTree/$(am__dirstamp) \819 SynTree/$(DEPDIR)/$(am__dirstamp)820 SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \821 SynTree/$(DEPDIR)/$(am__dirstamp)822 SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \823 SynTree/$(DEPDIR)/$(am__dirstamp)824 SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \825 SynTree/$(DEPDIR)/$(am__dirstamp)826 SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \827 SynTree/$(DEPDIR)/$(am__dirstamp)828 SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \829 SynTree/$(DEPDIR)/$(am__dirstamp)830 SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \831 SynTree/$(DEPDIR)/$(am__dirstamp)832 SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \833 SynTree/$(DEPDIR)/$(am__dirstamp)834 SynTree/AggregateDecl.$(OBJEXT): SynTree/$(am__dirstamp) \835 SynTree/$(DEPDIR)/$(am__dirstamp)836 SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \837 SynTree/$(DEPDIR)/$(am__dirstamp)838 SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \839 SynTree/$(DEPDIR)/$(am__dirstamp)840 SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \841 SynTree/$(DEPDIR)/$(am__dirstamp)842 SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \843 SynTree/$(DEPDIR)/$(am__dirstamp)844 SynTree/Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \845 SynTree/$(DEPDIR)/$(am__dirstamp)846 SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \847 SynTree/$(DEPDIR)/$(am__dirstamp)848 706 CodeGen/$(am__dirstamp): 849 707 @$(MKDIR_P) CodeGen … … 856 714 CodeGen/FixMain.$(OBJEXT): CodeGen/$(am__dirstamp) \ 857 715 CodeGen/$(DEPDIR)/$(am__dirstamp) 858 CodeGen/Generate.$(OBJEXT): CodeGen/$(am__dirstamp) \859 CodeGen/$(DEPDIR)/$(am__dirstamp)860 716 CodeGen/GenType.$(OBJEXT): CodeGen/$(am__dirstamp) \ 861 717 CodeGen/$(DEPDIR)/$(am__dirstamp) 862 718 CodeGen/OperatorTable.$(OBJEXT): CodeGen/$(am__dirstamp) \ 863 719 CodeGen/$(DEPDIR)/$(am__dirstamp) 720 Concurrency/$(am__dirstamp): 721 @$(MKDIR_P) Concurrency 722 @: > Concurrency/$(am__dirstamp) 723 Concurrency/$(DEPDIR)/$(am__dirstamp): 724 @$(MKDIR_P) Concurrency/$(DEPDIR) 725 @: > Concurrency/$(DEPDIR)/$(am__dirstamp) 726 Concurrency/Keywords.$(OBJEXT): Concurrency/$(am__dirstamp) \ 727 Concurrency/$(DEPDIR)/$(am__dirstamp) 864 728 Common/$(am__dirstamp): 865 729 @$(MKDIR_P) Common … … 872 736 Common/Eval.$(OBJEXT): Common/$(am__dirstamp) \ 873 737 Common/$(DEPDIR)/$(am__dirstamp) 738 Common/PassVisitor.$(OBJEXT): Common/$(am__dirstamp) \ 739 Common/$(DEPDIR)/$(am__dirstamp) 874 740 Common/SemanticError.$(OBJEXT): Common/$(am__dirstamp) \ 875 741 Common/$(DEPDIR)/$(am__dirstamp) 742 Common/Stats/$(am__dirstamp): 743 @$(MKDIR_P) Common/Stats 744 @: > Common/Stats/$(am__dirstamp) 745 Common/Stats/$(DEPDIR)/$(am__dirstamp): 746 @$(MKDIR_P) Common/Stats/$(DEPDIR) 747 @: > Common/Stats/$(DEPDIR)/$(am__dirstamp) 748 Common/Stats/Counter.$(OBJEXT): Common/Stats/$(am__dirstamp) \ 749 Common/Stats/$(DEPDIR)/$(am__dirstamp) 750 Common/Stats/Heap.$(OBJEXT): Common/Stats/$(am__dirstamp) \ 751 Common/Stats/$(DEPDIR)/$(am__dirstamp) 752 Common/Stats/Stats.$(OBJEXT): Common/Stats/$(am__dirstamp) \ 753 Common/Stats/$(DEPDIR)/$(am__dirstamp) 754 Common/Stats/Time.$(OBJEXT): Common/Stats/$(am__dirstamp) \ 755 Common/Stats/$(DEPDIR)/$(am__dirstamp) 876 756 Common/UniqueName.$(OBJEXT): Common/$(am__dirstamp) \ 877 757 Common/$(DEPDIR)/$(am__dirstamp) 878 Concurrency/$(am__dirstamp):879 @$(MKDIR_P) Concurrency880 @: > Concurrency/$(am__dirstamp)881 Concurrency/$(DEPDIR)/$(am__dirstamp):882 @$(MKDIR_P) Concurrency/$(DEPDIR)883 @: > Concurrency/$(DEPDIR)/$(am__dirstamp)884 Concurrency/Keywords.$(OBJEXT): Concurrency/$(am__dirstamp) \885 Concurrency/$(DEPDIR)/$(am__dirstamp)886 758 ControlStruct/$(am__dirstamp): 887 759 @$(MKDIR_P) ControlStruct … … 940 812 ResolvExpr/AlternativeFinder.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 941 813 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 814 ResolvExpr/CastCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 815 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 816 ResolvExpr/CommonType.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 817 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 818 ResolvExpr/ConversionCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 819 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 820 ResolvExpr/CurrentObject.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 821 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 942 822 ResolvExpr/ExplodedActual.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 943 823 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 944 ResolvExpr/CastCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \945 ResolvExpr/$(DEPDIR)/$(am__dirstamp)946 ResolvExpr/CommonType.$(OBJEXT): ResolvExpr/$(am__dirstamp) \947 ResolvExpr/$(DEPDIR)/$(am__dirstamp)948 ResolvExpr/ConversionCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \949 ResolvExpr/$(DEPDIR)/$(am__dirstamp)950 ResolvExpr/CurrentObject.$(OBJEXT): ResolvExpr/$(am__dirstamp) \951 ResolvExpr/$(DEPDIR)/$(am__dirstamp)952 824 ResolvExpr/FindOpenVars.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 953 825 ResolvExpr/$(DEPDIR)/$(am__dirstamp) … … 974 846 ResolvExpr/Unify.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 975 847 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 848 SymTab/$(am__dirstamp): 849 @$(MKDIR_P) SymTab 850 @: > SymTab/$(am__dirstamp) 851 SymTab/$(DEPDIR)/$(am__dirstamp): 852 @$(MKDIR_P) SymTab/$(DEPDIR) 853 @: > SymTab/$(DEPDIR)/$(am__dirstamp) 976 854 SymTab/Autogen.$(OBJEXT): SymTab/$(am__dirstamp) \ 977 855 SymTab/$(DEPDIR)/$(am__dirstamp) … … 982 860 SymTab/Mangler.$(OBJEXT): SymTab/$(am__dirstamp) \ 983 861 SymTab/$(DEPDIR)/$(am__dirstamp) 862 SymTab/ManglerCommon.$(OBJEXT): SymTab/$(am__dirstamp) \ 863 SymTab/$(DEPDIR)/$(am__dirstamp) 984 864 SymTab/Validate.$(OBJEXT): SymTab/$(am__dirstamp) \ 985 865 SymTab/$(DEPDIR)/$(am__dirstamp) 866 SymTab/Demangle.$(OBJEXT): SymTab/$(am__dirstamp) \ 867 SymTab/$(DEPDIR)/$(am__dirstamp) 868 SynTree/$(am__dirstamp): 869 @$(MKDIR_P) SynTree 870 @: > SynTree/$(am__dirstamp) 871 SynTree/$(DEPDIR)/$(am__dirstamp): 872 @$(MKDIR_P) SynTree/$(DEPDIR) 873 @: > SynTree/$(DEPDIR)/$(am__dirstamp) 874 SynTree/Type.$(OBJEXT): SynTree/$(am__dirstamp) \ 875 SynTree/$(DEPDIR)/$(am__dirstamp) 876 SynTree/VoidType.$(OBJEXT): SynTree/$(am__dirstamp) \ 877 SynTree/$(DEPDIR)/$(am__dirstamp) 878 SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \ 879 SynTree/$(DEPDIR)/$(am__dirstamp) 880 SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \ 881 SynTree/$(DEPDIR)/$(am__dirstamp) 882 SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \ 883 SynTree/$(DEPDIR)/$(am__dirstamp) 884 SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \ 885 SynTree/$(DEPDIR)/$(am__dirstamp) 886 SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \ 887 SynTree/$(DEPDIR)/$(am__dirstamp) 888 SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \ 889 SynTree/$(DEPDIR)/$(am__dirstamp) 890 SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \ 891 SynTree/$(DEPDIR)/$(am__dirstamp) 892 SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \ 893 SynTree/$(DEPDIR)/$(am__dirstamp) 894 SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \ 895 SynTree/$(DEPDIR)/$(am__dirstamp) 896 SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \ 897 SynTree/$(DEPDIR)/$(am__dirstamp) 898 SynTree/ZeroOneType.$(OBJEXT): SynTree/$(am__dirstamp) \ 899 SynTree/$(DEPDIR)/$(am__dirstamp) 900 SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \ 901 SynTree/$(DEPDIR)/$(am__dirstamp) 902 SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \ 903 SynTree/$(DEPDIR)/$(am__dirstamp) 904 SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \ 905 SynTree/$(DEPDIR)/$(am__dirstamp) 906 SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \ 907 SynTree/$(DEPDIR)/$(am__dirstamp) 908 SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \ 909 SynTree/$(DEPDIR)/$(am__dirstamp) 910 SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \ 911 SynTree/$(DEPDIR)/$(am__dirstamp) 912 SynTree/AddressExpr.$(OBJEXT): SynTree/$(am__dirstamp) \ 913 SynTree/$(DEPDIR)/$(am__dirstamp) 914 SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \ 915 SynTree/$(DEPDIR)/$(am__dirstamp) 916 SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \ 917 SynTree/$(DEPDIR)/$(am__dirstamp) 918 SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \ 919 SynTree/$(DEPDIR)/$(am__dirstamp) 920 SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \ 921 SynTree/$(DEPDIR)/$(am__dirstamp) 922 SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \ 923 SynTree/$(DEPDIR)/$(am__dirstamp) 924 SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \ 925 SynTree/$(DEPDIR)/$(am__dirstamp) 926 SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \ 927 SynTree/$(DEPDIR)/$(am__dirstamp) 928 SynTree/AggregateDecl.$(OBJEXT): SynTree/$(am__dirstamp) \ 929 SynTree/$(DEPDIR)/$(am__dirstamp) 930 SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \ 931 SynTree/$(DEPDIR)/$(am__dirstamp) 932 SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \ 933 SynTree/$(DEPDIR)/$(am__dirstamp) 934 SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \ 935 SynTree/$(DEPDIR)/$(am__dirstamp) 936 SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \ 937 SynTree/$(DEPDIR)/$(am__dirstamp) 938 SynTree/Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \ 939 SynTree/$(DEPDIR)/$(am__dirstamp) 940 SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \ 941 SynTree/$(DEPDIR)/$(am__dirstamp) 986 942 Tuples/$(am__dirstamp): 987 943 @$(MKDIR_P) Tuples … … 990 946 @$(MKDIR_P) Tuples/$(DEPDIR) 991 947 @: > Tuples/$(DEPDIR)/$(am__dirstamp) 992 Tuples/Explode.$(OBJEXT): Tuples/$(am__dirstamp) \993 Tuples/$(DEPDIR)/$(am__dirstamp)994 948 Tuples/TupleAssignment.$(OBJEXT): Tuples/$(am__dirstamp) \ 995 949 Tuples/$(DEPDIR)/$(am__dirstamp) 996 950 Tuples/TupleExpansion.$(OBJEXT): Tuples/$(am__dirstamp) \ 951 Tuples/$(DEPDIR)/$(am__dirstamp) 952 Tuples/Explode.$(OBJEXT): Tuples/$(am__dirstamp) \ 997 953 Tuples/$(DEPDIR)/$(am__dirstamp) 998 954 Validate/$(am__dirstamp): … … 1060 1016 echo " rm -f" $$list; \ 1061 1017 rm -f $$list 1018 CodeGen/Generate.$(OBJEXT): CodeGen/$(am__dirstamp) \ 1019 CodeGen/$(DEPDIR)/$(am__dirstamp) 1062 1020 CodeGen/FixNames.$(OBJEXT): CodeGen/$(am__dirstamp) \ 1063 1021 CodeGen/$(DEPDIR)/$(am__dirstamp) … … 1077 1035 Concurrency/$(DEPDIR)/$(am__dirstamp) 1078 1036 Common/DebugMalloc.$(OBJEXT): Common/$(am__dirstamp) \ 1079 Common/$(DEPDIR)/$(am__dirstamp)1080 Common/Heap.$(OBJEXT): Common/$(am__dirstamp) \1081 1037 Common/$(DEPDIR)/$(am__dirstamp) 1082 1038 ControlStruct/ExceptTranslate.$(OBJEXT): \ … … 1149 1105 -rm -f CodeTools/*.$(OBJEXT) 1150 1106 -rm -f Common/*.$(OBJEXT) 1107 -rm -f Common/Stats/*.$(OBJEXT) 1151 1108 -rm -f Concurrency/*.$(OBJEXT) 1152 1109 -rm -f ControlStruct/*.$(OBJEXT) … … 1179 1136 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/DebugMalloc.Po@am__quote@ 1180 1137 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/Eval.Po@am__quote@ 1181 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/ Heap.Po@am__quote@1138 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/PassVisitor.Po@am__quote@ 1182 1139 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/SemanticError.Po@am__quote@ 1183 1140 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/UniqueName.Po@am__quote@ 1141 @AMDEP_TRUE@@am__include@ @am__quote@Common/Stats/$(DEPDIR)/Counter.Po@am__quote@ 1142 @AMDEP_TRUE@@am__include@ @am__quote@Common/Stats/$(DEPDIR)/Heap.Po@am__quote@ 1143 @AMDEP_TRUE@@am__include@ @am__quote@Common/Stats/$(DEPDIR)/Stats.Po@am__quote@ 1144 @AMDEP_TRUE@@am__include@ @am__quote@Common/Stats/$(DEPDIR)/Time.Po@am__quote@ 1184 1145 @AMDEP_TRUE@@am__include@ @am__quote@Concurrency/$(DEPDIR)/Keywords.Po@am__quote@ 1185 1146 @AMDEP_TRUE@@am__include@ @am__quote@Concurrency/$(DEPDIR)/Waitfor.Po@am__quote@ … … 1444 1405 -rm -f Common/$(DEPDIR)/$(am__dirstamp) 1445 1406 -rm -f Common/$(am__dirstamp) 1407 -rm -f Common/Stats/$(DEPDIR)/$(am__dirstamp) 1408 -rm -f Common/Stats/$(am__dirstamp) 1446 1409 -rm -f Concurrency/$(DEPDIR)/$(am__dirstamp) 1447 1410 -rm -f Concurrency/$(am__dirstamp) … … 1481 1444 1482 1445 distclean: distclean-am 1483 -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Co ncurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)1446 -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Common/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR) 1484 1447 -rm -f Makefile 1485 1448 distclean-am: clean-am distclean-compile distclean-generic \ … … 1527 1490 1528 1491 maintainer-clean: maintainer-clean-am 1529 -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Co ncurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)1492 -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Common/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR) 1530 1493 -rm -f Makefile 1531 1494 maintainer-clean-am: distclean-am maintainer-clean-generic … … 1567 1530 1568 1531 1569 Parser/gcc-flags.h : 1570 ${AM_V_GEN}$(CC) -dM -E - < /dev/null | sed 's/define /define __GCC__/' > $(@) 1571 1572 Parser/lex.ll : Parser/gcc-flags.h 1532 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h 1533 1534 $(srcdir)/SynTree/Type.h : BasicTypes-gen.cc 1535 ${AM_V_GEN}${CXXCOMPILE} $< -o BasicTypes-gen -Wall -Wextra 1536 @./BasicTypes-gen 1537 @rm BasicTypes-gen 1573 1538 1574 1539 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
src/Parser/DeclarationNode.cc
r6a9d4b4 r933f32f 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Nov 1 20:54:26 201813 // Update Count : 11 0812 // Last Modified On : Fri Feb 1 16:49:17 2019 13 // Update Count : 1113 14 14 // 15 15 … … 41 41 42 42 // These must harmonize with the corresponding DeclarationNode enumerations. 43 const char * DeclarationNode::basicTypeNames[] = { "void", "_Bool", "char", "int", "float", "double", "long double", "int128", "float80", "float128", "NoBasicTypeNames" }; 44 const char * DeclarationNode::complexTypeNames[] = { "_Complex", "_Imaginary", "NoComplexTypeNames" }; 43 const char * DeclarationNode::basicTypeNames[] = { "void", "_Bool", "char", "int", "int128", 44 "float", "double", "long double", "float80", "float128", 45 "_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x", "NoBasicTypeNames" }; 46 const char * DeclarationNode::complexTypeNames[] = { "_Complex", "NoComplexTypeNames", "_Imaginary" }; // Imaginary unsupported => parse, but make invisible and print error message 45 47 const char * DeclarationNode::signednessNames[] = { "signed", "unsigned", "NoSignednessNames" }; 46 48 const char * DeclarationNode::lengthNames[] = { "short", "long", "long long", "NoLengthNames" }; -
src/Parser/ExpressionNode.cc
r6a9d4b4 r933f32f 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:45 201813 // Update Count : 80212 // Last Modified On : Sun Mar 10 16:10:32 2019 13 // Update Count : 976 14 14 // 15 15 … … 51 51 extern const Type::Qualifiers noQualifiers; // no qualifiers on constants 52 52 53 static inline bool checkH( char c ) { return c == 'h' || c == 'H'; } 54 static inline bool checkL( char c ) { return c == 'l' || c == 'L'; } 55 static inline bool checkZ( char c ) { return c == 'z' || c == 'Z'; } 56 static inline bool checkU( char c ) { return c == 'u' || c == 'U'; } 53 // static inline bool checkH( char c ) { return c == 'h' || c == 'H'; } 54 // static inline bool checkZ( char c ) { return c == 'z' || c == 'Z'; } 55 // static inline bool checkU( char c ) { return c == 'u' || c == 'U'; } 57 56 static inline bool checkF( char c ) { return c == 'f' || c == 'F'; } 58 57 static inline bool checkD( char c ) { return c == 'd' || c == 'D'; } 58 static inline bool checkF80( char c ) { return c == 'w' || c == 'W'; } 59 static inline bool checkF128( char c ) { return c == 'q' || c == 'Q'; } 60 static inline bool checkL( char c ) { return c == 'l' || c == 'L'; } 59 61 static inline bool checkI( char c ) { return c == 'i' || c == 'I'; } 60 62 static inline bool checkB( char c ) { return c == 'b' || c == 'B'; } 61 63 static inline bool checkX( char c ) { return c == 'x' || c == 'X'; } 62 63 static const char * lnthsInt[2][6] = { 64 { "int8_t", "int16_t", "int32_t", "int64_t", "size_t", }, 65 { "uint8_t", "uint16_t", "uint32_t", "uint64_t", "size_t", } 66 }; // lnthsInt 67 68 static inline void checkLNInt( string & str, int & lnth, int & size ) { 69 string::size_type posn = str.find_first_of( "lL" ), start = posn; 70 if ( posn == string::npos ) return; 71 size = 4; // assume largest size 72 posn += 1; // advance to size 73 if ( str[posn] == '8' ) { // 8 74 lnth = 0; 75 } else if ( str[posn] == '1' ) { 76 posn += 1; 77 if ( str[posn] == '6' ) { // 16 78 lnth = 1; 64 // static inline bool checkN( char c ) { return c == 'n' || c == 'N'; } 65 66 void lnthSuffix( string & str, int & type, int & ltype ) { 67 string::size_type posn = str.find_last_of( "lL" ); 68 69 if ( posn == string::npos ) return; // no suffix 70 if ( posn == str.length() - 1 ) { type = 3; return; } // no length => long 71 72 string::size_type next = posn + 1; // advance to length 73 if ( str[next] == '3' ) { // 32 74 type = ltype = 2; 75 } else if ( str[next] == '6' ) { // 64 76 type = ltype = 3; 77 } else if ( str[next] == '8' ) { // 8 78 type = ltype = 1; 79 } else if ( str[next] == '1' ) { 80 if ( str[next + 1] == '6' ) { // 16 81 type = ltype = 0; 79 82 } else { // 128 80 posn += 1; 81 lnth = 5; 82 } // if 83 } else { 84 if ( str[posn] == '3' ) { // 32 85 lnth = 2; 86 } else if ( str[posn] == '6' ) { // 64 87 lnth = 3; 88 } else { 89 assertf( false, "internal error, bad integral length %s", str.c_str() ); 90 } // if 91 posn += 1; 92 } // if 93 str.erase( start, posn - start + 1 ); // remove length suffix 94 } // checkLNInt 83 type = 5; ltype = 6; 84 } // if 85 } // if 86 // remove "lL" for these cases because it may not imply long 87 str.erase( posn ); // remove length 88 } // lnthSuffix 89 90 void valueToType( unsigned long long int & v, bool dec, int & type, bool & Unsigned ) { 91 // use value to determine type 92 if ( v <= INT_MAX ) { // signed int 93 type = 2; 94 } else if ( v <= UINT_MAX && ! dec ) { // unsigned int 95 type = 2; 96 Unsigned = true; // unsigned 97 } else if ( v <= LONG_MAX ) { // signed long int 98 type = 3; 99 } else if ( v <= ULONG_MAX && ( ! dec || LONG_MAX == LLONG_MAX ) ) { // signed long int 100 type = 3; 101 Unsigned = true; // unsigned long int 102 } else if ( v <= LLONG_MAX ) { // signed long long int 103 type = 4; 104 } else { // unsigned long long int 105 type = 4; 106 Unsigned = true; // unsigned long long int 107 } // if 108 } // valueToType 95 109 96 110 Expression * build_constantInteger( string & str ) { 97 static const BasicType::Kind kind[2][ 6] = {98 // short (h) must be before char (hh) 111 static const BasicType::Kind kind[2][7] = { 112 // short (h) must be before char (hh) because shorter type has the longer suffix 99 113 { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, BasicType::SignedInt128, }, 100 114 { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::UnsignedInt128, }, 101 115 }; 102 116 103 bool dec = true, Unsigned = false; // decimal, unsigned constant 104 int size; // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128 105 int lnth = -1; // literal length 117 static const char * lnthsInt[2][6] = { 118 { "int16_t", "int8_t", "int32_t", "int64_t", "size_t", "uintptr_t", }, 119 { "uint16_t", "uint8_t", "uint32_t", "uint64_t", "size_t", "uintptr_t", }, 120 }; // lnthsInt 106 121 107 122 unsigned long long int v; // converted integral value 108 123 size_t last = str.length() - 1; // last subscript of constant 109 124 Expression * ret; 125 //string fred( str ); 126 127 int type = -1; // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128 128 int ltype = -1; // 0 => 16 bits, 1 => 8 bits, 2 => 32 bits, 3 => 64 bits, 4 => size_t, 5 => intptr, 6 => pointer 129 bool dec = true, Unsigned = false; // decimal, unsigned constant 110 130 111 131 // special constants … … 119 139 } // if 120 140 121 // Cannot be "0"141 // Cannot be just "0"/"1"; sscanf stops at the suffix, if any; value goes over the wall => always generate 122 142 123 143 if ( str[0] == '0' ) { // radix character ? … … 127 147 //printf( "%llx %llu\n", v, v ); 128 148 } else if ( checkB( str[1] ) ) { // binary constant ? 129 v = 0; 130 for ( unsigned int i = 2;; i += 1 ) { // compute value149 v = 0; // compute value 150 for ( unsigned int i = 2;; ) { // ignore prefix 131 151 if ( str[i] == '1' ) v |= 1; 132 if ( i == last ) break; 152 i += 1; 153 if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break; 133 154 v <<= 1; 134 155 } // for 135 //printf( "% llx %llu\n", v, v );156 //printf( "%#llx %llu\n", v, v ); 136 157 } else { // octal constant 137 158 sscanf( (char *)str.c_str(), "%llo", &v ); 138 //printf( "% llo %llu\n", v, v );159 //printf( "%#llo %llu\n", v, v ); 139 160 } // if 140 161 } else { // decimal constant ? 141 162 sscanf( (char *)str.c_str(), "%llu", &v ); 142 //printf( "%llu %llu\n", v, v ); 143 } // if 144 145 if ( v <= INT_MAX ) { // signed int 146 size = 2; 147 } else if ( v <= UINT_MAX && ! dec ) { // unsigned int 148 size = 2; 149 Unsigned = true; // unsigned 150 } else if ( v <= LONG_MAX ) { // signed long int 151 size = 3; 152 } else if ( v <= ULONG_MAX && ( ! dec || LONG_MAX == LLONG_MAX ) ) { // signed long int 153 size = 3; 154 Unsigned = true; // unsigned long int 155 } else if ( v <= LLONG_MAX ) { // signed long long int 156 size = 4; 157 } else { // unsigned long long int 158 size = 4; 159 Unsigned = true; // unsigned long long int 160 } // if 161 162 // At least one digit in integer constant, so safe to backup while looking for suffix. 163 164 if ( checkU( str[last] ) ) { // suffix 'u' ? 165 Unsigned = true; 166 if ( checkL( str[last - 1] ) ) { // suffix 'l' ? 167 size = 3; 168 if ( checkL( str[last - 2] ) ) { // suffix "ll" ? 169 size = 4; 163 //printf( "%llu\n", v ); 164 } // if 165 166 string::size_type posn; 167 168 if ( isdigit( str[last] ) ) { // no suffix ? 169 lnthSuffix( str, type, ltype ); // could have length suffix 170 if ( type == -1 ) { // no suffix 171 valueToType( v, dec, type, Unsigned ); 172 } // if 173 } else { 174 // At least one digit in integer constant, so safe to backup while looking for suffix. 175 176 posn = str.find_last_of( "pP" ); 177 if ( posn != string::npos ) { valueToType( v, dec, type, Unsigned ); ltype = 5; str.erase( posn, 1 ); goto FINI; } 178 179 posn = str.find_last_of( "zZ" ); 180 if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; } 181 182 // 'u' can appear before or after length suffix 183 if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true; 184 185 posn = str.rfind( "hh" ); 186 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; } 187 188 posn = str.rfind( "HH" ); 189 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; } 190 191 posn = str.find_last_of( "hH" ); 192 if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; } 193 194 posn = str.find_last_of( "nN" ); 195 if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; } 196 197 if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; } 198 199 lnthSuffix( str, type, ltype ); // must be after check for "ll" 200 if ( type == -1 ) { // only 'u' suffix ? 201 valueToType( v, dec, type, Unsigned ); 202 } // if 203 FINI: ; 204 } // if 205 206 //if ( !( 0 <= type && type <= 6 ) ) { printf( "%s %lu %d %s\n", fred.c_str(), fred.length(), type, str.c_str() ); } 207 assert( 0 <= type && type <= 6 ); 208 209 // Constant type is correct for overload resolving. 210 ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[Unsigned][type] ), str, v ) ); 211 if ( Unsigned && type < 2 ) { // hh or h, less than int ? 212 // int i = -1uh => 65535 not -1, so cast is necessary for unsigned, which unfortunately eliminates warnings for large values. 213 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false ); 214 } else if ( ltype != -1 ) { // explicit length ? 215 if ( ltype == 6 ) { // int128, (int128)constant 216 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false ); 217 } else { // explicit length, (length_type)constant 218 ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][ltype], false ), false ); 219 if ( ltype == 5 ) { // pointer, intptr( (uintptr_t)constant ) 220 ret = build_func( new ExpressionNode( build_varref( new string( "intptr" ) ) ), new ExpressionNode( ret ) ); 170 221 } // if 171 } else if ( checkH( str[last - 1] ) ) { // suffix 'h' ? 172 size = 0; 173 if ( checkH( str[last - 2] ) ) { // suffix "hh" ? 174 size = 1; 175 } // if 176 str.erase( last - size - 1, size + 1 ); // remove 'h'/"hh" 177 } else { // suffix "ln" ? 178 checkLNInt( str, lnth, size ); 179 } // if 180 } else if ( checkL( str[ last ] ) ) { // suffix 'l' ? 181 size = 3; 182 if ( checkL( str[last - 1] ) ) { // suffix 'll' ? 183 size = 4; 184 if ( checkU( str[last - 2] ) ) { // suffix 'u' ? 185 Unsigned = true; 186 } // if 187 } else if ( checkU( str[last - 1] ) ) { // suffix 'u' ? 188 Unsigned = true; 189 } // if 190 } else if ( checkH( str[ last ] ) ) { // suffix 'h' ? 191 size = 0; 192 if ( checkH( str[last - 1] ) ) { // suffix "hh" ? 193 size = 1; 194 if ( checkU( str[last - 2] ) ) { // suffix 'u' ? 195 Unsigned = true; 196 } // if 197 } else if ( checkU( str[last - 1] ) ) { // suffix 'u' ? 198 Unsigned = true; 199 } // if 200 str.erase( last - size, size + 1 ); // remove 'h'/"hh" 201 } else if ( checkZ( str[last] ) ) { // suffix 'z' ? 202 lnth = 4; 203 str.erase( last, 1 ); // remove 'z' 204 } else { // suffix "ln" ? 205 checkLNInt( str, lnth, size ); 206 } // if 207 208 assert( 0 <= size && size < 6 ); 209 // Constant type is correct for overload resolving. 210 ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[Unsigned][size] ), str, v ) ); 211 if ( Unsigned && size < 2 ) { // hh or h, less than int ? 212 // int i = -1uh => 65535 not -1, so cast is necessary for unsigned, which unfortunately eliminates warnings for large values. 213 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][size] ), false ); 214 } else if ( lnth != -1 ) { // explicit length ? 215 if ( lnth == 5 ) { // int128 ? 216 size = 5; 217 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][size] ), false ); 218 } else { 219 ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][lnth], false ), false ); 220 } // if 221 } // if 222 CLEANUP: 223 222 } // if 223 } // if 224 225 CLEANUP: ; 224 226 delete &str; // created by lex 225 227 return ret; … … 227 229 228 230 229 static inline void checkLNFloat( string & str, int & lnth, int & size ) { 230 string::size_type posn = str.find_first_of( "lL" ), start = posn; 231 static inline void checkFnxFloat( string & str, size_t last, bool & explnth, int & type ) { 232 string::size_type posn; 233 // floating-point constant has minimum of 2 characters, 1. or .1, so safe to look ahead 234 if ( str[1] == 'x' ) { // hex ? 235 posn = str.find_last_of( "pP" ); // back for exponent (must have) 236 posn = str.find_first_of( "fF", posn + 1 ); // forward for size (fF allowed in hex constant) 237 } else { 238 posn = str.find_last_of( "fF" ); // back for size (fF not allowed) 239 } // if 231 240 if ( posn == string::npos ) return; 232 size = 2; // assume largest size 233 lnth = 0; 241 explnth = true; 234 242 posn += 1; // advance to size 235 243 if ( str[posn] == '3' ) { // 32 236 size = 0; 244 if ( str[last] != 'x' ) type = 6; 245 else type = 7; 237 246 } else if ( str[posn] == '6' ) { // 64 238 size = 1; 239 } else if ( str[posn] == '8' || str[posn] == '1' ) { // 80, 128 240 size = 2; 241 if ( str[posn] == '1' ) posn += 1; 247 if ( str[last] != 'x' ) type = 8; 248 else type = 9; 249 } else if ( str[posn] == '8' ) { // 80 250 type = 3; 251 } else if ( str[posn] == '1' ) { // 16/128 252 if ( str[posn + 1] == '6' ) { // 16 253 type = 5; 254 } else { // 128 255 if ( str[last] != 'x' ) type = 10; 256 else type = 11; 257 } // if 242 258 } else { 243 259 assertf( false, "internal error, bad floating point length %s", str.c_str() ); 244 260 } // if 245 posn += 1; 246 str.erase( start, posn - start + 1 ); // remove length suffix 247 } // checkLNFloat 261 } // checkFnxFloat 248 262 249 263 250 264 Expression * build_constantFloat( string & str ) { 251 static const BasicType::Kind kind[2][ 3] = {252 { BasicType::Float, BasicType::Double, BasicType::LongDouble },253 { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex },265 static const BasicType::Kind kind[2][12] = { 266 { BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::uuFloat80, BasicType::uuFloat128, BasicType::uFloat16, BasicType::uFloat32, BasicType::uFloat32x, BasicType::uFloat64, BasicType::uFloat64x, BasicType::uFloat128, BasicType::uFloat128x }, 267 { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, (BasicType::Kind)-1, (BasicType::Kind)-1, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex }, 254 268 }; 255 269 256 bool complx = false; // real, complex 257 int size = 1; // 0 => float, 1 => double, 2 => long double 258 int lnth = -1; // literal length 259 // floating-point constant has minimum of 2 characters: 1. or .1 270 // floating-point constant has minimum of 2 characters 1. or .1 260 271 size_t last = str.length() - 1; 261 272 double v; 273 int type; // 0 => float, 1 => double, 3 => long double, ... 274 bool complx = false; // real, complex 275 bool explnth = false; // explicit literal length 262 276 263 277 sscanf( str.c_str(), "%lg", &v ); … … 269 283 270 284 if ( checkF( str[last] ) ) { // float ? 271 size = 0;285 type = 0; 272 286 } else if ( checkD( str[last] ) ) { // double ? 273 size = 1;287 type = 1; 274 288 } else if ( checkL( str[last] ) ) { // long double ? 275 size = 2; 289 type = 2; 290 } else if ( checkF80( str[last] ) ) { // __float80 ? 291 type = 3; 292 } else if ( checkF128( str[last] ) ) { // __float128 ? 293 type = 4; 276 294 } else { 277 size = 1; // double (default) 278 checkLNFloat( str, lnth, size ); 279 } // if 295 type = 1; // double (default if no suffix) 296 checkFnxFloat( str, last, explnth, type ); 297 } // if 298 280 299 if ( ! complx && checkI( str[last - 1] ) ) { // imaginary ? 281 300 complx = true; 282 301 } // if 283 302 284 assert( 0 <= size && size < 3);285 Expression * ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[complx][ size] ), str, v ) );286 if ( lnth != -1) { // explicit length ?287 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[complx][ size] ), false );303 assert( 0 <= type && type < 12 ); 304 Expression * ret = new ConstantExpr( Constant( new BasicType( noQualifiers, kind[complx][type] ), str, v ) ); 305 if ( explnth ) { // explicit length ? 306 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[complx][type] ), false ); 288 307 } // if 289 308 -
src/Parser/ParseNode.h
r6a9d4b4 r933f32f 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Nov 1 20:54:53 201813 // Update Count : 8 5412 // Last Modified On : Mon Apr 15 14:22:39 2019 13 // Update Count : 874 14 14 // 15 15 … … 132 132 void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {} 133 133 134 Expression *get_expr() const { return expr.get(); }135 134 template<typename T> 136 135 bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); } 137 136 138 137 Expression * build() const { return const_cast<ExpressionNode *>(this)->expr.release(); } 138 139 std::unique_ptr<Expression> expr; // public because of lifetime implications 139 140 private: 140 141 bool extension = false; 141 std::unique_ptr<Expression> expr;142 142 }; // ExpressionNode 143 143 … … 206 206 class DeclarationNode : public ParseNode { 207 207 public: 208 // These enumerations must harmonize with their names. 209 enum BasicType { Void, Bool, Char, Int, Float, Double, LongDouble, Int128, Float80, Float128, NoBasicType }; 208 // These enumerations must harmonize with their names in DeclarationNode.cc. 209 enum BasicType { Void, Bool, Char, Int, Int128, 210 Float, Double, LongDouble, uuFloat80, uuFloat128, 211 uFloat16, uFloat32, uFloat32x, uFloat64, uFloat64x, uFloat128, uFloat128x, NoBasicType }; 210 212 static const char * basicTypeNames[]; 211 enum ComplexType { Complex, Imaginary, NoComplexType };213 enum ComplexType { Complex, NoComplexType, Imaginary }; // Imaginary unsupported => parse, but make invisible and print error message 212 214 static const char * complexTypeNames[]; 213 215 enum Signedness { Signed, Unsigned, NoSignedness }; -
src/Parser/TypeData.cc
r6a9d4b4 r933f32f 10 10 // Created On : Sat May 16 15:12:51 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Nov 2 07:54:26 201813 // Update Count : 6 2412 // Last Modified On : Wed Feb 13 18:16:23 2019 13 // Update Count : 649 14 14 // 15 15 … … 666 666 667 667 case DeclarationNode::Float: 668 case DeclarationNode::Float80:669 case DeclarationNode::Float128:670 668 case DeclarationNode::Double: 671 669 case DeclarationNode::LongDouble: // not set until below 672 static BasicType::Kind floattype[3][3] = { 673 { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex }, 674 { BasicType::FloatImaginary, BasicType::DoubleImaginary, BasicType::LongDoubleImaginary }, 675 { BasicType::Float, BasicType::Double, BasicType::LongDouble }, 670 case DeclarationNode::uuFloat80: 671 case DeclarationNode::uuFloat128: 672 case DeclarationNode::uFloat16: 673 case DeclarationNode::uFloat32: 674 case DeclarationNode::uFloat32x: 675 case DeclarationNode::uFloat64: 676 case DeclarationNode::uFloat64x: 677 case DeclarationNode::uFloat128: 678 case DeclarationNode::uFloat128x: 679 static BasicType::Kind floattype[2][12] = { 680 { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, (BasicType::Kind)-1, (BasicType::Kind)-1, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex, }, 681 { BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::uuFloat80, BasicType::uuFloat128, BasicType::uFloat16, BasicType::uFloat32, BasicType::uFloat32x, BasicType::uFloat64, BasicType::uFloat64x, BasicType::uFloat128, BasicType::uFloat128x, }, 676 682 }; 677 683 … … 686 692 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); 687 693 } // if 694 if ( td->complextype == DeclarationNode::Imaginary ) { 695 genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype ); 696 } // if 697 if ( (td->basictype == DeclarationNode::uuFloat80 || td->basictype == DeclarationNode::uuFloat128) && td->complextype == DeclarationNode::Complex ) { // gcc unsupported 698 genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype ); 699 } // if 688 700 if ( td->length == DeclarationNode::Long ) { 689 701 const_cast<TypeData *>(td)->basictype = DeclarationNode::LongDouble; 690 702 } // if 691 703 692 if ( td->basictype == DeclarationNode::Float80 || td->basictype == DeclarationNode::Float128 ) {693 // if ( td->complextype != DeclarationNode::NoComplexType ) {694 // genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype );695 // }696 if ( td->basictype == DeclarationNode::Float80 ) ret = BasicType::Float80;697 else ret = BasicType::Float128;698 break;699 }700 701 704 ret = floattype[ td->complextype ][ td->basictype - DeclarationNode::Float ]; 705 //printf( "XXXX %d %d %d %d\n", td->complextype, td->basictype, DeclarationNode::Float, ret ); 702 706 break; 703 707 -
src/Parser/TypeData.h
r6a9d4b4 r933f32f 31 31 struct Aggregate_t { 32 32 DeclarationNode::Aggregate kind; 33 const std::string * name ;34 DeclarationNode * params ;35 ExpressionNode * actuals ; // holds actual parameters later applied to AggInst36 DeclarationNode * fields ;33 const std::string * name = nullptr; 34 DeclarationNode * params = nullptr; 35 ExpressionNode * actuals = nullptr; // holds actual parameters later applied to AggInst 36 DeclarationNode * fields = nullptr; 37 37 bool body; 38 38 bool anon; 39 39 40 40 bool tagged; 41 const std::string * parent ;41 const std::string * parent = nullptr; 42 42 }; 43 43 44 44 struct AggInst_t { 45 TypeData * aggregate ;46 ExpressionNode * params ;45 TypeData * aggregate = nullptr; 46 ExpressionNode * params = nullptr; 47 47 bool hoistType; 48 48 }; 49 49 50 50 struct Array_t { 51 ExpressionNode * dimension ;51 ExpressionNode * dimension = nullptr; 52 52 bool isVarLen; 53 53 bool isStatic; … … 55 55 56 56 struct Enumeration_t { 57 const std::string * name ;58 DeclarationNode * constants ;57 const std::string * name = nullptr; 58 DeclarationNode * constants = nullptr; 59 59 bool body; 60 60 bool anon; … … 62 62 63 63 struct Function_t { 64 mutable DeclarationNode * params ; // mutables modified in buildKRFunction65 mutable DeclarationNode * idList ; // old-style66 mutable DeclarationNode * oldDeclList ;67 StatementNode * body ;68 ExpressionNode * withExprs ; // expressions from function's with_clause64 mutable DeclarationNode * params = nullptr; // mutables modified in buildKRFunction 65 mutable DeclarationNode * idList = nullptr; // old-style 66 mutable DeclarationNode * oldDeclList = nullptr; 67 StatementNode * body = nullptr; 68 ExpressionNode * withExprs = nullptr; // expressions from function's with_clause 69 69 }; 70 70 71 71 struct Symbolic_t { 72 const std::string * name ;72 const std::string * name = nullptr; 73 73 bool isTypedef; // false => TYPEGENname, true => TYPEDEFname 74 DeclarationNode * params ;75 ExpressionNode * actuals ;76 DeclarationNode * assertions ;74 DeclarationNode * params = nullptr; 75 ExpressionNode * actuals = nullptr; 76 DeclarationNode * assertions = nullptr; 77 77 }; 78 78 79 79 struct Qualified_t { // qualified type S.T 80 TypeData * parent ;81 TypeData * child ;80 TypeData * parent = nullptr; 81 TypeData * child = nullptr; 82 82 }; 83 83 … … 93 93 94 94 Type::Qualifiers qualifiers; 95 DeclarationNode * forall ;95 DeclarationNode * forall = nullptr; 96 96 97 97 Aggregate_t aggregate; … … 102 102 Symbolic_t symbolic; 103 103 Qualified_t qualified; 104 DeclarationNode * tuple ;105 ExpressionNode * typeexpr ;104 DeclarationNode * tuple = nullptr; 105 ExpressionNode * typeexpr = nullptr; 106 106 107 107 TypeData( Kind k = Unknown ); -
src/Parser/lex.ll
r6a9d4b4 r933f32f 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Thu Nov 1 20:57:35 201813 * Update Count : 68712 * Last Modified On : Wed May 15 21:25:27 2019 13 * Update Count : 708 14 14 */ 15 15 … … 39 39 using namespace std; 40 40 41 #include "config.h" // configure info 41 42 #include "ParseNode.h" 42 43 #include "TypedefTable.h" … … 59 60 #define IDENTIFIER_RETURN() RETURN_VAL( typedefTable.isKind( yytext ) ) 60 61 #define ATTRIBUTE_RETURN() RETURN_VAL( ATTR_IDENTIFIER ) 62 63 #ifdef HAVE_KEYWORDS_FLOATXX // GCC >= 7 => keyword, otherwise typedef 64 #define FLOATXX(v) KEYWORD_RETURN(v); 65 #else 66 #define FLOATXX(v) IDENTIFIER_RETURN(); 67 #endif // HAVE_KEYWORDS_FLOATXX 61 68 62 69 void rm_underscore() { … … 92 99 hex_quad {hex}("_"?{hex}){3} 93 100 size_opt (8|16|32|64|128)? 94 length ("ll"|"LL"|[lL]{size_opt})|("hh"|"HH"|[hH]) 95 integer_suffix_opt ("_"?(([uU]({length}?[iI]?)|([iI]{length}))|([iI]({length}?[uU]?)|([uU]{length}))|({length}([iI]?[uU]?)|([uU][iI]))|[zZ]))? 101 // CFA: explicit l8/l16/l32/l64/l128, char 'hh', short 'h', int 'n' 102 length ("ll"|"LL"|[lL]{size_opt})|("hh"|"HH"|[hHnN]) 103 // CFA: size_t 'z', pointer 'p', which define a sign and length 104 integer_suffix_opt ("_"?(([uU]({length}?[iI]?)|([iI]{length}))|([iI]({length}?[uU]?)|([uU]{length}))|({length}([iI]?[uU]?)|([uU][iI]))|[zZ]|[pP]))? 96 105 97 106 octal_digits ({octal})|({octal}({octal}|"_")*{octal}) … … 112 121 // GCC: D (double) and iI (imaginary) suffixes, and DL (long double) 113 122 exponent "_"?[eE]"_"?[+-]?{decimal_digits} 114 floating_size 32|64|80|128115 floating_length ([fFdDlL ]|[lL]{floating_size})123 floating_size 16|32|32x|64|64x|80|128|128x 124 floating_length ([fFdDlLwWqQ]|[fF]{floating_size}) 116 125 floating_suffix ({floating_length}?[iI]?)|([iI]{floating_length}) 117 126 floating_suffix_opt ("_"?({floating_suffix}|"DL"))? … … 217 226 char { KEYWORD_RETURN(CHAR); } 218 227 choose { KEYWORD_RETURN(CHOOSE); } // CFA 228 coerce { KEYWORD_RETURN(COERCE); } // CFA 219 229 _Complex { KEYWORD_RETURN(COMPLEX); } // C99 220 230 __complex { KEYWORD_RETURN(COMPLEX); } // GCC … … 240 250 finally { KEYWORD_RETURN(FINALLY); } // CFA 241 251 float { KEYWORD_RETURN(FLOAT); } 242 _Float32 { KEYWORD_RETURN(FLOAT); } // GCC 243 _Float32x { KEYWORD_RETURN(FLOAT); } // GCC 244 _Float64 { KEYWORD_RETURN(DOUBLE); } // GCC 245 _Float64x { KEYWORD_RETURN(DOUBLE); } // GCC 246 __float80 { KEYWORD_RETURN(FLOAT80); } // GCC 247 float80 { KEYWORD_RETURN(FLOAT80); } // GCC 248 _Float128 { KEYWORD_RETURN(FLOAT128); } // GCC 249 _Float128x { KEYWORD_RETURN(FLOAT128); } // GCC 250 __float128 { KEYWORD_RETURN(FLOAT128); } // GCC 251 float128 { KEYWORD_RETURN(FLOAT128); } // GCC 252 __float80 { KEYWORD_RETURN(uuFLOAT80); } // GCC 253 float80 { KEYWORD_RETURN(uuFLOAT80); } // GCC 254 __float128 { KEYWORD_RETURN(uuFLOAT128); } // GCC 255 float128 { KEYWORD_RETURN(uuFLOAT128); } // GCC 256 _Float16 { FLOATXX(uFLOAT16); } // GCC 257 _Float32 { FLOATXX(uFLOAT32); } // GCC 258 _Float32x { FLOATXX(uFLOAT32X); } // GCC 259 _Float64 { FLOATXX(uFLOAT64); } // GCC 260 _Float64x { FLOATXX(uFLOAT64X); } // GCC 261 _Float128 { FLOATXX(uFLOAT128); } // GCC 262 _Float128x { FLOATXX(uFLOAT128); } // GCC 252 263 for { KEYWORD_RETURN(FOR); } 253 264 forall { KEYWORD_RETURN(FORALL); } // CFA 254 265 fortran { KEYWORD_RETURN(FORTRAN); } 255 266 ftype { KEYWORD_RETURN(FTYPE); } // CFA 267 generator { KEYWORD_RETURN(GENERATOR); } // CFA 256 268 _Generic { KEYWORD_RETURN(GENERIC); } // C11 257 269 goto { KEYWORD_RETURN(GOTO); } -
src/Parser/module.mk
r6a9d4b4 r933f32f 31 31 Parser/parserutility.cc 32 32 33 SRCDEMANGLE += \ 34 Parser/LinkageSpec.cc 35 36 33 37 MOSTLYCLEANFILES += Parser/lex.cc Parser/parser.cc Parser/parser.hh Parser/parser.output -
src/Parser/parser.yy
r6a9d4b4 r933f32f 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Nov 8 18:08:23 201813 // Update Count : 4 05212 // Last Modified On : Wed May 15 21:25:27 2019 13 // Update Count : 4296 14 14 // 15 15 … … 99 99 // distribute declaration_specifier across all declared variables, e.g., static, const, __attribute__. 100 100 DeclarationNode * cur = declList, * cl = (new DeclarationNode)->addType( specifier ); 101 //cur->addType( specifier ); 102 for ( cur = dynamic_cast< DeclarationNode * >( cur->get_next() ); cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) { 101 for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) { 103 102 cl->cloneBaseType( cur ); 104 103 } // for 105 104 declList->addType( cl ); 106 // delete cl;107 105 return declList; 108 106 } // distAttr … … 175 173 DeclarationNode * fieldDecl( DeclarationNode * typeSpec, DeclarationNode * fieldList ) { 176 174 if ( ! fieldList ) { // field declarator ? 177 if ( ! ( typeSpec->type && typeSpec->type->kind == TypeData::Aggregate) ) {175 if ( ! ( typeSpec->type && (typeSpec->type->kind == TypeData::Aggregate || typeSpec->type->kind == TypeData::Enum) ) ) { 178 176 stringstream ss; 179 177 typeSpec->type->print( ss ); … … 187 185 188 186 ForCtrl * forCtrl( ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 189 ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type-> get_expr());187 ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->expr.get()); 190 188 if ( constant && (constant->get_constant()->get_value() == "0" || constant->get_constant()->get_value() == "1") ) { 191 189 type = new ExpressionNode( new CastExpr( maybeMoveBuild< Expression >(type), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ) ); … … 193 191 return new ForCtrl( 194 192 distAttr( DeclarationNode::newTypeof( type, true ), DeclarationNode::newName( index )->addInitializer( new InitializerNode( start ) ) ), 195 new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index ) ) ), comp ) ), 196 new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto 197 OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index ) ) ), inc ) ) ); 193 // NULL comp/inc => leave blank 194 comp ? new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index ) ) ), comp ) ) : 0, 195 inc ? new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto 196 OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index ) ) ), inc ) ) : 0 ); 198 197 } // forCtrl 199 198 200 199 ForCtrl * forCtrl( ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 201 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index-> get_expr()) ) {200 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->expr.get()) ) { 202 201 return forCtrl( type, new string( identifier->name ), start, compop, comp, inc ); 202 } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index->expr.get()) ) { 203 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(commaExpr->arg1 ) ) { 204 return forCtrl( type, new string( identifier->name ), start, compop, comp, inc ); 205 } else { 206 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr; 207 } // if 203 208 } else { 204 209 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr; … … 260 265 %token RESTRICT // C99 261 266 %token ATOMIC // C11 262 %token FORALL MUTEX VIRTUAL // CFA267 %token FORALL MUTEX VIRTUAL COERCE // CFA 263 268 %token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED 264 269 %token BOOL COMPLEX IMAGINARY // C99 265 %token INT128 FLOAT80 FLOAT128 // GCC 270 %token INT128 uuFLOAT80 uuFLOAT128 // GCC 271 %token uFLOAT16 uFLOAT32 uFLOAT32X uFLOAT64 uFLOAT64X uFLOAT128 // GCC 266 272 %token ZERO_T ONE_T // CFA 267 273 %token VALIST // GCC … … 269 275 %token ENUM STRUCT UNION 270 276 %token EXCEPTION // CFA 271 %token COROUTINE MONITOR THREAD// CFA277 %token GENERATOR COROUTINE MONITOR THREAD // CFA 272 278 %token OTYPE FTYPE DTYPE TTYPE TRAIT // CFA 273 279 %token SIZEOF OFFSETOF … … 324 330 %type<en> argument_expression_list argument_expression default_initialize_opt 325 331 %type<ifctl> if_control_expression 326 %type<fctl> for_control_expression 332 %type<fctl> for_control_expression for_control_expression_list 327 333 %type<compop> inclexcl 328 334 %type<en> subrange 329 335 %type<decl> asm_name_opt 330 %type<en> asm_operands_opt asm_operands_listasm_operand336 %type<en> asm_operands_opt asm_operands_list asm_operand 331 337 %type<label> label_list 332 338 %type<en> asm_clobbers_list_opt 333 339 %type<flag> asm_volatile_opt 334 340 %type<en> handler_predicate_opt 335 %type<genexpr> generic_association generic_assoc_list341 %type<genexpr> generic_association generic_assoc_list 336 342 337 343 // statements … … 671 677 // empty 672 678 { $$ = nullptr; } 673 | ' ?' // CFA, default parameter679 | '@' // CFA, default parameter 674 680 { SemanticError( yylloc, "Default parameter for argument is currently unimplemented." ); $$ = nullptr; } 675 681 // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); } … … 789 795 | '(' type_no_function ')' cast_expression 790 796 { $$ = new ExpressionNode( build_cast( $2, $4 ) ); } 797 // keyword cast cannot be grouped because of reduction in aggregate_key 798 | '(' GENERATOR '&' ')' cast_expression // CFA 799 { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); } 791 800 | '(' COROUTINE '&' ')' cast_expression // CFA 792 801 { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); } … … 800 809 | '(' VIRTUAL type_no_function ')' cast_expression // CFA 801 810 { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild< Expression >( $5 ), maybeMoveBuildType( $3 ) ) ); } 811 | '(' RETURN type_no_function ')' cast_expression // CFA 812 { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; } 813 | '(' COERCE type_no_function ')' cast_expression // CFA 814 { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; } 815 | '(' qualifier_cast_list ')' cast_expression // CFA 816 { SemanticError( yylloc, "Qualifier cast is currently unimplemented." ); $$ = nullptr; } 802 817 // | '(' type_no_function ')' tuple 803 818 // { $$ = new ExpressionNode( build_cast( $2, $4 ) ); } 819 ; 820 821 qualifier_cast_list: 822 cast_modifier type_qualifier_name 823 | cast_modifier MUTEX 824 | qualifier_cast_list cast_modifier type_qualifier_name 825 | qualifier_cast_list cast_modifier MUTEX 826 ; 827 828 cast_modifier: 829 '-' 830 | '+' 804 831 ; 805 832 … … 984 1011 // labels cannot be identifiers 0 or 1 or ATTR_IDENTIFIER 985 1012 identifier_or_type_name ':' attribute_list_opt statement 986 { 987 $$ = $4->add_label( $1, $3 ); 988 } 1013 { $$ = $4->add_label( $1, $3 ); } 989 1014 ; 990 1015 … … 1002 1027 statement_decl 1003 1028 | statement_decl_list statement_decl 1004 { if ( $1 != 0 ) { $1->set_last( $2 ); $$ = $1; }}1029 { assert( $1 ); $1->set_last( $2 ); $$ = $1; } 1005 1030 ; 1006 1031 … … 1009 1034 { $$ = new StatementNode( $1 ); } 1010 1035 | EXTENSION declaration // GCC 1011 { 1012 distExt( $2 ); 1013 $$ = new StatementNode( $2 ); 1014 } 1036 { distExt( $2 ); $$ = new StatementNode( $2 ); } 1015 1037 | function_definition 1016 1038 { $$ = new StatementNode( $1 ); } 1017 1039 | EXTENSION function_definition // GCC 1018 { 1019 distExt( $2 ); 1020 $$ = new StatementNode( $2 ); 1021 } 1040 { distExt( $2 ); $$ = new StatementNode( $2 ); } 1022 1041 | statement 1023 1042 ; … … 1026 1045 statement 1027 1046 | statement_list_nodecl statement 1028 { if ( $1 != 0 ) { $1->set_last( $2 ); $$ = $1; }}1047 { assert( $1 ); $1->set_last( $2 ); $$ = $1; } 1029 1048 ; 1030 1049 … … 1138 1157 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1139 1158 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2 ) ); } 1140 | FOR '(' push for_control_expression ')' statement pop1159 | FOR '(' push for_control_expression_list ')' statement pop 1141 1160 { $$ = new StatementNode( build_for( $4, $6 ) ); } 1142 1161 | FOR '(' ')' statement // CFA => for ( ;; ) … … 1144 1163 ; 1145 1164 1165 for_control_expression_list: 1166 for_control_expression 1167 | for_control_expression_list ':' for_control_expression 1168 // ForCtrl + ForCtrl: 1169 // init + init => multiple declaration statements that are hoisted 1170 // condition + condition => (expression) && (expression) 1171 // change + change => (expression), (expression) 1172 { 1173 $1->init->set_last( $3->init ); 1174 if ( $1->condition ) { 1175 if ( $3->condition ) { 1176 $1->condition->expr.reset( new LogicalExpr( $1->condition->expr.release(), $3->condition->expr.release(), true ) ); 1177 } // if 1178 } else $1->condition = $3->condition; 1179 if ( $1->change ) { 1180 if ( $3->change ) { 1181 $1->change->expr.reset( new CommaExpr( $1->change->expr.release(), $3->change->expr.release() ) ); 1182 } // if 1183 } else $1->change = $3->change; 1184 $$ = $1; 1185 } 1186 ; 1187 1146 1188 for_control_expression: 1147 comma_expression // CFA 1189 ';' comma_expression_opt ';' comma_expression_opt 1190 { $$ = new ForCtrl( (ExpressionNode * )nullptr, $2, $4 ); } 1191 | comma_expression ';' comma_expression_opt ';' comma_expression_opt 1192 { $$ = new ForCtrl( $1, $3, $5 ); } 1193 | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';' 1194 { $$ = new ForCtrl( $1, $2, $4 ); } 1195 1196 | comma_expression // CFA 1148 1197 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ), 1149 1198 OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1150 | co nstant_expression inclexcl constant_expression// CFA1199 | comma_expression inclexcl comma_expression // CFA 1151 1200 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1152 | co nstant_expression inclexcl constant_expression '~' constant_expression // CFA1201 | comma_expression inclexcl comma_expression '~' comma_expression // CFA 1153 1202 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, $5 ); } 1154 1203 | comma_expression ';' comma_expression // CFA 1155 1204 { $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ), 1156 1205 OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1157 | comma_expression ';' co nstant_expression inclexcl constant_expression // CFA1206 | comma_expression ';' comma_expression inclexcl comma_expression // CFA 1158 1207 { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1159 | comma_expression ';' co nstant_expression inclexcl constant_expression '~' constant_expression // CFA1208 | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA 1160 1209 { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); } 1161 | comma_expression ';' comma_expression_opt ';' comma_expression_opt 1162 { $$ = new ForCtrl( $1, $3, $5 ); } 1163 | ';' comma_expression_opt ';' comma_expression_opt 1164 { $$ = new ForCtrl( (ExpressionNode * )nullptr, $2, $4 ); } 1165 | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';' 1166 { $$ = new ForCtrl( $1, $2, $4 ); } 1210 1211 // There is a S/R conflicit if ~ and -~ are factored out. 1212 | comma_expression ';' comma_expression '~' '@' // CFA 1213 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1214 | comma_expression ';' comma_expression ErangeDown '@' // CFA 1215 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::GThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1216 | comma_expression ';' comma_expression '~' '@' '~' comma_expression // CFA 1217 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, $7 ); } 1218 | comma_expression ';' comma_expression ErangeDown '@' '~' comma_expression // CFA 1219 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::GThan, nullptr, $7 ); } 1220 | comma_expression ';' comma_expression '~' '@' '~' '@' // CFA 1221 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, nullptr ); } 1167 1222 ; 1168 1223 … … 1771 1826 | FLOAT 1772 1827 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float ); } 1773 | FLOAT801774 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float80 ); }1775 | FLOAT1281776 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float128 ); }1777 1828 | DOUBLE 1778 1829 { $$ = DeclarationNode::newBasicType( DeclarationNode::Double ); } 1830 | uuFLOAT80 1831 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat80 ); } 1832 | uuFLOAT128 1833 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat128 ); } 1834 | uFLOAT16 1835 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat16 ); } 1836 | uFLOAT32 1837 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32 ); } 1838 | uFLOAT32X 1839 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32x ); } 1840 | uFLOAT64 1841 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64 ); } 1842 | uFLOAT64X 1843 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64x ); } 1844 | uFLOAT128 1845 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat128 ); } 1779 1846 | COMPLEX // C99 1780 1847 { $$ = DeclarationNode::newComplexType( DeclarationNode::Complex ); } … … 1996 2063 | EXCEPTION 1997 2064 { yyy = true; $$ = DeclarationNode::Exception; } 2065 | GENERATOR 2066 { yyy = true; $$ = DeclarationNode::Coroutine; } 1998 2067 | COROUTINE 1999 2068 { yyy = true; $$ = DeclarationNode::Coroutine; } -
src/ResolvExpr/AlternativeFinder.cc
r6a9d4b4 r933f32f 258 258 // - necessary pre-requisite to pruning 259 259 AltList candidates; 260 std::list<std::string> errors; 260 261 for ( unsigned i = 0; i < alternatives.size(); ++i ) { 261 resolveAssertions( alternatives[i], indexer, candidates );262 resolveAssertions( alternatives[i], indexer, candidates, errors ); 262 263 } 263 264 // fail early if none such 264 265 if ( mode.failFast && candidates.empty() ) { 265 266 std::ostringstream stream; 266 stream << "No resolvable alternatives for expression " << expr << "\n" 267 << "Alternatives with failing assertions are:\n"; 268 printAlts( alternatives, stream, 1 ); 267 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 268 // << "Alternatives with failing assertions are:\n"; 269 // printAlts( alternatives, stream, 1 ); 270 for ( const auto& err : errors ) { 271 stream << err; 272 } 269 273 SemanticError( expr->location, stream.str() ); 270 274 } -
src/ResolvExpr/CommonType.cc
r6a9d4b4 r933f32f 10 10 // Created On : Sun May 17 06:59:27 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Sep 25 15:18:17 201713 // Update Count : 912 // Last Modified On : Thu Feb 14 17:10:10 2019 13 // Update Count : 24 14 14 // 15 15 … … 176 176 } 177 177 178 static const BasicType::Kind combinedType[][ BasicType::NUMBER_OF_BASIC_TYPES ] = 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 }, 206 }; 178 // GENERATED START, DO NOT EDIT 179 // GENERATED BY BasicTypes-gen.cc 180 #define BT BasicType:: 181 static const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor 182 /* B C SC UC SI SUI 183 I UI LI LUI LLI LLUI 184 IB UIB _FH _FH _F _FC 185 F FC _FX _FXC FD _FDC 186 D DC F80X _FDXC F80 _FB 187 _FLDC FB LD LDC _FBX _FLDXC 188 */ 189 { 190 /* B*/ BT Bool, BT Char, BT SignedChar, BT UnsignedChar, BT ShortSignedInt, BT ShortUnsignedInt, 191 BT SignedInt, BT UnsignedInt, BT LongSignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 192 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 193 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 194 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 195 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 196 }, 197 { 198 /* C*/ BT Char, BT Char, BT SignedChar, BT UnsignedChar, BT ShortSignedInt, BT ShortUnsignedInt, 199 BT SignedInt, BT UnsignedInt, BT LongSignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 200 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 201 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 202 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 203 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 204 }, 205 { 206 /* SC*/ BT SignedChar, BT SignedChar, BT SignedChar, BT UnsignedChar, BT ShortSignedInt, BT ShortUnsignedInt, 207 BT SignedInt, BT UnsignedInt, BT LongSignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 208 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 209 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 210 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 211 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 212 }, 213 { 214 /* UC*/ BT UnsignedChar, BT UnsignedChar, BT UnsignedChar, BT UnsignedChar, BT ShortSignedInt, BT ShortUnsignedInt, 215 BT SignedInt, BT UnsignedInt, BT LongSignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 216 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 217 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 218 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 219 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 220 }, 221 { 222 /* SI*/ BT ShortSignedInt, BT ShortSignedInt, BT ShortSignedInt, BT ShortSignedInt, BT ShortSignedInt, BT ShortUnsignedInt, 223 BT SignedInt, BT UnsignedInt, BT LongSignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 224 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 225 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 226 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 227 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 228 }, 229 { 230 /* SUI*/ BT ShortUnsignedInt, BT ShortUnsignedInt, BT ShortUnsignedInt, BT ShortUnsignedInt, BT ShortUnsignedInt, BT ShortUnsignedInt, 231 BT SignedInt, BT UnsignedInt, BT LongSignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 232 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 233 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 234 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 235 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 236 }, 237 { 238 /* I*/ BT SignedInt, BT SignedInt, BT SignedInt, BT SignedInt, BT SignedInt, BT SignedInt, 239 BT SignedInt, BT UnsignedInt, BT LongSignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 240 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 241 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 242 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 243 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 244 }, 245 { 246 /* UI*/ BT UnsignedInt, BT UnsignedInt, BT UnsignedInt, BT UnsignedInt, BT UnsignedInt, BT UnsignedInt, 247 BT UnsignedInt, BT UnsignedInt, BT LongSignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 248 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 249 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 250 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 251 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 252 }, 253 { 254 /* LI*/ BT LongSignedInt, BT LongSignedInt, BT LongSignedInt, BT LongSignedInt, BT LongSignedInt, BT LongSignedInt, 255 BT LongSignedInt, BT LongSignedInt, BT LongSignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 256 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 257 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 258 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 259 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 260 }, 261 { 262 /* LUI*/ BT LongUnsignedInt, BT LongUnsignedInt, BT LongUnsignedInt, BT LongUnsignedInt, BT LongUnsignedInt, BT LongUnsignedInt, 263 BT LongUnsignedInt, BT LongUnsignedInt, BT LongUnsignedInt, BT LongUnsignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 264 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 265 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 266 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 267 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 268 }, 269 { 270 /* LLI*/ BT LongLongSignedInt, BT LongLongSignedInt, BT LongLongSignedInt, BT LongLongSignedInt, BT LongLongSignedInt, BT LongLongSignedInt, 271 BT LongLongSignedInt, BT LongLongSignedInt, BT LongLongSignedInt, BT LongLongSignedInt, BT LongLongSignedInt, BT LongLongUnsignedInt, 272 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 273 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 274 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 275 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 276 }, 277 { 278 /* LLUI*/ BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, 279 BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, 280 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 281 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 282 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 283 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 284 }, 285 { 286 /* IB*/ BT SignedInt128, BT SignedInt128, BT SignedInt128, BT SignedInt128, BT SignedInt128, BT SignedInt128, 287 BT SignedInt128, BT SignedInt128, BT SignedInt128, BT SignedInt128, BT SignedInt128, BT SignedInt128, 288 BT SignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 289 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 290 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 291 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 292 }, 293 { 294 /* UIB*/ BT UnsignedInt128, BT UnsignedInt128, BT UnsignedInt128, BT UnsignedInt128, BT UnsignedInt128, BT UnsignedInt128, 295 BT UnsignedInt128, BT UnsignedInt128, BT UnsignedInt128, BT UnsignedInt128, BT UnsignedInt128, BT UnsignedInt128, 296 BT UnsignedInt128, BT UnsignedInt128, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 297 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 298 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 299 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 300 }, 301 { 302 /* _FH*/ BT uFloat16, BT uFloat16, BT uFloat16, BT uFloat16, BT uFloat16, BT uFloat16, 303 BT uFloat16, BT uFloat16, BT uFloat16, BT uFloat16, BT uFloat16, BT uFloat16, 304 BT uFloat16, BT uFloat16, BT uFloat16, BT uFloat16Complex, BT uFloat32, BT uFloat32Complex, 305 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 306 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 307 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 308 }, 309 { 310 /* _FH*/ BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, 311 BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, 312 BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, BT uFloat16Complex, BT uFloat32Complex, BT uFloat32Complex, 313 BT FloatComplex, BT FloatComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat64Complex, BT uFloat64Complex, 314 BT DoubleComplex, BT DoubleComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat128Complex, 315 BT uFloat128Complex, BT uFloat128Complex, BT LongDoubleComplex, BT LongDoubleComplex, BT uFloat128xComplex, BT uFloat128xComplex, 316 }, 317 { 318 /* _F*/ BT uFloat32, BT uFloat32, BT uFloat32, BT uFloat32, BT uFloat32, BT uFloat32, 319 BT uFloat32, BT uFloat32, BT uFloat32, BT uFloat32, BT uFloat32, BT uFloat32, 320 BT uFloat32, BT uFloat32, BT uFloat32, BT uFloat32Complex, BT uFloat32, BT uFloat32Complex, 321 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 322 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 323 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 324 }, 325 { 326 /* _FC*/ BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, 327 BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, 328 BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, BT uFloat32Complex, 329 BT FloatComplex, BT FloatComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat64Complex, BT uFloat64Complex, 330 BT DoubleComplex, BT DoubleComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat128Complex, 331 BT uFloat128Complex, BT uFloat128Complex, BT LongDoubleComplex, BT LongDoubleComplex, BT uFloat128xComplex, BT uFloat128xComplex, 332 }, 333 { 334 /* F*/ BT Float, BT Float, BT Float, BT Float, BT Float, BT Float, 335 BT Float, BT Float, BT Float, BT Float, BT Float, BT Float, 336 BT Float, BT Float, BT Float, BT FloatComplex, BT Float, BT FloatComplex, 337 BT Float, BT FloatComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 338 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 339 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 340 }, 341 { 342 /* FC*/ BT FloatComplex, BT FloatComplex, BT FloatComplex, BT FloatComplex, BT FloatComplex, BT FloatComplex, 343 BT FloatComplex, BT FloatComplex, BT FloatComplex, BT FloatComplex, BT FloatComplex, BT FloatComplex, 344 BT FloatComplex, BT FloatComplex, BT FloatComplex, BT FloatComplex, BT FloatComplex, BT FloatComplex, 345 BT FloatComplex, BT FloatComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat64Complex, BT uFloat64Complex, 346 BT DoubleComplex, BT DoubleComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat128Complex, 347 BT uFloat128Complex, BT uFloat128Complex, BT LongDoubleComplex, BT LongDoubleComplex, BT uFloat128xComplex, BT uFloat128xComplex, 348 }, 349 { 350 /* _FX*/ BT uFloat32x, BT uFloat32x, BT uFloat32x, BT uFloat32x, BT uFloat32x, BT uFloat32x, 351 BT uFloat32x, BT uFloat32x, BT uFloat32x, BT uFloat32x, BT uFloat32x, BT uFloat32x, 352 BT uFloat32x, BT uFloat32x, BT uFloat32x, BT uFloat32xComplex, BT uFloat32x, BT uFloat32xComplex, 353 BT uFloat32x, BT uFloat32xComplex, BT uFloat32x, BT uFloat32xComplex, BT uFloat64, BT uFloat64Complex, 354 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 355 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 356 }, 357 { 358 /* _FXC*/ BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, 359 BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, 360 BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, 361 BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat32xComplex, BT uFloat64Complex, BT uFloat64Complex, 362 BT DoubleComplex, BT DoubleComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat128Complex, 363 BT uFloat128Complex, BT uFloat128Complex, BT LongDoubleComplex, BT LongDoubleComplex, BT uFloat128xComplex, BT uFloat128xComplex, 364 }, 365 { 366 /* FD*/ BT uFloat64, BT uFloat64, BT uFloat64, BT uFloat64, BT uFloat64, BT uFloat64, 367 BT uFloat64, BT uFloat64, BT uFloat64, BT uFloat64, BT uFloat64, BT uFloat64, 368 BT uFloat64, BT uFloat64, BT uFloat64, BT uFloat64Complex, BT uFloat64, BT uFloat64Complex, 369 BT uFloat64, BT uFloat64Complex, BT uFloat64, BT uFloat64Complex, BT uFloat64, BT uFloat64Complex, 370 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 371 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 372 }, 373 { 374 /* _FDC*/ BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, 375 BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, 376 BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, 377 BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, BT uFloat64Complex, 378 BT DoubleComplex, BT DoubleComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat128Complex, 379 BT uFloat128Complex, BT uFloat128Complex, BT LongDoubleComplex, BT LongDoubleComplex, BT uFloat128xComplex, BT uFloat128xComplex, 380 }, 381 { 382 /* D*/ BT Double, BT Double, BT Double, BT Double, BT Double, BT Double, 383 BT Double, BT Double, BT Double, BT Double, BT Double, BT Double, 384 BT Double, BT Double, BT Double, BT DoubleComplex, BT Double, BT DoubleComplex, 385 BT Double, BT DoubleComplex, BT Double, BT DoubleComplex, BT Double, BT DoubleComplex, 386 BT Double, BT DoubleComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 387 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 388 }, 389 { 390 /* DC*/ BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, 391 BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, 392 BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, 393 BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, BT DoubleComplex, 394 BT DoubleComplex, BT DoubleComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat128Complex, 395 BT uFloat128Complex, BT uFloat128Complex, BT LongDoubleComplex, BT LongDoubleComplex, BT uFloat128xComplex, BT uFloat128xComplex, 396 }, 397 { 398 /* F80X*/ BT uFloat64x, BT uFloat64x, BT uFloat64x, BT uFloat64x, BT uFloat64x, BT uFloat64x, 399 BT uFloat64x, BT uFloat64x, BT uFloat64x, BT uFloat64x, BT uFloat64x, BT uFloat64x, 400 BT uFloat64x, BT uFloat64x, BT uFloat64x, BT uFloat64xComplex, BT uFloat64x, BT uFloat64xComplex, 401 BT uFloat64x, BT uFloat64xComplex, BT uFloat64x, BT uFloat64xComplex, BT uFloat64x, BT uFloat64xComplex, 402 BT uFloat64x, BT uFloat64xComplex, BT uFloat64x, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 403 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 404 }, 405 { 406 /* _FDXC*/ BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, 407 BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, 408 BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, 409 BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, 410 BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat64xComplex, BT uFloat128Complex, 411 BT uFloat128Complex, BT uFloat128Complex, BT LongDoubleComplex, BT LongDoubleComplex, BT uFloat128xComplex, BT uFloat128xComplex, 412 }, 413 { 414 /* F80*/ BT uuFloat80, BT uuFloat80, BT uuFloat80, BT uuFloat80, BT uuFloat80, BT uuFloat80, 415 BT uuFloat80, BT uuFloat80, BT uuFloat80, BT uuFloat80, BT uuFloat80, BT uuFloat80, 416 BT uuFloat80, BT uuFloat80, BT uuFloat80, BT uFloat64xComplex, BT uuFloat80, BT uFloat64xComplex, 417 BT uuFloat80, BT uFloat64xComplex, BT uuFloat80, BT uFloat64xComplex, BT uuFloat80, BT uFloat64xComplex, 418 BT uuFloat80, BT uFloat64xComplex, BT uuFloat80, BT uFloat64xComplex, BT uuFloat80, BT uFloat128, 419 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 420 }, 421 { 422 /* _FB*/ BT uFloat128, BT uFloat128, BT uFloat128, BT uFloat128, BT uFloat128, BT uFloat128, 423 BT uFloat128, BT uFloat128, BT uFloat128, BT uFloat128, BT uFloat128, BT uFloat128, 424 BT uFloat128, BT uFloat128, BT uFloat128, BT uFloat128Complex, BT uFloat128, BT uFloat128Complex, 425 BT uFloat128, BT uFloat128Complex, BT uFloat128, BT uFloat128Complex, BT uFloat128, BT uFloat128Complex, 426 BT uFloat128, BT uFloat128Complex, BT uFloat128, BT uFloat128Complex, BT uFloat128, BT uFloat128, 427 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 428 }, 429 { 430 /* _FLDC*/ BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, 431 BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, 432 BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, 433 BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, 434 BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, BT uFloat128Complex, 435 BT uFloat128Complex, BT uFloat128Complex, BT LongDoubleComplex, BT LongDoubleComplex, BT uFloat128xComplex, BT uFloat128xComplex, 436 }, 437 { 438 /* FB*/ BT uuFloat128, BT uuFloat128, BT uuFloat128, BT uuFloat128, BT uuFloat128, BT uuFloat128, 439 BT uuFloat128, BT uuFloat128, BT uuFloat128, BT uuFloat128, BT uuFloat128, BT uuFloat128, 440 BT uuFloat128, BT uuFloat128, BT uuFloat128, BT uFloat128Complex, BT uuFloat128, BT uFloat128Complex, 441 BT uuFloat128, BT uFloat128Complex, BT uuFloat128, BT uFloat128Complex, BT uuFloat128, BT uFloat128Complex, 442 BT uuFloat128, BT uFloat128Complex, BT uuFloat128, BT uFloat128Complex, BT uuFloat128, BT uuFloat128, 443 BT uFloat128Complex, BT uuFloat128, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 444 }, 445 { 446 /* LD*/ BT LongDouble, BT LongDouble, BT LongDouble, BT LongDouble, BT LongDouble, BT LongDouble, 447 BT LongDouble, BT LongDouble, BT LongDouble, BT LongDouble, BT LongDouble, BT LongDouble, 448 BT LongDouble, BT LongDouble, BT LongDouble, BT LongDoubleComplex, BT LongDouble, BT LongDoubleComplex, 449 BT LongDouble, BT LongDoubleComplex, BT LongDouble, BT LongDoubleComplex, BT LongDouble, BT LongDoubleComplex, 450 BT LongDouble, BT LongDoubleComplex, BT LongDouble, BT LongDoubleComplex, BT LongDouble, BT LongDouble, 451 BT LongDoubleComplex, BT LongDouble, BT LongDouble, BT LongDoubleComplex, BT uFloat128x, BT uFloat128xComplex, 452 }, 453 { 454 /* LDC*/ BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, 455 BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, 456 BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, 457 BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, 458 BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, 459 BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT LongDoubleComplex, BT uFloat128xComplex, BT uFloat128xComplex, 460 }, 461 { 462 /* _FBX*/ BT uFloat128x, BT uFloat128x, BT uFloat128x, BT uFloat128x, BT uFloat128x, BT uFloat128x, 463 BT uFloat128x, BT uFloat128x, BT uFloat128x, BT uFloat128x, BT uFloat128x, BT uFloat128x, 464 BT uFloat128x, BT uFloat128x, BT uFloat128x, BT uFloat128xComplex, BT uFloat128x, BT uFloat128xComplex, 465 BT uFloat128x, BT uFloat128xComplex, BT uFloat128x, BT uFloat128xComplex, BT uFloat128x, BT uFloat128xComplex, 466 BT uFloat128x, BT uFloat128xComplex, BT uFloat128x, BT uFloat128xComplex, BT uFloat128x, BT uFloat128x, 467 BT uFloat128xComplex, BT uFloat128x, BT uFloat128x, BT uFloat128xComplex, BT uFloat128x, BT uFloat128xComplex, 468 }, 469 { 470 /*_FLDXC*/ BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, 471 BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, 472 BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, 473 BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, 474 BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, 475 BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, BT uFloat128xComplex, 476 }, 477 }; // commonTypes 478 #undef BT 479 // GENERATED END 207 480 static_assert( 208 sizeof(com binedType)/sizeof(combinedType[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,481 sizeof(commonTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES, 209 482 "Each basic type kind should have a corresponding row in the combined type matrix" 210 483 ); … … 218 491 void CommonType::postvisit( BasicType *basicType ) { 219 492 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) { 220 BasicType::Kind newType = com binedType[ basicType->get_kind() ][ otherBasic->get_kind() ];493 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ otherBasic->get_kind() ]; 221 494 if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= otherBasic->get_qualifiers() ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->get_qualifiers() <= otherBasic->get_qualifiers() ) || widenSecond ) ) { 222 495 result = new BasicType( basicType->get_qualifiers() | otherBasic->get_qualifiers(), newType ); … … 224 497 } else if ( dynamic_cast< EnumInstType * > ( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) { 225 498 // use signed int in lieu of the enum/zero/one type 226 BasicType::Kind newType = com binedType[ basicType->get_kind() ][ BasicType::SignedInt ];499 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ]; 227 500 if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= type2->get_qualifiers() ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->get_qualifiers() <= type2->get_qualifiers() ) || widenSecond ) ) { 228 501 result = new BasicType( basicType->get_qualifiers() | type2->get_qualifiers(), newType ); -
src/ResolvExpr/ConversionCost.cc
r6a9d4b4 r933f32f 10 10 // Created On : Sun May 17 07:06:19 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Sep 25 15:43:34 201713 // Update Count : 1012 // Last Modified On : Mon May 6 14:18:22 2019 13 // Update Count : 25 14 14 // 15 15 … … 28 28 29 29 namespace ResolvExpr { 30 const Cost Cost::zero = Cost{ 0, 0, 0, 0, 0, 0 }; 31 const Cost Cost::infinity = Cost{ -1, -1, -1, -1, 1, -1 }; 32 const Cost Cost::unsafe = Cost{ 1, 0, 0, 0, 0, 0 }; 33 const Cost Cost::poly = Cost{ 0, 1, 0, 0, 0, 0 }; 34 const Cost Cost::safe = Cost{ 0, 0, 1, 0, 0, 0 }; 35 const Cost Cost::var = Cost{ 0, 0, 0, 1, 0, 0 }; 36 const Cost Cost::spec = Cost{ 0, 0, 0, 0, -1, 0 }; 37 const Cost Cost::reference = Cost{ 0, 0, 0, 0, 0, 1 }; 30 #if 0 31 const Cost Cost::zero = Cost{ 0, 0, 0, 0, 0, 0, 0 }; 32 const Cost Cost::infinity = Cost{ -1, -1, -1, -1, -1, 1, -1 }; 33 const Cost Cost::unsafe = Cost{ 1, 0, 0, 0, 0, 0, 0 }; 34 const Cost Cost::poly = Cost{ 0, 1, 0, 0, 0, 0, 0 }; 35 const Cost Cost::safe = Cost{ 0, 0, 1, 0, 0, 0, 0 }; 36 const Cost Cost::sign = Cost{ 0, 0, 0, 1, 0, 0, 0 }; 37 const Cost Cost::var = Cost{ 0, 0, 0, 0, 1, 0, 0 }; 38 const Cost Cost::spec = Cost{ 0, 0, 0, 0, 0, -1, 0 }; 39 const Cost Cost::reference = Cost{ 0, 0, 0, 0, 0, 0, 1 }; 40 #endif 38 41 39 42 #if 0 … … 42 45 #define PRINT(x) 43 46 #endif 47 44 48 Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 45 49 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { … … 179 183 } 180 184 181 /* 182 Old 183 === 184 Double 185 | 186 Float 187 | 188 ULong 189 / \ 190 UInt Long 191 \ / 192 Int 193 | 194 Ushort 195 | 196 Short 197 | 198 Uchar 199 / \ 200 Schar Char 201 202 New 203 === 204 +-----LongDoubleComplex--+ 205 LongDouble--+ | +-LongDoubleImag 206 | +---DoubleComplex---+ | 207 Double------+ | +----DoubleImag 208 | +-FloatComplex-+ | 209 Float---------+ +-------FloatImag 210 | 211 ULongLong 212 | 213 LongLong 214 | 215 ULong 216 / \ 217 UInt Long 218 \ / 219 Int 220 | 221 Ushort 222 | 223 Short 224 | 225 Uchar 226 / \ 227 Schar Char 228 \ / 229 Bool 230 */ 231 232 static const int costMatrix[][ BasicType::NUMBER_OF_BASIC_TYPES ] = { 233 /* 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 */ 234 /* 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}, 235 /* 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}, 236 /* 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}, 237 /* 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}, 238 /* 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}, 239 /* 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}, 240 /* 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}, 241 /* 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}, 242 /* 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}, 243 /* 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}, 244 /* 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}, 245 /* 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}, 246 247 /* 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}, 248 /* 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}, 249 /* 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}, 250 /* 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}, 251 /* 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}, 252 /* 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}, 253 /* 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}, 254 /* 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}, 255 /* 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}, 256 257 /* 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}, 258 /* 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}, 259 260 /* 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}, 261 /* 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}, 262 }; 185 // GENERATED START, DO NOT EDIT 186 // GENERATED BY BasicTypes-gen.cc 187 /* EXTENDED INTEGRAL RANK HIERARCHY (root to leaves) 188 _Bool 189 char signed char unsigned char 190 signed short int unsigned short int 191 signed int unsigned int 192 signed long int unsigned long int 193 signed long long int unsigned long long int 194 __int128 unsigned __int128 195 _Float16 _Float16 _Complex 196 _Float32 _Float32 _Complex 197 float float _Complex 198 _Float32x _Float32x _Complex 199 _Float64 _Float64 _Complex 200 double double _Complex 201 _Float64x _Float64x _Complex 202 __float80 203 _Float128 _Float128 _Complex 204 __float128 205 long double long double _Complex 206 _Float128x _Float128x _Complex 207 */ 208 // GENERATED END 209 210 // GENERATED START, DO NOT EDIT 211 // GENERATED BY BasicTypes-gen.cc 212 static const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node 213 /* B C SC UC SI SUI I UI LI LUI LLI LLUI IB UIB _FH _FH _F _FC F FC _FX _FXC FD _FDC D DC F80X_FDXC F80 _FB_FLDC FB LD LDC _FBX_FLDXC */ 214 /* B*/ { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 17, 16, 18, 17, }, 215 /* C*/ { -1, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 15, 17, 16, }, 216 /* SC*/ { -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 15, 17, 16, }, 217 /* UC*/ { -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 15, 17, 16, }, 218 /* SI*/ { -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15, 14, 16, 15, }, 219 /* SUI*/ { -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15, 14, 16, 15, }, 220 /* I*/ { -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 13, 15, 14, }, 221 /* UI*/ { -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 13, 15, 14, }, 222 /* LI*/ { -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13, 12, 14, 13, }, 223 /* LUI*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13, 12, 14, 13, }, 224 /* LLI*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 11, 13, 12, }, 225 /* LLUI*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 11, 13, 12, }, 226 /* IB*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 10, 12, 11, }, 227 /* UIB*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 10, 12, 11, }, 228 /* _FH*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 9, 11, 10, }, 229 /* _FH*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1, -1, 7, -1, -1, 8, -1, 9, }, 230 /* _F*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 8, 10, 9, }, 231 /* _FC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, -1, 6, -1, -1, 7, -1, 8, }, 232 /* F*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 7, 9, 8, }, 233 /* FC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, -1, 5, -1, -1, 6, -1, 7, }, 234 /* _FX*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 6, 8, 7, }, 235 /* _FXC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, -1, 4, -1, -1, 5, -1, 6, }, 236 /* FD*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 5, 7, 6, }, 237 /* _FDC*/ { -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, 1, -1, 2, -1, -1, 3, -1, -1, 4, -1, 5, }, 238 /* D*/ { -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, 1, 1, 2, 2, 3, 3, 4, 5, 4, 6, 5, }, 239 /* DC*/ { -1, -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, -1, 1, -1, -1, 2, -1, -1, 3, -1, 4, }, 240 /* F80X*/ { -1, -1, -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, 1, 1, 2, 2, 3, 4, 3, 5, 4, }, 241 /* _FDXC*/ { -1, -1, -1, -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, -1, -1, 1, -1, -1, 2, -1, 3, }, 242 /* F80*/ { -1, -1, -1, -1, -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, 1, 2, 2, 3, 3, 4, 4, }, 243 /* _FB*/ { -1, -1, -1, -1, -1, -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, 1, 1, 2, 2, 3, 3, }, 244 /* _FLDC*/ { -1, -1, -1, -1, -1, -1, -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, -1, -1, 1, -1, 2, }, 245 /* FB*/ { -1, -1, -1, -1, -1, -1, -1, -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, 1, 2, 2, 3, }, 246 /* LD*/ { -1, -1, -1, -1, -1, -1, -1, -1, -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, 1, 1, 2, }, 247 /* LDC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, -1, 1, }, 248 /* _FBX*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, 1, }, 249 /*_FLDXC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, }, 250 }; // costMatrix 251 static const int maxIntCost = 15; 252 // GENERATED END 263 253 static_assert( 264 254 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES, 265 " Each basic type kind should have a corresponding row in the cost matrix"255 "Missing row in the cost matrix" 266 256 ); 267 257 258 // GENERATED START, DO NOT EDIT 259 // GENERATED BY BasicTypes-gen.cc 260 static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion 261 /* B C SC UC SI SUI I UI LI LUI LLI LLUI IB UIB _FH _FH _F _FC F FC _FX _FXC FD _FDC D DC F80X_FDXC F80 _FB_FLDC FB LD LDC _FBX_FLDXC */ 262 /* B*/ { 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 263 /* C*/ { -1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 264 /* SC*/ { -1, -1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 265 /* UC*/ { -1, -1, -1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 266 /* SI*/ { -1, -1, -1, -1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 267 /* SUI*/ { -1, -1, -1, -1, -1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 268 /* I*/ { -1, -1, -1, -1, -1, -1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 269 /* UI*/ { -1, -1, -1, -1, -1, -1, -1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 270 /* LI*/ { -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 271 /* LUI*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 272 /* LLI*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 273 /* LLUI*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 274 /* IB*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 275 /* UIB*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 276 /* _FH*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 277 /* _FH*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -1, 0, -1, -1, 0, -1, 0, }, 278 /* _F*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 279 /* _FC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -1, 0, -1, -1, 0, -1, 0, }, 280 /* F*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 281 /* FC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -1, 0, -1, -1, 0, -1, 0, }, 282 /* _FX*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 283 /* _FXC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, 0, -1, 0, -1, -1, 0, -1, -1, 0, -1, 0, }, 284 /* FD*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 285 /* _FDC*/ { -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, 0, -1, 0, -1, -1, 0, -1, -1, 0, -1, 0, }, 286 /* D*/ { -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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 287 /* DC*/ { -1, -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, -1, 0, -1, -1, 0, -1, -1, 0, -1, 0, }, 288 /* F80X*/ { -1, -1, -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, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 289 /* _FDXC*/ { -1, -1, -1, -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, -1, -1, 0, -1, -1, 0, -1, 0, }, 290 /* F80*/ { -1, -1, -1, -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, 0, 0, 0, 0, 0, 0, 0, 0, }, 291 /* _FB*/ { -1, -1, -1, -1, -1, -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, 0, 0, 0, 0, 0, 0, }, 292 /* _FLDC*/ { -1, -1, -1, -1, -1, -1, -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, -1, -1, 0, -1, 0, }, 293 /* FB*/ { -1, -1, -1, -1, -1, -1, -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, 0, 0, 0, 0, 0, }, 294 /* LD*/ { -1, -1, -1, -1, -1, -1, -1, -1, -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, 0, 0, 0, }, 295 /* LDC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, -1, 0, }, 296 /* _FBX*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, 0, }, 297 /*_FLDXC*/ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, }, 298 }; // signMatrix 299 // GENERATED END 300 static_assert( 301 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES, 302 "Missing row in the sign matrix" 303 ); 268 304 269 305 void ConversionCost::postvisit( VoidType * ) { … … 279 315 cost = Cost::zero; 280 316 cost.incSafe( tableResult ); 317 cost.incSign( signMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ] ); 281 318 } // if 282 319 } else if ( dynamic_cast< EnumInstType *>( dest ) ) { … … 300 337 // types are the same, except otherPointer has more qualifiers 301 338 cost = Cost::safe; 302 } 339 } // if 303 340 } else { 304 341 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env ); … … 422 459 cost = Cost::zero; 423 460 cost.incSafe( tableResult + 1 ); 424 } 461 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] ); 462 } // if 425 463 } else if ( dynamic_cast< PointerType* >( dest ) ) { 426 cost = Cost::safe; 427 } 464 cost = Cost::zero; 465 cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation 466 } // if 428 467 } 429 468 … … 439 478 cost = Cost::zero; 440 479 cost.incSafe( tableResult + 1 ); 441 } 442 } 480 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] ); 481 } // if 482 } // if 443 483 } 444 484 } // namespace ResolvExpr -
src/ResolvExpr/Cost.h
r6a9d4b4 r933f32f 7 7 // Cost.h -- 8 8 // 9 // Author : Richard C. Bilson9 // Author : Peter Buhr and Aaron Moss 10 10 // Created On : Sun May 17 09:39:50 2015 11 // Last Modified By : Aaron B. Moss12 // Last Modified On : Fri Oct 05 14:32:00 201813 // Update Count : 711 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 29 18:33:44 2019 13 // Update Count : 49 14 14 // 15 15 … … 17 17 18 18 #include <iostream> 19 #include <cassert> 20 #include <climits> 19 21 20 22 namespace ResolvExpr { 23 #if 0 24 25 //*************************** OLD *************************** 26 21 27 class Cost { 22 28 private: 23 Cost( int unsafeCost, int polyCost, int safeCost, int varCost, int specCost, 24 int referenceCost ); 25 29 Cost( int unsafeCost, int polyCost, int safeCost, int signCost, 30 int varCost, int specCost, int referenceCost ); 26 31 public: 27 32 Cost & incUnsafe( int inc = 1 ); 28 33 Cost & incPoly( int inc = 1 ); 29 34 Cost & incSafe( int inc = 1 ); 35 Cost & incSign( int inc = 1 ); 30 36 Cost & incVar( int inc = 1 ); 31 37 Cost & decSpec( int inc = 1 ); … … 35 41 int get_polyCost() const { return polyCost; } 36 42 int get_safeCost() const { return safeCost; } 43 int get_signCost() const { return signCost; } 37 44 int get_varCost() const { return varCost; } 38 45 int get_specCost() const { return specCost; } … … 40 47 41 48 Cost operator+( const Cost &other ) const; 42 Cost operator-( const Cost &other ) const;43 49 Cost &operator+=( const Cost &other ); 44 50 bool operator<( const Cost &other ) const; … … 55 61 static const Cost poly; 56 62 static const Cost safe; 63 static const Cost sign; 57 64 static const Cost var; 58 65 static const Cost spec; … … 63 70 int polyCost; ///< Count of parameters and return values bound to some poly type 64 71 int safeCost; ///< Safe (widening) conversions 72 int signCost; ///< Count of safe sign conversions 65 73 int varCost; ///< Count of polymorphic type variables 66 74 int specCost; ///< Polymorphic type specializations (type assertions), negative cost … … 68 76 }; 69 77 70 inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int varCost, int specCost,71 int referenceCost )72 : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), varCost( varCost ),73 specCost( specCost ), referenceCost( referenceCost ) {}78 inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int signCost, 79 int varCost, int specCost, int referenceCost ) 80 : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), signCost( signCost ), 81 varCost( varCost ), specCost( specCost ), referenceCost( referenceCost ) {} 74 82 75 83 inline Cost & Cost::incUnsafe( int inc ) { … … 88 96 if ( *this == infinity ) return *this; 89 97 safeCost += inc; 98 return *this; 99 } 100 101 inline Cost & Cost::incSign( int inc ) { 102 if ( *this == infinity ) return *this; 103 signCost += inc; 90 104 return *this; 91 105 } … … 111 125 inline Cost Cost::operator+( const Cost &other ) const { 112 126 if ( *this == infinity || other == infinity ) return infinity; 113 return Cost{ 114 unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost, 115 varCost + other.varCost, specCost + other.specCost, 116 referenceCost + other.referenceCost }; 117 } 118 119 inline Cost Cost::operator-( const Cost &other ) const { 120 if ( *this == infinity || other == infinity ) return infinity; 121 return Cost{ 122 unsafeCost - other.unsafeCost, polyCost - other.polyCost, safeCost - other.safeCost, 123 varCost - other.varCost, specCost - other.specCost, 124 referenceCost - other.referenceCost }; 127 return Cost{ 128 unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost, 129 signCost + other.signCost, varCost + other.varCost, specCost + other.specCost, 130 referenceCost + other.referenceCost }; 125 131 } 126 132 … … 134 140 polyCost += other.polyCost; 135 141 safeCost += other.safeCost; 142 signCost += other.signCost; 136 143 varCost += other.varCost; 137 144 specCost += other.specCost; … … 156 163 } else if ( safeCost < other.safeCost ) { 157 164 return true; 165 } else if ( signCost > other.signCost ) { 166 return false; 167 } else if ( signCost < other.signCost ) { 168 return true; 158 169 } else if ( varCost > other.varCost ) { 159 170 return false; … … 180 191 c = polyCost - other.polyCost; if ( c ) return c; 181 192 c = safeCost - other.safeCost; if ( c ) return c; 193 c = signCost - other.signCost; if ( c ) return c; 182 194 c = varCost - other.varCost; if ( c ) return c; 183 195 c = specCost - other.specCost; if ( c ) return c; … … 189 201 && polyCost == other.polyCost 190 202 && safeCost == other.safeCost 203 && signCost == other.signCost 191 204 && varCost == other.varCost 192 205 && specCost == other.specCost … … 199 212 200 213 inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) { 201 return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " 202 << cost.safeCost << ", " << cost.varCost << ", " << cost.specCost << ", " 214 return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " 215 << cost.safeCost << ", " << cost.signCost << ", " 216 << cost.varCost << ", " << cost.specCost << ", " 203 217 << cost.referenceCost << " )"; 204 218 } 219 220 #else 221 222 //*************************** NEW *************************** 223 224 // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the 225 // specialization cost is a negative value so a correction is needed is a few places. 226 227 class Cost { 228 union { 229 struct { 230 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 231 // Little-endian => first value is low priority and last is high priority. 232 unsigned char padding; ///< unused 233 unsigned char referenceCost; ///< reference conversions 234 unsigned char specCost; ///< Polymorphic type specializations (type assertions), negative cost 235 unsigned char varCost; ///< Count of polymorphic type variables 236 unsigned char signCost; ///< Count of safe sign conversions 237 unsigned char safeCost; ///< Safe (widening) conversions 238 unsigned char polyCost; ///< Count of parameters and return values bound to some poly type 239 unsigned char unsafeCost; ///< Unsafe (narrowing) conversions 240 #else 241 #error Cost BIG_ENDIAN unsupported 242 #endif 243 } v; 244 uint64_t all; 245 }; 246 static const unsigned char correctb = 0xff; // byte correction for negative spec cost 247 static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost 248 public: 249 // Compiler adjusts constants for correct endian. 250 enum : uint64_t { 251 zero = 0x00'00'00'00'00'ff'00'00, 252 infinity = 0xff'ff'ff'ff'ff'00'ff'ff, 253 unsafe = 0x01'00'00'00'00'ff'00'00, 254 poly = 0x00'01'00'00'00'ff'00'00, 255 safe = 0x00'00'01'00'00'ff'00'00, 256 sign = 0x00'00'00'01'00'ff'00'00, 257 var = 0x00'00'00'00'01'ff'00'00, 258 spec = 0x00'00'00'00'00'fe'00'00, 259 reference = 0x00'00'00'00'00'ff'01'00, 260 }; //' 261 262 Cost( uint64_t all ) { Cost::all = all; } 263 Cost( int unsafeCost, int polyCost, int safeCost, int signCost, int varCost, int specCost, int referenceCost ) { 264 // Assume little-endian => first value is low priority and last is high priority. 265 v = { 266 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 267 (unsigned char)0, // padding 268 (unsigned char)referenceCost, // low priority 269 (unsigned char)(specCost + correctb), // correct for signedness 270 (unsigned char)varCost, 271 (unsigned char)signCost, 272 (unsigned char)safeCost, 273 (unsigned char)polyCost, 274 (unsigned char)unsafeCost, // high priority 275 #else 276 #error Cost BIG_ENDIAN unsupported 277 #endif 278 }; 279 } 280 281 int get_unsafeCost() const { return v.unsafeCost; } 282 int get_polyCost() const { return v.polyCost; } 283 int get_safeCost() const { return v.safeCost; } 284 int get_signCost() const { return v.signCost; } 285 int get_varCost() const { return v.varCost; } 286 int get_specCost() const { return -(correctb - v.specCost); } 287 int get_referenceCost() const { return v.referenceCost; } 288 289 friend bool operator==( const Cost, const Cost ); 290 friend bool operator!=( const Cost lhs, const Cost rhs ); 291 // returns negative for *this < rhs, 0 for *this == rhs, positive for *this > rhs 292 int compare( const Cost rhs ) const { 293 if ( all == infinity ) return 1; 294 if ( rhs.all == infinity ) return -1; 295 return all > rhs.all ? 1 : all == rhs.all ? 0 : -1; 296 } 297 friend bool operator<( const Cost lhs, const Cost rhs ); 298 299 friend Cost operator+( const Cost lhs, const Cost rhs ); 300 301 Cost operator+=( const Cost rhs ) { 302 if ( all == infinity ) return *this; 303 if ( rhs.all == infinity ) { 304 all = infinity; 305 return *this; 306 } 307 all += rhs.all - correctw; // correct for negative spec cost 308 return *this; 309 } 310 311 Cost incUnsafe( int inc = 1 ) { 312 if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; } 313 return *this; 314 } 315 316 Cost incPoly( int inc = 1 ) { 317 if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; } 318 return *this; 319 } 320 321 Cost incSafe( int inc = 1 ) { 322 if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; } 323 return *this; 324 } 325 326 Cost incSign( int inc = 1 ) { 327 if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; } 328 return *this; 329 } 330 331 Cost incVar( int inc = 1 ) { 332 if ( all != infinity ) { assert( v.varCost + inc <= UCHAR_MAX ); v.varCost += inc; } 333 return *this; 334 } 335 336 Cost decSpec( int dec = 1 ) { 337 if ( all != infinity ) { assert( v.specCost - dec >= 0 ); v.specCost -= dec; } 338 return *this; 339 } 340 341 Cost incReference( int inc = 1 ) { 342 if ( all != infinity ) { assert( v.referenceCost + inc <= UCHAR_MAX ); v.referenceCost += inc; } 343 return *this; 344 } 345 346 friend std::ostream & operator<<( std::ostream & os, const Cost cost ); 347 }; 348 349 inline bool operator==( const Cost lhs, const Cost rhs ) { 350 return lhs.all == rhs.all; 351 } 352 353 inline bool operator!=( const Cost lhs, const Cost rhs ) { 354 return !( lhs.all == rhs.all ); 355 } 356 357 inline bool operator<( const Cost lhs, const Cost rhs ) { 358 if ( lhs.all == Cost::infinity ) return false; 359 if ( rhs.all == Cost::infinity ) return true; 360 return lhs.all < rhs.all; 361 } 362 363 inline Cost operator+( const Cost lhs, const Cost rhs ) { 364 if ( lhs.all == Cost::infinity || rhs.all == Cost::infinity ) return Cost{ Cost::infinity }; 365 return Cost{ lhs.all + rhs.all - Cost::correctw }; // correct for negative spec cost 366 } 367 368 inline std::ostream & operator<<( std::ostream & os, const Cost cost ) { 369 return os << "( " << cost.get_unsafeCost() << ", " << cost.get_polyCost() << ", " << cost.get_safeCost() 370 << ", " << cost.get_signCost() << ", " << cost.get_varCost() << ", " << cost.get_specCost() 371 << ", " << cost.get_referenceCost() << " )"; 372 } 373 #endif // 0 205 374 } // namespace ResolvExpr 206 375 -
src/ResolvExpr/RenameVars.cc
r6a9d4b4 r933f32f 10 10 // Created On : Sun May 17 12:05:18 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Mar 2 17:36:32 201613 // Update Count : 512 // Last Modified On : Tue Apr 30 17:07:57 2019 13 // Update Count : 7 14 14 // 15 15 … … 39 39 private: 40 40 int level, resetCount; 41 std::list< std:: map< std::string, std::string > > mapStack;41 std::list< std::unordered_map< std::string, std::string > > mapStack; 42 42 }; 43 43 … … 55 55 namespace { 56 56 RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) { 57 mapStack.push_front( std:: map< std::string, std::string >() );57 mapStack.push_front( std::unordered_map< std::string, std::string >() ); 58 58 } 59 59 … … 65 65 void RenameVars::previsit( TypeInstType * instType ) { 66 66 previsit( (Type *)instType ); 67 std:: map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name );67 std::unordered_map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name ); 68 68 if ( i != mapStack.front().end() ) { 69 69 instType->name = i->second; -
src/ResolvExpr/ResolveAssertions.cc
r6a9d4b4 r933f32f 20 20 #include <list> // for list 21 21 #include <memory> // for unique_ptr 22 #include <string> 22 #include <sstream> // for ostringstream 23 #include <string> // for string 23 24 #include <unordered_map> // for unordered_map, unordered_multimap 24 25 #include <utility> // for move … … 27 28 #include "Alternative.h" // for Alternative, AssertionItem, AssertionList 28 29 #include "Common/FilterCombos.h" // for filterCombos 30 #include "Common/Indenter.h" // for Indenter 29 31 #include "Common/utility.h" // for sort_mins 30 32 #include "ResolvExpr/RenameVars.h" // for renameTyVars … … 33 35 #include "SynTree/Expression.h" // for InferredParams 34 36 #include "TypeEnvironment.h" // for TypeEnvironment, etc. 35 #include "typeops.h" // for adjustExprType 37 #include "typeops.h" // for adjustExprType, specCost 36 38 #include "Unify.h" // for unify 37 39 … … 56 58 using CandidateList = std::vector<AssnCandidate>; 57 59 58 /// Unique identifier for a yet-to-be-resolved assertion59 struct AssnId {60 DeclarationWithType* decl; ///< Declaration of assertion61 AssertionSetValue info; ///< Information about assertion62 63 AssnId(DeclarationWithType* decl, const AssertionSetValue& info) : decl(decl), info(info) {}64 };65 66 /// Cached assertion items67 struct AssnCacheItem {68 CandidateList matches; ///< Possible matches for this assertion69 std::vector<AssnId> deferIds; ///< Deferred assertions which resolve to this item70 71 AssnCacheItem( CandidateList&& m ) : matches(std::move(m)), deferIds() {}72 };73 74 /// Cache of resolved assertions75 using AssnCache = std::unordered_map<std::string, AssnCacheItem>;76 77 60 /// Reference to single deferred item 78 61 struct DeferRef { 79 const AssnCacheItem& item; 62 const DeclarationWithType* decl; 63 const AssertionSetValue& info; 80 64 const AssnCandidate& match; 81 65 }; … … 84 68 /// Acts like indexed list of DeferRef 85 69 struct DeferItem { 86 const AssnCache* cache; ///< Cache storing assertion item 87 std::string key; ///< Key into cache 88 89 DeferItem( const AssnCache& cache, const std::string& key ) : cache(&cache), key(key) {} 90 91 bool empty() const { return cache->at(key).matches.empty(); } 92 93 CandidateList::size_type size() const { return cache->at(key).matches.size(); } 94 95 DeferRef operator[] ( unsigned i ) const { 96 const AssnCacheItem& item = cache->at(key); 97 return { item, item.matches[i] }; 98 } 99 100 // sortable by key 101 // TODO look into optimizing combination process with other sort orders (e.g. by number 102 // of matches in candidate) 103 bool operator< ( const DeferItem& o ) const { return key < o.key; } 104 bool operator== ( const DeferItem& o ) const { return key == o.key; } 70 const DeclarationWithType* decl; 71 const AssertionSetValue& info; 72 CandidateList matches; 73 74 DeferItem( DeclarationWithType* decl, const AssertionSetValue& info, CandidateList&& matches ) 75 : decl(decl), info(info), matches(std::move(matches)) {} 76 77 bool empty() const { return matches.empty(); } 78 79 CandidateList::size_type size() const { return matches.size(); } 80 81 DeferRef operator[] ( unsigned i ) const { return { decl, info, matches[i] }; } 105 82 }; 106 83 … … 177 154 for ( const auto& assn : x.assns ) { 178 155 k += computeConversionCost( 179 assn.match.adjType, assn.item.deferIds[0].decl->get_type(), indexer, 180 x.env ); 156 assn.match.adjType, assn.decl->get_type(), indexer, x.env ); 157 158 // mark vars+specialization cost on function-type assertions 159 PointerType* ptr = dynamic_cast< PointerType* >( assn.decl->get_type() ); 160 if ( ! ptr ) continue; 161 FunctionType* func = dynamic_cast< FunctionType* >( ptr->base ); 162 if ( ! func ) continue; 163 164 for ( DeclarationWithType* formal : func->parameters ) { 165 k.decSpec( specCost( formal->get_type() ) ); 166 } 167 k.incVar( func->forall.size() ); 168 for ( TypeDecl* td : func->forall ) { 169 k.decSpec( td->assertions.size() ); 170 } 181 171 } 182 172 it = cache.emplace_hint( it, &x, k ); … … 249 239 250 240 /// Resolve a single assertion, in context 251 bool resolveAssertion( AssertionItem& assn, ResnState& resn , AssnCache& cache) {241 bool resolveAssertion( AssertionItem& assn, ResnState& resn ) { 252 242 // skip unused assertions 253 243 if ( ! assn.info.isUsed ) return true; 254 244 255 // check cache for this assertion 256 std::string assnKey = SymTab::Mangler::mangleAssnKey( assn.decl, resn.alt.env ); 257 auto it = cache.find( assnKey ); 258 259 // attempt to resolve assertion if this is the first time seen 260 if ( it == cache.end() ) { 261 // lookup candidates for this assertion 262 std::list< SymTab::Indexer::IdData > candidates; 263 resn.indexer.lookupId( assn.decl->name, candidates ); 264 265 // find the candidates that unify with the desired type 266 CandidateList matches; 267 for ( const auto& cdata : candidates ) { 268 DeclarationWithType* candidate = cdata.id; 269 270 // build independent unification context for candidate 271 AssertionSet have, newNeed; 272 TypeEnvironment newEnv{ resn.alt.env }; 273 OpenVarSet newOpenVars{ resn.alt.openVars }; 274 Type* adjType = candidate->get_type()->clone(); 275 adjustExprType( adjType, newEnv, resn.indexer ); 276 renameTyVars( adjType ); 277 278 // keep unifying candidates 279 if ( unify( assn.decl->get_type(), adjType, newEnv, newNeed, have, newOpenVars, 280 resn.indexer ) ) { 281 // set up binding slot for recursive assertions 282 UniqueId crntResnSlot = 0; 283 if ( ! newNeed.empty() ) { 284 crntResnSlot = ++globalResnSlot; 285 for ( auto& a : newNeed ) { 286 a.second.resnSlot = crntResnSlot; 287 } 288 } 289 290 matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have), 291 std::move(newNeed), std::move(newOpenVars), crntResnSlot ); 292 } else { 293 delete adjType; 294 } 245 // lookup candidates for this assertion 246 std::list< SymTab::Indexer::IdData > candidates; 247 resn.indexer.lookupId( assn.decl->name, candidates ); 248 249 // find the candidates that unify with the desired type 250 CandidateList matches; 251 for ( const auto& cdata : candidates ) { 252 DeclarationWithType* candidate = cdata.id; 253 254 // build independent unification context for candidate 255 AssertionSet have, newNeed; 256 TypeEnvironment newEnv{ resn.alt.env }; 257 OpenVarSet newOpenVars{ resn.alt.openVars }; 258 Type* adjType = candidate->get_type()->clone(); 259 adjustExprType( adjType, newEnv, resn.indexer ); 260 renameTyVars( adjType ); 261 262 // keep unifying candidates 263 if ( unify( assn.decl->get_type(), adjType, newEnv, newNeed, have, newOpenVars, 264 resn.indexer ) ) { 265 // set up binding slot for recursive assertions 266 UniqueId crntResnSlot = 0; 267 if ( ! newNeed.empty() ) { 268 crntResnSlot = ++globalResnSlot; 269 for ( auto& a : newNeed ) { 270 a.second.resnSlot = crntResnSlot; 271 } 272 } 273 274 matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have), 275 std::move(newNeed), std::move(newOpenVars), crntResnSlot ); 276 } else { 277 delete adjType; 295 278 } 296 297 it = cache.emplace_hint( it, assnKey, AssnCacheItem{ std::move(matches) } ); 298 } 299 300 CandidateList& matches = it->second.matches; 279 } 301 280 302 281 // break if no suitable assertion … … 305 284 // defer if too many suitable assertions 306 285 if ( matches.size() > 1 ) { 307 it->second.deferIds.emplace_back( assn.decl, assn.info ); 308 resn.deferred.emplace_back( cache, assnKey ); 286 resn.deferred.emplace_back( assn.decl, assn.info, std::move(matches) ); 309 287 return true; 310 288 } … … 314 292 addToIndexer( match.have, resn.indexer ); 315 293 resn.newNeed.insert( match.need.begin(), match.need.end() ); 316 resn.alt.env = match.env;317 resn.alt.openVars = match.openVars;294 resn.alt.env = std::move(match.env); 295 resn.alt.openVars = std::move(match.openVars); 318 296 319 297 bindAssertion( assn.decl, assn.info, resn.alt, match, resn.inferred ); … … 364 342 static const int recursionLimit = /* 10 */ 4; 365 343 366 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ) {344 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out, std::list<std::string>& errors ) { 367 345 // finish early if no assertions to resolve 368 346 if ( alt.need.empty() ) { … … 376 354 ResnList resns{ ResnState{ alt, root_indexer } }; 377 355 ResnList new_resns{}; 378 AssnCache assnCache;379 356 380 357 // resolve assertions in breadth-first-order up to a limited number of levels deep … … 385 362 for ( auto& assn : resn.need ) { 386 363 // fail early if any assertion is not resolvable 387 if ( ! resolveAssertion( assn, resn, assnCache ) ) goto nextResn; 364 if ( ! resolveAssertion( assn, resn ) ) { 365 Indenter tabs{ Indenter::tabsize, 3 }; 366 std::ostringstream ss; 367 ss << tabs << "Unsatisfiable alternative:\n"; 368 resn.alt.print( ss, ++tabs ); 369 ss << --tabs << "Could not satisfy assertion:\n"; 370 assn.decl->print( ss, ++tabs ); 371 372 errors.emplace_back( ss.str() ); 373 goto nextResn; 374 } 388 375 } 389 376 … … 396 383 } 397 384 } else { 398 // only resolve each deferred assertion once399 std::sort( resn.deferred.begin(), resn.deferred.end() );400 auto last = std::unique( resn.deferred.begin(), resn.deferred.end() );401 resn.deferred.erase( last, resn.deferred.end() );402 385 // resolve deferred assertions by mutual compatibility 403 386 std::vector<CandidateEnvMerger::OutType> compatible = filterCombos( 404 387 resn.deferred, 405 388 CandidateEnvMerger{ resn.alt.env, resn.alt.openVars, resn.indexer } ); 389 // fail early if no mutually-compatible assertion satisfaction 390 if ( compatible.empty() ) { 391 Indenter tabs{ Indenter::tabsize, 3 }; 392 std::ostringstream ss; 393 ss << tabs << "Unsatisfiable alternative:\n"; 394 resn.alt.print( ss, ++tabs ); 395 ss << --tabs << "No mutually-compatible satisfaction for assertions:\n"; 396 ++tabs; 397 for ( const auto& d : resn.deferred ) { 398 d.decl->print( ss, tabs ); 399 } 400 401 errors.emplace_back( ss.str() ); 402 goto nextResn; 403 } 406 404 // sort by cost 407 405 CandidateCost coster{ resn.indexer }; … … 429 427 new_resn.newNeed.insert( match.need.begin(), match.need.end() ); 430 428 431 // for each deferred assertion with the same form 432 for ( AssnId id : r.item.deferIds ) { 433 bindAssertion( 434 id.decl, id.info, new_resn.alt, match, new_resn.inferred ); 435 } 429 bindAssertion( r.decl, r.info, new_resn.alt, match, new_resn.inferred ); 436 430 } 437 431 -
src/ResolvExpr/ResolveAssertions.h
r6a9d4b4 r933f32f 24 24 namespace ResolvExpr { 25 25 /// Recursively resolves all assertions provided in an alternative; returns true iff succeeds 26 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out );26 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out, std::list<std::string>& errors ); 27 27 } // namespace ResolvExpr 28 28 -
src/ResolvExpr/Resolver.cc
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:17:01 2015 11 // Last Modified By : Aaron B. Moss12 // Last Modified On : Fri Oct 05 09:43:00 201813 // Update Count : 2 1411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Feb 19 18:09:56 2019 13 // Update Count : 240 14 14 // 15 15 … … 54 54 } 55 55 56 void previsit( FunctionDecl * functionDecl );57 void postvisit( FunctionDecl * functionDecl );58 void previsit( ObjectDecl * objectDecll );56 void previsit( FunctionDecl * functionDecl ); 57 void postvisit( FunctionDecl * functionDecl ); 58 void previsit( ObjectDecl * objectDecll ); 59 59 void previsit( EnumDecl * enumDecl ); 60 60 void previsit( StaticAssertDecl * assertDecl ); … … 63 63 void previsit( PointerType * at ); 64 64 65 void previsit( ExprStmt * exprStmt );66 void previsit( AsmExpr * asmExpr );67 void previsit( AsmStmt * asmStmt );68 void previsit( IfStmt * ifStmt );69 void previsit( WhileStmt * whileStmt );70 void previsit( ForStmt * forStmt );71 void previsit( SwitchStmt * switchStmt );72 void previsit( CaseStmt * caseStmt );73 void previsit( BranchStmt * branchStmt );74 void previsit( ReturnStmt * returnStmt );75 void previsit( ThrowStmt * throwStmt );76 void previsit( CatchStmt * catchStmt );65 void previsit( ExprStmt * exprStmt ); 66 void previsit( AsmExpr * asmExpr ); 67 void previsit( AsmStmt * asmStmt ); 68 void previsit( IfStmt * ifStmt ); 69 void previsit( WhileStmt * whileStmt ); 70 void previsit( ForStmt * forStmt ); 71 void previsit( SwitchStmt * switchStmt ); 72 void previsit( CaseStmt * caseStmt ); 73 void previsit( BranchStmt * branchStmt ); 74 void previsit( ReturnStmt * returnStmt ); 75 void previsit( ThrowStmt * throwStmt ); 76 void previsit( CatchStmt * catchStmt ); 77 77 void previsit( WaitForStmt * stmt ); 78 78 79 void previsit( SingleInit * singleInit );80 void previsit( ListInit * listInit );81 void previsit( ConstructorInit * ctorInit );79 void previsit( SingleInit * singleInit ); 80 void previsit( ListInit * listInit ); 81 void previsit( ConstructorInit * ctorInit ); 82 82 private: 83 83 typedef std::list< Initializer * >::iterator InitIterator; … … 105 105 } 106 106 107 void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {107 void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) { 108 108 PassVisitor<Resolver> resolver( indexer ); 109 109 maybeAccept( decl, resolver ); … … 149 149 }; 150 150 151 void finishExpr( Expression *& expr, const TypeEnvironment &env, TypeSubstitution * oldenv = nullptr ) {151 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) { 152 152 expr->env = oldenv ? oldenv->clone() : new TypeSubstitution; 153 153 env.makeSubstitution( *expr->env ); … … 280 280 281 281 // used in resolveTypeof 282 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer &indexer ) {282 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) { 283 283 TypeEnvironment env; 284 284 return resolveInVoidContext( expr, indexer, env ); 285 285 } 286 286 287 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {287 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) { 288 288 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0 289 289 // interpretations, an exception has already been thrown. 290 290 assertf( expr, "expected a non-null expression." ); 291 291 292 static CastExpr untyped( nullptr ); // cast to void293 untyped .location = expr->location;292 CastExpr * untyped = new CastExpr( expr ); // cast to void 293 untyped->location = expr->location; 294 294 295 295 // set up and resolve expression cast to void 296 untyped.arg = expr;297 296 Alternative choice; 298 findUnfinishedKindExpression( &untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );297 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() ); 299 298 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr ); 299 assert( castExpr ); 300 300 env = std::move( choice.env ); 301 301 … … 305 305 306 306 // unlink the arg so that it isn't deleted twice at the end of the program 307 untyped .arg = nullptr;307 untyped->arg = nullptr; 308 308 return ret; 309 309 } 310 310 311 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {311 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) { 312 312 resetTyVarRenaming(); 313 313 TypeEnvironment env; … … 318 318 } 319 319 320 void findSingleExpression( Expression *& untyped, const SymTab::Indexer &indexer ) {320 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) { 321 321 findKindExpression( untyped, indexer, "", standardAlternativeFilter ); 322 322 } … … 337 337 if ( dynamic_cast< EnumInstType * >( type ) ) { 338 338 return true; 339 } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {339 } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) { 340 340 return bt->isInteger(); 341 341 } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) { … … 346 346 } 347 347 348 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {348 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) { 349 349 findKindExpression( untyped, indexer, "condition", isIntegralType ); 350 350 } … … 402 402 } 403 403 404 void Resolver::previsit( ObjectDecl * objectDecl ) {404 void Resolver::previsit( ObjectDecl * objectDecl ) { 405 405 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that 406 406 // class-variable initContext is changed multiple time because the LHS is analysed twice. … … 432 432 } 433 433 434 void Resolver::previsit( FunctionDecl * functionDecl ) {434 void Resolver::previsit( FunctionDecl * functionDecl ) { 435 435 #if 0 436 436 std::cerr << "resolver visiting functiondecl "; … … 442 442 } 443 443 444 void Resolver::postvisit( FunctionDecl * functionDecl ) {444 void Resolver::postvisit( FunctionDecl * functionDecl ) { 445 445 // default value expressions have an environment which shouldn't be there and trips up 446 446 // later passes. … … 467 467 } 468 468 469 void Resolver::previsit( ExprStmt * exprStmt ) {469 void Resolver::previsit( ExprStmt * exprStmt ) { 470 470 visit_children = false; 471 471 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" ); … … 473 473 } 474 474 475 void Resolver::previsit( AsmExpr * asmExpr ) {475 void Resolver::previsit( AsmExpr * asmExpr ) { 476 476 visit_children = false; 477 477 findVoidExpression( asmExpr->operand, indexer ); … … 481 481 } 482 482 483 void Resolver::previsit( AsmStmt * asmStmt ) {483 void Resolver::previsit( AsmStmt * asmStmt ) { 484 484 visit_children = false; 485 485 acceptAll( asmStmt->get_input(), *visitor ); … … 487 487 } 488 488 489 void Resolver::previsit( IfStmt * ifStmt ) {489 void Resolver::previsit( IfStmt * ifStmt ) { 490 490 findIntegralExpression( ifStmt->condition, indexer ); 491 491 } 492 492 493 void Resolver::previsit( WhileStmt * whileStmt ) {493 void Resolver::previsit( WhileStmt * whileStmt ) { 494 494 findIntegralExpression( whileStmt->condition, indexer ); 495 495 } 496 496 497 void Resolver::previsit( ForStmt * forStmt ) {497 void Resolver::previsit( ForStmt * forStmt ) { 498 498 if ( forStmt->condition ) { 499 499 findIntegralExpression( forStmt->condition, indexer ); … … 505 505 } 506 506 507 void Resolver::previsit( SwitchStmt * switchStmt ) {507 void Resolver::previsit( SwitchStmt * switchStmt ) { 508 508 GuardValue( currentObject ); 509 509 findIntegralExpression( switchStmt->condition, indexer ); … … 512 512 } 513 513 514 void Resolver::previsit( CaseStmt * caseStmt ) {514 void Resolver::previsit( CaseStmt * caseStmt ) { 515 515 if ( caseStmt->condition ) { 516 516 std::list< InitAlternative > initAlts = currentObject.getOptions(); … … 531 531 } 532 532 533 void Resolver::previsit( BranchStmt * branchStmt ) {533 void Resolver::previsit( BranchStmt * branchStmt ) { 534 534 visit_children = false; 535 535 // must resolve the argument for a computed goto … … 542 542 } 543 543 544 void Resolver::previsit( ReturnStmt * returnStmt ) {544 void Resolver::previsit( ReturnStmt * returnStmt ) { 545 545 visit_children = false; 546 546 if ( returnStmt->expr ) { … … 549 549 } 550 550 551 void Resolver::previsit( ThrowStmt * throwStmt ) {551 void Resolver::previsit( ThrowStmt * throwStmt ) { 552 552 visit_children = false; 553 553 // TODO: Replace *exception type with &exception type. … … 561 561 } 562 562 563 void Resolver::previsit( CatchStmt * catchStmt ) {563 void Resolver::previsit( CatchStmt * catchStmt ) { 564 564 if ( catchStmt->cond ) { 565 565 findSingleExpression( catchStmt->cond, new BasicType( noQualifiers, BasicType::Bool ), indexer ); … … 725 725 726 726 } 727 catch( SemanticErrorException & e ) {727 catch( SemanticErrorException & e ) { 728 728 errors.append( e ); 729 729 } 730 730 } 731 731 } 732 catch( SemanticErrorException & e ) {732 catch( SemanticErrorException & e ) { 733 733 errors.append( e ); 734 734 } … … 782 782 } 783 783 784 void Resolver::previsit( SingleInit * singleInit ) {784 void Resolver::previsit( SingleInit * singleInit ) { 785 785 visit_children = false; 786 786 // resolve initialization using the possibilities as determined by the currentObject cursor … … 814 814 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) { 815 815 if ( isCharType( pt->get_base() ) ) { 816 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {816 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) { 817 817 // strip cast if we're initializing a char[] with a char *, 818 818 // e.g. char x[] = "hello"; … … 894 894 } 895 895 896 void Resolver::previsit( ConstructorInit * ctorInit ) {896 void Resolver::previsit( ConstructorInit * ctorInit ) { 897 897 visit_children = false; 898 898 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit -
src/ResolvExpr/Resolver.h
r6a9d4b4 r933f32f 10 10 // Created On : Sun May 17 12:18:34 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 09:36:57 201713 // Update Count : 312 // Last Modified On : Mon Feb 18 20:40:38 2019 13 // Update Count : 4 14 14 // 15 15 … … 29 29 /// Checks types and binds syntactic constructs to typed representations 30 30 void resolve( std::list< Declaration * > translationUnit ); 31 void resolveDecl( Declaration *, const SymTab::Indexer & indexer );32 Expression *resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer );33 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer );34 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer );35 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer );31 void resolveDecl( Declaration *, const SymTab::Indexer & indexer ); 32 Expression *resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ); 33 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ); 34 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ); 35 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ); 36 36 void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ); 37 37 void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ); -
src/ResolvExpr/TypeEnvironment.cc
r6a9d4b4 r933f32f 386 386 } 387 387 388 bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 388 bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, 389 TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, 390 const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 389 391 390 392 auto class1 = internal_lookup( var1->get_name() ); … … 428 430 class1->set_type( common ); 429 431 } 432 class1->data.isComplete |= data.isComplete; 430 433 env.erase( class2 ); 431 434 } else return false; … … 435 438 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 436 439 class1->allowWidening = widen1; 440 class1->data.isComplete |= data.isComplete; 437 441 env.erase( class2 ); 438 442 } else { 439 443 class2->vars.insert( class1->vars.begin(), class1->vars.end() ); 440 444 class2->allowWidening = widen2; 445 class2->data.isComplete |= data.isComplete; 441 446 env.erase( class1 ); 442 447 } // if … … 445 450 class1->vars.insert( var2->get_name() ); 446 451 class1->allowWidening = widen1; 452 class1->data.isComplete |= data.isComplete; 447 453 } else if ( class2 != env.end() ) { 448 454 // var1 unbound, add to class2 449 455 class2->vars.insert( var1->get_name() ); 450 456 class2->allowWidening = widen2; 457 class2->data.isComplete |= data.isComplete; 451 458 } else { 452 459 // neither var bound, create new class -
src/ResolvExpr/TypeEnvironment.h
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:24:58 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 : Tue Apr 30 23:04:10 2019 13 // Update Count : 9 14 14 // 15 15 … … 18 18 #include <iostream> // for ostream 19 19 #include <list> // for list, list<>::iterator, list<>... 20 #include <map> // for map, map<>::value_compare 21 #include <set> // for set 20 #include <map> // for map, map<>::value_compare 21 #include <unordered_map> 22 #include <set> // for set 22 23 #include <string> // for string 23 24 #include <utility> // for move, swap … … 64 65 AssertionSetValue() : isUsed(false), resnSlot(0) {} 65 66 }; 66 typedef std::map< DeclarationWithType *, AssertionSetValue, AssertCompare > AssertionSet;67 typedef std:: map< std::string, TypeDecl::Data > OpenVarSet;67 typedef std::map< DeclarationWithType *, AssertionSetValue, AssertCompare > AssertionSet; 68 typedef std::unordered_map< std::string, TypeDecl::Data > OpenVarSet; 68 69 69 70 /// merges one set of open vars into another … … 139 140 /// Binds the type classes represented by `var1` and `var2` together; will add 140 141 /// one or both classes if needed. Returns false on failure. 141 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data& data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );142 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ); 142 143 143 144 /// Disallows widening for all bindings in the environment -
src/ResolvExpr/Unify.cc
r6a9d4b4 r933f32f 21 21 #include <string> // for string, operator==, operator!=, bas... 22 22 #include <utility> // for pair, move 23 23 #include <vector> 24 25 #include "AST/Node.hpp" 26 #include "AST/Type.hpp" 24 27 #include "Common/PassVisitor.h" // for PassVisitor 25 28 #include "FindOpenVars.h" // for findOpenVars … … 172 175 bool isopen2 = var2 && ( entry2 != openVars.end() ); 173 176 174 if ( isopen1 && isopen2 && entry1->second == entry2->second ) { 175 result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer ); 177 if ( isopen1 && isopen2 ) { 178 if ( entry1->second.kind != entry2->second.kind ) { 179 result = false; 180 } else { 181 result = env.bindVarToVar( 182 var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions, 183 haveAssertions, openVars, widenMode, indexer ); 184 } 176 185 } else if ( isopen1 ) { 177 186 result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer ); … … 624 633 } 625 634 626 // xxx - compute once and store in the FunctionType?627 635 Type * extractResultType( FunctionType * function ) { 628 636 if ( function->get_returnVals().size() == 0 ) { … … 638 646 } 639 647 } 648 649 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) { 650 assert(!"restore after AST added to build"); 651 // if ( func->returns.empty() ) return new ast::VoidType{}; 652 // if ( func->returns.size() == 1 ) return func->returns[0]->get_type(); 653 654 // std::vector<ast::ptr<ast::Type>> tys; 655 // for ( const ast::DeclWithType * decl : func->returns ) { 656 // tys.emplace_back( decl->get_type() ); 657 // } 658 // return new ast::TupleType{ std::move(tys) }; 659 } 640 660 } // namespace ResolvExpr 641 661 -
src/ResolvExpr/module.mk
r6a9d4b4 r933f32f 15 15 ############################################################################### 16 16 17 SRC += ResolvExpr/AlternativeFinder.cc \ 18 ResolvExpr/Alternative.cc \ 19 ResolvExpr/Unify.cc \ 20 ResolvExpr/PtrsAssignable.cc \ 21 ResolvExpr/CommonType.cc \ 22 ResolvExpr/ConversionCost.cc \ 23 ResolvExpr/CastCost.cc \ 24 ResolvExpr/PtrsCastable.cc \ 25 ResolvExpr/AdjustExprType.cc \ 26 ResolvExpr/AlternativePrinter.cc \ 27 ResolvExpr/Resolver.cc \ 28 ResolvExpr/ResolveTypeof.cc \ 29 ResolvExpr/RenameVars.cc \ 30 ResolvExpr/FindOpenVars.cc \ 31 ResolvExpr/PolyCost.cc \ 32 ResolvExpr/Occurs.cc \ 33 ResolvExpr/TypeEnvironment.cc \ 34 ResolvExpr/CurrentObject.cc \ 35 ResolvExpr/ExplodedActual.cc \ 36 ResolvExpr/SpecCost.cc \ 37 ResolvExpr/ResolveAssertions.cc 17 SRC_RESOLVEXPR = \ 18 ResolvExpr/AdjustExprType.cc \ 19 ResolvExpr/Alternative.cc \ 20 ResolvExpr/AlternativeFinder.cc \ 21 ResolvExpr/CastCost.cc \ 22 ResolvExpr/CommonType.cc \ 23 ResolvExpr/ConversionCost.cc \ 24 ResolvExpr/CurrentObject.cc \ 25 ResolvExpr/ExplodedActual.cc \ 26 ResolvExpr/FindOpenVars.cc \ 27 ResolvExpr/Occurs.cc \ 28 ResolvExpr/PolyCost.cc \ 29 ResolvExpr/PtrsAssignable.cc \ 30 ResolvExpr/PtrsCastable.cc \ 31 ResolvExpr/RenameVars.cc \ 32 ResolvExpr/ResolveAssertions.cc \ 33 ResolvExpr/Resolver.cc \ 34 ResolvExpr/ResolveTypeof.cc \ 35 ResolvExpr/SpecCost.cc \ 36 ResolvExpr/TypeEnvironment.cc \ 37 ResolvExpr/Unify.cc 38 39 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc 40 SRCDEMANGLE += $(SRC_RESOLVEXPR) -
src/ResolvExpr/typeops.h
r6a9d4b4 r933f32f 10 10 // Created On : Sun May 17 07:28:22 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 09:36:18 201713 // Update Count : 312 // Last Modified On : Fri Feb 8 09:30:34 2019 13 // Update Count : 4 14 14 // 15 15 … … 18 18 #include <vector> 19 19 20 #include "AST/Node.hpp" 21 #include "AST/Type.hpp" 20 22 #include "SynTree/SynTree.h" 21 23 #include "SynTree/Type.h" … … 99 101 /// creates the type represented by the list of returnVals in a FunctionType. The caller owns the return value. 100 102 Type * extractResultType( FunctionType * functionType ); 103 /// Creates or extracts the type represented by the list of returns in a `FunctionType`. 104 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ); 101 105 102 106 // in CommonType.cc 103 Type * commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );107 Type * commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ); 104 108 105 109 // in PolyCost.cc -
src/SymTab/Indexer.cc
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:37:33 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Aug 17 16:08:40 201713 // Update Count : 2 011 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Fri Mar 8 13:55:00 2019 13 // Update Count : 21 14 14 // 15 15 … … 17 17 18 18 #include <cassert> // for assert, strict_dynamic_cast 19 #include <iostream> // for operator<<, basic_ostream, ostream20 19 #include <string> // for string, operator<<, operator!= 20 #include <memory> // for shared_ptr, make_shared 21 21 #include <unordered_map> // for operator!=, unordered_map<>::const... 22 22 #include <unordered_set> // for unordered_set 23 23 #include <utility> // for pair, make_pair, move 24 #include <vector> // for vector 24 25 25 26 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign 26 27 #include "Common/SemanticError.h" // for SemanticError 27 28 #include "Common/utility.h" // for cloneAll 28 #include "GenPoly/GenPoly.h" 29 #include "Common/Stats/Counter.h" // for counters 30 #include "GenPoly/GenPoly.h" // for getFunctionType 29 31 #include "InitTweak/InitTweak.h" // for isConstructor, isCopyFunction, isC... 30 32 #include "Mangler.h" // for Mangler … … 38 40 #include "SynTree/Type.h" // for Type, StructInstType, UnionInstType 39 41 40 #define debugPrint(x) if ( doDebug ) { std::cerr << x; }41 42 42 namespace SymTab { 43 std::ostream & operator<<( std::ostream & out, const Indexer::IdData & data ) { 44 return out << "(" << data.id << "," << data.baseExpr << ")"; 45 } 46 47 typedef std::unordered_map< std::string, Indexer::IdData > MangleTable; 48 typedef std::unordered_map< std::string, MangleTable > IdTable; 49 typedef std::unordered_map< std::string, NamedTypeDecl* > TypeTable; 50 typedef std::unordered_map< std::string, StructDecl* > StructTable; 51 typedef std::unordered_map< std::string, EnumDecl* > EnumTable; 52 typedef std::unordered_map< std::string, UnionDecl* > UnionTable; 53 typedef std::unordered_map< std::string, TraitDecl* > TraitTable; 54 55 void dump( const IdTable &table, std::ostream &os ) { 56 for ( IdTable::const_iterator id = table.begin(); id != table.end(); ++id ) { 57 for ( MangleTable::const_iterator mangle = id->second.begin(); mangle != id->second.end(); ++mangle ) { 58 os << mangle->second << std::endl; 59 } 60 } 61 } 62 63 template< typename Decl > 64 void dump( const std::unordered_map< std::string, Decl* > &table, std::ostream &os ) { 65 for ( typename std::unordered_map< std::string, Decl* >::const_iterator it = table.begin(); it != table.end(); ++it ) { 66 os << it->second << std::endl; 67 } // for 68 } 69 70 struct Indexer::Impl { 71 Impl( unsigned long _scope ) : refCount(1), scope( _scope ), size( 0 ), base(), 72 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {} 73 Impl( unsigned long _scope, Indexer &&_base ) : refCount(1), scope( _scope ), size( 0 ), base( _base ), 74 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {} 75 unsigned long refCount; ///< Number of references to these tables 76 unsigned long scope; ///< Scope these tables are associated with 77 unsigned long size; ///< Number of elements stored in this table 78 const Indexer base; ///< Base indexer this extends 79 80 IdTable idTable; ///< Identifier namespace 81 TypeTable typeTable; ///< Type namespace 82 StructTable structTable; ///< Struct namespace 83 EnumTable enumTable; ///< Enum namespace 84 UnionTable unionTable; ///< Union namespace 85 TraitTable traitTable; ///< Trait namespace 86 }; 87 88 Indexer::Impl *Indexer::newRef( Indexer::Impl *toClone ) { 89 if ( ! toClone ) return 0; 90 91 // shorten the search chain by skipping empty links 92 Indexer::Impl *ret = toClone->size == 0 ? toClone->base.tables : toClone; 93 if ( ret ) { ++ret->refCount; } 94 95 return ret; 96 } 97 98 void Indexer::deleteRef( Indexer::Impl *toFree ) { 99 if ( ! toFree ) return; 100 101 if ( --toFree->refCount == 0 ) delete toFree; 102 } 103 104 void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const { 105 // only need to perform this step for constructors, destructors, and assignment functions 106 if ( ! CodeGen::isCtorDtorAssign( id ) ) return; 107 108 // helpful data structure to organize properties for a type 109 struct ValueType { 110 struct DeclBall { // properties for this particular decl 111 IdData decl; 112 bool isUserDefinedFunc; 113 bool isCopyFunc; 43 44 // Statistics block 45 namespace { 46 static inline auto stats() { 47 using namespace Stats::Counters; 48 static auto group = build<CounterGroup>("Indexers"); 49 static struct { 50 SimpleCounter * count; 51 AverageCounter<double> * size; 52 SimpleCounter * new_scopes; 53 SimpleCounter * lazy_scopes; 54 AverageCounter<double> * avg_scope_depth; 55 MaxCounter<size_t> * max_scope_depth; 56 SimpleCounter * add_calls; 57 SimpleCounter * lookup_calls; 58 SimpleCounter * map_lookups; 59 SimpleCounter * map_mutations; 60 } ret = { 61 .count = build<SimpleCounter>("Count", group), 62 .size = build<AverageCounter<double>>("Average Size", group), 63 .new_scopes = build<SimpleCounter>("Scopes", group), 64 .lazy_scopes = build<SimpleCounter>("Lazy Scopes", group), 65 .avg_scope_depth = build<AverageCounter<double>>("Average Scope", group), 66 .max_scope_depth = build<MaxCounter<size_t>>("Max Scope", group), 67 .add_calls = build<SimpleCounter>("Add Calls", group), 68 .lookup_calls = build<SimpleCounter>("Lookup Calls", group), 69 .map_lookups = build<SimpleCounter>("Map Lookups", group), 70 .map_mutations = build<SimpleCounter>("Map Mutations", group) 114 71 }; 115 // properties for this type 116 bool existsUserDefinedCopyFunc = false; // user-defined copy ctor found 117 BaseSyntaxNode * deleteStmt = nullptr; // non-null if a user-defined function is found 118 std::list< DeclBall > decls; 119 120 // another FunctionDecl for the current type was found - determine 121 // if it has special properties and update data structure accordingly 122 ValueType & operator+=( IdData data ) { 123 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 } ); 127 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 } 133 return *this; 134 } 135 }; // ValueType 136 137 std::list< IdData > copy; 138 copy.splice( copy.end(), out ); 139 140 // organize discovered declarations by type 141 std::unordered_map< std::string, ValueType > funcMap; 142 for ( auto decl : copy ) { 143 if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) { 144 std::list< DeclarationWithType * > & params = function->type->parameters; 145 assert( ! params.empty() ); 146 // use base type of pointer, so that qualifiers on the pointer type aren't considered. 147 Type * base = InitTweak::getPointerBase( params.front()->get_type() ); 148 assert( base ); 149 funcMap[ Mangler::mangle( base ) ] += decl; 150 } else { 151 out.push_back( decl ); 152 } 153 } 154 155 // 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 for ( std::pair< const std::string, ValueType > & pair : funcMap ) { 163 ValueType & val = pair.second; 164 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 } 183 } 184 out.push_back( ball.decl ); 185 } 186 } 187 } 188 189 void Indexer::makeWritable() { 190 if ( ! tables ) { 191 // create indexer if not yet set 192 tables = new Indexer::Impl( scope ); 193 } else if ( tables->refCount > 1 || tables->scope != scope ) { 194 // make this indexer the base of a fresh indexer at the current scope 195 tables = new Indexer::Impl( scope, std::move( *this ) ); 196 } 197 } 198 199 Indexer::Indexer() : tables( 0 ), scope( 0 ) {} 200 201 Indexer::Indexer( const Indexer &that ) : doDebug( that.doDebug ), tables( newRef( that.tables ) ), scope( that.scope ) {} 202 203 Indexer::Indexer( Indexer &&that ) : doDebug( that.doDebug ), tables( that.tables ), scope( that.scope ) { 204 that.tables = 0; 205 } 72 return ret; 73 } 74 } 75 76 Indexer::Indexer() 77 : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(), 78 prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; } 206 79 207 80 Indexer::~Indexer() { 208 deleteRef( tables ); 209 } 210 211 Indexer& Indexer::operator= ( const Indexer &that ) { 212 deleteRef( tables ); 213 214 tables = newRef( that.tables ); 215 scope = that.scope; 216 doDebug = that.doDebug; 217 218 return *this; 219 } 220 221 Indexer& Indexer::operator= ( Indexer &&that ) { 222 deleteRef( tables ); 223 224 tables = that.tables; 225 scope = that.scope; 226 doDebug = that.doDebug; 227 228 that.tables = 0; 229 230 return *this; 81 stats().size->push( idTable ? idTable->size() : 0 ); 82 } 83 84 void Indexer::lazyInitScope() { 85 if ( repScope < scope ) { 86 ++*stats().lazy_scopes; 87 // create rollback 88 prevScope = std::make_shared<Indexer>( *this ); 89 // update repScope 90 repScope = scope; 91 } 92 } 93 94 void Indexer::enterScope() { 95 ++scope; 96 97 ++*stats().new_scopes; 98 stats().avg_scope_depth->push( scope ); 99 stats().max_scope_depth->push( scope ); 100 } 101 102 void Indexer::leaveScope() { 103 if ( repScope == scope ) { 104 Ptr prev = prevScope; // make sure prevScope stays live 105 *this = std::move(*prevScope); // replace with previous scope 106 } 107 108 --scope; 231 109 } 232 110 233 111 void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const { 234 std::unordered_set< std::string > foundMangleNames; 235 236 Indexer::Impl *searchTables = tables; 237 while ( searchTables ) { 238 239 IdTable::const_iterator decls = searchTables->idTable.find( id ); 240 if ( decls != searchTables->idTable.end() ) { 241 const MangleTable &mangleTable = decls->second; 242 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) { 243 // mark the mangled name as found, skipping this insertion if a declaration for that name has already been found 244 if ( foundMangleNames.insert( decl->first ).second == false ) continue; 245 246 out.push_back( decl->second ); 247 } 248 } 249 250 // get declarations from base indexers 251 searchTables = searchTables->base.tables; 252 } 253 254 // some special functions, e.g. constructors and destructors 255 // remove autogenerated functions when they are defined so that 256 // they can never be matched 257 removeSpecialOverrides( id, out ); 112 ++*stats().lookup_calls; 113 if ( ! idTable ) return; 114 115 ++*stats().map_lookups; 116 auto decls = idTable->find( id ); 117 if ( decls == idTable->end() ) return; 118 119 for ( auto decl : *(decls->second) ) { 120 out.push_back( decl.second ); 121 } 258 122 } 259 123 260 124 NamedTypeDecl *Indexer::lookupType( const std::string &id ) const { 261 if ( ! tables ) return 0; 262 263 TypeTable::const_iterator ret = tables->typeTable.find( id ); 264 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupType( id ); 125 ++*stats().lookup_calls; 126 if ( ! typeTable ) return nullptr; 127 ++*stats().map_lookups; 128 auto it = typeTable->find( id ); 129 return it == typeTable->end() ? nullptr : it->second.decl; 265 130 } 266 131 267 132 StructDecl *Indexer::lookupStruct( const std::string &id ) const { 268 if ( ! tables ) return 0; 269 270 StructTable::const_iterator ret = tables->structTable.find( id ); 271 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStruct( id ); 133 ++*stats().lookup_calls; 134 if ( ! structTable ) return nullptr; 135 ++*stats().map_lookups; 136 auto it = structTable->find( id ); 137 return it == structTable->end() ? nullptr : it->second.decl; 138 } 139 140 EnumDecl *Indexer::lookupEnum( const std::string &id ) const { 141 ++*stats().lookup_calls; 142 if ( ! enumTable ) return nullptr; 143 ++*stats().map_lookups; 144 auto it = enumTable->find( id ); 145 return it == enumTable->end() ? nullptr : it->second.decl; 146 } 147 148 UnionDecl *Indexer::lookupUnion( const std::string &id ) const { 149 ++*stats().lookup_calls; 150 if ( ! unionTable ) return nullptr; 151 ++*stats().map_lookups; 152 auto it = unionTable->find( id ); 153 return it == unionTable->end() ? nullptr : it->second.decl; 154 } 155 156 TraitDecl *Indexer::lookupTrait( const std::string &id ) const { 157 ++*stats().lookup_calls; 158 if ( ! traitTable ) return nullptr; 159 ++*stats().map_lookups; 160 auto it = traitTable->find( id ); 161 return it == traitTable->end() ? nullptr : it->second.decl; 162 } 163 164 const Indexer* Indexer::atScope( unsigned long target ) const { 165 // by lazy construction, final indexer in list has repScope 0, cannot be > target 166 // otherwise, will find first scope representing the target 167 const Indexer* indexer = this; 168 while ( indexer->repScope > target ) { 169 indexer = indexer->prevScope.get(); 170 } 171 return indexer; 272 172 } 273 173 274 174 NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const { 275 return lookupTypeAtScope( id, 0);175 return atScope( 0 )->lookupType( id ); 276 176 } 277 177 278 178 StructDecl *Indexer::globalLookupStruct( const std::string &id ) const { 279 return lookupStructAtScope( id, 0);179 return atScope( 0 )->lookupStruct( id ); 280 180 } 281 181 282 182 UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const { 283 return lookupUnionAtScope( id, 0);183 return atScope( 0 )->lookupUnion( id ); 284 184 } 285 185 286 186 EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const { 287 return lookupEnumAtScope( id, 0 ); 288 } 289 290 EnumDecl *Indexer::lookupEnum( const std::string &id ) const { 291 if ( ! tables ) return 0; 292 293 EnumTable::const_iterator ret = tables->enumTable.find( id ); 294 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnum( id ); 295 } 296 297 UnionDecl *Indexer::lookupUnion( const std::string &id ) const { 298 if ( ! tables ) return 0; 299 300 UnionTable::const_iterator ret = tables->unionTable.find( id ); 301 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnion( id ); 302 } 303 304 TraitDecl *Indexer::lookupTrait( const std::string &id ) const { 305 if ( ! tables ) return 0; 306 307 TraitTable::const_iterator ret = tables->traitTable.find( id ); 308 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTrait( id ); 309 } 310 311 const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const { 312 if ( ! tables ) return nullptr; 313 if ( tables->scope < scope ) return nullptr; 314 315 IdTable::const_iterator decls = tables->idTable.find( id ); 316 if ( decls != tables->idTable.end() ) { 317 const MangleTable &mangleTable = decls->second; 318 MangleTable::const_iterator decl = mangleTable.find( mangleName ); 319 if ( decl != mangleTable.end() ) return &decl->second; 320 } 321 322 return tables->base.lookupIdAtScope( id, mangleName, scope ); 323 } 324 325 Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) { 326 return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope )); 327 } 328 329 bool Indexer::hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const { 330 if ( ! tables ) return false; 331 if ( tables->scope < scope ) return false; 332 333 IdTable::const_iterator decls = tables->idTable.find( id ); 334 if ( decls != tables->idTable.end() ) { 335 const MangleTable &mangleTable = decls->second; 336 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) { 337 // check for C decls with the same name, skipping those with a compatible type (by mangleName) 338 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first != mangleName ) return true; 339 } 340 } 341 342 return tables->base.hasIncompatibleCDecl( id, mangleName, scope ); 343 } 344 345 bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const { 346 if ( ! tables ) return false; 347 if ( tables->scope < scope ) return false; 348 349 IdTable::const_iterator decls = tables->idTable.find( id ); 350 if ( decls != tables->idTable.end() ) { 351 const MangleTable &mangleTable = decls->second; 352 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) { 353 // check for C decls with the same name, skipping 354 // those with an incompatible type (by mangleName) 355 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first == mangleName ) return true; 356 } 357 } 358 359 return tables->base.hasCompatibleCDecl( id, mangleName, scope ); 360 } 361 362 NamedTypeDecl *Indexer::lookupTypeAtScope( const std::string &id, unsigned long scope ) const { 363 if ( ! tables ) return 0; 364 if ( tables->scope < scope ) return 0; 365 if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope ); 366 367 TypeTable::const_iterator ret = tables->typeTable.find( id ); 368 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupTypeAtScope( id, scope ); 369 } 370 371 StructDecl *Indexer::lookupStructAtScope( const std::string &id, unsigned long scope ) const { 372 if ( ! tables ) return 0; 373 if ( tables->scope < scope ) return 0; 374 if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope ); 375 376 StructTable::const_iterator ret = tables->structTable.find( id ); 377 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStructAtScope( id, scope ); 378 } 379 380 EnumDecl *Indexer::lookupEnumAtScope( const std::string &id, unsigned long scope ) const { 381 if ( ! tables ) return 0; 382 if ( tables->scope < scope ) return 0; 383 if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope ); 384 385 EnumTable::const_iterator ret = tables->enumTable.find( id ); 386 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnumAtScope( id, scope ); 387 } 388 389 UnionDecl *Indexer::lookupUnionAtScope( const std::string &id, unsigned long scope ) const { 390 if ( ! tables ) return 0; 391 if ( tables->scope < scope ) return 0; 392 if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope ); 393 394 UnionTable::const_iterator ret = tables->unionTable.find( id ); 395 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnionAtScope( id, scope ); 396 } 397 398 TraitDecl *Indexer::lookupTraitAtScope( const std::string &id, unsigned long scope ) const { 399 if ( ! tables ) return 0; 400 if ( tables->scope < scope ) return 0; 401 if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope ); 402 403 TraitTable::const_iterator ret = tables->traitTable.find( id ); 404 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTraitAtScope( id, scope ); 187 return atScope( 0 )->lookupEnum( id ); 405 188 } 406 189 … … 424 207 } 425 208 426 bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) { 427 // if we're giving the same name mangling to things of different types then there is something wrong 209 210 bool Indexer::addedIdConflicts( 211 const Indexer::IdData & existing, DeclarationWithType *added, 212 Indexer::OnConflict handleConflicts, BaseSyntaxNode * deleteStmt ) { 213 // if we're giving the same name mangling to things of different types then there is 214 // something wrong 428 215 assert( (isObject( added ) && isObject( existing.id ) ) 429 216 || ( isFunction( added ) && isFunction( existing.id ) ) ); 430 217 431 if ( LinkageSpec::isOverridable( existing.id-> get_linkage()) ) {218 if ( LinkageSpec::isOverridable( existing.id->linkage ) ) { 432 219 // new definition shadows the autogenerated one, even at the same scope 433 220 return false; 434 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) { 221 } else if ( LinkageSpec::isMangled( added->linkage ) 222 || ResolvExpr::typesCompatible( 223 added->get_type(), existing.id->get_type(), Indexer() ) ) { 435 224 436 225 // it is a conflict if one declaration is deleted and the other is not 437 226 if ( deleteStmt && ! existing.deleteStmt ) { 438 return handleConflicts( existing, "deletion of defined identifier " ); 227 if ( handleConflicts.mode == OnConflict::Error ) { 228 SemanticError( added, "deletion of defined identifier " ); 229 } 230 return true; 439 231 } else if ( ! deleteStmt && existing.deleteStmt ) { 440 return handleConflicts( existing, "definition of deleted identifier " ); 232 if ( handleConflicts.mode == OnConflict::Error ) { 233 SemanticError( added, "definition of deleted identifier " ); 234 } 235 return true; 441 236 } 442 237 443 238 if ( isDefinition( added ) && isDefinition( existing.id ) ) { 444 if ( isFunction( added ) ) { 445 return handleConflicts( existing, "duplicate function definition for " ); 239 if ( handleConflicts.mode == OnConflict::Error ) { 240 SemanticError( added, 241 isFunction( added ) ? 242 "duplicate function definition for " : 243 "duplicate object definition for " ); 244 } 245 return true; 246 } // if 247 } else { 248 if ( handleConflicts.mode == OnConflict::Error ) { 249 SemanticError( added, "duplicate definition for " ); 250 } 251 return true; 252 } // if 253 254 return true; 255 } 256 257 bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const { 258 if ( ! idTable ) return false; 259 260 ++*stats().map_lookups; 261 auto decls = idTable->find( id ); 262 if ( decls == idTable->end() ) return false; 263 264 for ( auto decl : *(decls->second) ) { 265 // skip other scopes (hidden by this decl) 266 if ( decl.second.scope != scope ) continue; 267 // check for C decl with compatible type (by mangleName) 268 if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first == mangleName ) { 269 return true; 270 } 271 } 272 273 return false; 274 } 275 276 bool Indexer::hasIncompatibleCDecl( 277 const std::string &id, const std::string &mangleName ) const { 278 if ( ! idTable ) return false; 279 280 ++*stats().map_lookups; 281 auto decls = idTable->find( id ); 282 if ( decls == idTable->end() ) return false; 283 284 for ( auto decl : *(decls->second) ) { 285 // skip other scopes (hidden by this decl) 286 if ( decl.second.scope != scope ) continue; 287 // check for C decl with incompatible type (by manglename) 288 if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first != mangleName ) { 289 return true; 290 } 291 } 292 293 return false; 294 } 295 296 /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function 297 std::string getOtypeKey( FunctionDecl* function ) { 298 auto& params = function->type->parameters; 299 assert( ! params.empty() ); 300 // use base type of pointer, so that qualifiers on the pointer type aren't considered. 301 Type* base = InitTweak::getPointerBase( params.front()->get_type() ); 302 assert( base ); 303 return Mangler::mangle( base ); 304 } 305 306 /// gets the declaration for the function acting on a type specified by otype key, 307 /// nullptr if none such 308 FunctionDecl * getFunctionForOtype( DeclarationWithType * decl, const std::string& otypeKey ) { 309 FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl ); 310 if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr; 311 return func; 312 } 313 314 bool Indexer::removeSpecialOverrides( 315 Indexer::IdData& data, Indexer::MangleTable::Ptr& mangleTable ) { 316 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which 317 // determinethe set of ctor/dtor/assign that can be used by the requester. In particular, 318 // if the user defines a default ctor, then the generated default ctor is unavailable, 319 // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated 320 // field ctors are available. If the user defines any ctor then the generated default ctor 321 // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines 322 // anything that looks like a copy constructor, then the generated copy constructor is 323 // unavailable, and likewise for the assignment operator. 324 325 // only relevant on function declarations 326 FunctionDecl * function = dynamic_cast< FunctionDecl * >( data.id ); 327 if ( ! function ) return true; 328 // only need to perform this check for constructors, destructors, and assignment functions 329 if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true; 330 331 // set up information for this type 332 bool dataIsUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage ); 333 bool dataIsCopyFunc = InitTweak::isCopyFunction( function, function->name ); 334 std::string dataOtypeKey = getOtypeKey( function ); 335 336 if ( dataIsUserDefinedFunc && dataIsCopyFunc ) { 337 // this is a user-defined copy function 338 // if this is the first such, delete/remove non-user-defined overloads as needed 339 std::vector< std::string > removed; 340 std::vector< MangleTable::value_type > deleted; 341 bool alreadyUserDefinedFunc = false; 342 343 for ( const auto& entry : *mangleTable ) { 344 // skip decls that aren't functions or are for the wrong type 345 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey ); 346 if ( ! decl ) continue; 347 348 bool isCopyFunc = InitTweak::isCopyFunction( decl, decl->name ); 349 if ( ! LinkageSpec::isOverridable( decl->linkage ) ) { 350 // matching user-defined function 351 if ( isCopyFunc ) { 352 // mutation already performed, return early 353 return true; 354 } else { 355 // note that non-copy deletions already performed 356 alreadyUserDefinedFunc = true; 357 } 446 358 } else { 447 return handleConflicts( existing, "duplicate object definition for " ); 448 } // if 449 } // if 450 } else { 451 return handleConflicts( existing, "duplicate definition for " ); 452 } // if 453 359 // non-user-defined function; mark for deletion/removal as appropriate 360 if ( isCopyFunc ) { 361 removed.push_back( entry.first ); 362 } else if ( ! alreadyUserDefinedFunc ) { 363 deleted.push_back( entry ); 364 } 365 } 366 } 367 368 // perform removals from mangle table, and deletions if necessary 369 for ( const auto& key : removed ) { 370 ++*stats().map_mutations; 371 mangleTable = mangleTable->erase( key ); 372 } 373 if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) { 374 ++*stats().map_mutations; 375 mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } ); 376 } 377 } else if ( dataIsUserDefinedFunc ) { 378 // this is a user-defined non-copy function 379 // if this is the first user-defined function, delete non-user-defined overloads 380 std::vector< MangleTable::value_type > deleted; 381 382 for ( const auto& entry : *mangleTable ) { 383 // skip decls that aren't functions or are for the wrong type 384 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey ); 385 if ( ! decl ) continue; 386 387 // exit early if already a matching user-defined function; 388 // earlier function will have mutated table 389 if ( ! LinkageSpec::isOverridable( decl->linkage ) ) return true; 390 391 // skip mutating intrinsic functions 392 if ( decl->linkage == LinkageSpec::Intrinsic ) continue; 393 394 // user-defined non-copy functions do not override copy functions 395 if ( InitTweak::isCopyFunction( decl, decl->name ) ) continue; 396 397 // this function to be deleted after mangleTable iteration is complete 398 deleted.push_back( entry ); 399 } 400 401 // mark deletions to update mangle table 402 // this needs to be a separate loop because of iterator invalidation 403 for ( const auto& entry : deleted ) { 404 ++*stats().map_mutations; 405 mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } ); 406 } 407 } else if ( function->linkage != LinkageSpec::Intrinsic ) { 408 // this is an overridable generated function 409 // if there already exists a matching user-defined function, delete this appropriately 410 for ( const auto& entry : *mangleTable ) { 411 // skip decls that aren't functions or are for the wrong type 412 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey ); 413 if ( ! decl ) continue; 414 415 // skip non-user-defined functions 416 if ( LinkageSpec::isOverridable( decl->linkage ) ) continue; 417 418 if ( dataIsCopyFunc ) { 419 // remove current function if exists a user-defined copy function 420 // since the signatures for copy functions don't need to match exactly, using 421 // a delete statement is the wrong approach 422 if ( InitTweak::isCopyFunction( decl, decl->name ) ) return false; 423 } else { 424 // mark current function deleted by first user-defined function found 425 data.deleteStmt = decl; 426 return true; 427 } 428 } 429 } 430 431 // nothing (more) to fix, return true 454 432 return true; 455 433 } 456 434 457 void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) { 458 if ( decl->name == "" ) return; 459 debugPrint( "Adding Id " << decl->name << std::endl ); 460 makeWritable(); 461 435 void Indexer::addId( 436 DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr, 437 BaseSyntaxNode * deleteStmt ) { 438 ++*stats().add_calls; 462 439 const std::string &name = decl->name; 440 if ( name == "" ) return; 441 463 442 std::string mangleName; 464 443 if ( LinkageSpec::isOverridable( decl->linkage ) ) { 465 // mangle the name without including the appropriate suffix, so overridable routines are placed into the466 // same "bucket" as their user defined versions.444 // mangle the name without including the appropriate suffix, so overridable routines 445 // are placed into the same "bucket" as their user defined versions. 467 446 mangleName = Mangler::mangle( decl, false ); 468 447 } else { … … 470 449 } // if 471 450 472 // this ensures that no two declarations with the same unmangled name at the same scope both have C linkage 473 if ( ! LinkageSpec::isMangled( decl->linkage ) ) { 474 // NOTE this is broken in Richard's original code in such a way that it never triggers (it 475 // doesn't check decls that have the same manglename, and all C-linkage decls are defined to 476 // have their name as their manglename, hence the error can never trigger). 477 // The code here is closer to correct, but name mangling would have to be completely 478 // isomorphic to C type-compatibility, which it may not be. 479 if ( hasIncompatibleCDecl( name, mangleName, scope ) ) { 451 // this ensures that no two declarations with the same unmangled name at the same scope 452 // both have C linkage 453 if ( LinkageSpec::isMangled( decl->linkage ) ) { 454 // Check that a Cforall declaration doesn't override any C declaration 455 if ( hasCompatibleCDecl( name, mangleName ) ) { 456 SemanticError( decl, "Cforall declaration hides C function " ); 457 } 458 } else { 459 // NOTE: only correct if name mangling is completely isomorphic to C 460 // type-compatibility, which it may not be. 461 if ( hasIncompatibleCDecl( name, mangleName ) ) { 480 462 SemanticError( decl, "conflicting overload of C function " ); 481 463 } 482 } else { 483 // Check that a Cforall declaration doesn't override any C declaration 484 if ( hasCompatibleCDecl( name, mangleName, scope ) ) { 485 SemanticError( decl, "Cforall declaration hides C function " ); 486 } 487 } 488 489 // Skip repeat declarations of the same identifier 490 IdData * existing = lookupIdAtScope( name, mangleName, scope ); 491 if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return; 492 493 // add to indexer 494 tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt }; 495 ++tables->size; 464 } 465 466 // ensure tables exist and add identifier 467 MangleTable::Ptr mangleTable; 468 if ( ! idTable ) { 469 idTable = IdTable::new_ptr(); 470 mangleTable = MangleTable::new_ptr(); 471 } else { 472 ++*stats().map_lookups; 473 auto decls = idTable->find( name ); 474 if ( decls == idTable->end() ) { 475 mangleTable = MangleTable::new_ptr(); 476 } else { 477 mangleTable = decls->second; 478 // skip in-scope repeat declarations of same identifier 479 ++*stats().map_lookups; 480 auto existing = mangleTable->find( mangleName ); 481 if ( existing != mangleTable->end() 482 && existing->second.scope == scope 483 && existing->second.id ) { 484 if ( addedIdConflicts( existing->second, decl, handleConflicts, deleteStmt ) ) { 485 if ( handleConflicts.mode == OnConflict::Delete ) { 486 // set delete expression for conflicting identifier 487 lazyInitScope(); 488 *stats().map_mutations += 2; 489 idTable = idTable->set( 490 name, 491 mangleTable->set( 492 mangleName, 493 IdData{ existing->second, handleConflicts.deleteStmt } ) ); 494 } 495 return; 496 } 497 } 498 } 499 } 500 501 // add/overwrite with new identifier 502 lazyInitScope(); 503 IdData data{ decl, baseExpr, deleteStmt, scope }; 504 // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary 505 if ( ! removeSpecialOverrides( data, mangleTable ) ) return; 506 *stats().map_mutations += 2; 507 idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) ); 496 508 } 497 509 498 510 void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) { 499 511 // default handling of conflicts is to raise an error 500 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );512 addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr ); 501 513 } 502 514 503 515 void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) { 504 516 // default handling of conflicts is to raise an error 505 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );517 addId( decl, OnConflict::error(), nullptr, deleteStmt ); 506 518 } 507 519 … … 518 530 } 519 531 } 520 // does not need to be added to the table if both existing and added have a base that are the same 532 // does not need to be added to the table if both existing and added have a base that are 533 // the same 521 534 return true; 522 535 } 523 536 524 537 void Indexer::addType( NamedTypeDecl *decl ) { 525 debugPrint( "Adding type " << decl->name << std::endl ); 526 makeWritable(); 527 538 ++*stats().add_calls; 528 539 const std::string &id = decl->name; 529 TypeTable::iterator existing = tables->typeTable.find( id ); 530 if ( existing == tables->typeTable.end() ) { 531 NamedTypeDecl *parent = tables->base.lookupTypeAtScope( id, scope ); 532 if ( ! parent || ! addedTypeConflicts( parent, decl ) ) { 533 tables->typeTable.insert( existing, std::make_pair( id, decl ) ); 534 ++tables->size; 535 } 536 } else { 537 if ( ! addedTypeConflicts( existing->second, decl ) ) { 538 existing->second = decl; 539 } 540 } 540 541 if ( ! typeTable ) { 542 typeTable = TypeTable::new_ptr(); 543 } else { 544 ++*stats().map_lookups; 545 auto existing = typeTable->find( id ); 546 if ( existing != typeTable->end() 547 && existing->second.scope == scope 548 && addedTypeConflicts( existing->second.decl, decl ) ) return; 549 } 550 551 lazyInitScope(); 552 ++*stats().map_mutations; 553 typeTable = typeTable->set( id, Scoped<NamedTypeDecl>{ decl, scope } ); 541 554 } 542 555 … … 551 564 552 565 void Indexer::addStruct( const std::string &id ) { 553 debugPrint( "Adding fwd decl for struct " << id << std::endl );554 566 addStruct( new StructDecl( id ) ); 555 567 } 556 568 557 569 void Indexer::addStruct( StructDecl *decl ) { 558 debugPrint( "Adding struct " << decl->name << std::endl ); 559 makeWritable(); 560 570 ++*stats().add_calls; 561 571 const std::string &id = decl->name; 562 StructTable::iterator existing = tables->structTable.find( id ); 563 if ( existing == tables->structTable.end() ) { 564 StructDecl *parent = tables->base.lookupStructAtScope( id, scope ); 565 if ( ! parent || ! addedDeclConflicts( parent, decl ) ) { 566 tables->structTable.insert( existing, std::make_pair( id, decl ) ); 567 ++tables->size; 568 } 569 } else { 570 if ( ! addedDeclConflicts( existing->second, decl ) ) { 571 existing->second = decl; 572 } 573 } 572 573 if ( ! structTable ) { 574 structTable = StructTable::new_ptr(); 575 } else { 576 ++*stats().map_lookups; 577 auto existing = structTable->find( id ); 578 if ( existing != structTable->end() 579 && existing->second.scope == scope 580 && addedDeclConflicts( existing->second.decl, decl ) ) return; 581 } 582 583 lazyInitScope(); 584 ++*stats().map_mutations; 585 structTable = structTable->set( id, Scoped<StructDecl>{ decl, scope } ); 574 586 } 575 587 576 588 void Indexer::addEnum( EnumDecl *decl ) { 577 debugPrint( "Adding enum " << decl->name << std::endl ); 578 makeWritable(); 579 589 ++*stats().add_calls; 580 590 const std::string &id = decl->name; 581 EnumTable::iterator existing = tables->enumTable.find( id ); 582 if ( existing == tables->enumTable.end() ) { 583 EnumDecl *parent = tables->base.lookupEnumAtScope( id, scope ); 584 if ( ! parent || ! addedDeclConflicts( parent, decl ) ) { 585 tables->enumTable.insert( existing, std::make_pair( id, decl ) ); 586 ++tables->size; 587 } 588 } else { 589 if ( ! addedDeclConflicts( existing->second, decl ) ) { 590 existing->second = decl; 591 } 592 } 591 592 if ( ! enumTable ) { 593 enumTable = EnumTable::new_ptr(); 594 } else { 595 ++*stats().map_lookups; 596 auto existing = enumTable->find( id ); 597 if ( existing != enumTable->end() 598 && existing->second.scope == scope 599 && addedDeclConflicts( existing->second.decl, decl ) ) return; 600 } 601 602 lazyInitScope(); 603 ++*stats().map_mutations; 604 enumTable = enumTable->set( id, Scoped<EnumDecl>{ decl, scope } ); 593 605 } 594 606 595 607 void Indexer::addUnion( const std::string &id ) { 596 debugPrint( "Adding fwd decl for union " << id << std::endl );597 608 addUnion( new UnionDecl( id ) ); 598 609 } 599 610 600 611 void Indexer::addUnion( UnionDecl *decl ) { 601 debugPrint( "Adding union " << decl->name << std::endl ); 602 makeWritable(); 603 612 ++*stats().add_calls; 604 613 const std::string &id = decl->name; 605 UnionTable::iterator existing = tables->unionTable.find( id ); 606 if ( existing == tables->unionTable.end() ) { 607 UnionDecl *parent = tables->base.lookupUnionAtScope( id, scope ); 608 if ( ! parent || ! addedDeclConflicts( parent, decl ) ) { 609 tables->unionTable.insert( existing, std::make_pair( id, decl ) ); 610 ++tables->size; 611 } 612 } else { 613 if ( ! addedDeclConflicts( existing->second, decl ) ) { 614 existing->second = decl; 615 } 616 } 614 615 if ( ! unionTable ) { 616 unionTable = UnionTable::new_ptr(); 617 } else { 618 ++*stats().map_lookups; 619 auto existing = unionTable->find( id ); 620 if ( existing != unionTable->end() 621 && existing->second.scope == scope 622 && addedDeclConflicts( existing->second.decl, decl ) ) return; 623 } 624 625 lazyInitScope(); 626 ++*stats().map_mutations; 627 unionTable = unionTable->set( id, Scoped<UnionDecl>{ decl, scope } ); 617 628 } 618 629 619 630 void Indexer::addTrait( TraitDecl *decl ) { 620 debugPrint( "Adding trait " << decl->name << std::endl ); 621 makeWritable(); 622 631 ++*stats().add_calls; 623 632 const std::string &id = decl->name; 624 TraitTable::iterator existing = tables->traitTable.find( id ); 625 if ( existing == tables->traitTable.end() ) { 626 TraitDecl *parent = tables->base.lookupTraitAtScope( id, scope ); 627 if ( ! parent || ! addedDeclConflicts( parent, decl ) ) { 628 tables->traitTable.insert( existing, std::make_pair( id, decl ) ); 629 ++tables->size; 630 } 631 } else { 632 if ( ! addedDeclConflicts( existing->second, decl ) ) { 633 existing->second = decl; 634 } 635 } 636 } 637 638 void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) { 633 634 if ( ! traitTable ) { 635 traitTable = TraitTable::new_ptr(); 636 } else { 637 ++*stats().map_lookups; 638 auto existing = traitTable->find( id ); 639 if ( existing != traitTable->end() 640 && existing->second.scope == scope 641 && addedDeclConflicts( existing->second.decl, decl ) ) return; 642 } 643 644 lazyInitScope(); 645 ++*stats().map_mutations; 646 traitTable = traitTable->set( id, Scoped<TraitDecl>{ decl, scope } ); 647 } 648 649 void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, 650 OnConflict handleConflicts ) { 639 651 for ( Declaration * decl : aggr->members ) { 640 652 if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) { … … 642 654 if ( dwt->name == "" ) { 643 655 Type * t = dwt->get_type()->stripReferences(); 644 if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType *>( t ) ) {656 if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) { 645 657 Expression * base = expr->clone(); 646 658 ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost? … … 659 671 assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() ); 660 672 661 addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) { 662 // on conflict, delete the identifier 663 existing.deleteStmt = withStmt; 664 return true; 665 }); 673 addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) ); 666 674 } 667 675 } … … 685 693 addIds( ftype->returnVals ); 686 694 addIds( ftype->parameters ); 687 }688 689 void Indexer::enterScope() {690 ++scope;691 692 if ( doDebug ) {693 std::cerr << "--- Entering scope " << scope << std::endl;694 }695 }696 697 void Indexer::leaveScope() {698 using std::cerr;699 700 assert( scope > 0 && "cannot leave initial scope" );701 if ( doDebug ) {702 cerr << "--- Leaving scope " << scope << " containing" << std::endl;703 }704 --scope;705 706 while ( tables && tables->scope > scope ) {707 if ( doDebug ) {708 dump( tables->idTable, cerr );709 dump( tables->typeTable, cerr );710 dump( tables->structTable, cerr );711 dump( tables->enumTable, cerr );712 dump( tables->unionTable, cerr );713 dump( tables->traitTable, cerr );714 }715 716 // swap tables for base table until we find one at an appropriate scope717 Indexer::Impl *base = newRef( tables->base.tables );718 deleteRef( tables );719 tables = base;720 }721 }722 723 void Indexer::print( std::ostream &os, int indent ) const {724 using std::cerr;725 726 if ( tables ) {727 os << "--- scope " << tables->scope << " ---" << std::endl;728 729 os << "===idTable===" << std::endl;730 dump( tables->idTable, os );731 os << "===typeTable===" << std::endl;732 dump( tables->typeTable, os );733 os << "===structTable===" << std::endl;734 dump( tables->structTable, os );735 os << "===enumTable===" << std::endl;736 dump( tables->enumTable, os );737 os << "===unionTable===" << std::endl;738 dump( tables->unionTable, os );739 os << "===contextTable===" << std::endl;740 dump( tables->traitTable, os );741 742 tables->base.print( os, indent );743 } else {744 os << "--- end ---" << std::endl;745 }746 747 695 } 748 696 -
src/SymTab/Indexer.h
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:38:55 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Aug 17 16:09:12 201713 // Update Count : 811 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Fri Mar 8 13:55:00 2019 13 // Update Count : 9 14 14 // 15 15 16 16 #pragma once 17 17 18 #include < iosfwd> // for ostream19 #include <list> // for list20 #include < string> // for string21 #include < functional> // for function18 #include <functional> // for function 19 #include <list> // for list 20 #include <memory> // for shared_ptr, enable_shared_from_this 21 #include <string> // for string 22 22 23 #include " SynTree/Visitor.h" // for Visitor24 #include "SynTree/SynTree.h" // for AST nodes23 #include "Common/PersistentMap.h" // for PersistentMap 24 #include "SynTree/SynTree.h" // for AST nodes 25 25 26 26 namespace ResolvExpr { 27 class Cost;27 class Cost; 28 28 } 29 29 30 30 namespace SymTab { 31 class Indexer {32 public:31 class Indexer : public std::enable_shared_from_this<SymTab::Indexer> { 32 public: 33 33 explicit Indexer(); 34 virtual ~Indexer(); 34 35 35 Indexer( const Indexer &that ); 36 Indexer( Indexer &&that ); 37 virtual ~Indexer(); 38 Indexer& operator= ( const Indexer &that ); 39 Indexer& operator= ( Indexer &&that ); 40 41 // when using an indexer manually (e.g., within a mutator traversal), it is necessary to tell the indexer 42 // explicitly when scopes begin and end 36 // when using an indexer manually (e.g., within a mutator traversal), it is necessary to 37 // tell the indexer explicitly when scopes begin and end 43 38 void enterScope(); 44 39 void leaveScope(); … … 50 45 /// non-null if this declaration is deleted 51 46 BaseSyntaxNode * deleteStmt = nullptr; 47 /// scope of identifier 48 unsigned long scope = 0; 52 49 53 50 // NOTE: shouldn't need either of these constructors, but gcc-4 does not properly support initializer lists with default members. 54 51 IdData() = default; 55 IdData( DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ) {} 52 IdData( 53 DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt, 54 unsigned long scope ) 55 : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ), scope( scope ) {} 56 IdData( const IdData& o, BaseSyntaxNode * deleteStmt ) 57 : id( o.id ), baseExpr( o.baseExpr ), deleteStmt( deleteStmt ), scope( o.scope ) {} 56 58 57 59 Expression * combine( ResolvExpr::Cost & cost ) const; … … 80 82 EnumDecl *globalLookupEnum( const std::string &id ) const; 81 83 82 void print( std::ostream &os, int indent = 0 ) const;83 84 /// looks up a specific mangled ID at the given scope85 IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope );86 const IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const;87 /// returns true if there exists a declaration with C linkage and the given name with a different mangled name88 bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;89 /// returns true if there exists a declaration with C linkage and the given name with the same mangled name90 bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;91 // equivalents to lookup functions that only look at tables at scope `scope` (which should be >= tables->scope)92 NamedTypeDecl *lookupTypeAtScope( const std::string &id, unsigned long scope ) const;93 StructDecl *lookupStructAtScope( const std::string &id, unsigned long scope ) const;94 EnumDecl *lookupEnumAtScope( const std::string &id, unsigned long scope ) const;95 UnionDecl *lookupUnionAtScope( const std::string &id, unsigned long scope ) const;96 TraitDecl *lookupTraitAtScope( const std::string &id, unsigned long scope ) const;97 98 typedef std::function<bool(IdData &, const std::string &)> ConflictFunction;99 100 84 void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr ); 101 85 void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ); … … 112 96 void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt ); 113 97 114 /// adds all of the members of the Aggregate (addWith helper)115 void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction );116 117 98 /// convenience function for adding a list of Ids to the indexer 118 99 void addIds( const std::list< DeclarationWithType * > & decls ); … … 124 105 void addFunctionType( FunctionType * ftype ); 125 106 126 bool doDebug = false; ///< Display debugging trace?127 107 private: 128 struct Impl; 108 /// Wraps a Decl* with a scope 109 template<typename Decl> 110 struct Scoped { 111 Decl* decl; ///< declaration 112 unsigned long scope; ///< scope of this declaration 129 113 130 Impl *tables; ///< Copy-on-write instance of table data structure131 unsigned long scope; ///< Scope index of this pointer114 Scoped(Decl* d, unsigned long s) : decl(d), scope(s) {} 115 }; 132 116 133 /// Takes a new ref to a table (returns null if null) 134 static Impl *newRef( Impl *toClone ); 135 /// Clears a ref to a table (does nothing if null) 136 static void deleteRef( Impl *toFree ); 117 using Ptr = std::shared_ptr<const Indexer>; 137 118 138 // Removes matching autogenerated constructors and destructors 139 // so that they will not be selected 140 // void removeSpecialOverrides( FunctionDecl *decl ); 141 void removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const; 119 using MangleTable = PersistentMap< std::string, IdData >; 120 using IdTable = PersistentMap< std::string, MangleTable::Ptr >; 121 using TypeTable = PersistentMap< std::string, Scoped<NamedTypeDecl> >; 122 using StructTable = PersistentMap< std::string, Scoped<StructDecl> >; 123 using EnumTable = PersistentMap< std::string, Scoped<EnumDecl> >; 124 using UnionTable = PersistentMap< std::string, Scoped<UnionDecl> >; 125 using TraitTable = PersistentMap< std::string, Scoped<TraitDecl> >; 142 126 143 /// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope) 144 void makeWritable(); 127 IdTable::Ptr idTable; ///< identifier namespace 128 TypeTable::Ptr typeTable; ///< type namespace 129 StructTable::Ptr structTable; ///< struct namespace 130 EnumTable::Ptr enumTable; ///< enum namespace 131 UnionTable::Ptr unionTable; ///< union namespace 132 TraitTable::Ptr traitTable; ///< trait namespace 133 134 Ptr prevScope; ///< reference to indexer for parent scope 135 unsigned long scope; ///< Scope index of this indexer 136 unsigned long repScope; ///< Scope index of currently represented scope 137 138 /// Ensures that a proper backtracking scope exists before a mutation 139 void lazyInitScope(); 140 141 /// Gets the indexer at the given scope 142 const Indexer* atScope( unsigned long scope ) const; 143 144 /// Removes matching autogenerated constructors and destructors so that they will not be 145 /// selected. If returns false, passed decl should not be added. 146 bool removeSpecialOverrides( IdData& decl, MangleTable::Ptr& mangleTable ); 147 148 /// Options for handling identifier conflicts 149 struct OnConflict { 150 enum { 151 Error, ///< Throw a semantic error 152 Delete ///< Delete the earlier version with the delete statement 153 } mode; 154 BaseSyntaxNode * deleteStmt; ///< Statement that deletes this expression 155 156 private: 157 OnConflict() : mode(Error), deleteStmt(nullptr) {} 158 OnConflict( BaseSyntaxNode * d ) : mode(Delete), deleteStmt(d) {} 159 public: 160 OnConflict( const OnConflict& ) = default; 161 162 static OnConflict error() { return {}; } 163 static OnConflict deleteWith( BaseSyntaxNode * d ) { return { d }; } 164 }; 165 166 /// true if the existing identifier conflicts with the added identifier 167 bool addedIdConflicts( 168 const IdData& existing, DeclarationWithType * added, OnConflict handleConflicts, 169 BaseSyntaxNode * deleteStmt ); 145 170 146 171 /// common code for addId, addDeletedId, etc. 147 void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr ); 172 void addId( 173 DeclarationWithType * decl, OnConflict handleConflicts, 174 Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr ); 175 176 /// adds all of the members of the Aggregate (addWith helper) 177 void addMembers( AggregateDecl * aggr, Expression * expr, OnConflict handleConflicts ); 178 179 /// returns true if there exists a declaration with C linkage and the given name with the same mangled name 180 bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const; 181 /// returns true if there exists a declaration with C linkage and the given name with a different mangled name 182 bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName ) const; 148 183 }; 149 184 } // namespace SymTab -
src/SymTab/Mangler.cc
r6a9d4b4 r933f32f 38 38 struct Mangler : public WithShortCircuiting, public WithVisitorRef<Mangler>, public WithGuards { 39 39 Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams ); 40 Mangler( const ResolvExpr::TypeEnvironment& env );41 40 Mangler( const Mangler & ) = delete; 42 41 … … 67 66 private: 68 67 std::ostringstream mangleName; ///< Mangled name being constructed 69 typedef std::map< std::string, std::pair< std::string, int > > VarMapType;68 typedef std::map< std::string, std::pair< int, int > > VarMapType; 70 69 VarMapType varNums; ///< Map of type variables to indices 71 70 int nextVarNum; ///< Next type variable index 72 const ResolvExpr::TypeEnvironment* env; ///< optional environment for substitutions73 71 bool isTopLevel; ///< Is the Mangler at the top level 74 72 bool mangleOverridable; ///< Specially mangle overridable built-in methods … … 80 78 public: 81 79 Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 82 int nextVarNum, const ResolvExpr::TypeEnvironment* env, 83 const VarMapType& varNums ); 80 int nextVarNum, const VarMapType& varNums ); 84 81 85 82 private: … … 109 106 } 110 107 111 std::string mangleAssnKey( DeclarationWithType* decl,112 const ResolvExpr::TypeEnvironment& env ) {113 PassVisitor<Mangler> mangler( env );114 maybeAccept( decl, mangler );115 return mangler.pass.get_mangleName();116 }117 118 108 namespace { 119 109 Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams ) 120 : nextVarNum( 0 ), env(nullptr),isTopLevel( true ),110 : nextVarNum( 0 ), isTopLevel( true ), 121 111 mangleOverridable( mangleOverridable ), typeMode( typeMode ), 122 112 mangleGenericParams( mangleGenericParams ) {} 123 113 124 Mangler::Mangler( const ResolvExpr::TypeEnvironment& env )125 : nextVarNum( 0 ), env( &env ), isTopLevel( true ), mangleOverridable( false ),126 typeMode( false ), mangleGenericParams( true ) {}127 128 114 Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 129 int nextVarNum, const ResolvExpr::TypeEnvironment* env, 130 const VarMapType& varNums ) 131 : varNums( varNums ), nextVarNum( nextVarNum ), env( env ), isTopLevel( false ), 115 int nextVarNum, const VarMapType& varNums ) 116 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ), 132 117 mangleOverridable( mangleOverridable ), typeMode( typeMode ), 133 118 mangleGenericParams( mangleGenericParams ) {} … … 358 343 assert( false ); 359 344 } // switch 360 std::string varName; 361 // replace type with substitution name if environment is available and bound 362 if ( env ) { 363 const ResolvExpr::EqvClass* varClass = env->lookup( (*i)->name ); 364 if ( varClass && varClass->type ) { 365 PassVisitor<Mangler> sub_mangler( 366 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, 367 env, varNums ); 368 varClass->type->accept( sub_mangler ); 369 varName = std::string{"%"} + sub_mangler.pass.get_mangleName(); 370 } 371 } 372 // otherwise just give type numeric name 373 if ( varName.empty() ) { 374 varName = std::to_string( nextVarNum++ ); 375 } 376 varNums[ (*i)->name ] = std::make_pair( varName, (int)(*i)->get_kind() ); 345 varNums[ (*i)->name ] = std::make_pair( nextVarNum, (int)(*i)->get_kind() ); 377 346 for ( std::list< DeclarationWithType* >::iterator assert = (*i)->assertions.begin(); assert != (*i)->assertions.end(); ++assert ) { 378 347 PassVisitor<Mangler> sub_mangler( 379 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, env, 380 varNums ); 348 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ); 381 349 (*assert)->accept( sub_mangler ); 382 350 assertionNames.push_back( sub_mangler.pass.get_mangleName() ); -
src/SymTab/Mangler.h
r6a9d4b4 r933f32f 44 44 /// Mangle ignoring generic type parameters 45 45 std::string mangleConcrete( Type* ty ); 46 /// Mangle for assertion key47 std::string mangleAssnKey( DeclarationWithType* decl,48 const ResolvExpr::TypeEnvironment& env );49 46 50 47 namespace Encoding { -
src/SymTab/ManglerCommon.cc
r6a9d4b4 r933f32f 10 10 // Created On : Sun May 17 21:44:03 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 09:45:30 201713 // Update Count : 1512 // Last Modified On : Thu Feb 14 17:06:37 2019 13 // Update Count : 26 14 14 // 15 15 … … 23 23 const std::string manglePrefix = "_X"; 24 24 25 const std::string basicTypes[] = { 26 "b", // Bool 27 "c", // Char 28 "a", // SignedChar 29 "h", // UnsignedChar 30 "s", // ShortSignedInt 31 "t", // ShortUnsignedInt 32 "i", // SignedInt 33 "j", // UnsignedInt 34 "l", // LongSignedInt 35 "m", // LongUnsignedInt 36 "x", // LongLongSignedInt 37 "y", // LongLongUnsignedInt 38 "f", // Float 39 "d", // Double 40 "e", // LongDouble 41 "Cf", // FloatComplex 42 "Cd", // DoubleComplex 43 "Ce", // LongDoubleComplex 44 // Note: imaginary is not an overloadable type in C++ 45 "If", // FloatImaginary 46 "Id", // DoubleImaginary 47 "Ie", // LongDoubleImaginary 48 "n", // SignedInt128 49 "o", // UnsignedInt128 50 "Dq", // Float80 -- TODO: itanium says Float80 and LongDouble both encode to "e", but doing this causes problems with constructing long double, because the cost tables are incorrect 51 "g", // Float128 52 // "z", // ellipsis 53 // "Dd" // # IEEE 754r decimal floating point (64 bits) 54 // "De" // # IEEE 754r decimal floating point (128 bits) 55 // "Df" // # IEEE 754r decimal floating point (32 bits) 56 // "Dh" // # IEEE 754r half-precision floating point (16 bits) 57 // "DF"N_ // # ISO/IEC TS 18661 binary floating point type _FloatN (N bits) 58 // "Di" // char32_t 59 // "Ds" // char16_t 60 }; 25 // GENERATED START, DO NOT EDIT 26 // GENERATED BY BasicTypes-gen.cc 27 // NOTES ON MANGLING: 28 // * Itanium spec says that Float80 encodes to "e" (like LongDouble), but the distinct lengths cause resolution problems. 29 // * Float128 is supposed to encode to "g", but I wanted it to mangle equal to LongDouble. 30 // * Mangling for non-standard complex types is by best guess 31 // * _FloatN is supposed to encode as "DF"N"_"; modified for same reason as above. 32 // * unused mangling identifiers: 33 // - "z" ellipsis 34 // - "Dd" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x) 35 // - "De" IEEE 754r 128-bit decimal floating point 36 // - "Df" IEEE 754r 32-bit decimal floating point 37 // - "Dh" IEEE 754r 16-bit decimal floating point (borrowed for _Float16) 38 // - "DF"N"_" ISO/IEC TS 18661 N-bit binary floating point (_FloatN) 39 // - "Di" char32_t 40 // - "Ds" char16_t 41 const std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = { 42 "b", // _Bool 43 "c", // char 44 "a", // signed char 45 "h", // unsigned char 46 "s", // signed short int 47 "t", // unsigned short int 48 "i", // signed int 49 "j", // unsigned int 50 "l", // signed long int 51 "m", // unsigned long int 52 "x", // signed long long int 53 "y", // unsigned long long int 54 "n", // __int128 55 "o", // unsigned __int128 56 "DF16_", // _Float16 57 "CDF16_", // _Float16 _Complex 58 "DF32_", // _Float32 59 "CDF32_", // _Float32 _Complex 60 "f", // float 61 "Cf", // float _Complex 62 "DF32x_", // _Float32x 63 "CDF32x_", // _Float32x _Complex 64 "DF64_", // _Float64 65 "CDF64_", // _Float64 _Complex 66 "d", // double 67 "Cd", // double _Complex 68 "DF64x_", // _Float64x 69 "CDF64x_", // _Float64x _Complex 70 "Dq", // __float80 71 "DF128_", // _Float128 72 "CDF128_", // _Float128 _Complex 73 "g", // __float128 74 "e", // long double 75 "Ce", // long double _Complex 76 "DF128x_", // _Float128x 77 "CDF128x_", // _Float128x _Complex 78 }; // basicTypes 79 // GENERATED END 61 80 static_assert( 62 81 sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES, -
src/SymTab/Validate.cc
r6a9d4b4 r933f32f 49 49 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign 50 50 #include "ControlStruct/Mutate.h" // for ForExprMutator 51 #include "Common/Stats.h" // for Stats::Heap 51 52 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd 52 53 #include "Common/ScopedMap.h" // for ScopedMap … … 298 299 PassVisitor<FixQualifiedTypes> fixQual; 299 300 300 acceptAll( translationUnit, hoistDecls ); 301 ReplaceTypedef::replaceTypedef( translationUnit ); 302 ReturnTypeFixer::fix( translationUnit ); // must happen before autogen 303 acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes because it is an indexer and needs correct types for mangling 304 acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions 305 mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes, because aggregate members are accessed 306 HoistStruct::hoistStruct( translationUnit ); // must happen after EliminateTypedef, so that aggregate typedefs occur in the correct order 307 EliminateTypedef::eliminateTypedef( translationUnit ); // 308 acceptAll( translationUnit, genericParams ); // check as early as possible - can't happen before LinkReferenceToTypes 309 VerifyCtorDtorAssign::verify( translationUnit ); // must happen before autogen, because autogen examines existing ctor/dtors 310 ReturnChecker::checkFunctionReturns( translationUnit ); 311 InitTweak::fixReturnStatements( translationUnit ); // must happen before autogen 312 Concurrency::applyKeywords( translationUnit ); 313 acceptAll( translationUnit, fpd ); // must happen before autogenerateRoutines, after Concurrency::applyKeywords because uniqueIds must be set on declaration before resolution 314 ControlStruct::hoistControlDecls( translationUnit ); // hoist initialization out of for statements; must happen before autogenerateRoutines 315 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay 316 Concurrency::implementMutexFuncs( translationUnit ); 317 Concurrency::implementThreadStarter( translationUnit ); 318 mutateAll( translationUnit, compoundliteral ); 319 ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables 320 FixObjectType::fix( translationUnit ); 321 ArrayLength::computeLength( translationUnit ); 322 Validate::findSpecialDecls( translationUnit ); 323 mutateAll( translationUnit, labelAddrFixer ); 324 Validate::handleAttributes( translationUnit ); 301 { 302 Stats::Heap::newPass("validate-A"); 303 Stats::Time::BlockGuard guard("validate-A"); 304 acceptAll( translationUnit, hoistDecls ); 305 ReplaceTypedef::replaceTypedef( translationUnit ); 306 ReturnTypeFixer::fix( translationUnit ); // must happen before autogen 307 acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes because it is an indexer and needs correct types for mangling 308 } 309 { 310 Stats::Heap::newPass("validate-B"); 311 Stats::Time::BlockGuard guard("validate-B"); 312 Stats::Time::TimeBlock("Link Reference To Types", [&]() { 313 acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions 314 }); 315 Stats::Time::TimeBlock("Fix Qualified Types", [&]() { 316 mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes, because aggregate members are accessed 317 }); 318 Stats::Time::TimeBlock("Hoist Structs", [&]() { 319 HoistStruct::hoistStruct( translationUnit ); // must happen after EliminateTypedef, so that aggregate typedefs occur in the correct order 320 }); 321 Stats::Time::TimeBlock("Eliminate Typedefs", [&]() { 322 EliminateTypedef::eliminateTypedef( translationUnit ); // 323 }); 324 } 325 { 326 Stats::Heap::newPass("validate-C"); 327 Stats::Time::BlockGuard guard("validate-C"); 328 acceptAll( translationUnit, genericParams ); // check as early as possible - can't happen before LinkReferenceToTypes 329 VerifyCtorDtorAssign::verify( translationUnit ); // must happen before autogen, because autogen examines existing ctor/dtors 330 ReturnChecker::checkFunctionReturns( translationUnit ); 331 InitTweak::fixReturnStatements( translationUnit ); // must happen before autogen 332 } 333 { 334 Stats::Heap::newPass("validate-D"); 335 Stats::Time::BlockGuard guard("validate-D"); 336 Stats::Time::TimeBlock("Apply Concurrent Keywords", [&]() { 337 Concurrency::applyKeywords( translationUnit ); 338 }); 339 Stats::Time::TimeBlock("Forall Pointer Decay", [&]() { 340 acceptAll( translationUnit, fpd ); // must happen before autogenerateRoutines, after Concurrency::applyKeywords because uniqueIds must be set on declaration before resolution 341 }); 342 Stats::Time::TimeBlock("Hoist Control Declarations", [&]() { 343 ControlStruct::hoistControlDecls( translationUnit ); // hoist initialization out of for statements; must happen before autogenerateRoutines 344 }); 345 Stats::Time::TimeBlock("Generate Autogen routines", [&]() { 346 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay 347 }); 348 } 349 { 350 Stats::Heap::newPass("validate-E"); 351 Stats::Time::BlockGuard guard("validate-E"); 352 Stats::Time::TimeBlock("Implement Mutex Func", [&]() { 353 Concurrency::implementMutexFuncs( translationUnit ); 354 }); 355 Stats::Time::TimeBlock("Implement Thread Start", [&]() { 356 Concurrency::implementThreadStarter( translationUnit ); 357 }); 358 Stats::Time::TimeBlock("Compound Literal", [&]() { 359 mutateAll( translationUnit, compoundliteral ); 360 }); 361 Stats::Time::TimeBlock("Resolve With Expressions", [&]() { 362 ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables 363 }); 364 } 365 { 366 Stats::Heap::newPass("validate-F"); 367 Stats::Time::BlockGuard guard("validate-F"); 368 Stats::Time::TimeBlock("Fix Object Type", [&]() { 369 FixObjectType::fix( translationUnit ); 370 }); 371 Stats::Time::TimeBlock("Array Length", [&]() { 372 ArrayLength::computeLength( translationUnit ); 373 }); 374 Stats::Time::TimeBlock("Find Special Declarations", [&]() { 375 Validate::findSpecialDecls( translationUnit ); 376 }); 377 Stats::Time::TimeBlock("Fix Label Address", [&]() { 378 mutateAll( translationUnit, labelAddrFixer ); 379 }); 380 Stats::Time::TimeBlock("Handle Attributes", [&]() { 381 Validate::handleAttributes( translationUnit ); 382 }); 383 } 325 384 } 326 385 -
src/SymTab/module.mk
r6a9d4b4 r933f32f 15 15 ############################################################################### 16 16 17 SRC += SymTab/Indexer.cc \ 18 SymTab/Mangler.cc \ 19 SymTab/ManglerCommon.cc \ 20 SymTab/Validate.cc \ 21 SymTab/FixFunction.cc \ 22 SymTab/Autogen.cc 17 SRC_SYMTAB = \ 18 SymTab/Autogen.cc \ 19 SymTab/FixFunction.cc \ 20 SymTab/Indexer.cc \ 21 SymTab/Mangler.cc \ 22 SymTab/ManglerCommon.cc \ 23 SymTab/Validate.cc 24 25 SRC += $(SRC_SYMTAB) 26 SRCDEMANGLE += $(SRC_SYMTAB) SymTab/Demangle.cc -
src/SynTree/AddressExpr.cc
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 23:54:44 2015 11 // Last Modified By : Rob Schluntz12 // Last Modified On : T ue Apr 26 12:35:13 201613 // Update Count : 611 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Feb 28 13:13:38 2019 13 // Update Count : 10 14 14 // 15 15 … … 47 47 } else { 48 48 // taking address of non-lvalue -- must be a reference, loses one layer of reference 49 ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( arg->result ); 50 set_result( addrType( refType->base ) ); 49 if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( arg->result ) ) { 50 set_result( addrType( refType->base ) ); 51 } else { 52 SemanticError( arg->result, "Attempt to take address of non-lvalue expression: " ); 53 } // if 51 54 } 52 55 // result of & is never an lvalue -
src/SynTree/Attribute.cc
r6a9d4b4 r933f32f 21 21 #include "Expression.h" // for Expression 22 22 23 Attribute::Attribute( const Attribute &other ) : name( other.name ) {23 Attribute::Attribute( const Attribute &other ) : BaseSyntaxNode( other ), name( other.name ) { 24 24 cloneAll( other.parameters, parameters ); 25 25 } -
src/SynTree/BaseSyntaxNode.h
r6a9d4b4 r933f32f 18 18 #include "Common/CodeLocation.h" 19 19 #include "Common/Indenter.h" 20 #include "Common/Stats.h" 21 20 22 class Visitor; 21 23 class Mutator; … … 23 25 class BaseSyntaxNode { 24 26 public: 27 static Stats::Counters::SimpleCounter* new_nodes; 28 25 29 CodeLocation location; 30 31 BaseSyntaxNode() { ++*new_nodes; } 32 BaseSyntaxNode( const BaseSyntaxNode& o ) : location(o.location) { ++*new_nodes; } 26 33 27 34 virtual ~BaseSyntaxNode() {} -
src/SynTree/BasicType.cc
r6a9d4b4 r933f32f 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Sep 25 14:14:03 201713 // Update Count : 1 112 // Last Modified On : Thu Jan 31 21:37:36 2019 13 // Update Count : 12 14 14 // 15 15 … … 30 30 31 31 bool BasicType::isInteger() const { 32 return kind <= UnsignedInt128; 33 #if 0 32 34 switch ( kind ) { 33 35 case Bool: … … 63 65 assert( false ); 64 66 return false; 67 #endif 65 68 } 66 69 -
src/SynTree/Constant.cc
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Spt 28 14:49:00 201813 // Update Count : 3 011 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 13 18:11:22 2019 13 // Update Count : 32 14 14 // 15 15 … … 25 25 Constant::Constant( Type * type, std::string rep, double val ) : type( type ), rep( rep ), val( val ) {} 26 26 27 Constant::Constant( const Constant &other ) : rep( other.rep ), val( other.val ) {27 Constant::Constant( const Constant &other ) : BaseSyntaxNode( other ), rep( other.rep ), val( other.val ) { 28 28 type = other.type->clone(); 29 29 } -
src/SynTree/Declaration.cc
r6a9d4b4 r933f32f 31 31 32 32 Declaration::Declaration( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage ) 33 : name( name ), linkage( linkage ), storageClasses( scs ), uniqueId( 0) {33 : name( name ), linkage( linkage ), uniqueId( 0 ), storageClasses( scs ) { 34 34 } 35 35 36 36 Declaration::Declaration( const Declaration &other ) 37 : BaseSyntaxNode( other ), name( other.name ), linkage( other.linkage ), extension( other.extension ), storageClasses( other.storageClasses ), uniqueId( other.uniqueId) {37 : BaseSyntaxNode( other ), name( other.name ), linkage( other.linkage ), extension( other.extension ), uniqueId( other.uniqueId ), storageClasses( other.storageClasses ) { 38 38 } 39 39 -
src/SynTree/Declaration.h
r6a9d4b4 r933f32f 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sun Sep 3 19:24:06 201713 // Update Count : 13 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr May 2 10:47:00 2019 13 // Update Count : 135 14 14 // 15 15 … … 19 19 #include <iosfwd> // for ostream 20 20 #include <list> // for list 21 #include <unordered_map> // for unordered_map 21 22 #include <string> // for string, operator+, allocator, to_string 22 23 … … 70 71 static Declaration *declFromId( UniqueId id ); 71 72 72 private: 73 UniqueId uniqueId; 73 74 Type::StorageClasses storageClasses; 74 UniqueId uniqueId; 75 private: 75 76 }; 76 77 … … 166 167 CompoundStmt *get_statements() const { return statements; } 167 168 void set_statements( CompoundStmt *newValue ) { statements = newValue; } 169 bool has_body() const { return NULL != statements; } 168 170 169 171 static FunctionDecl * newFunction( const std::string & name, FunctionType * type, CompoundStmt * statements ); … … 211 213 TypeDecl::Kind kind; 212 214 bool isComplete; 215 213 216 Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {} 214 217 Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {} 215 218 Data( Kind kind, bool isComplete ) : kind( kind ), isComplete( isComplete ) {} 219 Data( const Data& d1, const Data& d2 ) 220 : kind( d1.kind ), isComplete ( d1.isComplete || d2.isComplete ) {} 221 216 222 bool operator==(const Data & other) const { return kind == other.kind && isComplete == other.isComplete; } 217 223 bool operator!=(const Data & other) const { return !(*this == other);} … … 239 245 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 240 246 241 private:242 247 Kind kind; 243 248 }; … … 300 305 virtual void accept( Visitor &v ) override { v.visit( this ); } 301 306 virtual Declaration *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 302 private:303 307 DeclarationNode::Aggregate kind; 308 private: 304 309 virtual std::string typeString() const override; 305 310 }; … … 330 335 virtual Declaration *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 331 336 private: 332 std:: map< std::string, long long int > enumValues;337 std::unordered_map< std::string, long long int > enumValues; 333 338 virtual std::string typeString() const override; 334 339 }; -
src/SynTree/Expression.cc
r6a9d4b4 r933f32f 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jul 25 14:15:47 201713 // Update Count : 5412 // Last Modified On : Tue Feb 19 18:10:55 2019 13 // Update Count : 60 14 14 // 15 15 … … 33 33 #include "GenPoly/Lvalue.h" 34 34 35 void printInferParams( const InferredParams & inferParams, std::ostream & os, Indenter indent, int level ) {35 void printInferParams( const InferredParams & inferParams, std::ostream & os, Indenter indent, int level ) { 36 36 if ( ! inferParams.empty() ) { 37 37 os << indent << "with inferred parameters " << level << ":" << std::endl; … … 47 47 Expression::Expression() : result( 0 ), env( 0 ) {} 48 48 49 Expression::Expression( const Expression & other ) : BaseSyntaxNode( other ), result( maybeClone( other.result ) ), env( maybeClone( other.env ) ), extension( other.extension ), inferParams( other.inferParams ), resnSlots( other.resnSlots ) {}49 Expression::Expression( const Expression & other ) : BaseSyntaxNode( other ), result( maybeClone( other.result ) ), env( maybeClone( other.env ) ), extension( other.extension ), inferParams( other.inferParams ), resnSlots( other.resnSlots ) {} 50 50 51 51 void Expression::spliceInferParams( Expression * other ) { … … 62 62 } 63 63 64 void Expression::print( std::ostream & os, Indenter indent ) const {64 void Expression::print( std::ostream & os, Indenter indent ) const { 65 65 printInferParams( inferParams, os, indent+1, 0 ); 66 66 … … 79 79 } 80 80 81 ConstantExpr::ConstantExpr( const ConstantExpr & other) : Expression( other ), constant( other.constant ) {81 ConstantExpr::ConstantExpr( const ConstantExpr & other) : Expression( other ), constant( other.constant ) { 82 82 } 83 83 84 84 ConstantExpr::~ConstantExpr() {} 85 85 86 void ConstantExpr::print( std::ostream & os, Indenter indent ) const {86 void ConstantExpr::print( std::ostream & os, Indenter indent ) const { 87 87 os << "constant expression " ; 88 88 constant.print( os ); … … 124 124 } 125 125 126 VariableExpr::VariableExpr( const VariableExpr & other ) : Expression( other ), var( other.var ) {126 VariableExpr::VariableExpr( const VariableExpr & other ) : Expression( other ), var( other.var ) { 127 127 } 128 128 … … 137 137 } 138 138 139 void VariableExpr::print( std::ostream & os, Indenter indent ) const {139 void VariableExpr::print( std::ostream & os, Indenter indent ) const { 140 140 os << "Variable Expression: "; 141 141 var->printShort(os, indent); … … 143 143 } 144 144 145 SizeofExpr::SizeofExpr( Expression * expr_ ) :145 SizeofExpr::SizeofExpr( Expression * expr_ ) : 146 146 Expression(), expr(expr_), type(0), isType(false) { 147 147 set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ); 148 148 } 149 149 150 SizeofExpr::SizeofExpr( Type * type_ ) :150 SizeofExpr::SizeofExpr( Type * type_ ) : 151 151 Expression(), expr(0), type(type_), isType(true) { 152 152 set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ); 153 153 } 154 154 155 SizeofExpr::SizeofExpr( const SizeofExpr & other ) :155 SizeofExpr::SizeofExpr( const SizeofExpr & other ) : 156 156 Expression( other ), expr( maybeClone( other.expr ) ), type( maybeClone( other.type ) ), isType( other.isType ) { 157 157 } … … 162 162 } 163 163 164 void SizeofExpr::print( std::ostream & os, Indenter indent) const {164 void SizeofExpr::print( std::ostream & os, Indenter indent) const { 165 165 os << "Sizeof Expression on: "; 166 166 if (isType) type->print(os, indent+1); … … 169 169 } 170 170 171 AlignofExpr::AlignofExpr( Expression * expr_ ) :171 AlignofExpr::AlignofExpr( Expression * expr_ ) : 172 172 Expression(), expr(expr_), type(0), isType(false) { 173 173 set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ); 174 174 } 175 175 176 AlignofExpr::AlignofExpr( Type * type_ ) :176 AlignofExpr::AlignofExpr( Type * type_ ) : 177 177 Expression(), expr(0), type(type_), isType(true) { 178 178 set_result( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ); 179 179 } 180 180 181 AlignofExpr::AlignofExpr( const AlignofExpr & other ) :181 AlignofExpr::AlignofExpr( const AlignofExpr & other ) : 182 182 Expression( other ), expr( maybeClone( other.expr ) ), type( maybeClone( other.type ) ), isType( other.isType ) { 183 183 } … … 188 188 } 189 189 190 void AlignofExpr::print( std::ostream & os, Indenter indent) const {190 void AlignofExpr::print( std::ostream & os, Indenter indent) const { 191 191 os << "Alignof Expression on: "; 192 192 if (isType) type->print(os, indent+1); … … 195 195 } 196 196 197 UntypedOffsetofExpr::UntypedOffsetofExpr( Type * type, const std::string &member ) :197 UntypedOffsetofExpr::UntypedOffsetofExpr( Type * type, const std::string & member ) : 198 198 Expression(), type(type), member(member) { 199 199 assert( type ); … … 201 201 } 202 202 203 UntypedOffsetofExpr::UntypedOffsetofExpr( const UntypedOffsetofExpr & other ) :203 UntypedOffsetofExpr::UntypedOffsetofExpr( const UntypedOffsetofExpr & other ) : 204 204 Expression( other ), type( maybeClone( other.type ) ), member( other.member ) {} 205 205 … … 208 208 } 209 209 210 void UntypedOffsetofExpr::print( std::ostream & os, Indenter indent) const {210 void UntypedOffsetofExpr::print( std::ostream & os, Indenter indent) const { 211 211 os << "Untyped Offsetof Expression on member " << member << " of "; 212 212 type->print(os, indent+1); … … 214 214 } 215 215 216 OffsetofExpr::OffsetofExpr( Type * type, DeclarationWithType *member ) :216 OffsetofExpr::OffsetofExpr( Type * type, DeclarationWithType * member ) : 217 217 Expression(), type(type), member(member) { 218 218 assert( member ); … … 221 221 } 222 222 223 OffsetofExpr::OffsetofExpr( const OffsetofExpr & other ) :223 OffsetofExpr::OffsetofExpr( const OffsetofExpr & other ) : 224 224 Expression( other ), type( maybeClone( other.type ) ), member( other.member ) {} 225 225 … … 228 228 } 229 229 230 void OffsetofExpr::print( std::ostream & os, Indenter indent) const {230 void OffsetofExpr::print( std::ostream & os, Indenter indent) const { 231 231 os << "Offsetof Expression on member " << member->name << " of "; 232 232 type->print(os, indent+1); … … 234 234 } 235 235 236 OffsetPackExpr::OffsetPackExpr( StructInstType * type ) : Expression(), type( type ) {236 OffsetPackExpr::OffsetPackExpr( StructInstType * type ) : Expression(), type( type ) { 237 237 assert( type ); 238 238 set_result( new ArrayType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), 0, false, false ) ); 239 239 } 240 240 241 OffsetPackExpr::OffsetPackExpr( const OffsetPackExpr & other ) : Expression( other ), type( maybeClone( other.type ) ) {}241 OffsetPackExpr::OffsetPackExpr( const OffsetPackExpr & other ) : Expression( other ), type( maybeClone( other.type ) ) {} 242 242 243 243 OffsetPackExpr::~OffsetPackExpr() { delete type; } 244 244 245 void OffsetPackExpr::print( std::ostream & os, Indenter indent ) const {245 void OffsetPackExpr::print( std::ostream & os, Indenter indent ) const { 246 246 os << "Offset pack expression on "; 247 247 type->print(os, indent+1); … … 249 249 } 250 250 251 AttrExpr::AttrExpr( Expression * attr, Expression *expr_ ) :251 AttrExpr::AttrExpr( Expression * attr, Expression * expr_ ) : 252 252 Expression(), attr( attr ), expr(expr_), type(0), isType(false) { 253 253 } 254 254 255 AttrExpr::AttrExpr( Expression * attr, Type *type_ ) :255 AttrExpr::AttrExpr( Expression * attr, Type * type_ ) : 256 256 Expression(), attr( attr ), expr(0), type(type_), isType(true) { 257 257 } 258 258 259 AttrExpr::AttrExpr( const AttrExpr & other ) :259 AttrExpr::AttrExpr( const AttrExpr & other ) : 260 260 Expression( other ), attr( maybeClone( other.attr ) ), expr( maybeClone( other.expr ) ), type( maybeClone( other.type ) ), isType( other.isType ) { 261 261 } … … 267 267 } 268 268 269 void AttrExpr::print( std::ostream & os, Indenter indent) const {269 void AttrExpr::print( std::ostream & os, Indenter indent) const { 270 270 os << "Attr "; 271 271 attr->print( os, indent+1); … … 278 278 } 279 279 280 CastExpr::CastExpr( Expression * arg, Type *toType, bool isGenerated ) : Expression(),arg(arg), isGenerated( isGenerated ) {280 CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) { 281 281 set_result(toType); 282 282 } 283 283 284 CastExpr::CastExpr( Expression * arg, bool isGenerated ) : Expression(),arg(arg), isGenerated( isGenerated ) {284 CastExpr::CastExpr( Expression * arg, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) { 285 285 set_result( new VoidType( Type::Qualifiers() ) ); 286 286 } 287 287 288 CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ) {288 CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ) { 289 289 } 290 290 … … 293 293 } 294 294 295 void CastExpr::print( std::ostream & os, Indenter indent ) const {296 os << "Cast of:" << std::endl << indent+1;295 void CastExpr::print( std::ostream & os, Indenter indent ) const { 296 os << (isGenerated ? "Generated " : "Explicit ") << "Cast of:" << std::endl << indent+1; 297 297 arg->print(os, indent+1); 298 298 os << std::endl << indent << "... to:"; … … 306 306 } 307 307 308 KeywordCastExpr::KeywordCastExpr( Expression * arg, Target target ) : Expression(), arg(arg), target( target ) {309 } 310 311 KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {308 KeywordCastExpr::KeywordCastExpr( Expression * arg, Target target ) : Expression(), arg(arg), target( target ) { 309 } 310 311 KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) { 312 312 } 313 313 … … 327 327 } 328 328 329 void KeywordCastExpr::print( std::ostream & os, Indenter indent ) const {329 void KeywordCastExpr::print( std::ostream & os, Indenter indent ) const { 330 330 os << "Keyword Cast of:" << std::endl << indent+1; 331 331 arg->print(os, indent+1); … … 335 335 } 336 336 337 VirtualCastExpr::VirtualCastExpr( Expression * arg_, Type *toType ) : Expression(), arg(arg_) {337 VirtualCastExpr::VirtualCastExpr( Expression * arg_, Type * toType ) : Expression(), arg(arg_) { 338 338 set_result(toType); 339 339 } 340 340 341 VirtualCastExpr::VirtualCastExpr( const VirtualCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ) {341 VirtualCastExpr::VirtualCastExpr( const VirtualCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ) { 342 342 } 343 343 … … 346 346 } 347 347 348 void VirtualCastExpr::print( std::ostream & os, Indenter indent ) const {348 void VirtualCastExpr::print( std::ostream & os, Indenter indent ) const { 349 349 os << "Virtual Cast of:" << std::endl << indent+1; 350 350 arg->print(os, indent+1); … … 359 359 } 360 360 361 UntypedMemberExpr::UntypedMemberExpr( Expression * member, Expression * aggregate ) :361 UntypedMemberExpr::UntypedMemberExpr( Expression * member, Expression * aggregate ) : 362 362 Expression(), member(member), aggregate(aggregate) { 363 363 assert( aggregate ); 364 364 } 365 365 366 UntypedMemberExpr::UntypedMemberExpr( const UntypedMemberExpr & other ) :366 UntypedMemberExpr::UntypedMemberExpr( const UntypedMemberExpr & other ) : 367 367 Expression( other ), member( maybeClone( other.member ) ), aggregate( maybeClone( other.aggregate ) ) { 368 368 } … … 373 373 } 374 374 375 void UntypedMemberExpr::print( std::ostream & os, Indenter indent ) const {375 void UntypedMemberExpr::print( std::ostream & os, Indenter indent ) const { 376 376 os << "Untyped Member Expression, with field: " << std::endl << indent+1; 377 377 member->print(os, indent+1 ); … … 381 381 } 382 382 383 MemberExpr::MemberExpr( DeclarationWithType * member, Expression *aggregate ) :383 MemberExpr::MemberExpr( DeclarationWithType * member, Expression * aggregate ) : 384 384 Expression(), member(member), aggregate(aggregate) { 385 385 assert( member ); … … 395 395 } 396 396 397 MemberExpr::MemberExpr( const MemberExpr & other ) :397 MemberExpr::MemberExpr( const MemberExpr & other ) : 398 398 Expression( other ), member( other.member ), aggregate( maybeClone( other.aggregate ) ) { 399 399 } … … 404 404 } 405 405 406 void MemberExpr::print( std::ostream & os, Indenter indent ) const {406 void MemberExpr::print( std::ostream & os, Indenter indent ) const { 407 407 os << "Member Expression, with field:" << std::endl; 408 408 os << indent+1; … … 413 413 } 414 414 415 UntypedExpr::UntypedExpr( Expression * function, const std::list<Expression *> &args ) :415 UntypedExpr::UntypedExpr( Expression * function, const std::list<Expression *> & args ) : 416 416 Expression(), function(function), args(args) {} 417 417 418 UntypedExpr::UntypedExpr( const UntypedExpr & other ) :418 UntypedExpr::UntypedExpr( const UntypedExpr & other ) : 419 419 Expression( other ), function( maybeClone( other.function ) ) { 420 420 cloneAll( other.args, args ); … … 455 455 456 456 457 void UntypedExpr::print( std::ostream & os, Indenter indent ) const {457 void UntypedExpr::print( std::ostream & os, Indenter indent ) const { 458 458 os << "Applying untyped:" << std::endl; 459 459 os << indent+1; … … 469 469 } 470 470 471 NameExpr::NameExpr( const NameExpr & other ) : Expression( other ), name( other.name ) {471 NameExpr::NameExpr( const NameExpr & other ) : Expression( other ), name( other.name ) { 472 472 } 473 473 474 474 NameExpr::~NameExpr() {} 475 475 476 void NameExpr::print( std::ostream & os, Indenter indent ) const {476 void NameExpr::print( std::ostream & os, Indenter indent ) const { 477 477 os << "Name: " << get_name(); 478 478 Expression::print( os, indent ); 479 479 } 480 480 481 LogicalExpr::LogicalExpr( Expression * arg1_, Expression *arg2_, bool andp ) :481 LogicalExpr::LogicalExpr( Expression * arg1_, Expression * arg2_, bool andp ) : 482 482 Expression(), arg1(arg1_), arg2(arg2_), isAnd(andp) { 483 483 set_result( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ); 484 484 } 485 485 486 LogicalExpr::LogicalExpr( const LogicalExpr & other ) :486 LogicalExpr::LogicalExpr( const LogicalExpr & other ) : 487 487 Expression( other ), arg1( maybeClone( other.arg1 ) ), arg2( maybeClone( other.arg2 ) ), isAnd( other.isAnd ) { 488 488 } … … 493 493 } 494 494 495 void LogicalExpr::print( std::ostream & os, Indenter indent )const {495 void LogicalExpr::print( std::ostream & os, Indenter indent )const { 496 496 os << "Short-circuited operation (" << (isAnd ? "and" : "or") << ") on: "; 497 497 arg1->print(os); … … 504 504 Expression(), arg1(arg1), arg2(arg2), arg3(arg3) {} 505 505 506 ConditionalExpr::ConditionalExpr( const ConditionalExpr & other ) :506 ConditionalExpr::ConditionalExpr( const ConditionalExpr & other ) : 507 507 Expression( other ), arg1( maybeClone( other.arg1 ) ), arg2( maybeClone( other.arg2 ) ), arg3( maybeClone( other.arg3 ) ) { 508 508 } … … 514 514 } 515 515 516 void ConditionalExpr::print( std::ostream & os, Indenter indent ) const {516 void ConditionalExpr::print( std::ostream & os, Indenter indent ) const { 517 517 os << "Conditional expression on: " << std::endl << indent+1; 518 518 arg1->print( os, indent+1 ); … … 527 527 528 528 529 void AsmExpr::print( std::ostream & os, Indenter indent ) const {529 void AsmExpr::print( std::ostream & os, Indenter indent ) const { 530 530 os << "Asm Expression: " << std::endl; 531 531 if ( inout ) inout->print( os, indent+1 ); … … 549 549 } 550 550 551 void ImplicitCopyCtorExpr::print( std::ostream & os, Indenter indent ) const {551 void ImplicitCopyCtorExpr::print( std::ostream & os, Indenter indent ) const { 552 552 os << "Implicit Copy Constructor Expression: " << std::endl << indent+1; 553 553 callExpr->print( os, indent+1 ); … … 570 570 } 571 571 572 void ConstructorExpr::print( std::ostream & os, Indenter indent ) const {572 void ConstructorExpr::print( std::ostream & os, Indenter indent ) const { 573 573 os << "Constructor Expression: " << std::endl << indent+1; 574 574 callExpr->print( os, indent + 2 ); … … 583 583 } 584 584 585 CompoundLiteralExpr::CompoundLiteralExpr( const CompoundLiteralExpr & other ) : Expression( other ), initializer( other.initializer->clone() ) {}585 CompoundLiteralExpr::CompoundLiteralExpr( const CompoundLiteralExpr & other ) : Expression( other ), initializer( other.initializer->clone() ) {} 586 586 587 587 CompoundLiteralExpr::~CompoundLiteralExpr() { … … 589 589 } 590 590 591 void CompoundLiteralExpr::print( std::ostream & os, Indenter indent ) const {591 void CompoundLiteralExpr::print( std::ostream & os, Indenter indent ) const { 592 592 os << "Compound Literal Expression: " << std::endl << indent+1; 593 593 result->print( os, indent+1 ); … … 597 597 } 598 598 599 RangeExpr::RangeExpr( Expression * low, Expression *high ) : low( low ), high( high ) {}600 RangeExpr::RangeExpr( const RangeExpr & other ) : Expression( other ), low( other.low->clone() ), high( other.high->clone() ) {}601 void RangeExpr::print( std::ostream & os, Indenter indent ) const {599 RangeExpr::RangeExpr( Expression * low, Expression * high ) : low( low ), high( high ) {} 600 RangeExpr::RangeExpr( const RangeExpr & other ) : Expression( other ), low( other.low->clone() ), high( other.high->clone() ) {} 601 void RangeExpr::print( std::ostream & os, Indenter indent ) const { 602 602 os << "Range Expression: "; 603 603 low->print( os, indent ); … … 607 607 } 608 608 609 StmtExpr::StmtExpr( CompoundStmt * statements ) : statements( statements ) {609 StmtExpr::StmtExpr( CompoundStmt * statements ) : statements( statements ) { 610 610 computeResult(); 611 611 } 612 StmtExpr::StmtExpr( const StmtExpr & other ) : Expression( other ), statements( other.statements->clone() ) {612 StmtExpr::StmtExpr( const StmtExpr & other ) : Expression( other ), statements( other.statements->clone() ) { 613 613 cloneAll( other.returnDecls, returnDecls ); 614 614 cloneAll( other.dtors, dtors ); … … 639 639 } 640 640 } 641 void StmtExpr::print( std::ostream & os, Indenter indent ) const {641 void StmtExpr::print( std::ostream & os, Indenter indent ) const { 642 642 os << "Statement Expression: " << std::endl << indent+1; 643 643 statements->print( os, indent+1 ); … … 655 655 656 656 long long UniqueExpr::count = 0; 657 UniqueExpr::UniqueExpr( Expression * expr, long long idVal ) : expr( expr ), object( nullptr ), var( nullptr ), id( idVal ) {657 UniqueExpr::UniqueExpr( Expression * expr, long long idVal ) : expr( expr ), object( nullptr ), var( nullptr ), id( idVal ) { 658 658 assert( expr ); 659 659 assert( count != -1 ); … … 663 663 } 664 664 } 665 UniqueExpr::UniqueExpr( const UniqueExpr & other ) : Expression( other ), expr( maybeClone( other.expr ) ), object( maybeClone( other.object ) ), var( maybeClone( other.var ) ), id( other.id ) {665 UniqueExpr::UniqueExpr( const UniqueExpr & other ) : Expression( other ), expr( maybeClone( other.expr ) ), object( maybeClone( other.object ) ), var( maybeClone( other.var ) ), id( other.id ) { 666 666 } 667 667 UniqueExpr::~UniqueExpr() { … … 670 670 delete var; 671 671 } 672 void UniqueExpr::print( std::ostream & os, Indenter indent ) const {672 void UniqueExpr::print( std::ostream & os, Indenter indent ) const { 673 673 os << "Unique Expression with id:" << id << std::endl << indent+1; 674 674 expr->print( os, indent+1 ); -
src/SynTree/Expression.h
r6a9d4b4 r933f32f 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Sep 3 19:23:46 201713 // Update Count : 4 812 // Last Modified On : Mon Feb 18 18:29:51 2019 13 // Update Count : 49 14 14 // 15 15 … … 195 195 public: 196 196 Expression * arg; 197 bool isGenerated = true; // whether this cast appeared in the sourceprogram197 bool isGenerated = true; // cast generated implicitly by code generation or explicit in program 198 198 199 199 CastExpr( Expression * arg, bool isGenerated = true ); -
src/SynTree/Label.h
r6a9d4b4 r933f32f 35 35 operator std::string() const { return name; } 36 36 bool empty() { return name.empty(); } 37 private: 37 38 38 std::string name; 39 39 Statement * labelled; -
src/SynTree/Mutator.h
r6a9d4b4 r933f32f 121 121 virtual Initializer * mutate( ConstructorInit * ctorInit ) = 0 ; 122 122 123 virtual Subrange * mutate( Subrange * subrange ) = 0;124 125 123 virtual Constant * mutate( Constant * constant ) = 0; 126 124 -
src/SynTree/Statement.h
r6a9d4b4 r933f32f 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Mar 8 14:53:02 201813 // Update Count : 7812 // Last Modified On : Tue Mar 12 09:01:53 2019 13 // Update Count : 83 14 14 // 15 15 … … 19 19 #include <list> // for list 20 20 #include <memory> // for allocator 21 #include <vector> // for vector21 #include <vector> // for vector 22 22 23 23 #include "BaseSyntaxNode.h" // for BaseSyntaxNode … … 43 43 const std::list<Label> & get_labels() const { return labels; } 44 44 45 virtual Statement * clone() const override = 0;46 virtual void accept( Visitor & v ) override = 0;47 virtual Statement * acceptMutator( Mutator &m ) override = 0;48 virtual void print( std::ostream & os, Indenter indent = {} ) const override;45 virtual Statement * clone() const override = 0; 46 virtual void accept( Visitor & v ) override = 0; 47 virtual Statement * acceptMutator( Mutator & m ) override = 0; 48 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 49 49 }; 50 50 … … 55 55 CompoundStmt(); 56 56 CompoundStmt( std::list<Statement *> stmts ); 57 CompoundStmt( const CompoundStmt & other );57 CompoundStmt( const CompoundStmt & other ); 58 58 virtual ~CompoundStmt(); 59 59 … … 62 62 void push_front( Statement * stmt ) { kids.push_front( stmt ); } 63 63 64 virtual CompoundStmt * clone() const override { return new CompoundStmt( *this ); }65 virtual void accept( Visitor & v ) override { v.visit( this ); }66 virtual CompoundStmt * acceptMutator( Mutator &m ) override { return m.mutate( this ); }67 virtual void print( std::ostream & os, Indenter indent = {} ) const override;64 virtual CompoundStmt * clone() const override { return new CompoundStmt( *this ); } 65 virtual void accept( Visitor & v ) override { v.visit( this ); } 66 virtual CompoundStmt * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 67 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 68 68 }; 69 69 … … 72 72 NullStmt( const std::list<Label> & labels = {} ); 73 73 74 virtual NullStmt * clone() const override { return new NullStmt( *this ); }75 virtual void accept( Visitor & v ) override { v.visit( this ); }76 virtual NullStmt * acceptMutator( Mutator &m ) override { return m.mutate( this ); }77 virtual void print( std::ostream & os, Indenter indent = {} ) const override;74 virtual NullStmt * clone() const override { return new NullStmt( *this ); } 75 virtual void accept( Visitor & v ) override { v.visit( this ); } 76 virtual NullStmt * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 77 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 78 78 }; 79 79 80 80 class ExprStmt : public Statement { 81 81 public: 82 Expression * expr;83 84 ExprStmt( Expression * expr );85 ExprStmt( const ExprStmt & other );82 Expression * expr; 83 84 ExprStmt( Expression * expr ); 85 ExprStmt( const ExprStmt & other ); 86 86 virtual ~ExprStmt(); 87 87 88 Expression * get_expr() { return expr; }89 void set_expr( Expression * newValue ) { expr = newValue; }90 91 virtual ExprStmt * clone() const override { return new ExprStmt( *this ); }92 virtual void accept( Visitor & v ) override { v.visit( this ); }93 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }94 virtual void print( std::ostream & os, Indenter indent = {} ) const override;88 Expression * get_expr() { return expr; } 89 void set_expr( Expression * newValue ) { expr = newValue; } 90 91 virtual ExprStmt * clone() const override { return new ExprStmt( *this ); } 92 virtual void accept( Visitor & v ) override { v.visit( this ); } 93 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 94 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 95 95 }; 96 96 … … 98 98 public: 99 99 bool voltile; 100 Expression * instruction;100 Expression * instruction; 101 101 std::list<Expression *> output, input; 102 102 std::list<ConstantExpr *> clobber; 103 103 std::list<Label> gotolabels; 104 104 105 AsmStmt( bool voltile, Expression * instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels );106 AsmStmt( const AsmStmt & other );105 AsmStmt( bool voltile, Expression * instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels ); 106 AsmStmt( const AsmStmt & other ); 107 107 virtual ~AsmStmt(); 108 108 … … 114 114 void set_output( const std::list<Expression *> & newValue ) { output = newValue; } 115 115 std::list<Expression *> & get_input() { return input; } 116 void set_input( const std::list<Expression *> & newValue ) { input = newValue; }116 void set_input( const std::list<Expression *> & newValue ) { input = newValue; } 117 117 std::list<ConstantExpr *> & get_clobber() { return clobber; } 118 void set_clobber( const std::list<ConstantExpr *> & newValue ) { clobber = newValue; }118 void set_clobber( const std::list<ConstantExpr *> & newValue ) { clobber = newValue; } 119 119 std::list<Label> & get_gotolabels() { return gotolabels; } 120 void set_gotolabels( const std::list<Label> & newValue ) { gotolabels = newValue; }120 void set_gotolabels( const std::list<Label> & newValue ) { gotolabels = newValue; } 121 121 122 122 virtual AsmStmt * clone() const { return new AsmStmt( *this ); } … … 141 141 class IfStmt : public Statement { 142 142 public: 143 Expression * condition;144 Statement * thenPart;145 Statement * elsePart;143 Expression * condition; 144 Statement * thenPart; 145 Statement * elsePart; 146 146 std::list<Statement *> initialization; 147 147 148 IfStmt( Expression * condition, Statement *thenPart, Statement *elsePart,148 IfStmt( Expression * condition, Statement * thenPart, Statement * elsePart, 149 149 std::list<Statement *> initialization = std::list<Statement *>() ); 150 IfStmt( const IfStmt & other );150 IfStmt( const IfStmt & other ); 151 151 virtual ~IfStmt(); 152 152 153 std::list<Statement *> & get_initialization() { return initialization; }154 Expression * get_condition() { return condition; }155 void set_condition( Expression * newValue ) { condition = newValue; }156 Statement * get_thenPart() { return thenPart; }157 void set_thenPart( Statement * newValue ) { thenPart = newValue; }158 Statement * get_elsePart() { return elsePart; }159 void set_elsePart( Statement * newValue ) { elsePart = newValue; }160 161 virtual IfStmt * clone() const override { return new IfStmt( *this ); }162 virtual void accept( Visitor & v ) override { v.visit( this ); }163 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }164 virtual void print( std::ostream & os, Indenter indent = {} ) const override;153 std::list<Statement *> & get_initialization() { return initialization; } 154 Expression * get_condition() { return condition; } 155 void set_condition( Expression * newValue ) { condition = newValue; } 156 Statement * get_thenPart() { return thenPart; } 157 void set_thenPart( Statement * newValue ) { thenPart = newValue; } 158 Statement * get_elsePart() { return elsePart; } 159 void set_elsePart( Statement * newValue ) { elsePart = newValue; } 160 161 virtual IfStmt * clone() const override { return new IfStmt( *this ); } 162 virtual void accept( Visitor & v ) override { v.visit( this ); } 163 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 164 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 165 165 }; 166 166 … … 170 170 std::list<Statement *> statements; 171 171 172 SwitchStmt( Expression * condition, const std::list<Statement *> &statements );173 SwitchStmt( const SwitchStmt & other );172 SwitchStmt( Expression * condition, const std::list<Statement *> & statements ); 173 SwitchStmt( const SwitchStmt & other ); 174 174 virtual ~SwitchStmt(); 175 175 176 Expression * get_condition() { return condition; }177 void set_condition( Expression * newValue ) { condition = newValue; }176 Expression * get_condition() { return condition; } 177 void set_condition( Expression * newValue ) { condition = newValue; } 178 178 179 179 std::list<Statement *> & get_statements() { return statements; } 180 180 181 virtual void accept( Visitor & v ) override { v.visit( this ); }182 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }183 184 virtual SwitchStmt * clone() const override { return new SwitchStmt( *this ); }185 virtual void print( std::ostream & os, Indenter indent = {} ) const override;181 virtual void accept( Visitor & v ) override { v.visit( this ); } 182 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 183 184 virtual SwitchStmt * clone() const override { return new SwitchStmt( *this ); } 185 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 186 186 187 187 }; … … 192 192 std::list<Statement *> stmts; 193 193 194 CaseStmt( Expression * conditions, const std::list<Statement *> &stmts, bool isdef = false ) throw (SemanticErrorException);195 CaseStmt( const CaseStmt & other );194 CaseStmt( Expression * conditions, const std::list<Statement *> & stmts, bool isdef = false ) throw (SemanticErrorException); 195 CaseStmt( const CaseStmt & other ); 196 196 virtual ~CaseStmt(); 197 197 … … 201 201 void set_default(bool b) { _isDefault = b; } 202 202 203 Expression * & get_condition() { return condition; }204 void set_condition( Expression * newValue ) { condition = newValue; }205 206 std::list<Statement *> & get_statements() { return stmts; }207 void set_statements( std::list<Statement *> & newValue ) { stmts = newValue; }208 209 virtual void accept( Visitor & v ) override { v.visit( this ); }210 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }211 212 virtual CaseStmt * clone() const override { return new CaseStmt( *this ); }213 virtual void print( std::ostream & os, Indenter indent = {} ) const override;203 Expression * & get_condition() { return condition; } 204 void set_condition( Expression * newValue ) { condition = newValue; } 205 206 std::list<Statement *> & get_statements() { return stmts; } 207 void set_statements( std::list<Statement *> & newValue ) { stmts = newValue; } 208 209 virtual void accept( Visitor & v ) override { v.visit( this ); } 210 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 211 212 virtual CaseStmt * clone() const override { return new CaseStmt( *this ); } 213 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 214 214 private: 215 215 bool _isDefault; … … 218 218 class WhileStmt : public Statement { 219 219 public: 220 Expression * condition;221 Statement * body;220 Expression * condition; 221 Statement * body; 222 222 std::list<Statement *> initialization; 223 223 bool isDoWhile; 224 224 225 WhileStmt( Expression *condition, 226 Statement *body, std::list<Statement *> & initialization, bool isDoWhile = false ); 227 WhileStmt( const WhileStmt &other ); 225 WhileStmt( Expression * condition, Statement * body, std::list<Statement *> & initialization, bool isDoWhile = false ); 226 WhileStmt( const WhileStmt & other ); 228 227 virtual ~WhileStmt(); 229 228 230 Expression * get_condition() { return condition; }231 void set_condition( Expression * newValue ) { condition = newValue; }232 Statement * get_body() { return body; }233 void set_body( Statement * newValue ) { body = newValue; }229 Expression * get_condition() { return condition; } 230 void set_condition( Expression * newValue ) { condition = newValue; } 231 Statement * get_body() { return body; } 232 void set_body( Statement * newValue ) { body = newValue; } 234 233 bool get_isDoWhile() { return isDoWhile; } 235 234 void set_isDoWhile( bool newValue ) { isDoWhile = newValue; } 236 235 237 virtual WhileStmt * clone() const override { return new WhileStmt( *this ); }238 virtual void accept( Visitor & v ) override { v.visit( this ); }239 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }240 virtual void print( std::ostream & os, Indenter indent = {} ) const override;236 virtual WhileStmt * clone() const override { return new WhileStmt( *this ); } 237 virtual void accept( Visitor & v ) override { v.visit( this ); } 238 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 239 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 241 240 }; 242 241 … … 244 243 public: 245 244 std::list<Statement *> initialization; 246 Expression *condition; 247 Expression *increment; 248 Statement *body; 249 250 ForStmt( std::list<Statement *> initialization, 251 Expression *condition = 0, Expression *increment = 0, Statement *body = 0 ); 252 ForStmt( const ForStmt &other ); 245 Expression * condition; 246 Expression * increment; 247 Statement * body; 248 249 ForStmt( std::list<Statement *> initialization, Expression * condition = 0, Expression * increment = 0, Statement * body = 0 ); 250 ForStmt( const ForStmt & other ); 253 251 virtual ~ForStmt(); 254 252 255 std::list<Statement *> & get_initialization() { return initialization; }256 Expression * get_condition() { return condition; }257 void set_condition( Expression * newValue ) { condition = newValue; }258 Expression * get_increment() { return increment; }259 void set_increment( Expression * newValue ) { increment = newValue; }260 Statement * get_body() { return body; }261 void set_body( Statement * newValue ) { body = newValue; }262 263 virtual ForStmt * clone() const override { return new ForStmt( *this ); }264 virtual void accept( Visitor & v ) override { v.visit( this ); }265 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }266 virtual void print( std::ostream & os, Indenter indent = {} ) const override;253 std::list<Statement *> & get_initialization() { return initialization; } 254 Expression * get_condition() { return condition; } 255 void set_condition( Expression * newValue ) { condition = newValue; } 256 Expression * get_increment() { return increment; } 257 void set_increment( Expression * newValue ) { increment = newValue; } 258 Statement * get_body() { return body; } 259 void set_body( Statement * newValue ) { body = newValue; } 260 261 virtual ForStmt * clone() const override { return new ForStmt( *this ); } 262 virtual void accept( Visitor & v ) override { v.visit( this ); } 263 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 264 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 267 265 }; 268 266 … … 274 272 const Label originalTarget; 275 273 Label target; 276 Expression * computedTarget;274 Expression * computedTarget; 277 275 Type type; 278 276 279 277 BranchStmt( Label target, Type ) throw (SemanticErrorException); 280 BranchStmt( Expression * computedTarget, Type ) throw (SemanticErrorException);278 BranchStmt( Expression * computedTarget, Type ) throw (SemanticErrorException); 281 279 282 280 Label get_originalTarget() { return originalTarget; } … … 284 282 void set_target( Label newValue ) { target = newValue; } 285 283 286 Expression * get_computedTarget() { return computedTarget; }284 Expression * get_computedTarget() { return computedTarget; } 287 285 void set_target( Expression * newValue ) { computedTarget = newValue; } 288 286 289 287 Type get_type() { return type; } 290 const char * get_typename() { return brType[ type ]; }291 292 virtual BranchStmt * clone() const override { return new BranchStmt( *this ); }293 virtual void accept( Visitor & v ) override { v.visit( this ); }294 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }295 virtual void print( std::ostream & os, Indenter indent = {} ) const override;288 const char * get_typename() { return brType[ type ]; } 289 290 virtual BranchStmt * clone() const override { return new BranchStmt( *this ); } 291 virtual void accept( Visitor & v ) override { v.visit( this ); } 292 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 293 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 296 294 private: 297 static const char * brType[];295 static const char * brType[]; 298 296 }; 299 297 300 298 class ReturnStmt : public Statement { 301 299 public: 302 Expression * expr;303 304 ReturnStmt( Expression * expr );305 ReturnStmt( const ReturnStmt & other );300 Expression * expr; 301 302 ReturnStmt( Expression * expr ); 303 ReturnStmt( const ReturnStmt & other ); 306 304 virtual ~ReturnStmt(); 307 305 308 Expression * get_expr() { return expr; }309 void set_expr( Expression * newValue ) { expr = newValue; }310 311 virtual ReturnStmt * clone() const override { return new ReturnStmt( *this ); }312 virtual void accept( Visitor & v ) override { v.visit( this ); }313 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }314 virtual void print( std::ostream & os, Indenter indent = {} ) const override;306 Expression * get_expr() { return expr; } 307 void set_expr( Expression * newValue ) { expr = newValue; } 308 309 virtual ReturnStmt * clone() const override { return new ReturnStmt( *this ); } 310 virtual void accept( Visitor & v ) override { v.visit( this ); } 311 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 312 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 315 313 }; 316 314 … … 324 322 325 323 ThrowStmt( Kind kind, Expression * expr, Expression * target = nullptr ); 326 ThrowStmt( const ThrowStmt & other );324 ThrowStmt( const ThrowStmt & other ); 327 325 virtual ~ThrowStmt(); 328 326 … … 333 331 void set_target( Expression * newTarget ) { target = newTarget; } 334 332 335 virtual ThrowStmt * clone() const override { return new ThrowStmt( *this ); }336 virtual void accept( Visitor & v ) override { v.visit( this ); }337 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }338 virtual void print( std::ostream & os, Indenter indent = {} ) const override;333 virtual ThrowStmt * clone() const override { return new ThrowStmt( *this ); } 334 virtual void accept( Visitor & v ) override { v.visit( this ); } 335 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 336 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 339 337 }; 340 338 … … 345 343 FinallyStmt * finallyBlock; 346 344 347 TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> &handlers, FinallyStmt *finallyBlock = 0 );348 TryStmt( const TryStmt & other );345 TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = 0 ); 346 TryStmt( const TryStmt & other ); 349 347 virtual ~TryStmt(); 350 348 351 CompoundStmt * get_block() const { return block; }352 void set_block( CompoundStmt * newValue ) { block = newValue; }349 CompoundStmt * get_block() const { return block; } 350 void set_block( CompoundStmt * newValue ) { block = newValue; } 353 351 std::list<CatchStmt *>& get_catchers() { return handlers; } 354 352 355 FinallyStmt * get_finally() const { return finallyBlock; }356 void set_finally( FinallyStmt * newValue ) { finallyBlock = newValue; }357 358 virtual TryStmt * clone() const override { return new TryStmt( *this ); }359 virtual void accept( Visitor & v ) override { v.visit( this ); }360 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }361 virtual void print( std::ostream & os, Indenter indent = {} ) const override;353 FinallyStmt * get_finally() const { return finallyBlock; } 354 void set_finally( FinallyStmt * newValue ) { finallyBlock = newValue; } 355 356 virtual TryStmt * clone() const override { return new TryStmt( *this ); } 357 virtual void accept( Visitor & v ) override { v.visit( this ); } 358 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 359 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 362 360 }; 363 361 … … 367 365 368 366 const Kind kind; 369 Declaration * decl;370 Expression * cond;371 Statement * body;372 373 CatchStmt( Kind kind, Declaration * decl,374 Expression * cond, Statement *body );375 CatchStmt( const CatchStmt & other );367 Declaration * decl; 368 Expression * cond; 369 Statement * body; 370 371 CatchStmt( Kind kind, Declaration * decl, 372 Expression * cond, Statement * body ); 373 CatchStmt( const CatchStmt & other ); 376 374 virtual ~CatchStmt(); 377 375 378 376 Kind get_kind() { return kind; } 379 Declaration * get_decl() { return decl; }380 void set_decl( Declaration * newValue ) { decl = newValue; }381 Expression * get_cond() { return cond; }382 void set_cond( Expression * newCond ) { cond = newCond; }383 Statement * get_body() { return body; }384 void set_body( Statement * newValue ) { body = newValue; }385 386 virtual CatchStmt * clone() const override { return new CatchStmt( *this ); }387 virtual void accept( Visitor & v ) override { v.visit( this ); }388 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }389 virtual void print( std::ostream & os, Indenter indent = {} ) const override;377 Declaration * get_decl() { return decl; } 378 void set_decl( Declaration * newValue ) { decl = newValue; } 379 Expression * get_cond() { return cond; } 380 void set_cond( Expression * newCond ) { cond = newCond; } 381 Statement * get_body() { return body; } 382 void set_body( Statement * newValue ) { body = newValue; } 383 384 virtual CatchStmt * clone() const override { return new CatchStmt( *this ); } 385 virtual void accept( Visitor & v ) override { v.visit( this ); } 386 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 387 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 390 388 }; 391 389 392 390 class FinallyStmt : public Statement { 393 391 public: 394 CompoundStmt * block;395 396 FinallyStmt( CompoundStmt * block );397 FinallyStmt( const FinallyStmt & other );392 CompoundStmt * block; 393 394 FinallyStmt( CompoundStmt * block ); 395 FinallyStmt( const FinallyStmt & other ); 398 396 virtual ~FinallyStmt(); 399 397 400 CompoundStmt * get_block() const { return block; }401 void set_block( CompoundStmt * newValue ) { block = newValue; }402 403 virtual FinallyStmt * clone() const override { return new FinallyStmt( *this ); }404 virtual void accept( Visitor & v ) override { v.visit( this ); }405 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }406 virtual void print( std::ostream & os, Indenter indent = {} ) const override;398 CompoundStmt * get_block() const { return block; } 399 void set_block( CompoundStmt * newValue ) { block = newValue; } 400 401 virtual FinallyStmt * clone() const override { return new FinallyStmt( *this ); } 402 virtual void accept( Visitor & v ) override { v.visit( this ); } 403 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 404 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 407 405 }; 408 406 … … 438 436 } orelse; 439 437 440 virtual WaitForStmt * clone() const override { return new WaitForStmt( *this ); }441 virtual void accept( Visitor & v ) override { v.visit( this ); }442 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }443 virtual void print( std::ostream & os, Indenter indent = {} ) const override;438 virtual WaitForStmt * clone() const override { return new WaitForStmt( *this ); } 439 virtual void accept( Visitor & v ) override { v.visit( this ); } 440 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 441 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 444 442 445 443 }; … … 464 462 class DeclStmt : public Statement { 465 463 public: 466 Declaration * decl;467 468 DeclStmt( Declaration * decl );469 DeclStmt( const DeclStmt & other );464 Declaration * decl; 465 466 DeclStmt( Declaration * decl ); 467 DeclStmt( const DeclStmt & other ); 470 468 virtual ~DeclStmt(); 471 469 472 Declaration *get_decl() const { return decl; } 473 void set_decl( Declaration *newValue ) { decl = newValue; } 474 475 virtual DeclStmt *clone() const override { return new DeclStmt( *this ); } 476 virtual void accept( Visitor &v ) override { v.visit( this ); } 477 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 478 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 479 }; 480 481 482 /// represents an implicit application of a constructor or destructor. Qualifiers are replaced 483 /// immediately before and after the call so that qualified objects can be constructed 484 /// with the same functions as unqualified objects. 470 Declaration * get_decl() const { return decl; } 471 void set_decl( Declaration * newValue ) { decl = newValue; } 472 473 virtual DeclStmt * clone() const override { return new DeclStmt( *this ); } 474 virtual void accept( Visitor & v ) override { v.visit( this ); } 475 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 476 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 477 }; 478 479 480 /// represents an implicit application of a constructor or destructor. Qualifiers are replaced immediately before and 481 /// after the call so that qualified objects can be constructed with the same functions as unqualified objects. 485 482 class ImplicitCtorDtorStmt : public Statement { 486 483 public: … … 492 489 virtual ~ImplicitCtorDtorStmt(); 493 490 494 Statement * get_callStmt() const { return callStmt; }491 Statement * get_callStmt() const { return callStmt; } 495 492 void set_callStmt( Statement * newValue ) { callStmt = newValue; } 496 493 497 virtual ImplicitCtorDtorStmt * clone() const override { return new ImplicitCtorDtorStmt( *this ); }498 virtual void accept( Visitor & v ) override { v.visit( this ); }499 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }500 virtual void print( std::ostream & os, Indenter indent = {} ) const override;494 virtual ImplicitCtorDtorStmt * clone() const override { return new ImplicitCtorDtorStmt( *this ); } 495 virtual void accept( Visitor & v ) override { v.visit( this ); } 496 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 497 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 501 498 }; 502 499 -
src/SynTree/SynTree.h
r6a9d4b4 r933f32f 34 34 class NamedTypeDecl; 35 35 class TypeDecl; 36 class FtypeDecl;37 class DtypeDecl;38 36 class TypedefDecl; 39 37 class AsmDecl; … … 90 88 class ConstructorExpr; 91 89 class CompoundLiteralExpr; 92 class UntypedValofExpr;93 90 class RangeExpr; 94 91 class UntypedTupleExpr; … … 132 129 class ConstructorInit; 133 130 134 class Subrange;135 136 131 //template <class T> // emulate a union with templates? 137 132 class Constant; -
src/SynTree/Type.cc
r6a9d4b4 r933f32f 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 : 3912 // Last Modified On : Thu Jan 31 21:54:16 2019 13 // Update Count : 43 14 14 // 15 15 #include "Type.h" … … 25 25 26 26 const char *BasicType::typeNames[] = { 27 #if 0 27 28 "_Bool", 28 29 "char", … … 49 50 "unsigned __int128", 50 51 "__float80", 51 "__float128" 52 "__float128", 53 "_Float16", 54 "_Float32", 55 "_Float32x", 56 "_Float64", 57 "_Float64x", 58 "_Float128", 59 "_Float128x", 60 "_Float16 _Complex", 61 "_Float32 _Complex", 62 "_Float32x _Complex", 63 "_Float64 _Complex", 64 "_Float64x _Complex", 65 "_Float128 _Complex", 66 "_Float128x _Complex", 67 #endif 68 "_Bool", 69 "char", 70 "signed char", 71 "unsigned char", 72 "signed short int", 73 "unsigned short int", 74 "signed int", 75 "unsigned int", 76 "signed long int", 77 "unsigned long int", 78 "signed long long int", 79 "unsigned long long int", 80 "__int128", 81 "unsigned __int128", 82 "_Float16", 83 "_Float16 _Complex", 84 "_Float32", 85 "_Float32 _Complex", 86 "float", 87 "float _Complex", 88 //"float _Imaginary", 89 "_Float32x", 90 "_Float32x _Complex", 91 "_Float64", 92 "_Float64 _Complex", 93 "double", 94 "double _Complex", 95 //"double _Imaginary", 96 "_Float64x", 97 "_Float64x _Complex", 98 "__float80", 99 "_Float128", 100 "_Float128 _Complex", 101 "__float128", 102 "long double", 103 "long double _Complex", 104 //"long double _Imaginary", 105 "_Float128x", 106 "_Float128x _Complex", 52 107 }; 53 108 static_assert( -
src/SynTree/Type.h
r6a9d4b4 r933f32f 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Sep 25 14:14:01 201713 // Update Count : 1 5412 // Last Modified On : Thu Feb 14 17:11:24 2019 13 // Update Count : 169 14 14 // 15 15 … … 207 207 class BasicType : public Type { 208 208 public: 209 // GENERATED START, DO NOT EDIT 210 // GENERATED BY BasicTypes-gen.cc 209 211 enum Kind { 210 212 Bool, … … 220 222 LongLongSignedInt, 221 223 LongLongUnsignedInt, 222 Float,223 Double,224 LongDouble,225 FloatComplex,226 DoubleComplex,227 LongDoubleComplex,228 FloatImaginary,229 DoubleImaginary,230 LongDoubleImaginary,231 224 SignedInt128, 232 225 UnsignedInt128, 233 Float80, 234 Float128, 226 uFloat16, 227 uFloat16Complex, 228 uFloat32, 229 uFloat32Complex, 230 Float, 231 FloatComplex, 232 uFloat32x, 233 uFloat32xComplex, 234 uFloat64, 235 uFloat64Complex, 236 Double, 237 DoubleComplex, 238 uFloat64x, 239 uFloat64xComplex, 240 uuFloat80, 241 uFloat128, 242 uFloat128Complex, 243 uuFloat128, 244 LongDouble, 245 LongDoubleComplex, 246 uFloat128x, 247 uFloat128xComplex, 235 248 NUMBER_OF_BASIC_TYPES 236 249 } kind; 250 // GENERATED END 237 251 238 252 static const char *typeNames[]; // string names for basic types, MUST MATCH with Kind -
src/SynTree/TypeSubstitution.cc
r6a9d4b4 r933f32f 64 64 } 65 65 66 void TypeSubstitution::addVar( std::string formalExpr, Expression *actualExpr ) { 67 varEnv[ formalExpr ] = actualExpr; 68 } 69 66 70 void TypeSubstitution::remove( std::string formalType ) { 67 71 TypeEnvType::iterator i = typeEnv.find( formalType ); … … 108 112 namespace { 109 113 struct EnvTrimmer { 110 TypeSubstitution * env, * newEnv; 111 EnvTrimmer( TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){} 114 const TypeSubstitution * env; 115 TypeSubstitution * newEnv; 116 EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){} 112 117 void previsit( TypeDecl * tyDecl ) { 113 118 // transfer known bindings for seen type variables … … 120 125 121 126 /// reduce environment to just the parts that are referenced in a given expression 122 TypeSubstitution * TypeSubstitution::newFromExpr( Expression * expr, TypeSubstitution * env ) {127 TypeSubstitution * TypeSubstitution::newFromExpr( Expression * expr, const TypeSubstitution * env ) { 123 128 if ( env ) { 124 129 TypeSubstitution * newEnv = new TypeSubstitution(); -
src/SynTree/TypeSubstitution.h
r6a9d4b4 r933f32f 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 09:52:24 201713 // Update Count : 312 // Last Modified On : Tue Apr 30 22:52:47 2019 13 // Update Count : 9 14 14 // 15 15 … … 19 19 #include <iosfwd> // for ostream 20 20 #include <list> // for list<>::iterator, _List_iterator 21 #include < map> // for _Rb_tree_iterator, map, map<>::val...22 #include < set> // for set21 #include <unordered_map> 22 #include <unordered_set> 23 23 #include <string> // for string, operator!= 24 24 #include <utility> // for pair … … 39 39 TypeSubstitution &operator=( const TypeSubstitution &other ); 40 40 41 template< typename SynTreeClass > int apply( SynTreeClass *&input ) ;42 template< typename SynTreeClass > int applyFree( SynTreeClass *&input ) ;41 template< typename SynTreeClass > int apply( SynTreeClass *&input ) const; 42 template< typename SynTreeClass > int applyFree( SynTreeClass *&input ) const; 43 43 44 44 void add( std::string formalType, Type *actualType ); … … 48 48 bool empty() const; 49 49 50 void addVar( std::string formalExpr, Expression *actualExpr ); 51 50 52 template< typename FormalIterator, typename ActualIterator > 51 53 void add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ); … … 56 58 57 59 /// create a new TypeSubstitution using bindings from env containing all of the type variables in expr 58 static TypeSubstitution * newFromExpr( Expression * expr, TypeSubstitution * env );60 static TypeSubstitution * newFromExpr( Expression * expr, const TypeSubstitution * env ); 59 61 60 62 void normalize(); … … 78 80 friend class PassVisitor; 79 81 80 typedef std:: map< std::string, Type* > TypeEnvType;81 typedef std:: map< std::string, Expression* > VarEnvType;82 typedef std::unordered_map< std::string, Type * > TypeEnvType; 83 typedef std::unordered_map< std::string, Expression * > VarEnvType; 82 84 TypeEnvType typeEnv; 83 85 VarEnvType varEnv; … … 89 91 auto begin() const -> decltype( typeEnv.begin() ) { return typeEnv.begin(); } 90 92 auto end() const -> decltype( typeEnv. end() ) { return typeEnv. end(); } 93 94 auto beginVar() -> decltype( varEnv.begin() ) { return varEnv.begin(); } 95 auto endVar() -> decltype( varEnv. end() ) { return varEnv. end(); } 96 auto beginVar() const -> decltype( varEnv.begin() ) { return varEnv.begin(); } 97 auto endVar() const -> decltype( varEnv. end() ) { return varEnv. end(); } 91 98 }; 92 99 … … 98 105 ActualIterator actualIt = actualBegin; 99 106 for ( ; formalIt != formalEnd; ++formalIt, ++actualIt ) { 100 if ( TypeDecl *formal = dynamic_cast< TypeDecl * >( *formalIt ) ) {101 if ( TypeExpr *actual = dynamic_cast< TypeExpr * >( *actualIt ) ) {107 if ( TypeDecl *formal = dynamic_cast< TypeDecl * >( *formalIt ) ) { 108 if ( TypeExpr *actual = dynamic_cast< TypeExpr * >( *actualIt ) ) { 102 109 if ( formal->get_name() != "" ) { 103 110 TypeEnvType::iterator i = typeEnv.find( formal->get_name() ); … … 130 137 // definitition must happen after PassVisitor is included so that WithGuards can be used 131 138 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> { 132 Substituter( TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}139 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {} 133 140 134 141 Type * postmutate( TypeInstType * aggregateUseType ); … … 143 150 void premutate( UnionInstType * aggregateUseType ); 144 151 145 TypeSubstitution & sub;152 const TypeSubstitution & sub; 146 153 int subCount = 0; 147 154 bool freeOnly; 148 typedef std:: set< std::string > BoundVarsType;155 typedef std::unordered_set< std::string > BoundVarsType; 149 156 BoundVarsType boundVars; 150 157 }; 151 158 152 159 template< typename SynTreeClass > 153 int TypeSubstitution::apply( SynTreeClass *&input ) {160 int TypeSubstitution::apply( SynTreeClass *&input ) const { 154 161 assert( input ); 155 162 PassVisitor<Substituter> sub( *this, false ); … … 163 170 164 171 template< typename SynTreeClass > 165 int TypeSubstitution::applyFree( SynTreeClass *&input ) {172 int TypeSubstitution::applyFree( SynTreeClass *&input ) const { 166 173 assert( input ); 167 174 PassVisitor<Substituter> sub( *this, true ); -
src/SynTree/Visitor.h
r6a9d4b4 r933f32f 123 123 virtual void visit( ConstructorInit * ctorInit ) = 0; 124 124 125 virtual void visit( Subrange * subrange ) = 0;126 127 125 virtual void visit( Constant * constant ) = 0; 128 126 -
src/SynTree/module.mk
r6a9d4b4 r933f32f 15 15 ############################################################################### 16 16 17 SRC += SynTree/Type.cc \ 18 SynTree/VoidType.cc \ 19 SynTree/BasicType.cc \ 20 SynTree/PointerType.cc \ 21 SynTree/ArrayType.cc \ 22 SynTree/ReferenceType.cc \ 23 SynTree/FunctionType.cc \ 24 SynTree/ReferenceToType.cc \ 25 SynTree/TupleType.cc \ 26 SynTree/TypeofType.cc \ 27 SynTree/AttrType.cc \ 28 SynTree/VarArgsType.cc \ 29 SynTree/ZeroOneType.cc \ 30 SynTree/Constant.cc \ 31 SynTree/Expression.cc \ 32 SynTree/TupleExpr.cc \ 33 SynTree/CommaExpr.cc \ 34 SynTree/TypeExpr.cc \ 35 SynTree/ApplicationExpr.cc \ 36 SynTree/AddressExpr.cc \ 37 SynTree/Statement.cc \ 38 SynTree/CompoundStmt.cc \ 39 SynTree/DeclStmt.cc \ 40 SynTree/Declaration.cc \ 41 SynTree/DeclarationWithType.cc \ 42 SynTree/ObjectDecl.cc \ 43 SynTree/FunctionDecl.cc \ 44 SynTree/AggregateDecl.cc \ 45 SynTree/NamedTypeDecl.cc \ 46 SynTree/TypeDecl.cc \ 47 SynTree/Initializer.cc \ 48 SynTree/TypeSubstitution.cc \ 49 SynTree/Attribute.cc \ 50 SynTree/DeclReplacer.cc 17 SRC_SYNTREE = \ 18 SynTree/Type.cc \ 19 SynTree/VoidType.cc \ 20 SynTree/BasicType.cc \ 21 SynTree/PointerType.cc \ 22 SynTree/ArrayType.cc \ 23 SynTree/ReferenceType.cc \ 24 SynTree/FunctionType.cc \ 25 SynTree/ReferenceToType.cc \ 26 SynTree/TupleType.cc \ 27 SynTree/TypeofType.cc \ 28 SynTree/AttrType.cc \ 29 SynTree/VarArgsType.cc \ 30 SynTree/ZeroOneType.cc \ 31 SynTree/Constant.cc \ 32 SynTree/Expression.cc \ 33 SynTree/TupleExpr.cc \ 34 SynTree/CommaExpr.cc \ 35 SynTree/TypeExpr.cc \ 36 SynTree/ApplicationExpr.cc \ 37 SynTree/AddressExpr.cc \ 38 SynTree/Statement.cc \ 39 SynTree/CompoundStmt.cc \ 40 SynTree/DeclStmt.cc \ 41 SynTree/Declaration.cc \ 42 SynTree/DeclarationWithType.cc \ 43 SynTree/ObjectDecl.cc \ 44 SynTree/FunctionDecl.cc \ 45 SynTree/AggregateDecl.cc \ 46 SynTree/NamedTypeDecl.cc \ 47 SynTree/TypeDecl.cc \ 48 SynTree/Initializer.cc \ 49 SynTree/TypeSubstitution.cc \ 50 SynTree/Attribute.cc \ 51 SynTree/DeclReplacer.cc 51 52 53 SRC += $(SRC_SYNTREE) 54 SRCDEMANGLE += $(SRC_SYNTREE) -
src/Tuples/TupleExpansion.cc
r6a9d4b4 r933f32f 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jun 21 17:35:04 201713 // Update Count : 1912 // Last Modified On : Wed Feb 13 18:14:12 2019 13 // Update Count : 21 14 14 // 15 15 … … 17 17 #include <cassert> // for assert 18 18 #include <list> // for list 19 19 #include <vector> 20 21 #include "AST/CVQualifiers.hpp" 22 #include "AST/Expr.hpp" 23 #include "AST/Node.hpp" 24 #include "AST/Type.hpp" 20 25 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd, WithGu... 21 26 #include "Common/ScopedMap.h" // for ScopedMap … … 58 63 }; 59 64 60 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public With TypeSubstitution {65 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution { 61 66 Type * postmutate( TupleType * tupleType ); 62 67 … … 314 319 return new TupleType( qualifiers, types ); 315 320 } 321 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) { 322 (void) exprs; 323 #warning Not implemented; needs Type.cpp in build 324 assertf(false, "Not implemented; needs Type.cpp in build"); 325 // // produce the TupleType which aggregates the types of the exprs 326 // std::vector<ast::ptr<ast::Type>> types; 327 // ast::CV::Qualifiers quals{ 328 // ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue | 329 // ast::CV::Atomic | ast::CV::Mutex }; 330 331 // for ( const ast::Expr * expr : exprs ) { 332 // assert( expr->result ); 333 // // if the type of any expr is void, the type of the entire tuple is void 334 // if ( expr->result->isVoid() ) return new ast::VoidType{}; 335 336 // // qualifiers on the tuple type are the qualifiers that exist on all components 337 // quals &= expr->result->qualifiers; 338 339 // types.emplace_back( expr->result ); 340 // } 341 342 // if ( exprs.empty() ) { quals = ast::CV::Qualifiers{}; } 343 // return new ast::TupleType{ std::move(types), quals }; 344 } 316 345 317 346 TypeInstType * isTtype( Type * type ) { -
src/Tuples/Tuples.h
r6a9d4b4 r933f32f 19 19 #include <vector> 20 20 21 #include "AST/Fwd.hpp" 22 #include "AST/Node.hpp" 21 23 #include "SynTree/Expression.h" 22 24 #include "SynTree/Declaration.h" … … 27 29 namespace Tuples { 28 30 // TupleAssignment.cc 29 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 31 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 30 32 std::vector< ResolvExpr::AlternativeFinder >& args ); 31 33 32 34 // TupleExpansion.cc 33 35 /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate … … 42 44 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types 43 45 Type * makeTupleType( const std::list< Expression * > & exprs ); 46 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ); 44 47 45 48 /// returns a TypeInstType if `type` is a ttype, nullptr otherwise 46 49 TypeInstType * isTtype( Type * type ); 50 const ast::TypeInstType * isTtype( const ast::Type * type ); 47 51 48 52 /// returns true if the expression may contain side-effects. -
src/Tuples/module.mk
r6a9d4b4 r933f32f 15 15 ############################################################################### 16 16 17 SRC += Tuples/TupleAssignment.cc \ 18 Tuples/TupleExpansion.cc \ 19 Tuples/Explode.cc 17 SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc 18 SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc -
src/Validate/module.mk
r6a9d4b4 r933f32f 15 15 ############################################################################### 16 16 17 SRC += Validate/HandleAttributes.cc \18 Validate/FindSpecialDecls.cc17 SRC += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc 18 SRCDEMANGLE += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc -
src/config.h.in
r6a9d4b4 r933f32f 52 52 #undef CFA_VERSION_SHORT 53 53 54 /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP 55 systems. This function is required for `alloca.c' support on those systems. 56 */ 57 #undef CRAY_STACKSEG_END 58 59 /* Define to 1 if using `alloca.c'. */ 60 #undef C_ALLOCA 61 62 /* Define to 1 if you have `alloca', as a function or macro. */ 63 #undef HAVE_ALLOCA 64 65 /* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). 66 */ 67 #undef HAVE_ALLOCA_H 54 /* Have compiler warning cast-function-type. */ 55 #undef HAVE_CAST_FUNCTION_TYPE 68 56 69 57 /* Define to 1 if you have the <dlfcn.h> header file. */ 70 58 #undef HAVE_DLFCN_H 71 59 72 /* Define to 1 if you have the <fenv.h> header file. */73 #undef HAVE_FENV_H74 75 /* Define to 1 if you have the <float.h> header file. */76 #undef HAVE_FLOAT_H77 78 60 /* Define to 1 if you have the <inttypes.h> header file. */ 79 61 #undef HAVE_INTTYPES_H 80 62 63 /* Have keywords _FloatXX. */ 64 #undef HAVE_KEYWORDS_FLOATXX 65 81 66 /* Define to 1 if you have the <libintl.h> header file. */ 82 67 #undef HAVE_LIBINTL_H 83 84 /* Define to 1 if you have the <limits.h> header file. */85 #undef HAVE_LIMITS_H86 68 87 69 /* Define to 1 if you have the <malloc.h> header file. */ … … 91 73 #undef HAVE_MEMORY_H 92 74 93 /* Define to 1 if you have the `memset' function. */94 #undef HAVE_MEMSET95 96 /* Define to 1 if you have the `putenv' function. */97 #undef HAVE_PUTENV98 99 /* Define to 1 if stdbool.h conforms to C99. */100 #undef HAVE_STDBOOL_H101 102 /* Define to 1 if you have the <stddef.h> header file. */103 #undef HAVE_STDDEF_H104 105 75 /* Define to 1 if you have the <stdint.h> header file. */ 106 76 #undef HAVE_STDINT_H … … 109 79 #undef HAVE_STDLIB_H 110 80 111 /* Define to 1 if you have the `strchr' function. */112 #undef HAVE_STRCHR113 114 81 /* Define to 1 if you have the <strings.h> header file. */ 115 82 #undef HAVE_STRINGS_H … … 117 84 /* Define to 1 if you have the <string.h> header file. */ 118 85 #undef HAVE_STRING_H 119 120 /* Define to 1 if you have the `strtol' function. */121 #undef HAVE_STRTOL122 86 123 87 /* Define to 1 if you have the <sys/stat.h> header file. */ … … 130 94 #undef HAVE_UNISTD_H 131 95 132 /* Define to 1 if the system has the type `_ Bool'. */133 #undef HAVE__ BOOL96 /* Define to 1 if the system has the type `_Float32'. */ 97 #undef HAVE__FLOAT32 134 98 135 99 /* Define to the sub-directory where libtool stores uninstalled libraries. */ … … 157 121 #undef PACKAGE_VERSION 158 122 159 /* If using the C implementation of alloca, define if you know the160 direction of stack growth for your system; otherwise it will be161 automatically deduced at runtime.162 STACK_DIRECTION > 0 => grows toward higher addresses163 STACK_DIRECTION < 0 => grows toward lower addresses164 STACK_DIRECTION = 0 => direction of growth unknown */165 #undef STACK_DIRECTION166 167 123 /* Define to 1 if you have the ANSI C header files. */ 168 124 #undef STDC_HEADERS … … 180 136 `char[]'. */ 181 137 #undef YYTEXT_POINTER 182 183 /* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,184 <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the185 #define below would cause a syntax error. */186 #undef _UINT32_T187 188 /* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,189 <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the190 #define below would cause a syntax error. */191 #undef _UINT8_T192 193 /* Define to `__inline__' or `__inline' if that's what the C compiler194 calls it, or to nothing if 'inline' is not supported under any name. */195 #ifndef __cplusplus196 #undef inline197 #endif198 199 /* Define to the type of a signed integer type of width exactly 16 bits if200 such a type exists and the standard includes do not define it. */201 #undef int16_t202 203 /* Define to the type of a signed integer type of width exactly 32 bits if204 such a type exists and the standard includes do not define it. */205 #undef int32_t206 207 /* Define to the type of a signed integer type of width exactly 8 bits if such208 a type exists and the standard includes do not define it. */209 #undef int8_t210 211 /* Define to the equivalent of the C99 'restrict' keyword, or to212 nothing if this is not supported. Do not define if restrict is213 supported directly. */214 #undef restrict215 /* Work around a bug in Sun C++: it does not support _Restrict or216 __restrict__, even though the corresponding Sun C compiler ends up with217 "#define restrict _Restrict" or "#define restrict __restrict__" in the218 previous line. Perhaps some future version of Sun C++ will work with219 restrict; if so, hopefully it defines __RESTRICT like Sun C does. */220 #if defined __SUNPRO_CC && !defined __RESTRICT221 # define _Restrict222 # define __restrict__223 #endif224 225 /* Define to `unsigned int' if <sys/types.h> does not define. */226 #undef size_t227 228 /* Define to the type of an unsigned integer type of width exactly 16 bits if229 such a type exists and the standard includes do not define it. */230 #undef uint16_t231 232 /* Define to the type of an unsigned integer type of width exactly 32 bits if233 such a type exists and the standard includes do not define it. */234 #undef uint32_t235 236 /* Define to the type of an unsigned integer type of width exactly 8 bits if237 such a type exists and the standard includes do not define it. */238 #undef uint8_t -
src/include/cassert
r6a9d4b4 r933f32f 45 45 } 46 46 47 extern void abort(const char *fmt, ... ) noexcept __attribute__((noreturn, format(printf, 1, 2))); 47 48 // Local Variables: // 48 49 // tab-width: 4 // -
src/main.cc
r6a9d4b4 r933f32f 7 7 // main.cc -- 8 8 // 9 // Author : Richard C. Bilson9 // Author : Peter Buhr and Rob Schluntz 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 26 08:11:19 201813 // Update Count : 49912 // Last Modified On : Fri May 3 16:10:52 2019 13 // Update Count : 599 14 14 // 15 15 … … 24 24 #include <fstream> // for ofstream 25 25 #include <iostream> // for operator<<, basic_ostream 26 #include <iomanip> 26 27 #include <iterator> // for back_inserter 27 28 #include <list> // for list … … 37 38 #include "CodeTools/TrackLoc.h" // for fillLocations 38 39 #include "Common/CompilerError.h" // for CompilerError 39 #include "Common/ Heap.h"40 #include "Common/Stats.h" 40 41 #include "Common/PassVisitor.h" 42 // #include "AST/Pass.hpp" 41 43 #include "Common/SemanticError.h" // for SemanticError 42 44 #include "Common/UnimplementedError.h" // for UnimplementedError … … 65 67 using namespace std; 66 68 67 #define PASS(name, pass) \ 69 static void NewPass( const char * const name ) { 70 Stats::Heap::newPass( name ); 71 using namespace Stats::Counters; 72 { 73 static auto group = build<CounterGroup>( "Pass Visitor" ); 74 auto pass = build<CounterGroup>( name, group ); 75 pass_visitor_stats.depth = 0; 76 pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass ); 77 pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass ); 78 } 79 { 80 static auto group = build<CounterGroup>( "Syntax Node" ); 81 auto pass = build<CounterGroup>( name, group ); 82 BaseSyntaxNode::new_nodes = build<SimpleCounter>( "Allocs", pass ); 83 } 84 } 85 86 #define PASS( name, pass ) \ 68 87 if ( errorp ) { cerr << name << endl; } \ 69 HeapStats::newPass(name); \ 70 pass; 88 NewPass(name); \ 89 Stats::Time::StartBlock(name); \ 90 pass; \ 91 Stats::Time::StopBlock(); 71 92 72 93 LinkageSpec::Spec linkage = LinkageSpec::Cforall; … … 74 95 DeclarationNode * parseTree = nullptr; // program parse tree 75 96 76 st d::string PreludeDirector = "";97 static std::string PreludeDirector = ""; 77 98 78 99 static void parse_cmdline( int argc, char *argv[], const char *& filename ); … … 130 151 } // backtrace 131 152 132 void sigSegvBusHandler( int sig_num ) {153 static void sigSegvBusHandler( int sig_num ) { 133 154 cerr << "*CFA runtime error* program cfa-cpp terminated with " 134 155 << (sig_num == SIGSEGV ? "segment fault" : "bus error") … … 136 157 backtrace( 2 ); // skip first 2 stack frames 137 158 //_exit( EXIT_FAILURE ); 138 abort(); 159 abort(); // cause core dump for debugging 139 160 } // sigSegvBusHandler 140 161 141 void sigAbortHandler( __attribute__((unused)) int sig_num ) {162 static void sigAbortHandler( __attribute__((unused)) int sig_num ) { 142 163 backtrace( 6 ); // skip first 6 stack frames 143 164 signal( SIGABRT, SIG_DFL); // reset default signal handler 144 raise( SIGABRT ); // reraise SIGABRT165 raise( SIGABRT ); // reraise SIGABRT 145 166 } // sigAbortHandler 146 167 … … 148 169 int main( int argc, char * argv[] ) { 149 170 FILE * input; // use FILE rather than istream because yyin is FILE 150 ostream * output = & cout;151 const char * filename = nullptr;171 ostream * output = & cout; 172 const char * filename = nullptr; 152 173 list< Declaration * > translationUnit; 153 174 … … 181 202 } // if 182 203 204 Stats::Time::StartGlobal(); 205 NewPass("Parse"); 206 Stats::Time::StartBlock("Parse"); 207 183 208 // read in the builtins, extras, and the prelude 184 209 if ( ! nopreludep ) { // include gcc builtins … … 215 240 parseTree->printList( cout ); 216 241 delete parseTree; 217 return 0;242 return EXIT_SUCCESS; 218 243 } // if 219 244 … … 224 249 if ( astp ) { 225 250 dump( translationUnit ); 226 return 0;251 return EXIT_SUCCESS; 227 252 } // if 228 253 … … 231 256 // works okay for now. 232 257 CodeTools::fillLocations( translationUnit ); 258 Stats::Time::StopBlock(); 233 259 234 260 // add the assignment statement after the initialization of a type parameter 235 PASS( " validate", SymTab::validate( translationUnit, symtabp ) );261 PASS( "Validate", SymTab::validate( translationUnit, symtabp ) ); 236 262 if ( symtabp ) { 237 263 deleteAll( translationUnit ); 238 return 0;264 return EXIT_SUCCESS; 239 265 } // if 240 266 … … 242 268 PassVisitor<ResolvExpr::AlternativePrinter> printer( cout ); 243 269 acceptAll( translationUnit, printer ); 244 return 0;270 return EXIT_SUCCESS; 245 271 } // if 246 272 247 273 if ( validp ) { 248 274 dump( translationUnit ); 249 return 0;250 } // if 251 252 PASS( " fixLabels", ControlStruct::fixLabels( translationUnit ) );253 PASS( " fixNames", CodeGen::fixNames( translationUnit ) );254 PASS( " genInit", InitTweak::genInit( translationUnit ) );255 PASS( " expandMemberTuples" , Tuples::expandMemberTuples( translationUnit ) );275 return EXIT_SUCCESS; 276 } // if 277 278 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) ); 279 PASS( "Fix Names", CodeGen::fixNames( translationUnit ) ); 280 PASS( "Gen Init", InitTweak::genInit( translationUnit ) ); 281 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) ); 256 282 if ( libcfap ) { 257 283 // generate the bodies of cfa library functions … … 262 288 CodeTools::printDeclStats( translationUnit ); 263 289 deleteAll( translationUnit ); 264 return 0;265 } 290 return EXIT_SUCCESS; 291 } // if 266 292 267 293 if ( bresolvep ) { 268 294 dump( translationUnit ); 269 return 0;295 return EXIT_SUCCESS; 270 296 } // if 271 297 … … 274 300 if ( resolvprotop ) { 275 301 CodeTools::dumpAsResolvProto( translationUnit ); 276 return 0;277 } 278 279 PASS( " resolve", ResolvExpr::resolve( translationUnit ) );302 return EXIT_SUCCESS; 303 } // if 304 305 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); 280 306 if ( exprp ) { 281 307 dump( translationUnit ); 282 return 0;308 return EXIT_SUCCESS; 283 309 } // if 284 310 285 311 // fix ObjectDecl - replaces ConstructorInit nodes 286 PASS( " fixInit", InitTweak::fix( translationUnit, buildingLibrary() ) );312 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) ); 287 313 if ( ctorinitp ) { 288 314 dump ( translationUnit ); 289 return 0;290 } // if 291 292 PASS( " expandUniqueExpr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused293 294 PASS( " translateEHM" , ControlStruct::translateEHM( translationUnit ) );295 296 PASS( " generateWaitfor" , Concurrency::generateWaitFor( translationUnit ) );297 298 PASS( " convertSpecializations", GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded299 300 PASS( " expandTuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this?315 return EXIT_SUCCESS; 316 } // if 317 318 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused 319 320 PASS( "Translate EHM" , ControlStruct::translateEHM( translationUnit ) ); 321 322 PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) ); 323 324 PASS( "Convert Specializations", GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded 325 326 PASS( "Expand Tuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this? 301 327 302 328 if ( tuplep ) { 303 329 dump( translationUnit ); 304 return 0;305 } 306 307 PASS( " virtual expandCasts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM308 309 PASS( " instantiateGenerics", GenPoly::instantiateGeneric( translationUnit ) );330 return EXIT_SUCCESS; 331 } // if 332 333 PASS( "Virtual Expand Casts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM 334 335 PASS( "Instantiate Generics", GenPoly::instantiateGeneric( translationUnit ) ); 310 336 if ( genericsp ) { 311 337 dump( translationUnit ); 312 return 0;313 } 314 PASS( " convertLvalue", GenPoly::convertLvalue( translationUnit ) );338 return EXIT_SUCCESS; 339 } // if 340 PASS( "Convert L-Value", GenPoly::convertLvalue( translationUnit ) ); 315 341 316 342 317 343 if ( bboxp ) { 318 344 dump( translationUnit ); 319 return 0;320 } // if 321 PASS( " box", GenPoly::box( translationUnit ) );345 return EXIT_SUCCESS; 346 } // if 347 PASS( "Box", GenPoly::box( translationUnit ) ); 322 348 323 349 if ( bcodegenp ) { 324 350 dump( translationUnit ); 325 return 0;326 } 351 return EXIT_SUCCESS; 352 } // if 327 353 328 354 if ( optind < argc ) { // any commands after the flags and input file ? => output file name … … 331 357 332 358 CodeTools::fillLocations( translationUnit ); 333 PASS( " codegen", CodeGen::generate( translationUnit, *output, ! noprotop, prettycodegenp, true, linemarks ) );359 PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) ); 334 360 335 361 CodeGen::FixMain::fix( *output, (PreludeDirector + "/bootloader.c").c_str() ); … … 347 373 delete output; 348 374 } // if 349 return 1;375 return EXIT_FAILURE; 350 376 } catch ( UnimplementedError &e ) { 351 377 cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl; … … 353 379 delete output; 354 380 } // if 355 return 1;381 return EXIT_FAILURE; 356 382 } catch ( CompilerError &e ) { 357 383 cerr << "Compiler Error: " << e.get_what() << endl; … … 360 386 delete output; 361 387 } // if 362 return 1;363 } catch (...) {388 return EXIT_FAILURE; 389 } catch ( ... ) { 364 390 std::exception_ptr eptr = std::current_exception(); 365 391 try { 366 392 if (eptr) { 367 393 std::rethrow_exception(eptr); 368 } 369 else { 370 std::cerr << "Exception Uncaught and Unkown" << std::endl; 371 } 394 } else { 395 std::cerr << "Exception Uncaught and Unknown" << std::endl; 396 } // if 372 397 } catch(const std::exception& e) { 373 398 std::cerr << "Uncaught Exception \"" << e.what() << "\"\n"; 374 } 375 return 1;376 } // try399 } // try 400 return EXIT_FAILURE; 401 } // try 377 402 378 403 deleteAll( translationUnit ); 379 if(!libcfap && !treep) HeapStats::printStats();380 return 0;404 Stats::print(); 405 return EXIT_SUCCESS; 381 406 } // main 382 407 383 void parse_cmdline( int argc, char * argv[], const char *& filename ) { 384 enum { Ast, Bbox, Bresolver, CtorInitFix, DeclStats, Expr, ExprAlt, Grammar, LibCFA, Linemarks, Nolinemarks, Nopreamble, Parse, PreludeDir, Prototypes, Resolver, ResolvProto, Symbol, Tree, TupleExpansion, Validate, }; 385 386 static struct option long_opts[] = { 387 { "ast", no_argument, 0, Ast }, 388 { "before-box", no_argument, 0, Bbox }, 389 { "before-resolver", no_argument, 0, Bresolver }, 390 { "ctorinitfix", no_argument, 0, CtorInitFix }, 391 { "decl-stats", no_argument, 0, DeclStats }, 392 { "expr", no_argument, 0, Expr }, 393 { "expralt", no_argument, 0, ExprAlt }, 394 { "grammar", no_argument, 0, Grammar }, 395 { "libcfa", no_argument, 0, LibCFA }, 396 { "line-marks", no_argument, 0, Linemarks }, 397 { "no-line-marks", no_argument, 0, Nolinemarks }, 398 { "no-preamble", no_argument, 0, Nopreamble }, 399 { "parse", no_argument, 0, Parse }, 400 { "prelude-dir", required_argument, 0, PreludeDir }, 401 { "no-prototypes", no_argument, 0, Prototypes }, 402 { "resolver", no_argument, 0, Resolver }, 403 { "resolv-proto", no_argument, 0, ResolvProto }, 404 { "symbol", no_argument, 0, Symbol }, 405 { "tree", no_argument, 0, Tree }, 406 { "tuple-expansion", no_argument, 0, TupleExpansion }, 407 { "validate", no_argument, 0, Validate }, 408 { 0, 0, 0, 0 } 409 }; // long_opts 410 int long_index; 411 408 409 static const char optstring[] = ":hlLmNn:pP:S:twW:D:F:"; 410 411 enum { PreludeDir = 128 }; 412 static struct option long_opts[] = { 413 { "help", no_argument, nullptr, 'h' }, 414 { "libcfa", no_argument, nullptr, 'l' }, 415 { "linemarks", no_argument, nullptr, 'L' }, 416 { "no-main", no_argument, 0, 'm' }, 417 { "no-linemarks", no_argument, nullptr, 'N' }, 418 { "no-prelude", no_argument, nullptr, 'n' }, 419 { "prototypes", no_argument, nullptr, 'p' }, 420 { "print", required_argument, nullptr, 'P' }, 421 { "prelude-dir", required_argument, nullptr, PreludeDir }, 422 { "statistics", required_argument, nullptr, 'S' }, 423 { "tree", no_argument, nullptr, 't' }, 424 { "", no_argument, nullptr, 0 }, // -w 425 { "", no_argument, nullptr, 0 }, // -W 426 { "", no_argument, nullptr, 0 }, // -D 427 { "", no_argument, nullptr, 0 }, // -F 428 { nullptr, 0, nullptr, 0 } 429 }; // long_opts 430 431 static const char * description[] = { 432 "print help message", // -h 433 "generate libcfa.c", // -l 434 "generate line marks", // -L 435 "do not replace main", // -m 436 "do not generate line marks", // -N 437 "do not read prelude", // -n 438 "generate prototypes for prelude functions", // -p 439 "print", // -P 440 "<directory> prelude directory for debug/nodebug", // no flag 441 "<option-list> enable profiling information:\n counters,heap,time,all,none", // -S 442 "build in tree", // -t 443 "", // -w 444 "", // -W 445 "", // -D 446 "", // -F 447 }; // description 448 449 static_assert( sizeof( long_opts ) / sizeof( long_opts[0] ) - 1 == sizeof( description ) / sizeof( description[0] ), "Long opts and description must match" ); 450 451 static struct Printopts { 452 const char * name; 453 int & flag; 454 int val; 455 const char * descript; 456 } printopts[] = { 457 { "altexpr", expraltp, true, "alternatives for expressions" }, 458 { "ascodegen", codegenp, true, "as codegen rather than AST" }, 459 { "ast", astp, true, "AST after parsing" }, 460 { "astdecl", validp, true, "AST after declaration validation pass" }, 461 { "asterr", errorp, true, "AST on error" }, 462 { "astexpr", exprp, true, "AST after expression analysis" }, 463 { "astgen", genericsp, true, "AST after instantiate generics" }, 464 { "box", bboxp, true, "before box step" }, 465 { "ctordtor", ctorinitp, true, "after ctor/dtor are replaced" }, 466 { "codegen", bcodegenp, true, "before code generation" }, 467 { "declstats", declstatsp, true, "code property statistics" }, 468 { "parse", yydebug, true, "yacc (parsing) debug information" }, 469 { "pretty", prettycodegenp, true, "prettyprint for ascodegen flag" }, 470 { "resolver", bresolvep, true, "before resolver step" }, 471 { "rproto", resolvprotop, true, "resolver-proto instance" }, 472 { "rsteps", resolvep, true, "resolver steps" }, 473 { "symevt", symtabp, true, "symbol table events" }, 474 { "tree", parsep, true, "parse tree" }, 475 { "tuple", tuplep, true, "after tuple expansion" }, 476 }; 477 enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) }; 478 479 static void usage( char *argv[] ) { 480 cout << "Usage: " << argv[0] << " options are:" << endl; 481 int i = 0, j = 1; // j skips starting colon 482 for ( ; long_opts[i].name != 0 && optstring[j] != '\0'; i += 1, j += 1 ) { 483 if ( long_opts[i].name[0] != '\0' ) { // hidden option, internal usage only 484 if ( strcmp( long_opts[i].name, "prelude-dir" ) != 0 ) { // flag 485 cout << " -" << optstring[j] << ","; 486 } else { // no flag 487 j -= 1; // compensate 488 cout << " "; 489 } // if 490 cout << " --" << left << setw(12) << long_opts[i].name << " "; 491 if ( strcmp( long_opts[i].name, "print" ) == 0 ) { 492 cout << "one of: " << endl; 493 for ( int i = 0; i < printoptsSize; i += 1 ) { 494 cout << setw(10) << " " << left << setw(10) << printopts[i].name << " " << printopts[i].descript << endl; 495 } // for 496 } else { 497 cout << description[i] << endl; 498 } // if 499 } // if 500 if ( optstring[j + 1] == ':' ) j += 1; 501 } // for 502 if ( long_opts[i].name != 0 || optstring[j] != '\0' ) assertf( false, "internal error, mismatch of option flags and names\n" ); 503 exit( EXIT_FAILURE ); 504 } // usage 505 506 static void parse_cmdline( int argc, char * argv[], const char *& filename ) { 412 507 opterr = 0; // (global) prevent getopt from printing error messages 413 508 414 509 bool Wsuppress = false, Werror = false; 415 510 int c; 416 while ( (c = getopt_long( argc, argv, "abBcCdefgGlLmnNpqrRstTvwW:yzZD:F:", long_opts, &long_index)) != -1 ) {511 while ( (c = getopt_long( argc, argv, optstring, long_opts, nullptr )) != -1 ) { 417 512 switch ( c ) { 418 case Ast: 419 case 'a': // dump AST 420 astp = true; 421 break; 422 case Bresolver: 423 case 'b': // print before resolver steps 424 bresolvep = true; 425 break; 426 case 'B': // print before box steps 427 bboxp = true; 428 break; 429 case CtorInitFix: 430 case 'c': // print after constructors and destructors are replaced 431 ctorinitp = true; 432 break; 433 case 'C': // print before code generation 434 bcodegenp = true; 435 break; 436 case DeclStats: 437 case 'd': 438 declstatsp = true; 439 break; 440 case Expr: 441 case 'e': // dump AST after expression analysis 442 exprp = true; 443 break; 444 case ExprAlt: 445 case 'f': // print alternatives for expressions 446 expraltp = true; 447 break; 448 case Grammar: 449 case 'g': // bison debugging info (grammar rules) 450 yydebug = true; 451 break; 452 case 'G': // dump AST after instantiate generics 453 genericsp = true; 454 break; 455 case LibCFA: 513 case 'h': // help message 514 usage( argv ); // no return 515 break; 456 516 case 'l': // generate libcfa.c 457 517 libcfap = true; 458 518 break; 459 case Linemarks: 460 case 'L': // print lines marks 519 case 'L': // generate line marks 461 520 linemarks = true; 462 521 break; 463 case Nopreamble: 464 case 'n': // do not read preamble 522 case 'm': // do not replace main 523 nomainp = true; 524 break; 525 case 'N': // do not generate line marks 526 linemarks = false; 527 break; 528 case 'n': // do not read prelude 465 529 nopreludep = true; 466 530 break; 467 case Nolinemarks: 468 case 'N': // suppress line marks 469 linemarks = false; 470 break; 471 case Prototypes: 472 case 'p': // generate prototypes for preamble functions 473 noprotop = true; 474 break; 475 case PreludeDir: 476 PreludeDirector = optarg; 477 break; 478 case 'm': // don't replace the main 479 nomainp = true; 480 break; 481 case Parse: 482 case 'q': // dump parse tree 483 parsep = true; 484 break; 485 case Resolver: 486 case 'r': // print resolver steps 487 resolvep = true; 488 break; 489 case 'R': // dump resolv-proto instance 490 resolvprotop = true; 491 break; 492 case Symbol: 493 case 's': // print symbol table events 494 symtabp = true; 495 break; 496 case Tree: 531 case 'p': // generate prototypes for prelude functions 532 genproto = true; 533 break; 534 case 'P': // print options 535 for ( int i = 0;; i += 1 ) { 536 if ( i == printoptsSize ) { 537 cout << "Unknown --print option " << optarg << endl; 538 goto Default; 539 } // if 540 if ( strcmp( optarg, printopts[i].name ) == 0 ) { 541 printopts[i].flag = printopts[i].val; 542 break; 543 } // if 544 } // for 545 break; 546 case PreludeDir: // prelude directory for debug/nodebug, hidden 547 PreludeDirector = optarg; 548 break; 549 case 'S': // enable profiling information, argument comma separated list of names 550 Stats::parse_params( optarg ); 551 break; 497 552 case 't': // build in tree 498 553 treep = true; 499 554 break; 500 case TupleExpansion: 501 case 'T': // print after tuple expansion 502 tuplep = true; 503 break; 504 case 'v': // dump AST after decl validation pass 505 validp = true; 506 break; 507 case 'w': 555 case 'w': // suppress all warnings, hidden 508 556 Wsuppress = true; 509 557 break; 510 case 'W': 558 case 'W': // coordinate gcc -W with CFA, hidden 511 559 if ( strcmp( optarg, "all" ) == 0 ) { 512 560 SemanticWarning_EnableAll(); … … 525 573 } // if 526 574 break; 527 case 'y': // dump AST on error 528 errorp = true; 529 break; 530 case 'z': // dump as codegen rather than AST 531 codegenp = true; 532 break; 533 case 'Z': // prettyprint during codegen (i.e. print unmangled names, etc.) 534 prettycodegenp = true; 535 break; 536 case 'D': // ignore -Dxxx 537 break; 538 case 'F': // source file-name without suffix 575 case 'D': // ignore -Dxxx, forwarded by cpp, hidden 576 break; 577 case 'F': // source file-name without suffix, hidden 539 578 filename = optarg; 540 579 break; 541 case '?': 580 case '?': // unknown option 542 581 if ( optopt ) { // short option ? 543 assertf( false, "Unknown option: -%c\n", (char)optopt );582 cout << "Unknown option -" << (char)optopt << endl; 544 583 } else { 545 assertf( false, "Unknown option: %s\n", argv[optind - 1] ); 546 } // if 547 #if defined(__GNUC__) && __GNUC__ >= 7 548 __attribute__((fallthrough)); 549 #endif 584 cout << "Unknown option " << argv[optind - 1] << endl; 585 } // if 586 goto Default; 587 case ':': // missing option 588 if ( optopt ) { // short option ? 589 cout << "Missing option for -" << (char)optopt << endl; 590 } else { 591 cout << "Missing option for " << argv[optind - 1] << endl; 592 } // if 593 goto Default; 594 Default: 550 595 default: 551 abort();596 usage( argv ); // no return 552 597 } // switch 553 598 } // while … … 587 632 list< Declaration * > decls; 588 633 589 if ( noprotop) {634 if ( genproto ) { 590 635 filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), notPrelude ); 591 636 } else { … … 595 640 // depending on commandline options, either generate code or dump the AST 596 641 if ( codegenp ) { 597 CodeGen::generate( decls, out, ! noprotop, prettycodegenp );642 CodeGen::generate( decls, out, ! genproto, prettycodegenp ); 598 643 } else { 599 644 printAll( decls, out ); 600 } 645 } // if 601 646 deleteAll( translationUnit ); 602 647 } // dump -
tests/.expect/KRfunctions.x64.txt
r6a9d4b4 r933f32f 62 62 __attribute__ ((unused)) signed int _X10_retval_f5i_1; 63 63 } 64 signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))( signed int __anonymous_object0){64 signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(__attribute__ ((unused)) signed int __anonymous_object0){ 65 65 __attribute__ ((unused)) signed int (*_X10_retval_f6Fi_i__1)(signed int __anonymous_object1); 66 66 } … … 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret2)(signed int _X1xi_1, signed int _X1yi_1); 107 void __cleanup_dtor4(signed int *(**_dst)(signed int _X1xi_1, signed int _X1yi_1)){ 108 ((void)((*_dst)) /* ^?{} */); 109 } 110 __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object6))__cleanup_dtor4) }; 111 void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1)); 112 ((void)(_X1xFPi_ii__2=(((void)(((void)(_tmp_cp_ret2=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2))); 106 signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4))); 113 108 } 114 109 -
tests/.expect/KRfunctions.x86.txt
r6a9d4b4 r933f32f 62 62 __attribute__ ((unused)) signed int _X10_retval_f5i_1; 63 63 } 64 signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))( signed int __anonymous_object0){64 signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(__attribute__ ((unused)) signed int __anonymous_object0){ 65 65 __attribute__ ((unused)) signed int (*_X10_retval_f6Fi_i__1)(signed int __anonymous_object1); 66 66 } … … 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret2)(signed int _X1xi_1, signed int _X1yi_1); 107 void __cleanup_dtor4(signed int *(**_dst)(signed int _X1xi_1, signed int _X1yi_1)){ 108 ((void)((*_dst)) /* ^?{} */); 109 } 110 __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object6))__cleanup_dtor4) }; 111 void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1)); 112 ((void)(_X1xFPi_ii__2=(((void)(((void)(_tmp_cp_ret2=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2))); 106 signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4))); 113 108 } 114 109 -
tests/.expect/abs.txt
r6a9d4b4 r933f32f 3 3 signed long int -65 abs 65 4 4 signed long long int -65 abs 65 5 float -65 abs 656 double -65 abs 657 long double -65 abs 658 float _Complex -65 -2i abs 65.03089 double _Complex -65 -2i abs 65.030761951556410 long double _Complex -65 -2i abs 65.03076195155643425 float -65. abs 65. 6 double -65. abs 65. 7 long double -65. abs 65. 8 float _Complex -65.-2.i abs 65.0308 9 double _Complex -65.-2.i abs 65.0307619515564 10 long double _Complex -65.-2.i abs 65.0307619515564342 -
tests/.expect/ato.txt
r6a9d4b4 r933f32f 22 22 -123.456789012345679 -123.45678901234567890123456789 23 23 -123.456-123.456i -123.456-123.456i 24 0 +0i 2 324 0.+0.i 2 3 25 25 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i 26 26 123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i -
tests/.expect/attributes.x64.txt
r6a9d4b4 r933f32f 640 640 } 641 641 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1); 642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())( signed int __anonymous_object2){642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){ 643 643 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3); 644 644 } -
tests/.expect/attributes.x86.txt
r6a9d4b4 r933f32f 640 640 } 641 641 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1); 642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())( signed int __anonymous_object2){642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){ 643 643 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3); 644 644 } -
tests/.expect/castError.txt
r6a9d4b4 r933f32f 1 castError.cfa: 7:1 error: Cannot choose between 3 alternatives for expression2 Cast of:1 castError.cfa:21:1 error: Cannot choose between 3 alternatives for expression 2 Explicit Cast of: 3 3 Name: f 4 4 ... to: 5 5 char Alternatives are: 6 Cost ( 1, 0, 0, 0, 0, 0 ):Cast of:6 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: 7 7 Variable Expression: f: function 8 8 accepting unspecified arguments … … 16 16 Environment: 17 17 18 Cost ( 1, 0, 0, 0, 0, 0 ):Cast of:18 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: 19 19 Variable Expression: f: double 20 20 ... to: … … 25 25 Environment: 26 26 27 Cost ( 1, 0, 0, 0, 0, 0 ):Cast of:27 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: 28 28 Variable Expression: f: signed int 29 29 ... to: … … 35 35 36 36 37 castError.cfa:26:1 error: Cannot choose between 2 alternatives for expression 38 Generated Cast of: 39 Comma Expression: 40 constant expression (3 3: signed int) 41 Name: v 42 ... to: nothing Alternatives are: 43 Cost ( 0, 0, 2, 0, 0, 0, 0 ): Generated Cast of: 44 Comma Expression: 45 constant expression (3 3: signed int) 46 Variable Expression: v: unsigned char 47 ... to: nothing 48 (types: 49 void 50 ) 51 Environment: 52 53 Cost ( 0, 0, 2, 0, 0, 0, 0 ): Generated Cast of: 54 Comma Expression: 55 constant expression (3 3: signed int) 56 Variable Expression: v: signed short int 57 ... to: nothing 58 (types: 59 void 60 ) 61 Environment: 62 63 -
tests/.expect/completeTypeError.txt
r6a9d4b4 r933f32f 1 completeTypeError.cfa:33:1 error: No reasonable alternatives for expression Applying untyped: 2 Name: *? 3 ...to: 4 Name: v 1 completeTypeError.cfa:34:1 error: Cannot choose between 2 alternatives for expression 2 Generated Cast of: 3 Applying untyped: 4 Name: *? 5 ...to: 6 Name: x 5 7 6 completeTypeError.cfa:34:1 error: No reasonable alternatives for expression Applying untyped: 7 Name: *? 8 ...to: 9 Name: y 8 ... to: nothing Alternatives are: 9 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 10 Application of 11 Variable Expression: *?: forall 12 DT: object type 13 function 14 ... with parameters 15 intrinsic pointer to instance of type DT (not function type) 16 ... returning 17 _retval__operator_deref: reference to instance of type DT (not function type) 18 ... with attributes: 19 Attribute with name: unused 20 21 22 ... to arguments 23 Variable Expression: x: pointer to instance of struct A with body 0 24 25 ... to: nothing 26 (types: 27 void 28 ) 29 Environment:( _80_4_DT ) -> instance of struct A with body 0 (no widening) 30 31 32 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 33 Application of 34 Variable Expression: *?: forall 35 DT: object type 36 function 37 ... with parameters 38 intrinsic pointer to instance of type DT (not function type) 39 ... returning 40 _retval__operator_deref: reference to instance of type DT (not function type) 41 ... with attributes: 42 Attribute with name: unused 43 44 45 ... to arguments 46 Variable Expression: x: pointer to instance of struct B with body 1 47 48 ... to: nothing 49 (types: 50 void 51 ) 52 Environment:( _80_4_DT ) -> instance of struct B with body 1 (no widening) 53 54 10 55 11 56 completeTypeError.cfa:35:1 error: No reasonable alternatives for expression Applying untyped: … … 24 69 Name: v 25 70 26 completeTypeError.cfa:5 8:1 error: No reasonable alternatives for expression Applying untyped:71 completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped: 27 72 Name: baz 28 73 ...to: 29 74 Name: y 30 75 31 completeTypeError.cfa: 59:1 error: No reasonable alternatives for expression Applying untyped:76 completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped: 32 77 Name: quux 33 78 ...to: 34 79 Name: y 35 80 36 completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped: 37 Name: *? 38 ...to: 39 Name: y 40 41 completeTypeError.cfa:72:1 error: No resolvable alternatives for expression Applying untyped: 81 completeTypeError.cfa:72:1 error: No alternatives with satisfiable assertions for Applying untyped: 42 82 Name: baz 43 83 ...to: 44 84 Name: z 45 85 46 Alternatives with failing assertions are:47 Cost ( 0, 1, 0, 1, -5, 0 ): Application of48 Variable Expression: baz: forall49 T: sized object type50 ... with assertions51 ?=?: pointer to function52 ... with parameters53 reference to instance of type T (not function type)54 instance of type T (not function type)55 ... returning56 _retval__operator_assign: instance of type T (not function type)57 ... with attributes:58 Attribute with name: unused86 Unsatisfiable alternative: 87 Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of 88 Variable Expression: baz: forall 89 T: sized object type 90 ... with assertions 91 ?=?: pointer to function 92 ... with parameters 93 reference to instance of type T (not function type) 94 instance of type T (not function type) 95 ... returning 96 _retval__operator_assign: instance of type T (not function type) 97 ... with attributes: 98 Attribute with name: unused 59 99 60 100 61 ?{}: pointer to function 101 ?{}: pointer to function 102 ... with parameters 103 reference to instance of type T (not function type) 104 ... returning nothing 105 106 ?{}: pointer to function 107 ... with parameters 108 reference to instance of type T (not function type) 109 instance of type T (not function type) 110 ... returning nothing 111 112 ^?{}: pointer to function 113 ... with parameters 114 reference to instance of type T (not function type) 115 ... returning nothing 116 117 118 function 62 119 ... with parameters 63 referenceto instance of type T (not function type)120 pointer to instance of type T (not function type) 64 121 ... returning nothing 65 122 66 ?{}: pointer to function 67 ... with parameters 68 reference to instance of type T (not function type) 69 instance of type T (not function type) 70 ... returning nothing 123 ... to arguments 124 Variable Expression: z: pointer to instance of type T (not function type) 71 125 72 ^?{}: pointer to function 73 ... with parameters 74 reference to instance of type T (not function type) 75 ... returning nothing 126 (types: 127 void 128 ) 129 Environment:( _99_0_T ) -> instance of type T (not function type) (no widening) 130 131 Could not satisfy assertion: 132 ?=?: pointer to function 133 ... with parameters 134 reference to instance of type _99_0_T (not function type) 135 instance of type _99_0_T (not function type) 136 ... returning 137 _retval__operator_assign: instance of type _99_0_T (not function type) 138 ... with attributes: 139 Attribute with name: unused 76 140 77 141 78 function79 ... with parameters80 pointer to instance of type T (not function type)81 ... returning nothing82 83 ... to arguments84 Variable Expression: z: pointer to instance of type T (not function type)85 86 (types:87 void88 )89 Environment:( _73_0_T ) -> instance of type T (not function type) (no widening)90 91 92 -
tests/.expect/complex.txt
r6a9d4b4 r933f32f 1 1 x:3+2i y:4+5i z:7+7i 2 x:3 +2i y:4+5i z:7+7i2 x:3.+2.i y:4.+5.i z:7.+7.i 3 3 x:2.1+1.3i y:3.2+4.5i z:5.3+5.8i 4 4 x:2.1+1.3i y:3.2+4.5i z:5.3+5.8i -
tests/.expect/declarationSpecifier.x64.txt
r6a9d4b4 r933f32f 1122 1122 __attribute__ ((unused)) signed int _X12_retval_maini_1; 1123 1123 { 1124 ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */);1125 }1126 1127 return _X12_retval_maini_1;1128 {1129 1124 ((void)(_X12_retval_maini_1=0) /* ?{} */); 1130 1125 } … … 1137 1132 __attribute__ ((unused)) signed int _X12_retval_maini_1; 1138 1133 { 1139 signed int _tmp_cp_ret2; 1140 __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) }; 1141 void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1)); 1142 ((void)(_X12_retval_maini_1=(((void)(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)) /* ?{} */); 1134 signed int _tmp_cp_ret4; 1135 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 1143 1136 } 1144 1137 -
tests/.expect/declarationSpecifier.x86.txt
r6a9d4b4 r933f32f 1122 1122 __attribute__ ((unused)) signed int _X12_retval_maini_1; 1123 1123 { 1124 ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */);1125 }1126 1127 return _X12_retval_maini_1;1128 {1129 1124 ((void)(_X12_retval_maini_1=0) /* ?{} */); 1130 1125 } … … 1137 1132 __attribute__ ((unused)) signed int _X12_retval_maini_1; 1138 1133 { 1139 signed int _tmp_cp_ret2; 1140 __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) }; 1141 void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1)); 1142 ((void)(_X12_retval_maini_1=(((void)(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)) /* ?{} */); 1134 signed int _tmp_cp_ret4; 1135 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 1143 1136 } 1144 1137 -
tests/.expect/extension.x64.txt
r6a9d4b4 r933f32f 457 457 458 458 { 459 signed int _tmp_cp_ret2; 460 __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) }; 461 void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1)); 462 ((void)(((void)(((void)(_tmp_cp_ret2=__extension__ _X4fredFi_i__1(3))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)); 459 signed int _tmp_cp_ret4; 460 ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4)); 463 461 } 464 462 -
tests/.expect/extension.x86.txt
r6a9d4b4 r933f32f 457 457 458 458 { 459 signed int _tmp_cp_ret2; 460 __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) }; 461 void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1)); 462 ((void)(((void)(((void)(_tmp_cp_ret2=__extension__ _X4fredFi_i__1(3))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)); 459 signed int _tmp_cp_ret4; 460 ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4)); 463 461 } 464 462 -
tests/.expect/functions.x64.txt
r6a9d4b4 r933f32f 1 1 void _X1hFv___1(void){ 2 2 } 3 signed int _X1fFi_Fi__Fi_i_Fi__Fi_i_Fv____1( signed int (*__anonymous_object0)(void), signed int (*__anonymous_object1)(signed int __anonymous_object2), signed int (*__anonymous_object3)(void),signed int (*__anonymous_object4)(signed int __anonymous_object5), void (*_X1gFv___1)(void)){3 signed int _X1fFi_Fi__Fi_i_Fi__Fi_i_Fv____1(__attribute__ ((unused)) signed int (*__anonymous_object0)(void), __attribute__ ((unused)) signed int (*__anonymous_object1)(signed int __anonymous_object2), __attribute__ ((unused)) signed int (*__anonymous_object3)(void), __attribute__ ((unused)) signed int (*__anonymous_object4)(signed int __anonymous_object5), void (*_X1gFv___1)(void)){ 4 4 __attribute__ ((unused)) signed int _X9_retval_fi_1; 5 5 { … … 99 99 __attribute__ ((unused)) signed int _X9_retval_fi_1; 100 100 } 101 signed int _X1fFi_i__1( signed int __anonymous_object7){101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object7){ 102 102 __attribute__ ((unused)) signed int _X9_retval_fi_1; 103 103 } … … 130 130 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 131 131 } 132 struct _conc__tuple2_0 _X1fFT2ii_ii__1( signed int __anonymous_object9, signed int _X1xi_1){132 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object9, signed int _X1xi_1){ 133 133 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 134 134 } … … 167 167 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 168 168 } 169 struct _conc__tuple3_1 _X1fFT3iii_iii__1( signed int __anonymous_object12, signed int _X1xi_1,signed int __anonymous_object13){169 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object12, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object13){ 170 170 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 171 171 } … … 180 180 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 181 181 } 182 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1( signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){182 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){ 183 183 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 184 184 } … … 190 190 const double _X3fooFd___1(void); 191 191 const double _X3fooFd_i__1(signed int __anonymous_object19); 192 const double _X3fooFd_d__1( double __anonymous_object20){192 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object20){ 193 193 __attribute__ ((unused)) const double _X11_retval_fooKd_1; 194 194 { … … 242 242 243 243 } 244 struct S _X3rtnFS1S_i__1( signed int __anonymous_object21){244 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object21){ 245 245 __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1; 246 246 } 247 signed int _X1fFi_Fi_ii_Fi_i___1( signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1),signed int (*__anonymous_object24)(signed int __anonymous_object25)){247 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1), __attribute__ ((unused)) signed int (*__anonymous_object24)(signed int __anonymous_object25)){ 248 248 __attribute__ ((unused)) signed int _X9_retval_fi_1; 249 249 signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)]; … … 271 271 } 272 272 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object27)(), signed int *(*__anonymous_object28)(), signed int **(*__anonymous_object29)(), signed int *const *(*__anonymous_object30)(), signed int *const *const (*__anonymous_object31)(), signed int *__anonymous_object32, signed int __anonymous_object33[((unsigned long int )10)], signed int **__anonymous_object34, signed int *__anonymous_object35[((unsigned long int )10)], signed int ***__anonymous_object36, signed int **__anonymous_object37[((unsigned long int )10)], signed int *const **__anonymous_object38, signed int *const *__anonymous_object39[((unsigned long int )10)], signed int *const *const *__anonymous_object40, signed int *const *const __anonymous_object41[((unsigned long int )10)]); 273 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1( signed int (*__anonymous_object42)(), signed int *(*__anonymous_object43)(), signed int **(*__anonymous_object44)(), signed int *const *(*__anonymous_object45)(), signed int *const *const (*__anonymous_object46)(), signed int *__anonymous_object47, signed int __anonymous_object48[((unsigned long int )10)], signed int **__anonymous_object49, signed int *__anonymous_object50[((unsigned long int )10)], signed int ***__anonymous_object51, signed int **__anonymous_object52[((unsigned long int )10)], signed int *const **__anonymous_object53, signed int *const *__anonymous_object54[((unsigned long int )10)], signed int *const *const *__anonymous_object55,signed int *const *const __anonymous_object56[((unsigned long int )10)]){273 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object42)(), __attribute__ ((unused)) signed int *(*__anonymous_object43)(), __attribute__ ((unused)) signed int **(*__anonymous_object44)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object45)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object46)(), __attribute__ ((unused)) signed int *__anonymous_object47, __attribute__ ((unused)) signed int __anonymous_object48[((unsigned long int )10)], __attribute__ ((unused)) signed int **__anonymous_object49, __attribute__ ((unused)) signed int *__anonymous_object50[((unsigned long int )10)], __attribute__ ((unused)) signed int ***__anonymous_object51, __attribute__ ((unused)) signed int **__anonymous_object52[((unsigned long int )10)], __attribute__ ((unused)) signed int *const **__anonymous_object53, __attribute__ ((unused)) signed int *const *__anonymous_object54[((unsigned long int )10)], __attribute__ ((unused)) signed int *const *const *__anonymous_object55, __attribute__ ((unused)) signed int *const *const __anonymous_object56[((unsigned long int )10)]){ 274 274 __attribute__ ((unused)) signed int _X9_retval_fi_1; 275 275 } -
tests/.expect/functions.x86.txt
r6a9d4b4 r933f32f 1 1 void _X1hFv___1(void){ 2 2 } 3 signed int _X1fFi_Fi__Fi_i_Fi__Fi_i_Fv____1( signed int (*__anonymous_object0)(void), signed int (*__anonymous_object1)(signed int __anonymous_object2), signed int (*__anonymous_object3)(void),signed int (*__anonymous_object4)(signed int __anonymous_object5), void (*_X1gFv___1)(void)){3 signed int _X1fFi_Fi__Fi_i_Fi__Fi_i_Fv____1(__attribute__ ((unused)) signed int (*__anonymous_object0)(void), __attribute__ ((unused)) signed int (*__anonymous_object1)(signed int __anonymous_object2), __attribute__ ((unused)) signed int (*__anonymous_object3)(void), __attribute__ ((unused)) signed int (*__anonymous_object4)(signed int __anonymous_object5), void (*_X1gFv___1)(void)){ 4 4 __attribute__ ((unused)) signed int _X9_retval_fi_1; 5 5 { … … 99 99 __attribute__ ((unused)) signed int _X9_retval_fi_1; 100 100 } 101 signed int _X1fFi_i__1( signed int __anonymous_object7){101 signed int _X1fFi_i__1(__attribute__ ((unused)) signed int __anonymous_object7){ 102 102 __attribute__ ((unused)) signed int _X9_retval_fi_1; 103 103 } … … 130 130 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 131 131 } 132 struct _conc__tuple2_0 _X1fFT2ii_ii__1( signed int __anonymous_object9, signed int _X1xi_1){132 struct _conc__tuple2_0 _X1fFT2ii_ii__1(__attribute__ ((unused)) signed int __anonymous_object9, signed int _X1xi_1){ 133 133 __attribute__ ((unused)) struct _conc__tuple2_0 _X9_retval_fT2ii_1 = { }; 134 134 } … … 167 167 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 168 168 } 169 struct _conc__tuple3_1 _X1fFT3iii_iii__1( signed int __anonymous_object12, signed int _X1xi_1,signed int __anonymous_object13){169 struct _conc__tuple3_1 _X1fFT3iii_iii__1(__attribute__ ((unused)) signed int __anonymous_object12, signed int _X1xi_1, __attribute__ ((unused)) signed int __anonymous_object13){ 170 170 __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = { }; 171 171 } … … 180 180 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 181 181 } 182 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1( signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){182 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(__attribute__ ((unused)) signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){ 183 183 __attribute__ ((unused)) struct _conc__tuple3_2 _X9_retval_fT3iiPi_1 = { }; 184 184 } … … 190 190 const double _X3fooFd___1(void); 191 191 const double _X3fooFd_i__1(signed int __anonymous_object19); 192 const double _X3fooFd_d__1( double __anonymous_object20){192 const double _X3fooFd_d__1(__attribute__ ((unused)) double __anonymous_object20){ 193 193 __attribute__ ((unused)) const double _X11_retval_fooKd_1; 194 194 { … … 242 242 243 243 } 244 struct S _X3rtnFS1S_i__1( signed int __anonymous_object21){244 struct S _X3rtnFS1S_i__1(__attribute__ ((unused)) signed int __anonymous_object21){ 245 245 __attribute__ ((unused)) struct S _X11_retval_rtnS1S_1; 246 246 } 247 signed int _X1fFi_Fi_ii_Fi_i___1( signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1),signed int (*__anonymous_object24)(signed int __anonymous_object25)){247 signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1), __attribute__ ((unused)) signed int (*__anonymous_object24)(signed int __anonymous_object25)){ 248 248 __attribute__ ((unused)) signed int _X9_retval_fi_1; 249 249 signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned int )10)])[][((unsigned int )3)]; … … 271 271 } 272 272 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(signed int (*__anonymous_object27)(), signed int *(*__anonymous_object28)(), signed int **(*__anonymous_object29)(), signed int *const *(*__anonymous_object30)(), signed int *const *const (*__anonymous_object31)(), signed int *__anonymous_object32, signed int __anonymous_object33[((unsigned int )10)], signed int **__anonymous_object34, signed int *__anonymous_object35[((unsigned int )10)], signed int ***__anonymous_object36, signed int **__anonymous_object37[((unsigned int )10)], signed int *const **__anonymous_object38, signed int *const *__anonymous_object39[((unsigned int )10)], signed int *const *const *__anonymous_object40, signed int *const *const __anonymous_object41[((unsigned int )10)]); 273 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1( signed int (*__anonymous_object42)(), signed int *(*__anonymous_object43)(), signed int **(*__anonymous_object44)(), signed int *const *(*__anonymous_object45)(), signed int *const *const (*__anonymous_object46)(), signed int *__anonymous_object47, signed int __anonymous_object48[((unsigned int )10)], signed int **__anonymous_object49, signed int *__anonymous_object50[((unsigned int )10)], signed int ***__anonymous_object51, signed int **__anonymous_object52[((unsigned int )10)], signed int *const **__anonymous_object53, signed int *const *__anonymous_object54[((unsigned int )10)], signed int *const *const *__anonymous_object55,signed int *const *const __anonymous_object56[((unsigned int )10)]){273 signed int _X1fFi_Fi__FPi__FPPi__FPKPi__FPKPi__PiPiPPiPPiPPPiPPPiPPKPiPPKPiPKPKPiPKPKPi__1(__attribute__ ((unused)) signed int (*__anonymous_object42)(), __attribute__ ((unused)) signed int *(*__anonymous_object43)(), __attribute__ ((unused)) signed int **(*__anonymous_object44)(), __attribute__ ((unused)) signed int *const *(*__anonymous_object45)(), __attribute__ ((unused)) signed int *const *const (*__anonymous_object46)(), __attribute__ ((unused)) signed int *__anonymous_object47, __attribute__ ((unused)) signed int __anonymous_object48[((unsigned int )10)], __attribute__ ((unused)) signed int **__anonymous_object49, __attribute__ ((unused)) signed int *__anonymous_object50[((unsigned int )10)], __attribute__ ((unused)) signed int ***__anonymous_object51, __attribute__ ((unused)) signed int **__anonymous_object52[((unsigned int )10)], __attribute__ ((unused)) signed int *const **__anonymous_object53, __attribute__ ((unused)) signed int *const *__anonymous_object54[((unsigned int )10)], __attribute__ ((unused)) signed int *const *const *__anonymous_object55, __attribute__ ((unused)) signed int *const *const __anonymous_object56[((unsigned int )10)]){ 274 274 __attribute__ ((unused)) signed int _X9_retval_fi_1; 275 275 } -
tests/.expect/gccExtensions.x64.txt
r6a9d4b4 r933f32f 292 292 signed int _X2m3A0A0i_2[((unsigned long int )10)][((unsigned long int )10)]; 293 293 { 294 ((void)(_X12_retval_maini_1= ((signed int )0)) /* ?{} */);294 ((void)(_X12_retval_maini_1=0) /* ?{} */); 295 295 } 296 296 … … 307 307 __attribute__ ((unused)) signed int _X12_retval_maini_1; 308 308 { 309 signed int _tmp_cp_ret2; 310 __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) }; 311 void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1)); 312 ((void)(_X12_retval_maini_1=(((void)(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)) /* ?{} */); 309 signed int _tmp_cp_ret4; 310 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 313 311 } 314 312 -
tests/.expect/gccExtensions.x86.txt
r6a9d4b4 r933f32f 292 292 signed int _X2m3A0A0i_2[((unsigned int )10)][((unsigned int )10)]; 293 293 { 294 ((void)(_X12_retval_maini_1= ((signed int )0)) /* ?{} */);294 ((void)(_X12_retval_maini_1=0) /* ?{} */); 295 295 } 296 296 … … 307 307 __attribute__ ((unused)) signed int _X12_retval_maini_1; 308 308 { 309 signed int _tmp_cp_ret2; 310 __attribute__ ((cleanup(__destroy_Destructor))) struct __Destructor _ret_dtor4 = { 0, ((void (*)(void *__anonymous_object0))_X11_destructorFv_i_intrinsic___1) }; 311 void **_dtype_static_member_4 = ((void **)(&_ret_dtor4._X6objectPY12__T_generic__1)); 312 ((void)(_X12_retval_maini_1=(((void)(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , ((*_dtype_static_member_4)=((void *)(&_tmp_cp_ret2))))) , _tmp_cp_ret2)) /* ?{} */); 309 signed int _tmp_cp_ret4; 310 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 313 311 } 314 312 -
tests/.expect/identity.txt
r6a9d4b4 r933f32f 9 9 double 4.1 10 10 long double 4.1 11 float _Complex -4.1-2 i12 double _Complex -4.1-2 i13 long double _Complex -4.1-2 i11 float _Complex -4.1-2.i 12 double _Complex -4.1-2.i 13 long double _Complex -4.1-2.i -
tests/.expect/io1.txt
r6a9d4b4 r933f32f 1 1 9 6 28 0 7 1 2 2 1 2 33 1234 1232 0 1 2 3 3 0123 4 0123 5 5 6 6 opening delimiters -
tests/.expect/loopctrl.txt
r6a9d4b4 r933f32f 19 19 10 8 6 4 2 20 20 21 1 2 3 4 5 6 7 8 9 10 22 10 9 8 7 6 5 4 3 2 1 0 23 2 4 6 8 10 24 2.1 3.8 5.5 7.2 8.9 25 10 8 6 4 2 0 26 12.1 10.4 8.7 7. 5.3 3.6 21 27 22 28 N N N N N N N N N N … … 24 30 10 9 8 7 6 5 4 3 2 1 25 31 26 27 32 3 6 9 28 29 33 30 34 (0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9) … … 40 44 (10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0) 41 45 (10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0) 46 47 0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4 48 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14 49 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13 50 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23 51 52 0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4 53 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14 54 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13 55 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23 56 57 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5 58 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5 59 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5 -
tests/.expect/math1.txt
r6a9d4b4 r933f32f 1 fmod:1 1 1 1 1 12 remainder:-1 -1 -11 fmod:1. 1. 1. 1. 1. 1. 2 remainder:-1. -1. -1. 3 3 remquo:7 0.0999999 7 0.1 7 0.0999999999999999999 4 div:7 , 0.2 7, 0.2 7, 0.25 fma:-2 -2 -26 fdim:2 2 24 div:7., 0.2 7., 0.2 7., 0.2 5 fma:-2. -2. -2. 6 fdim:2. 2. 2. 7 7 nan:nan nan nan 8 8 exp:2.71828 2.71828182845905 2.71828182845904524 1.46869+2.28736i 1.46869393991589+2.28735528717884i 1.46869393991588516+2.28735528717884239i 9 exp2:2 2 29 exp2:2. 2. 2. 10 10 expm1:1.71828 1.71828182845905 1.71828182845904524 11 pow:1 1 1 0.273957+0.583701i 0.273957253830121+0.583700758758615i -0.638110484918098871+0.705394566961838155i 12 \ 16 256 13 \ 912673 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i 11 pow:1. 1. 1. 0.273957+0.583701i 0.273957253830121+0.583700758758615i -0.638110484918098871+0.705394566961838155i 12 16 \ 2 = 256 13 912673 256 64 -64 0 0 14 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i 15 0 0 18.3791736799526 0.264715-1.1922i 16 16 17 4 16 -
tests/.expect/math2.txt
r6a9d4b4 r933f32f 1 log:0 0 00.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i2 log2:3 3 33 log10:2 2 21 log:0. 0. 0. 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i 2 log2:3. 3. 3. 3 log10:2. 2. 2. 4 4 log1p:0.693147 0.693147180559945 0.693147180559945309 5 5 ilogb:0 0 0 6 logb:3 3 37 sqrt:1 1 11.09868+0.45509i 1.09868411346781+0.455089860562227i 1.09868411346780997+0.455089860562227341i8 cbrt:3 3 36 logb:3. 3. 3. 7 sqrt:1. 1. 1. 1.09868+0.45509i 1.09868411346781+0.455089860562227i 1.09868411346780997+0.455089860562227341i 8 cbrt:3. 3. 3. 9 9 hypot:1.41421 1.4142135623731 1.41421356237309505 10 10 sin:0.841471 0.841470984807897 0.841470984807896507 1.29846+0.634964i 1.29845758141598+0.634963914784736i 1.29845758141597729+0.634963914784736108i … … 12 12 tan:1.55741 1.5574077246549 1.55740772465490223 0.271753+1.08392i 0.271752585319512+1.08392332733869i 0.271752585319511717+1.08392332733869454i 13 13 asin:1.5708 1.5707963267949 1.57079632679489662 0.666239+1.06128i 0.666239432492515+1.06127506190504i 0.666239432492515255+1.06127506190503565i 14 acos:0 0 00.904557-1.06128i 0.904556894302381-1.06127506190504i 0.904556894302381364-1.06127506190503565i14 acos:0. 0. 0. 0.904557-1.06128i 0.904556894302381-1.06127506190504i 0.904556894302381364-1.06127506190503565i 15 15 atan:0.785398 0.785398163397448 0.78539816339744831 1.01722+0.402359i 1.01722196789785+0.402359478108525i 1.01722196789785137+0.402359478108525094i 16 16 atan2:0.785398 0.785398163397448 0.78539816339744831 atan:0.785398 0.785398163397448 0.78539816339744831 -
tests/.expect/math3.txt
r6a9d4b4 r933f32f 2 2 cosh:1.54308 1.54308063481524 1.54308063481524378 0.83373+0.988898i 0.833730025131149+0.988897705762865i 0.833730025131149049+0.988897705762865096i 3 3 tanh:0.761594 0.761594155955765 0.761594155955764888 1.08392+0.271753i 1.08392332733869+0.271752585319512i 1.08392332733869454+0.271752585319511717i 4 acosh:0 0 01.06128+0.904557i 1.06127506190504+0.904556894302381i 1.06127506190503565+0.904556894302381364i4 acosh:0. 0. 0. 1.06128+0.904557i 1.06127506190504+0.904556894302381i 1.06127506190503565+0.904556894302381364i 5 5 asinh:0.881374 0.881373587019543 0.881373587019543025 1.06128+0.666239i 1.06127506190504+0.666239432492515i 1.06127506190503565+0.666239432492515255i 6 6 atanh:inf inf inf 0.402359+1.01722i 0.402359478108525+1.01722196789785i 0.402359478108525094+1.01722196789785137i … … 9 9 lgamma:1.79176 1.79175946922805 1.791759469228055 10 10 lgamma:1.79176 1 1.79175946922805 1 1.791759469228055 1 11 tgamma:6 6 611 tgamma:6. 6. 6. -
tests/.expect/math4.txt
r6a9d4b4 r933f32f 1 floor:1 1 12 ceil:2 2 23 trunc:3 3 34 rint:2 2 21 floor:1. 1. 1. 2 ceil:2. 2. 2. 3 trunc:3. 3. 3. 4 rint:2. 2. 2. 5 5 rint:2 2 2 6 6 rint:2 2 2 7 7 lrint:2 2 2 8 8 llrint:2 2 2 9 nearbyint:4 4 410 round:2 2 29 nearbyint:4. 4. 4. 10 round:2. 2. 2. 11 11 round:2 2 2 12 12 round:2 2 2 13 13 lround:2 2 2 14 14 llround:2 2 2 15 copysign:-1 -1 -115 copysign:-1. -1. -1. 16 16 frexp:0.5 3 0.5 3 0.5 3 17 ldexp:8 8 818 modf:2 0.3 2 0.3 20.319 modf:2 , 0.3 2, 0.3 2, 0.320 nextafter:2 2 221 nexttoward:2 2 222 scalbn:16 16 1623 scalbln:16 16 1617 ldexp:8. 8. 8. 18 modf:2. 0.3 2. 0.3 2. 0.3 19 modf:2., 0.3 2., 0.3 2., 0.3 20 nextafter:2. 2. 2. 21 nexttoward:2. 2. 2. 22 scalbn:16. 16. 16. 23 scalbln:16. 16. 16. -
tests/.expect/minmax.txt
r6a9d4b4 r933f32f 6 6 signed long long int 4 3 min 3 7 7 unsigned long long int 4 3 min 3 8 float 4 3.1 min 3.19 double 4 3.1 min 3.110 long double 4 3.1 min 3.18 float 4. 3.1 min 3.1 9 double 4. 3.1 min 3.1 10 long double 4. 3.1 min 3.1 11 11 12 12 char z a max z … … 17 17 signed long long int 4 3 max 4 18 18 unsigned long long int 4 3 max 4 19 float 4 3.1 max 420 double 4 3.1 max 421 long double 4 3.1 max 419 float 4. 3.1 max 4. 20 double 4. 3.1 max 4. 21 long double 4. 3.1 max 4. -
tests/.expect/references.txt
r6a9d4b4 r933f32f 35 35 3 36 36 3 37 3 9 { 1 , 7}, [1, 2, 3]37 3 9 { 1., 7. }, [1, 2, 3] 38 38 Destructing a Y 39 39 Destructing a Y -
tests/.expect/sum.txt
r6a9d4b4 r933f32f 1 sum from 5 to 15 is 95, check 95 2 sum from 5 to 15 is 95, check 95 1 3 sum from 5 to 15 is 95, check 95 2 4 sum from 5 to 15 is 95, check 95 -
tests/Makefile.am
r6a9d4b4 r933f32f 23 23 installed=no 24 24 25 INSTALL_FLAGS=-in-tree 26 DEBUG_FLAGS=-debug -O0 27 25 28 quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes 26 29 … … 28 31 timeouts= 29 32 30 TEST_PY = python ${builddir}/test.py33 TEST_PY = python3 ${builddir}/test.py 31 34 32 35 # applies to both programs … … 36 39 -Wno-unused-function \ 37 40 -quiet @CFA_FLAGS@ \ 38 -DIN_DIR="${ srcdir}/.in/"41 -DIN_DIR="${abs_srcdir}/.in/" 39 42 40 43 AM_CFLAGS += ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS} 41 44 CC = @CFACC@ 42 45 43 PRETTY_PATH= cd ${srcdir} &&46 PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} && 44 47 45 48 .PHONY: list .validate … … 48 51 49 52 avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa 50 # automake doesn't know we still need C rules so pretend like we have a C program51 _dummy_hack_SOURCES = .dummy_hack.c 53 # automake doesn't know we still need C/CPP rules so pretend like we have a C program 54 _dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp 52 55 53 56 #---------------------------------------------------------------------------------------------------------------- … … 74 77 @echo "int main() { return 0; }" > ${@} 75 78 79 .dummy_hackxx.cpp: 80 @echo "int bar() { return 0; }" > ${@} 81 76 82 concurrency : 77 83 @+${TEST_PY} --debug=${debug} --install=${installed} -Iconcurrent … … 79 85 #---------------------------------------------------------------------------------------------------------------- 80 86 87 # Use for all tests, make sure the path are correct and all flags are added 88 CFACOMPILETEST=$(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) $($(shell echo "${@}_FLAGS" | sed 's/-\|\//_/g')) 89 90 # Use for tests that either generate an executable, print directyl to stdout or the make command is expected to fail 91 CFATEST_STDOUT=$(CFACOMPILETEST) -o $(abspath ${@}) 92 93 # Use for tests where the make command is expecte to succeed but the expected.txt should be compared to stderr 94 CFATEST_STDERR=$(CFACOMPILETEST) 2> $(abspath ${@}) 95 96 #---------------------------------------------------------------------------------------------------------------- 97 81 98 # implicit rule so not all test require a rule 82 99 % : %.cfa $(CFACC) 83 $( PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})100 $(CFATEST_STDOUT) 84 101 85 declarationSpecifier: declarationSpecifier.cfa $(CFACC) 86 $(PRETTY_PATH) $(C FACOMPILE) -CFA -XCFA -p$(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})102 % : %.cpp 103 $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 87 104 88 gccExtensions : gccExtensions.cfa $(CFACC) 89 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 105 #------------------------------------------------------------------------------ 106 # TARGET WITH STANDARD RULE BUT CUSTOM FLAGS 107 #------------------------------------------------------------------------------ 108 # Expected failures 109 declarationSpecifier_FLAGS= -CFA -XCFA -p 110 gccExtensions_FLAGS= -CFA -XCFA -p 111 extension_FLAGS= -CFA -XCFA -p 112 attributes_FLAGS= -CFA -XCFA -p 113 functions_FLAGS= -CFA -XCFA -p 114 KRfunctions_FLAGS= -CFA -XCFA -p 115 gmp_FLAGS= -lgmp 90 116 91 extension : extension.cfa $(CFACC) 92 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 117 #------------------------------------------------------------------------------ 118 # Expected failures 119 completeTypeError_FLAGS= -DERR1 93 120 94 attributes : attributes.cfa $(CFACC) 95 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 121 #------------------------------------------------------------------------------ 122 # CUSTOM TARGET 123 #------------------------------------------------------------------------------ 124 typedefRedef-ERR1: typedefRedef.cfa $(CFACC) 125 $(CFATEST_STDOUT) -DERR1 96 126 97 functions: functions.cfa $(CFACC)98 $( PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})127 alloc-ERROR: alloc.cfa $(CFACC) 128 $(CFATEST_STDOUT) -DERR1 99 129 100 KRfunctions : KRfunctions.cfa $(CFACC)101 $( PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})130 nested-types-ERR1: nested-types.cfa $(CFACC) 131 $(CFATEST_STDOUT) -DERR1 102 132 103 sched-ext-parse : sched-ext-parse.c$(CFACC)104 $( PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})133 nested-types-ERR2: nested-types.cfa $(CFACC) 134 $(CFATEST_STDOUT) -DERR2 105 135 106 gmp : gmp.cfa $(CFACC) 107 $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 136 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC) 137 $(CFATEST_STDOUT) -DERR1 138 139 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC) 140 $(CFATEST_STDOUT) -DERR2 141 142 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC) 143 $(CFATEST_STDOUT) -DERR1 144 145 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC) 146 $(CFATEST_STDOUT) -DERR1 108 147 109 148 #builtins 110 149 builtins/sync: builtins/sync.cfa $(CFACC) 111 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only 112 113 #------------------------------------------------------------------------------ 114 115 #To make errors path independent we need to cd into the correct directories 116 completeTypeError : completeTypeError.cfa $(CFACC) 117 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 118 119 typedefRedef-ERR1: typedefRedef.cfa $(CFACC) 120 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 121 122 alloc-ERROR: alloc.cfa $(CFACC) 123 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 124 125 fallthrough-ERROR: fallthrough.cfa $(CFACC) 126 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 127 128 nested-types-ERR1: nested-types.cfa $(CFACC) 129 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 130 131 nested-types-ERR2: nested-types.cfa $(CFACC) 132 $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 133 134 # Constructor/destructor tests 135 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC) 136 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 137 138 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC) 139 $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 140 141 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC) 142 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 143 144 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC) 145 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 150 $(CFATEST_STDERR) -fsyntax-only 146 151 147 152 # Warnings 148 153 warnings/self-assignment: warnings/self-assignment.cfa $(CFACC) 149 $( PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only154 $(CFATEST_STDERR) -fsyntax-only -
tests/Makefile.in
r6a9d4b4 r933f32f 107 107 CONFIG_CLEAN_FILES = config.py 108 108 CONFIG_CLEAN_VPATH_FILES = test.py 109 am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT) 109 am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT) .dummy_hackxx.$(OBJEXT) 110 110 _dummy_hack_OBJECTS = $(am__dummy_hack_OBJECTS) 111 111 _dummy_hack_LDADD = $(LDADD) … … 155 155 am__v_CCLD_0 = @echo " CCLD " $@; 156 156 am__v_CCLD_1 = 157 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ 158 $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) 159 LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ 160 $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ 161 $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ 162 $(AM_CXXFLAGS) $(CXXFLAGS) 163 AM_V_CXX = $(am__v_CXX_@AM_V@) 164 am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) 165 am__v_CXX_0 = @echo " CXX " $@; 166 am__v_CXX_1 = 167 CXXLD = $(CXX) 168 CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ 169 $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ 170 $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ 171 AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) 172 am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) 173 am__v_CXXLD_0 = @echo " CXXLD " $@; 174 am__v_CXXLD_1 = 157 175 SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES) 158 176 DIST_SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES) … … 186 204 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 187 205 ACLOCAL = @ACLOCAL@ 188 ALLOCA = @ALLOCA@189 206 AMTAR = @AMTAR@ 190 207 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 358 375 debug = yes 359 376 installed = no 377 INSTALL_FLAGS = -in-tree 378 DEBUG_FLAGS = -debug -O0 360 379 quick_test = avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes 361 380 concurrent = 362 381 timeouts = 363 TEST_PY = python ${builddir}/test.py382 TEST_PY = python3 ${builddir}/test.py 364 383 365 384 # applies to both programs 366 385 AM_CFLAGS = $(if $(test), 2> $(test), ) -g -Wall -Wno-unused-function \ 367 -quiet @CFA_FLAGS@ -DIN_DIR="${ srcdir}/.in/" ${DEBUG_FLAGS}\368 ${ INSTALL_FLAGS} ${ARCH_FLAGS}369 PRETTY_PATH = cd ${srcdir} &&386 -quiet @CFA_FLAGS@ -DIN_DIR="${abs_srcdir}/.in/" \ 387 ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS} 388 PRETTY_PATH = mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} && 370 389 avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa 371 # automake doesn't know we still need C rules so pretend like we have a C program 372 _dummy_hack_SOURCES = .dummy_hack.c 390 # automake doesn't know we still need C/CPP rules so pretend like we have a C program 391 _dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp 392 393 #---------------------------------------------------------------------------------------------------------------- 394 395 # Use for all tests, make sure the path are correct and all flags are added 396 CFACOMPILETEST = $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) $($(shell echo "${@}_FLAGS" | sed 's/-\|\//_/g')) 397 398 # Use for tests that either generate an executable, print directyl to stdout or the make command is expected to fail 399 CFATEST_STDOUT = $(CFACOMPILETEST) -o $(abspath ${@}) 400 401 # Use for tests where the make command is expecte to succeed but the expected.txt should be compared to stderr 402 CFATEST_STDERR = $(CFACOMPILETEST) 2> $(abspath ${@}) 403 404 #------------------------------------------------------------------------------ 405 # TARGET WITH STANDARD RULE BUT CUSTOM FLAGS 406 #------------------------------------------------------------------------------ 407 # Expected failures 408 declarationSpecifier_FLAGS = -CFA -XCFA -p 409 gccExtensions_FLAGS = -CFA -XCFA -p 410 extension_FLAGS = -CFA -XCFA -p 411 attributes_FLAGS = -CFA -XCFA -p 412 functions_FLAGS = -CFA -XCFA -p 413 KRfunctions_FLAGS = -CFA -XCFA -p 414 gmp_FLAGS = -lgmp 415 416 #------------------------------------------------------------------------------ 417 # Expected failures 418 completeTypeError_FLAGS = -DERR1 373 419 all: all-am 374 420 375 421 .SUFFIXES: 376 .SUFFIXES: .c .cfa . dummy_hack.lo .o .obj .validate422 .SUFFIXES: .c .cfa .cpp .dummy_hack .dummy_hackxx .lo .o .obj .validate 377 423 $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/src/cfa.make $(am__configure_deps) 378 424 @for dep in $?; do \ … … 410 456 .dummy_hack$(EXEEXT): $(_dummy_hack_OBJECTS) $(_dummy_hack_DEPENDENCIES) $(EXTRA__dummy_hack_DEPENDENCIES) 411 457 @rm -f .dummy_hack$(EXEEXT) 412 $(AM_V_C CLD)$(LINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)458 $(AM_V_CXXLD)$(CXXLINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS) 413 459 avltree/$(am__dirstamp): 414 460 @$(MKDIR_P) avltree … … 444 490 445 491 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/.dummy_hack.Po@am__quote@ 492 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/.dummy_hackxx.Po@am__quote@ 446 493 447 494 .c.o: … … 468 515 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 469 516 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< 517 518 .cpp.o: 519 @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ 520 @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ 521 @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po 522 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ 523 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 524 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< 525 526 .cpp.obj: 527 @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ 528 @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ 529 @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po 530 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ 531 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 532 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` 533 534 .cpp.lo: 535 @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ 536 @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ 537 @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo 538 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ 539 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 540 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< 470 541 471 542 mostlyclean-libtool: … … 718 789 @echo "int main() { return 0; }" > ${@} 719 790 791 .dummy_hackxx.cpp: 792 @echo "int bar() { return 0; }" > ${@} 793 720 794 concurrency : 721 795 @+${TEST_PY} --debug=${debug} --install=${installed} -Iconcurrent … … 725 799 # implicit rule so not all test require a rule 726 800 % : %.cfa $(CFACC) 727 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 728 729 declarationSpecifier: declarationSpecifier.cfa $(CFACC) 730 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 731 732 gccExtensions : gccExtensions.cfa $(CFACC) 733 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 734 735 extension : extension.cfa $(CFACC) 736 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 737 738 attributes : attributes.cfa $(CFACC) 739 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 740 741 functions: functions.cfa $(CFACC) 742 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 743 744 KRfunctions : KRfunctions.cfa $(CFACC) 745 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 746 747 sched-ext-parse : sched-ext-parse.c $(CFACC) 748 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 749 750 gmp : gmp.cfa $(CFACC) 751 $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 801 $(CFATEST_STDOUT) 802 803 % : %.cpp 804 $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 805 806 #------------------------------------------------------------------------------ 807 # CUSTOM TARGET 808 #------------------------------------------------------------------------------ 809 typedefRedef-ERR1: typedefRedef.cfa $(CFACC) 810 $(CFATEST_STDOUT) -DERR1 811 812 alloc-ERROR: alloc.cfa $(CFACC) 813 $(CFATEST_STDOUT) -DERR1 814 815 nested-types-ERR1: nested-types.cfa $(CFACC) 816 $(CFATEST_STDOUT) -DERR1 817 818 nested-types-ERR2: nested-types.cfa $(CFACC) 819 $(CFATEST_STDOUT) -DERR2 820 821 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC) 822 $(CFATEST_STDOUT) -DERR1 823 824 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC) 825 $(CFATEST_STDOUT) -DERR2 826 827 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC) 828 $(CFATEST_STDOUT) -DERR1 829 830 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC) 831 $(CFATEST_STDOUT) -DERR1 752 832 753 833 #builtins 754 834 builtins/sync: builtins/sync.cfa $(CFACC) 755 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only 756 757 #------------------------------------------------------------------------------ 758 759 #To make errors path independent we need to cd into the correct directories 760 completeTypeError : completeTypeError.cfa $(CFACC) 761 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 762 763 typedefRedef-ERR1: typedefRedef.cfa $(CFACC) 764 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 765 766 alloc-ERROR: alloc.cfa $(CFACC) 767 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 768 769 fallthrough-ERROR: fallthrough.cfa $(CFACC) 770 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 771 772 nested-types-ERR1: nested-types.cfa $(CFACC) 773 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 774 775 nested-types-ERR2: nested-types.cfa $(CFACC) 776 $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 777 778 # Constructor/destructor tests 779 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC) 780 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 781 782 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC) 783 $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 784 785 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC) 786 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 787 788 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC) 789 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 835 $(CFATEST_STDERR) -fsyntax-only 790 836 791 837 # Warnings 792 838 warnings/self-assignment: warnings/self-assignment.cfa $(CFACC) 793 $( PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only839 $(CFATEST_STDERR) -fsyntax-only 794 840 795 841 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
tests/array.cfa
r6a9d4b4 r933f32f 1 //Testing array declarations 1 // -*- Mode: C -*- 2 // 3 // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo 4 // 5 // The contents of this file are covered under the licence agreement in the 6 // file "LICENCE" distributed with Cforall. 7 // 8 // array.cfa -- test array declarations 9 // 10 // Author : Peter A. Buhr 11 // Created On : Tue Feb 19 21:18:06 2019 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Tue Feb 19 21:18:46 2019 14 // Update Count : 1 15 // 16 2 17 int a1[]; 3 18 //int a2[*]; … … 34 49 } 35 50 36 //Dummy main 37 int main(int argc, char const *argv[]) 38 { 39 return 0; 40 } 51 int main() {} 52 53 // Local Variables: // 54 // tab-width: 4 // 55 // compile-command: "cfa array.cfa" // 56 // End: // -
tests/builtins/sync.cfa
r6a9d4b4 r933f32f 11 11 volatile __int128 * vp16 = 0; __int128 * rp16 = 0; __int128 v16 = 0; 12 12 #endif 13 struct type * volatile * vpp = 0; struct type ** rpp = 0; struct type * vp = 0; 13 14 14 15 { char ret; ret = __sync_fetch_and_add(vp1, v1); } … … 180 181 { _Bool ret; ret = __sync_bool_compare_and_swap_16(vp16, v16,v16); } 181 182 #endif 183 { _Bool ret; ret = __sync_bool_compare_and_swap(vpp, vp, vp); } 182 184 183 185 { char ret; ret = __sync_val_compare_and_swap(vp1, v1, v1); } … … 193 195 { __int128 ret; ret = __sync_val_compare_and_swap_16(vp16, v16,v16); } 194 196 #endif 197 { struct type * ret; ret = __sync_val_compare_and_swap(vpp, vp, vp); } 198 195 199 196 200 { char ret; ret = __sync_lock_test_and_set(vp1, v1); } … … 230 234 { __atomic_clear(vp1, v1); } 231 235 232 { char ret; ret = __atomic_exchange_n(vp1, &v1, __ATOMIC_SEQ_CST); }236 { char ret; ret = __atomic_exchange_n(vp1, v1, __ATOMIC_SEQ_CST); } 233 237 { char ret; ret = __atomic_exchange_1(vp1, v1, __ATOMIC_SEQ_CST); } 234 238 { char ret; __atomic_exchange(vp1, &v1, &ret, __ATOMIC_SEQ_CST); } 235 { short ret; ret = __atomic_exchange_n(vp2, &v2, __ATOMIC_SEQ_CST); }239 { short ret; ret = __atomic_exchange_n(vp2, v2, __ATOMIC_SEQ_CST); } 236 240 { short ret; ret = __atomic_exchange_2(vp2, v2, __ATOMIC_SEQ_CST); } 237 241 { short ret; __atomic_exchange(vp2, &v2, &ret, __ATOMIC_SEQ_CST); } 238 { int ret; ret = __atomic_exchange_n(vp4, &v4, __ATOMIC_SEQ_CST); }242 { int ret; ret = __atomic_exchange_n(vp4, v4, __ATOMIC_SEQ_CST); } 239 243 { int ret; ret = __atomic_exchange_4(vp4, v4, __ATOMIC_SEQ_CST); } 240 244 { int ret; __atomic_exchange(vp4, &v4, &ret, __ATOMIC_SEQ_CST); } 241 { long long int ret; ret = __atomic_exchange_n(vp8, &v8, __ATOMIC_SEQ_CST); }245 { long long int ret; ret = __atomic_exchange_n(vp8, v8, __ATOMIC_SEQ_CST); } 242 246 { long long int ret; ret = __atomic_exchange_8(vp8, v8, __ATOMIC_SEQ_CST); } 243 247 { long long int ret; __atomic_exchange(vp8, &v8, &ret, __ATOMIC_SEQ_CST); } 244 248 #if defined(__SIZEOF_INT128__) 245 { __int128 ret; ret = __atomic_exchange_n(vp16, &v16, __ATOMIC_SEQ_CST); }249 { __int128 ret; ret = __atomic_exchange_n(vp16, v16, __ATOMIC_SEQ_CST); } 246 250 { __int128 ret; ret = __atomic_exchange_16(vp16, v16, __ATOMIC_SEQ_CST); } 247 251 { __int128 ret; __atomic_exchange(vp16, &v16, &ret, __ATOMIC_SEQ_CST); } 248 252 #endif 253 { struct type * ret; ret = __atomic_exchange_n(vpp, vp, __ATOMIC_SEQ_CST); } 254 { struct type * ret; __atomic_exchange(vpp, &vp, &ret, __ATOMIC_SEQ_CST); } 249 255 250 256 { char ret; ret = __atomic_load_n(vp1, __ATOMIC_SEQ_CST); } … … 265 271 { __int128 ret; __atomic_load(vp16, &ret, __ATOMIC_SEQ_CST); } 266 272 #endif 273 { struct type * ret; ret = __atomic_load_n(vpp, __ATOMIC_SEQ_CST); } 274 { struct type * ret; __atomic_load(vpp, &ret, __ATOMIC_SEQ_CST); } 267 275 268 276 { _Bool ret; ret = __atomic_compare_exchange_n(vp1, rp1, v1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } … … 283 291 { _Bool ret; ret = __atomic_compare_exchange(vp16, rp16, &v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 284 292 #endif 293 { _Bool ret; ret = __atomic_compare_exchange_n(vpp, rpp, vp, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 294 { _Bool ret; ret = __atomic_compare_exchange(vpp, rpp, &vp, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 285 295 286 296 { __atomic_store_n(vp1, v1, __ATOMIC_SEQ_CST); } … … 301 311 { __atomic_store(vp16, &v16, __ATOMIC_SEQ_CST); } 302 312 #endif 313 { __atomic_store_n(vpp, vp, __ATOMIC_SEQ_CST); } 314 { __atomic_store(vpp, &vp, __ATOMIC_SEQ_CST); } 303 315 304 316 { char ret; ret = __atomic_add_fetch(vp1, v1, __ATOMIC_SEQ_CST); } -
tests/castError.cfa
r6a9d4b4 r933f32f 1 //Testing some of the invalid casts of chars 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo 3 // 4 // The contents of this file are covered under the licence agreement in the 5 // file "LICENCE" distributed with Cforall. 6 // 7 // castError.cfa -- test invalid casts 8 // 9 // Author : Peter A. Buhr 10 // Created On : Tue Feb 19 21:15:39 2019 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Feb 19 21:16:44 2019 13 // Update Count : 1 14 // 15 2 16 int f; 3 17 … … 7 21 (char)f; 8 22 (int(*)())f; 23 24 unsigned char v; 25 short int v; 26 3, v; // implicit void cast 9 27 } 10 28 11 //Dummy main 12 int main(int argc, char const *argv[]) 13 { 14 return 0; 15 } 29 int main() {} 30 31 // Local Variables: // 32 // tab-width: 4 // 33 // compile-command: "cfa castError.cfa" // 34 // End: // -
tests/completeTypeError.cfa
r6a9d4b4 r933f32f 5 5 forall(dtype T | sized(T)) void quux(T *); 6 6 7 struct A; // incomplete8 struct B {}; // complete7 struct A; // incomplete 8 struct B {}; // complete 9 9 10 10 int main() { 11 int * i;12 void * v;11 int * i; 12 void * v; 13 13 14 14 A * x; … … 19 19 // okay 20 20 *i; 21 * x; // picks B21 *y; 22 22 *z; 23 23 foo(i); … … 32 32 // bad 33 33 *v; 34 * y;34 *x; // ambiguous 35 35 foo(v); 36 36 baz(v); … … 52 52 void qux(T * y) { 53 53 // okay 54 *y; 54 55 bar(y); 55 56 qux(y); … … 58 59 baz(y); 59 60 quux(y); 60 *y;61 61 } 62 62 -
tests/concurrent/examples/boundedBufferEXT.cfa
r6a9d4b4 r933f32f 1 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo 3 // 2 4 // The contents of this file are covered under the licence agreement in the 3 5 // file "LICENCE" distributed with Cforall. … … 8 10 // Created On : Wed Apr 18 22:52:12 2018 9 11 // Last Modified By : Peter A. Buhr 10 // Last Modified On : Tue Dec 11 21:55:02 201811 // Update Count : 912 // Last Modified On : Fri Mar 22 13:41:33 2019 13 // Update Count : 12 12 14 // 13 15 14 #include <stdlib.hfa> // random16 #include <stdlib.hfa> // random 15 17 #include <fstream.hfa> 16 18 #include <kernel.hfa> … … 120 122 // Local Variables: // 121 123 // tab-width: 4 // 122 // compile-command: "cfa boundedBufferEXT.c " //124 // compile-command: "cfa boundedBufferEXT.cfa" // 123 125 // End: // -
tests/concurrent/examples/boundedBufferINT.cfa
r6a9d4b4 r933f32f 1 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo 3 // 2 4 // The contents of this file are covered under the licence agreement in the 3 5 // file "LICENCE" distributed with Cforall. … … 8 10 // Created On : Mon Oct 30 12:45:13 2017 9 11 // Last Modified By : Peter A. Buhr 10 // Last Modified On : Tue Dec 11 21:55:45 201811 // Update Count : 8 412 // Last Modified On : Fri Mar 22 13:41:52 2019 13 // Update Count : 88 12 14 // 13 15 14 #include <stdlib.hfa> // random16 #include <stdlib.hfa> // random 15 17 #include <fstream.hfa> 16 18 #include <kernel.hfa> … … 121 123 // Local Variables: // 122 124 // tab-width: 4 // 123 // compile-command: "cfa boundedBufferINT.c " //125 // compile-command: "cfa boundedBufferINT.cfa" // 124 126 // End: // -
tests/concurrent/examples/datingService.cfa
r6a9d4b4 r933f32f 1 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo 3 // 2 4 // The contents of this file are covered under the licence agreement in the 3 5 // file "LICENCE" distributed with Cforall. … … 8 10 // Created On : Mon Oct 30 12:56:20 2017 9 11 // Last Modified By : Peter A. Buhr 10 // Last Modified On : Tue Dec 11 21:55:34 201811 // Update Count : 2812 // Last Modified On : Fri Mar 22 13:41:39 2019 13 // Update Count : 31 12 14 // 13 15 14 #include <stdlib.hfa> // random16 #include <stdlib.hfa> // random 15 17 #include <fstream.hfa> 16 18 #include <kernel.hfa> … … 110 112 // Local Variables: // 111 113 // tab-width: 4 // 112 // compile-command: "cfa datingService.c " //114 // compile-command: "cfa datingService.cfa" // 113 115 // End: // -
tests/concurrent/examples/matrixSum.cfa
r6a9d4b4 r933f32f 1 // -*- Mode: C -*-2 1 // 3 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo … … 11 10 // Created On : Mon Oct 9 08:29:28 2017 12 11 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Tue Dec 11 21:54:55 201814 // Update Count : 1 512 // Last Modified On : Wed Feb 20 08:37:53 2019 13 // Update Count : 16 15 14 // 16 15 -
tests/concurrent/examples/quickSort.cfa
r6a9d4b4 r933f32f 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo 1 3 // 2 4 // The contents of this file are covered under the licence agreement in the … … 9 11 // Created On : Wed Dec 6 12:15:52 2017 10 12 // Last Modified By : Peter A. Buhr 11 // Last Modified On : Sat Dec 22 08:44:27 201812 // Update Count : 1 6813 // Last Modified On : Fri Mar 22 13:42:01 2019 14 // Update Count : 170 13 15 // 14 16 … … 178 180 // Local Variables: // 179 181 // tab-width: 4 // 180 // compile-command: "cfa quickSort.c " //182 // compile-command: "cfa quickSort.cfa" // 181 183 // End: // -
tests/concurrent/waitfor/parse2.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed Aug 30 17:53:29 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Aug 30 17:55:17 201713 // Update Count : 212 // Last Modified On : Fri Mar 22 13:42:11 2019 13 // Update Count : 3 14 14 // 15 15 … … 246 246 // Local Variables: // 247 247 // tab-width: 4 // 248 // compile-command: "cfa waitfor.c " //248 // compile-command: "cfa waitfor.cfa" // 249 249 // End: // -
tests/config.py.in
r6a9d4b4 r933f32f 1 #!/usr/bin/env python 1 #!/usr/bin/env python3 2 2 # encoding: utf-8 3 3 """ -
tests/coroutine/.expect/fmtLines.txt
r6a9d4b4 r933f32f 16 16 difi ed B y : Pete r A. 17 17 Buh r// Last Mod ifie 18 d On : T ue D ec 1 1 2319 : 31: 12 2 018/ / Up date20 Cou nt : 3 2/ /#in18 d On : F ri M ar 2 2 13 19 :41: 03 2 019/ / Up date 20 Cou nt : 33/ /#in 21 21 clud e <f stre am.h fa># 22 22 incl ude <cor outi ne.h … … 76 76 th: 4 // // c ompi le-c 77 77 omma nd: "cfa fmt Line 78 s.c " /// / En d: //78 s.cf a" / /// End: // -
tests/coroutine/.in/fmtLines.txt
r6a9d4b4 r933f32f 10 10 // Created On : Sun Sep 17 21:56:15 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 11 23:31:12 201813 // Update Count : 3 212 // Last Modified On : Fri Mar 22 13:41:03 2019 13 // Update Count : 33 14 14 // 15 15 … … 64 64 // Local Variables: // 65 65 // tab-width: 4 // 66 // compile-command: "cfa fmtLines.c " //66 // compile-command: "cfa fmtLines.cfa" // 67 67 // End: // -
tests/coroutine/fibonacci.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Thu Jun 8 07:29:37 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 11 21:57:33 201813 // Update Count : 2 512 // Last Modified On : Fri Mar 22 13:40:35 2019 13 // Update Count : 26 14 14 // 15 15 … … 45 45 // Local Variables: // 46 46 // tab-width: 4 // 47 // compile-command: "cfa fibonacci.c " //47 // compile-command: "cfa fibonacci.cfa" // 48 48 // End: // -
tests/coroutine/fibonacci_1.cfa
r6a9d4b4 r933f32f 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // fibonacci_1.c -- 1-state finite-state machine: precomputed first two states returning f(n - 2)7 // fibonacci_1.cfa -- 1-state finite-state machine: precomputed first two states returning f(n - 1) 8 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Thu Apr 26 23:20:08 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Dec 11 21:57:54 201813 // Update Count : 1412 // Last Modified On : Thu Mar 21 08:10:45 2019 13 // Update Count : 25 14 14 // 15 15 … … 17 17 #include <coroutine.hfa> 18 18 19 coroutine Fibonacci { int ret; }; // used for communication19 coroutine Fibonacci { int fn1; }; // used for communication 20 20 21 21 void main( Fibonacci & fib ) with( fib ) { // called on first resume 22 int fn, fn1 = 1, fn2 = 0; // precompute first two states 22 int fn; 23 [fn1, fn] = [0, 1]; // precompute first two states 23 24 for () { 24 ret = fn2;25 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; // general case26 25 suspend(); // restart last resume 26 [fn1, fn] = [fn, fn1 + fn]; // general case 27 27 } // for 28 28 } … … 30 30 int next( Fibonacci & fib ) with( fib ) { 31 31 resume( fib ); // restart last suspend 32 return ret;32 return fn1; 33 33 } 34 34 … … 42 42 // Local Variables: // 43 43 // tab-width: 4 // 44 // compile-command: "cfa fibonacci_1.c " //44 // compile-command: "cfa fibonacci_1.cfa" // 45 45 // End: // -
tests/coroutine/fmtLines.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Sun Sep 17 21:56:15 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Dec 22 18:27:00 201813 // Update Count : 5 712 // Last Modified On : Fri Mar 22 13:41:16 2019 13 // Update Count : 58 14 14 // 15 15 … … 63 63 // Local Variables: // 64 64 // tab-width: 4 // 65 // compile-command: "cfa fmtLines.c " //65 // compile-command: "cfa fmtLines.cfa" // 66 66 // End: // -
tests/coroutine/pingpong.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed Sep 20 11:55:23 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 11 21:58:06 201813 // Update Count : 2912 // Last Modified On : Tue Mar 26 17:54:14 2019 13 // Update Count : 35 14 14 // 15 15 … … 20 20 const char * name; 21 21 /* const */ unsigned int N; 22 PingPong *part;22 PingPong & part; 23 23 }; 24 24 25 25 void ?{}( PingPong & this, const char * name, unsigned int N, PingPong & part ) { 26 (this.__cor){name}; 27 this.name = name; 28 this.N = N; 29 this.part = ∂ 26 this.[name, N] = [name, N]; &this.part = ∂ 30 27 } 31 28 void ?{}( PingPong & this, const char * name, unsigned int N ) { 32 this{ name, N, * (PingPong *)0 };29 this{ name, N, *0p }; // call first constructor 33 30 } 34 31 void cycle( PingPong & pingpong ) { … … 36 33 } 37 34 void partner( PingPong & this, PingPong & part ) { 38 this.part = ∂35 &this.part = ∂ 39 36 resume( this ); 40 37 } 41 void main( PingPong & pingpong ) {// ping's starter ::main, pong's starter ping42 for ( pingpong.N ) {// N ping-pongs43 sout | pingpong.name;44 cycle( *pingpong.part );38 void main( PingPong & pingpong ) with(pingpong) { // ping's starter ::main, pong's starter ping 39 for ( N ) { // N ping-pongs 40 sout | name; 41 cycle( part ); 45 42 } // for 46 43 } … … 53 50 // Local Variables: // 54 51 // tab-width: 4 // 55 // compile-command: "cfa pingpong.c " //52 // compile-command: "cfa pingpong.cfa" // 56 53 // End: // -
tests/coroutine/prodcons.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Mon Sep 18 12:23:39 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 12 23:04:49 201813 // Update Count : 5 312 // Last Modified On : Fri Mar 22 13:41:10 2019 13 // Update Count : 54 14 14 // 15 15 … … 91 91 // Local Variables: // 92 92 // tab-width: 4 // 93 // compile-command: "cfa prodcons.c " //93 // compile-command: "cfa prodcons.cfa" // 94 94 // End: // -
tests/coroutine/runningTotal.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed Dec 6 08:05:27 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 11 21:59:00 201813 // Update Count : 412 // Last Modified On : Fri Mar 22 13:40:49 2019 13 // Update Count : 5 14 14 // 15 15 … … 48 48 // Local Variables: // 49 49 // tab-width: 4 // 50 // compile-command: "cfa runningTotal.c " //50 // compile-command: "cfa runningTotal.cfa" // 51 51 // End: // -
tests/declarationSpecifier.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed Aug 17 08:21:04 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Nov 6 17:52:59 201813 // Update Count : 312 // Last Modified On : Tue Apr 30 18:20:36 2019 13 // Update Count : 4 14 14 // 15 15 … … 89 89 90 90 //Dummy main 91 int main(int argc, char const *argv[]) 92 { 93 return 0; 94 } 91 int main( int argc, char const * argv[] ) {} 95 92 96 93 // Local Variables: // -
tests/forall.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed May 9 08:48:15 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Nov 6 17:53:43 201813 // Update Count : 3 112 // Last Modified On : Tue Mar 19 08:29:38 2019 13 // Update Count : 32 14 14 // 15 15 … … 53 53 right = temp; 54 54 } 55 56 void ?{}( int & c, zero_t ) { c = 0; } // not in prelude57 55 58 56 trait sumable( otype T ) { -
tests/function-operator.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Fri Aug 25 15:21:11 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Dec 4 21:37:09 201813 // Update Count : 912 // Last Modified On : Thu Apr 11 18:27:45 2019 13 // Update Count : 10 14 14 // 15 15 … … 62 62 63 63 // test ?()(T, ...) -- ?() with function call-by-reference 64 forall(otype Generator, otype GenRet | { GenRet ?()(Generator &); }, dtype Iter, otype T | Iterator(Iter, T) | Assignable(T, GenRet))64 forall(otype Generator, otype GenRet | { GenRet ?()(Generator &); }, dtype Iter, otype T | Iterator(Iter, T) | Assignable(T, GenRet)) 65 65 void generate(Iter first, Iter last, Generator & gen) { 66 66 int i = 0; -
tests/io1.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed Mar 2 16:56:02 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 21 16:02:55 201813 // Update Count : 11 412 // Last Modified On : Mon Mar 4 21:42:47 2019 13 // Update Count : 115 14 14 // 15 15 … … 19 19 int x = 3, y = 5, z = 7; 20 20 sout | x * 3 | y + 1 | z << 2 | x == y | (x | y) | (x || y) | (x > z ? 1 : 2); 21 sout | 1 | 2 | 3;22 sout | ' 1' | '2' | '3';23 sout | 1 | "" | 2 | "" | 3;21 sout | 0 | 1 | 2 | 3; 22 sout | '0' | '1' | '2' | '3'; 23 sout | 0 | "" | 1 | "" | 2 | "" | 3; 24 24 sout | nl; 25 25 -
tests/io2.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed Mar 2 16:56:02 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 21 08:20:14 201813 // Update Count : 11 212 // Last Modified On : Thu Apr 18 08:03:30 2019 13 // Update Count : 113 14 14 // 15 15 … … 97 97 sout | 1 | sepOff | 2 | 3; // locally turn off implicit separator 98 98 sout | sepOn | sepOn | 1 | 2 | 3 | sepOn | sepOff | sepOn | '\n' | nonl; // no separator at start/end of line 99 sout | 1 | 2 | 3 | "\n\n" | sepOn | nonl; // no separator at start of next line99 sout | 1 | 2 | 3 | "\n\n" | sepOn | nonl; // no separator at start of next line 100 100 sout | 1 | 2 | 3; 101 101 sout | nl; -
tests/literals.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Sat Sep 9 16:34:38 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 4 21:44:01 2018 13 // Update Count : 139 14 // 15 12 // Last Modified On : Tue Feb 12 08:07:39 2019 13 // Update Count : 224 14 // 15 16 #include <features.h> // __GNUC_PREREQ 16 17 #ifdef __CFA__ 17 #include <stdint.h>18 18 #include <fstream.hfa> 19 19 … … 151 151 -0X0123456789.0123456789P-09; -0X0123456789.0123456789P-09f; -0X0123456789.0123456789P-09l; -0X0123456789.0123456789P-09F; -0X0123456789.0123456789P-09L; 152 152 153 #if defined(__GNUC__) && __GNUC_PREREQ(7,0) // gcc version >= 7 154 // floating with length, gcc f16/f128x unsupported and no prelude code for any _FloatXXx, so they work by conversion to long double 155 156 /* 0123456789.f16; */ 0123456789.f32; 0123456789.f32x; 0123456789.f64; 0123456789.f64x; 0123456789.W; 0123456789.f128; 0123456789.q; /* 0123456789.f128x; */ 157 /* +0123456789.f16; */ +0123456789.f32; +0123456789.f32x; +0123456789.f64; +0123456789.f64x; +0123456789.w; +0123456789.f128; +0123456789.Q; /* +0123456789.f128x; */ 158 /* -0123456789.f16; */ -0123456789.f32; -0123456789.f32x; -0123456789.f64; -0123456789.f64x; -0123456789.W; -0123456789.f128; -0123456789.q; /* -0123456789.f128x; */ 159 160 /* 0123456789.e09F16; */ 0123456789.e09F32; 0123456789.e09F32x; 0123456789.e09F64; 0123456789.e09F64x; 0123456789.e09W; 0123456789.e09F128; 0123456789.e09q; /* .0123456789e09q; */ 161 /* +0123456789.e+09F16; */ +0123456789.e+09F32; +0123456789.e+09F32x; +0123456789.e+09F64; +0123456789.e+09F64x; +0123456789.e+09w; +0123456789.e+09F128; +0123456789.e+09Q; /* +.0123456789E+09Q; */ 162 /* -0123456789.e-09F16; */ -0123456789.e-09F32; -0123456789.e-09F32x; -0123456789.e-09F64; -0123456789.e-09F64x; -0123456789.e-09W; -0123456789.e-09F128; -0123456789.e-09q; /* -.0123456789E-09q; */ 163 164 /* .0123456789e09F16; */ .0123456789e09F32; .0123456789e09F32x; .0123456789e09F64; .0123456789e09F64x; .0123456789e09W; .0123456789e09F128; .0123456789e09q; /* .0123456789e09q; */ 165 /* +.0123456789e+09F16; */ +.0123456789e+09F32; +.0123456789e+09F32x; +.0123456789e+09F64; +.0123456789e+09F64x; +.0123456789e+09w; +.0123456789e+09F128; +.0123456789e+09Q; /* +.0123456789E+09Q; */ 166 /* -.0123456789e-09F16; */ -.0123456789e-09F32; -.0123456789e-09F32x; -.0123456789e-09F64; -.0123456789e-09F64x; -.0123456789e-09W; -.0123456789e-09F128; -.0123456789e-09q; /* -.0123456789E-09q; */ 167 168 /* 0123456789.0123456789F16; */ 0123456789.0123456789F32; 0123456789.0123456789F32x; 0123456789.0123456789F64; 0123456789.0123456789F64x; 0123456789.0123456789W; 0123456789.0123456789F128; 0123456789.0123456789q; /* 0123456789.0123456789q; */ 169 /* +0123456789.0123456789F16; */ +0123456789.0123456789F32; +0123456789.0123456789F32x; +0123456789.0123456789F64; +0123456789.0123456789F64x; +0123456789.0123456789w; +0123456789.0123456789F128; +0123456789.0123456789Q; /* +0123456789.0123456789Q; */ 170 /* -0123456789.0123456789F16; */ -0123456789.0123456789F32; -0123456789.0123456789F32x; -0123456789.0123456789F64; -0123456789.0123456789F64x; -0123456789.0123456789W; -0123456789.0123456789F128; -0123456789.0123456789q; /* -0123456789.0123456789q; */ 171 172 /* 0123456789.0123456789E09F16; */ 0123456789.0123456789E09F32; 0123456789.0123456789E09F32x; 0123456789.0123456789E09F64; 0123456789.0123456789E09F64x; 0123456789.0123456789E09W; 0123456789.0123456789E09F128; 0123456789.0123456789E09q; /* 0123456789.0123456789E09q; */ 173 /* +0123456789.0123456789E+09F16; */ +0123456789.0123456789E+09F32; +0123456789.0123456789E+09F32x; +0123456789.0123456789E+09F64; +0123456789.0123456789E+09F64x; +0123456789.0123456789E+09w; +0123456789.0123456789E+09F128; +0123456789.0123456789E+09Q; /* +0123456789.0123456789E+09Q; */ 174 /* -0123456789.0123456789E-09F16; */ -0123456789.0123456789E-09F32; -0123456789.0123456789E-09F32x; -0123456789.0123456789E-09F64; -0123456789.0123456789E-09F64x; -0123456789.0123456789E-09W; -0123456789.0123456789E-09F128; -0123456789.0123456789E-09q; /* -0123456789.0123456789E-09q; */ 175 176 /* 0x123456789.p09f16; */ 0x123456789.p09f32; 0x123456789.p09f32x; 0x123456789.p09f64; 0x123456789.p09f64x; 0x123456789.p09W; 0x123456789.p09f128; 0x123456789.p09q; /* 0x123456789.p09f128x; */ 177 /* +0x123456789.P+09f16; */ +0x123456789.P+09f32; +0x123456789.P+09f32x; +0x123456789.P+09f64; +0x123456789.P+09f64x; +0x123456789.P+09w; +0x123456789.P+09f128; +0x123456789.P+09Q; /* +0x123456789.P+09f128x; */ 178 /* -0x123456789.P-09f16; */ -0x123456789.P-09f32; -0x123456789.P-09f32x; -0x123456789.P-09f64; -0x123456789.P-09f64x; -0x123456789.P-09W; -0x123456789.P-09f128; -0x123456789.P-09q; /* -0x123456789.P-09f128x; */ 179 180 /* 0x123456789.p09F16; */ 0x123456789.p09F32; 0x123456789.p09F32x; 0x123456789.p09F64; 0x123456789.p09F64x; 0x123456789.p09W; 0x123456789.p09F128; 0x123456789.p09q; /* .0123456789p09q; */ 181 /* +0x123456789.p+09F16; */ +0x123456789.p+09F32; +0x123456789.p+09F32x; +0x123456789.p+09F64; +0x123456789.p+09F64x; +0x123456789.p+09w; +0x123456789.p+09F128; +0x123456789.p+09Q; /* +.0123456789p+09Q; */ 182 /* -0x123456789.p-09F16; */ -0x123456789.p-09F32; -0x123456789.p-09F32x; -0x123456789.p-09F64; -0x123456789.p-09F64x; -0x123456789.p-09W; -0x123456789.p-09F128; -0x123456789.p-09q; /* -.0123456789P-09q; */ 183 184 /* 0X.0123456789p09F16; */ 0X.0123456789p09F32; 0X.0123456789p09F32x; 0X.0123456789p09F64; 0X.0123456789p09F64x; 0X.0123456789p09W; 0X.0123456789p09F128; 0X.0123456789p09q; /* 0X.0123456789p09q; */ 185 /* +0X.0123456789p+09F16; */ +0X.0123456789p+09F32; +0X.0123456789p+09F32x; +0X.0123456789p+09F64; +0X.0123456789p+09F64x; +0X.0123456789p+09w; +0X.0123456789p+09F128; +0X.0123456789p+09Q; /* +0X.0123456789p+09Q; */ 186 /* -0X.0123456789p-09F16; */ -0X.0123456789p-09F32; -0X.0123456789p-09F32x; -0X.0123456789p-09F64; -0X.0123456789p-09F64x; -0X.0123456789p-09W; -0X.0123456789p-09F128; -0X.0123456789p-09q; /* -0X.0123456789P-09q; */ 187 188 /* 0x123456789.0123456789P09F16; */ 0x123456789.0123456789P09F32; 0x123456789.0123456789P09F32x; 0x123456789.0123456789P09F64; 0x123456789.0123456789P09F64x; 0x123456789.0123456789P09W; 0x123456789.0123456789P09F128; 0x123456789.0123456789P09q; /* 0x123456789.0123456789P09q; */ 189 /* +0x123456789.0123456789P+09F16; */ +0x123456789.0123456789P+09F32; +0x123456789.0123456789P+09F32x; +0x123456789.0123456789P+09F64; +0x123456789.0123456789P+09F64x; +0x123456789.0123456789P+09w; +0x123456789.0123456789P+09F128; +0x123456789.0123456789P+09Q; /* +0x123456789.0123456789P+09Q; */ 190 /* -0x123456789.0123456789p-09F16; */ -0x123456789.0123456789p-09F32; -0x123456789.0123456789p-09F32x; -0x123456789.0123456789p-09F64; -0x123456789.0123456789p-09F64x; -0x123456789.0123456789p-09W; -0x123456789.0123456789p-09F128; -0x123456789.0123456789p-09q; /* -0x123456789.0123456789p-09q; */ 191 192 /* 0x123456789.0123456789P09F16; */ 0x123456789.0123456789P09F32; 0x123456789.0123456789P09F32x; 0x123456789.0123456789P09F64; 0x123456789.0123456789P09F64x; 0x123456789.0123456789P09W; 0x123456789.0123456789P09F128; 0x123456789.0123456789P09q; /* 0x123456789.0123456789P09q; */ 193 /* +0x123456789.0123456789p+09F16; */ +0x123456789.0123456789p+09F32; +0x123456789.0123456789p+09F32x; +0x123456789.0123456789p+09F64; +0x123456789.0123456789p+09F64x; +0x123456789.0123456789p+09w; +0x123456789.0123456789p+09F128; +0x123456789.0123456789p+09Q; /* +0x123456789.0123456789p+09Q; */ 194 /* -0x123456789.0123456789P-09F16; */ -0x123456789.0123456789P-09F32; -0x123456789.0123456789P-09F32x; -0x123456789.0123456789P-09F64; -0x123456789.0123456789P-09F64x; -0x123456789.0123456789P-09W; -0x123456789.0123456789P-09F128; -0x123456789.0123456789P-09q; /* -0x123456789.0123456789P-09q; */ 195 #endif // __GNUC_PREREQ(7,0) 196 153 197 #ifdef __CFA__ 154 198 // fixed-size length … … 167 211 // octal 168 212 01234567_l8; 01234567_l16; 01234567_l32; 01234567_l64; 01234567_l8u; 01234567_ul16; 01234567_l32u; 01234567_ul64; 169 +01234567_l8; +01234567_l16; +01234567_l32; +01234567_l64; +01234567_ l8u; +01234567_ul16; +01234567_l32u; +01234567_ul64;213 +01234567_l8; +01234567_l16; +01234567_l32; +01234567_l64; +01234567_ul8; +01234567_ul16; +01234567_l32u; +01234567_ul64; 170 214 -01234567_l8; -01234567_l16; -01234567_l32; -01234567_l64; -01234567_l8u; -01234567_ul16; -01234567_l32u; -01234567_ul64; 171 215 … … 203 247 +0X0123456789ABCDEF_l8; +0X0123456789ABCDEF_l16; +0X0123456789ABCDEFl32; +0X0123456789ABCDEFl64; +0X0123456789ABCDEF_ul8; +0X0123456789ABCDEF_l16u; +0X0123456789ABCDEFul32; +0X0123456789ABCDEFl64u; 204 248 -0X0123456789ABCDEF_l8; -0X0123456789ABCDEF_l16; -0X0123456789ABCDEFl32; -0X0123456789ABCDEFl64; -0X0123456789ABCDEF_ul8; -0X0123456789ABCDEF_l16u; -0X0123456789ABCDEFul32; -0X0123456789ABCDEFl64u; 205 206 // floating207 0123456789.l32; 0123456789.l64; 0123456789.l80; 0123456789.l128;208 +0123456789.l32; +0123456789.l64; +0123456789.l80; +0123456789.l128;209 -0123456789.l32; -0123456789.l64; -0123456789.l80; -0123456789.l128;210 211 0123456789.e09L32; 0123456789.e09L64; 0123456789.e09L80; 0123456789.e09L128;212 +0123456789.e+09L32; +0123456789.e+09L64; +0123456789.e+09L80; +0123456789.e+09L128;213 -0123456789.e-09L32; -0123456789.e-09L64; -0123456789.e-09L80; -0123456789.e-09L128;214 215 .0123456789e09L32; .0123456789e09L64; .0123456789e09L80; .0123456789e09L128;216 +.0123456789E+09L32; +.0123456789E+09L64; +.0123456789E+09L80; +.0123456789E+09L128;217 -.0123456789E-09L32; -.0123456789E-09L64; -.0123456789E-09L80; -.0123456789E-09L128;218 219 0123456789.0123456789L32; 0123456789.0123456789L64; 0123456789.0123456789L80; 0123456789.0123456789L128;220 +0123456789.0123456789E09L32; +0123456789.0123456789E09L64; +0123456789.0123456789E09L80; +0123456789.0123456789E09L128;221 -0123456789.0123456789E+09L32; -0123456789.0123456789E+09L64; -0123456789.0123456789E+09L80; -0123456789.0123456789E+09L128;222 0123456789.0123456789E-09L32; 0123456789.0123456789E-09L64; 0123456789.0123456789E-09L80; 0123456789.0123456789E-09L128;223 224 0x0123456789.p09l32; 0x0123456789.p09l64; 0x0123456789.p09l80; 0x0123456789.p09l128;225 +0x0123456789.p09l32; +0x0123456789.p09l64; +0x0123456789.p09l80; +0x0123456789.p09l128;226 -0x0123456789.p09l32; -0x0123456789.p09l64; -0x0123456789.p09l80; -0x0123456789.p09l128;227 228 0x0123456789.p+09l32; 0x0123456789.p+09L64; 0x0123456789.p+09L80; 0x0123456789.p+09L128;229 +0x0123456789.p-09l32; +0x0123456789.p-09L64; +0x0123456789.p-09L80; +0x0123456789.p-09L128;230 -0x.0123456789p09l32; -0x.0123456789p09L64; -0x.0123456789p09L80; -0x.0123456789p09L128;231 249 232 250 // char, short, int suffix overloading -
tests/loopctrl.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed Aug 8 18:32:59 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S un Dec 23 23:00:29 201813 // Update Count : 7912 // Last Modified On : Sat Apr 13 11:03:09 2019 13 // Update Count : 104 14 14 // 15 15 … … 54 54 for ( i; 5.5 -~ 0.5 ) { sout | i; } sout | nl; 55 55 for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; } sout | nl; 56 for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; } sout | nl | nl | nl;56 for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; } sout | nl | nl; 57 57 58 // @ means do nothing 59 for ( i; 1 ~ @ ) { 60 if ( i > 10 ) break; 61 sout | i; 62 } sout | nl; 63 for ( i; 10 -~ @ ) { 64 if ( i < 0 ) break; 65 sout | i; 66 } sout | nl; 67 for ( i; 2 ~ @ ~ 2 ) { 68 if ( i > 10 ) break; 69 sout | i; 70 } sout | nl; 71 for ( i; 2.1 ~ @ ~ @ ) { 72 if ( i > 10.5 ) break; 73 sout | i; 74 i += 1.7; 75 } sout | nl; 76 for ( i; 10 -~ @ ~ 2 ) { 77 if ( i < 0 ) break; 78 sout | i; 79 } sout | nl; 80 for ( i; 12.1 ~ @ ~ @ ) { 81 if ( i < 2.5 ) break; 82 sout | i; 83 i -= 1.7; 84 } sout | nl | nl; 85 58 86 enum { N = 10 }; 59 87 for ( N ) { sout | "N"; } sout | nl; 60 88 for ( i; N ) { sout | i; } sout | nl; 61 for ( i; N -~ 0 ) { sout | i; } sout | nl | nl | nl;89 for ( i; N -~ 0 ) { sout | i; } sout | nl | nl; 62 90 63 91 const int start = 3, comp = 10, inc = 2; 64 92 for ( i; start ~ comp ~ inc + 1 ) { sout | i; } sout | nl | nl; 65 93 66 sout | nl;67 94 for ( S s = (S){0}; s < (S){10,10}; s += (S){1} ) { sout | s; } sout | nl; 68 95 for ( s; (S){10,10} ) { sout | s; } sout | nl; … … 76 103 for ( s; (S){10,10} -~ (S){0} ~ (S){1} ) { sout | s; } sout | nl; 77 104 for ( s; (S){10,10} -~= (S){0} ) { sout | s; } sout | nl; 78 for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl; 105 for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl | nl; 106 107 for ( i; 10 : j; -5 ~ @ ) { sout | i | j; } sout | nl; 108 for ( i; 10 : j; -5 -~ @ ) { sout | i | j; } sout | nl; 109 for ( i; 10 : j; -5 ~ @ ~ 2 ) { sout | i | j; } sout | nl; 110 for ( i; 10 : j; -5 -~ @ ~ 2 ) { sout | i | j; } sout | nl | nl; 111 112 for ( j; -5 ~ @ : i; 10 ) { sout | i | j; } sout | nl; 113 for ( j; -5 -~ @ : i; 10 ) { sout | i | j; } sout | nl; 114 for ( j; -5 ~ @ ~ 2 : i; 10 ) { sout | i | j; } sout | nl; 115 for ( j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j; } sout | nl | nl; 116 117 for ( j; -5 -~ @ ~ 2 : i; 10 : k; 1.5 ~ @ ) { sout | i | j | k; } sout | nl; 118 for ( j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 10 ) { sout | i | j | k; } sout | nl; 119 for ( k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j | k; } sout | nl; 79 120 } 80 121 -
tests/math1.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Fri Apr 22 14:59:21 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 12 16:28:49 201813 // Update Count : 8912 // Last Modified On : Mon Mar 25 22:56:47 2019 13 // Update Count : 109 14 14 // 15 15 … … 49 49 unsigned int e = 2; 50 50 b \= e; 51 sout | "\\" | b | b \ e; 52 sout | "\\" | 'a' \ 3u | 2 \ 8u | 4 \ 3u | -4 \ 3u | nonl; 51 sout | b | "\\" | e | "= " | b \ e; 52 sout | 'a' \ 3 | 2 \ 8 | 4 \ 3 | -4 \ 3 | 4 \ -3 | -4 \ -3; 53 sout | 4.0 \ -3 | -4.0 \ -3 | 4.0 \ 2.1 | (1.0f+2.0fi) \ (3.0f+2.0fi); 53 54 sout | 4 \ -3 | -4 \ -3 | 4.0 \ 2.1 | (1.0f+2.0fi) \ (3.0f+2.0fi); 55 56 struct S { int i; }; 57 double ?*?( double d, S s ) { return d * s.i; } 58 double ?/?( double d, S s ) { return d / s.i; } 59 S ?\?( S s, unsigned long y ) { return (S){ s.i \ y }; } 60 ofstream & ?|?( ofstream & os, S s ) { return os | s.i; } 61 void ?|?( ofstream & os, S s ) { (ofstream &)(os | s); nl( os ); } 62 S s = { 4 }; 63 S x = s \ 2; 64 sout | x; 65 sout | s.i | s \ 2u; 54 66 } // main 55 67 -
tests/numericConstants.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Wed May 24 22:10:36 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Nov 6 17:59:53 201813 // Update Count : 312 // Last Modified On : Tue Feb 5 08:58:16 2019 13 // Update Count : 5 14 14 // 15 15 … … 67 67 // Local Variables: // 68 68 // tab-width: 4 // 69 // compile-command: "cfa minmax.cfa" //69 // compile-command: "cfa numericConstants.cfa" // 70 70 // End: // -
tests/pybin/settings.py
r6a9d4b4 r933f32f 1 from __future__ import print_function2 3 1 import os 2 import subprocess 4 3 import sys 5 import tools4 from . import tools 6 5 7 6 try : … … 39 38 def __init__(self, arch): 40 39 try: 41 canonical_host = Architecture.make Canonical( config.HOSTARCH )40 canonical_host = Architecture.make_canonical( config.HOSTARCH ) 42 41 except KeyError: 43 42 print("Unkown host architecture %s" % config.HOSTARCH, file=sys.stderr) … … 46 45 if arch: 47 46 try: 48 arch = Architecture.make Canonical( arch )47 arch = Architecture.make_canonical( arch ) 49 48 except KeyError: 50 49 print("Unkown architecture %s" % arch, file=sys.stderr) … … 77 76 78 77 @classmethod 79 def make Canonical(_, arch):78 def make_canonical(_, arch): 80 79 return Architecture.KnownArchitectures[arch] 81 80 … … 84 83 def __init__(self, value): 85 84 self.string = "debug" if value else "no debug" 86 self.flags = """DEBUG_FLAGS= "%s"""" % ("-debug -O0" if value else "-nodebug -O2")85 self.flags = """DEBUG_FLAGS=%s""" % ("-debug -O0" if value else "-nodebug -O2") 87 86 88 87 class Install: 89 88 def __init__(self, value): 90 89 self.string = "installed" if value else "in-tree" 91 self.flags = """INSTALL_FLAGS= "%s"""" % ("" if value else "-in-tree")90 self.flags = """INSTALL_FLAGS=%s""" % ("" if value else "-in-tree") 92 91 93 92 class Timeouts: … … 112 111 global install 113 112 global timeout 113 global output_width 114 114 115 dry_run = options.dry_run 116 generating = options.regenerate_expected 117 make = 'make' 118 debug = Debug(options.debug) 119 install = Install(options.install) 120 arch = Architecture(options.arch) 121 timeout = Timeouts(options.timeout, options.global_timeout) 115 dry_run = options.dry_run 116 generating = options.regenerate_expected 117 make = ['make'] 118 debug = Debug(options.debug) 119 install = Install(options.install) 120 arch = Architecture(options.arch) 121 timeout = Timeouts(options.timeout, options.global_timeout) 122 output_width = 24 122 123 123 124 124 def update MakeCmd(force, jobs):125 def update_make_cmd(force, jobs): 125 126 global make 126 127 127 make = "make" if not force else ("make -j%i" % jobs)128 make = ['make'] if not force else ['make', "-j%i" % jobs] 128 129 129 130 def validate(): 130 131 errf = os.path.join(BUILDDIR, ".validate.err") 131 make_ret, _ = tools.make( ".validate", error_file = errf, redirects = "2> /dev/null 1> /dev/null",)132 make_ret, out = tools.make( ".validate", error_file = errf, output=subprocess.DEVNULL, error=subprocess.DEVNULL ) 132 133 if make_ret != 0: 133 134 with open (errf, "r") as myfile: … … 139 140 140 141 tools.rm(errf) 142 143 def prep_output(tests): 144 global output_width 145 output_width = max(map(lambda t: len(t.target()), tests)) -
tests/pybin/test_run.py
r6a9d4b4 r933f32f 4 4 5 5 import pybin.settings 6 import datetime7 8 from string import Template9 10 class DeltaTemplate(Template):11 delimiter = "%"12 13 def strfdelta(tdelta, fmt):14 d["H"], rem = divmod(tdelta.seconds, 3600)15 d["M"], d["S"] = divmod(rem, 60)16 t = DeltaTemplate(fmt)17 return t.substitute(**d)18 6 19 7 # Test class that defines what a test is -
tests/pybin/tools.py
r6a9d4b4 r933f32f 1 from __future__ import print_function2 3 1 import __main__ 4 2 import argparse 3 import contextlib 5 4 import fileinput 6 5 import multiprocessing … … 10 9 import signal 11 10 import stat 11 import subprocess 12 12 import sys 13 import tempfile 13 14 import time 15 import types 14 16 15 17 from pybin import settings 16 from subprocess import Popen, PIPE, STDOUT17 18 18 19 ################################################################################ … … 21 22 22 23 # helper functions to run terminal commands 23 def sh(cmd, print2stdout = True, input = None): 24 # add input redirection if needed 25 if input and os.path.isfile(input): 26 cmd += " < %s" % input 24 def sh(*cmd, timeout = False, output = None, input = None, error = subprocess.STDOUT): 25 cmd = list(cmd) 27 26 28 27 # if this is a dry_run, only print the commands that would be ran 29 28 if settings.dry_run : 30 print("cmd: %s" % cmd) 29 cmd = "{} cmd: {}".format(os.getcwd(), ' '.join(cmd)) 30 if output and not isinstance(output, int): 31 cmd += " > " 32 cmd += output 33 34 if error and not isinstance(error, int): 35 cmd += " 2> " 36 cmd += error 37 38 if input and not isinstance(input, int) and os.path.isfile(input): 39 cmd += " < " 40 cmd += input 41 42 print(cmd) 31 43 return 0, None 32 44 33 # otherwise create a pipe and run the desired command 34 else : 35 proc = Popen(cmd, stdout=None if print2stdout else PIPE, stderr=STDOUT, shell=True) 36 out, err = proc.communicate() 37 return proc.returncode, out 45 with contextlib.ExitStack() as onexit: 46 # add input redirection if needed 47 input = openfd(input, 'r', onexit, True) 48 49 # add output redirection if needed 50 output = openfd(output, 'w', onexit, False) 51 52 # add error redirection if needed 53 error = openfd(error, 'w', onexit, False) 54 55 # run the desired command 56 try: 57 proc = subprocess.run( 58 cmd, 59 stdin =input, 60 stdout=output, 61 stderr=error, 62 timeout=settings.timeout.single if timeout else None 63 ) 64 return proc.returncode, proc.stdout.decode("utf-8") if proc.stdout else None 65 except subprocess.TimeoutExpired: 66 return 124, str(None) 38 67 39 68 def is_ascii(fname): … … 45 74 return False 46 75 47 code, out = sh("file %s" % fname, print2stdout = False)76 code, out = sh("file %s" % fname, output=subprocess.PIPE) 48 77 if code != 0: 49 78 return False … … 56 85 return match.group(1).startswith("ASCII text") 57 86 87 def is_exe(fname): 88 return os.path.isfile(fname) and os.access(fname, os.X_OK) 89 90 def openfd(file, mode, exitstack, checkfile): 91 if not file: 92 return file 93 94 if isinstance(file, int): 95 return file 96 97 if checkfile and not os.path.isfile(file): 98 return None 99 100 file = open(file, mode) 101 exitstack.push(file) 102 return file 103 58 104 # Remove 1 or more files silently 59 105 def rm( files ): 60 if isinstance( files, basestring ): 61 sh("rm -f %s > /dev/null 2>&1" % files ) 62 else: 63 for file in files: 64 sh("rm -f %s > /dev/null 2>&1" % file ) 106 if isinstance(files, str ): files = [ files ] 107 for file in files: 108 sh( 'rm', '-f', file, output=subprocess.DEVNULL, error=subprocess.DEVNULL ) 65 109 66 110 # Create 1 or more directory 67 111 def mkdir( files ): 68 if isinstance( files, basestring ):69 sh("mkdir -p %s" % os.path.dirname(files) )70 else:71 for file in files:72 sh("mkdir -p %s" % os.path.dirname(file))112 if isinstance(files, str ): files = [ files ] 113 for file in files: 114 p = os.path.normpath( file ) 115 d = os.path.dirname ( p ) 116 sh( 'mkdir', '-p', d, output=subprocess.DEVNULL, error=subprocess.DEVNULL ) 73 117 74 118 … … 80 124 # diff two files 81 125 def diff( lhs, rhs ): 82 # diff the output of the files83 diff_cmd = ("diff --text "84 # "--ignore-all-space "85 # "--ignore-blank-lines "86 "--old-group-format='\t\tmissing lines :\n"87 "%%<' \\\n"88 "--new-group-format='\t\tnew lines :\n"89 "%%>' \\\n"90 "--unchanged-group-format='%%=' \\"91 "--changed-group-format='\t\texpected :\n"92 "%%<"93 "\t\tgot :\n"94 "%%>\n' \\\n"95 "--new-line-format='\t\t%%dn\t%%L' \\\n"96 "--old-line-format='\t\t%%dn\t%%L' \\\n"97 "--unchanged-line-format='' \\\n"98 "%s %s")99 100 126 # fetch return code and error from the diff command 101 return sh(diff_cmd % (lhs, rhs), False) 127 return sh( 128 '''diff''', 129 '''--text''', 130 '''--old-group-format=\t\tmissing lines :\n%<''', 131 '''--new-line-format=\t\t%dn\t%L''', 132 '''--new-group-format=\t\tnew lines : \n%>''', 133 '''--old-line-format=\t\t%dn\t%L''', 134 '''--unchanged-group-format=%=''', 135 '''--changed-group-format=\t\texpected :\n%<\t\tgot :\n%>''', 136 '''--unchanged-line-format=''', 137 lhs, 138 rhs, 139 output=subprocess.PIPE 140 ) 102 141 103 142 # call make 104 def make(target, flags = '', redirects = '', error_file = None, silent = False):105 test_param = """test="%s" """ % (error_file) if error_file else ''106 cmd = ' '.join([107 settings.make,108 '-s' if silent else '',143 def make(target, *, flags = '', output = None, error = None, error_file = None, silent = False): 144 test_param = """test="%s" """ % (error_file) if error_file else None 145 cmd = [ 146 *settings.make, 147 '-s' if silent else None, 109 148 test_param, 110 149 settings.arch.flags, … … 112 151 settings.install.flags, 113 152 flags, 114 target ,115 redirects116 ])117 return sh( cmd)153 target 154 ] 155 cmd = [s for s in cmd if s] 156 return sh(*cmd, output=output, error=error) 118 157 119 158 def which(program): 120 import os121 def is_exe(fpath):122 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)123 124 159 fpath, fname = os.path.split(program) 125 160 if fpath: … … 134 169 return None 135 170 136 def run(exe, output, input): 137 ret, _ = sh("timeout %d %s > %s 2>&1" % (settings.timeout.single, exe, output), input = input) 138 return ret 171 @contextlib.contextmanager 172 def tempdir(): 173 cwd = os.getcwd() 174 with tempfile.TemporaryDirectory() as temp: 175 os.chdir(temp) 176 try: 177 yield temp 178 finally: 179 os.chdir(cwd) 139 180 140 181 ################################################################################ … … 143 184 # move a file 144 185 def mv(source, dest): 145 ret, _ = sh("mv %s %s" % (source, dest))186 ret, _ = sh("mv", source, dest) 146 187 return ret 147 188 148 189 # cat one file into the other 149 190 def cat(source, dest): 150 ret, _ = sh("cat %s > %s" % (source, dest))191 ret, _ = sh("cat", source, output=dest) 151 192 return ret 152 193 … … 163 204 164 205 # helper function to check if a files contains only a specific string 165 def file ContainsOnly(file, text) :206 def file_contains_only(file, text) : 166 207 with open(file) as f: 167 208 ff = f.read().strip() 168 209 result = ff == text.strip() 169 210 170 return result; 171 172 # check whether or not a file is executable 173 def fileIsExecutable(file) : 174 try : 175 fileinfo = os.stat(file) 176 return bool(fileinfo.st_mode & stat.S_IXUSR) 177 except Exception as inst: 178 print(type(inst)) # the exception instance 179 print(inst.args) # arguments stored in .args 180 print(inst) 181 return False 211 return result 182 212 183 213 # transform path to canonical form 184 def canonical Path(path):214 def canonical_path(path): 185 215 abspath = os.path.abspath(__main__.__file__) 186 216 dname = os.path.dirname(abspath) … … 188 218 189 219 # compare path even if form is different 190 def path Cmp(lhs, rhs):191 return canonical Path( lhs ) == canonicalPath( rhs )220 def path_cmp(lhs, rhs): 221 return canonical_path( lhs ) == canonical_path( rhs ) 192 222 193 223 # walk all files in a path 194 def pathWalk( op ): 195 def step(_, dirname, names): 224 def path_walk( op ): 225 dname = settings.SRCDIR 226 for dirname, _, names in os.walk(dname): 196 227 for name in names: 197 228 path = os.path.join(dirname, name) 198 229 op( path ) 199 230 200 # Start the walk201 dname = settings.SRCDIR202 os.path.walk(dname, step, '')203 204 231 ################################################################################ 205 232 # system 206 233 ################################################################################ 207 234 # count number of jobs to create 208 def job Count( options, tests ):235 def job_count( options, tests ): 209 236 # check if the user already passed in a number of jobs for multi-threading 210 237 if not options.jobs: … … 228 255 return min( options.jobs, len(tests) ), force 229 256 230 # setup a proper processor pool with correct signal handling231 def setupPool(jobs):232 original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)233 pool = multiprocessing.Pool(jobs)234 signal.signal(signal.SIGINT, original_sigint_handler)235 236 return pool237 238 # handle signals in scope239 class SignalHandling():240 def __enter__(self):241 # enable signal handling242 signal.signal(signal.SIGINT, signal.SIG_DFL)243 244 def __exit__(self, type, value, traceback):245 # disable signal handling246 signal.signal(signal.SIGINT, signal.SIG_IGN)247 248 249 257 # enable core dumps for all the test children 250 258 resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY)) … … 261 269 return False 262 270 raise argparse.ArgumentTypeError(msg) 263 return False264 271 265 272 def fancy_print(text): 266 273 column = which('column') 267 274 if column: 268 cmd = "%s 2> /dev/null" % column 269 proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True) 270 proc.communicate(input=text + "\n") 275 subprocess.run(column, input=bytes(text + "\n", "UTF-8")) 271 276 else: 272 277 print(text) 273 278 274 279 275 def coreInfo(path): 280 def core_info(path): 281 if not os.path.isfile(path): 282 return 1, "ERR Executable path is wrong" 283 276 284 cmd = os.path.join(settings.SRCDIR, "pybin/print-core.gdb") 277 285 if not os.path.isfile(cmd): 278 286 return 1, "ERR Printing format for core dumps not found" 279 287 280 dname = os.path.dirname(path) 281 core = os.path.join(dname, "core" ) 282 if not os.path.isfile(path): 283 return 1, "ERR Executable path is wrong" 288 core = os.path.join(os.getcwd(), "core" ) 284 289 285 290 if not os.path.isfile(core): 286 291 return 1, "ERR No core dump" 287 292 288 return sh( "gdb -n %s %s -batch -x %s" % (path, core, cmd), print2stdout=False)293 return sh('gdb', '-n', path, core, '-batch', '-x', cmd, output=subprocess.PIPE) 289 294 290 295 class Timed: -
tests/raii/.expect/ctor-autogen-ERR1.txt
r6a9d4b4 r933f32f 1 raii/ctor-autogen.cfa:102:1 error: Unique best alternative includes deleted identifier in Cast of:1 raii/ctor-autogen.cfa:102:1 error: Unique best alternative includes deleted identifier in Generated Cast of: 2 2 Application of 3 3 Deleted Expression … … 27 27 28 28 ... to arguments 29 Cast of:29 Generated Cast of: 30 30 Member Expression, with field: 31 31 x: signed int 32 32 ... from aggregate: 33 Cast of:33 Generated Cast of: 34 34 Variable Expression: m: reference to instance of struct Managed with body 1 35 35 ... to: … … 37 37 ... to: 38 38 reference to signed int 39 Cast of:39 Generated Cast of: 40 40 constant expression (0 0: zero_t) 41 41 ... to: … … 48 48 49 49 ... to arguments 50 Cast of:50 Generated Cast of: 51 51 Variable Expression: x: instance of struct Managed with body 1 52 52 ... to: -
tests/raii/init_once.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Tue Jun 14 15:43:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 9 11:30:29 201613 // Update Count : 312 // Last Modified On : Fri Mar 22 13:41:26 2019 13 // Update Count : 4 14 14 // 15 15 … … 192 192 // Local Variables: // 193 193 // tab-width: 4 // 194 // compile-command: "cfa init_once.c " //194 // compile-command: "cfa init_once.cfa" // 195 195 // End: // -
tests/rational.cfa
r6a9d4b4 r933f32f 10 10 // Created On : Mon Mar 28 08:43:12 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 4 21:46:42 201813 // Update Count : 6912 // Last Modified On : Wed Mar 27 07:37:17 2019 13 // Update Count : 80 14 14 // 15 15 … … 19 19 #include <fstream.hfa> 20 20 21 // UNNECESSARY, FIX ME22 void ?{}( int & this ) { this = 0; }23 void ?{}( int & this, zero_t ) { this = 0; }24 void ?{}( int & this, one_t ) { this = 1; }25 21 double convert( int i ) { return (double)i; } 26 22 int convert( double d ) { return (int)d; } … … 58 54 sout | a * b; 59 55 sout | a / b; 56 // sout | a \ 2 | b \ 2; // FIX ME 57 // sout | a \ -2 | b \ -2; 60 58 61 59 sout | "conversion"; -
tests/sum.cfa
r6a9d4b4 r933f32f 11 11 // Created On : Wed May 27 17:56:53 2015 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Sun Dec 23 23:00:38 201814 // Update Count : 28713 // Last Modified On : Sun May 19 11:21:02 2019 14 // Update Count : 330 15 15 // 16 16 17 17 #include <fstream.hfa> 18 18 #include <stdlib.hfa> 19 20 void ?{}( int & c, zero_t ) { c = 0; } // not in prelude21 19 22 20 trait sumable( otype T ) { … … 31 29 T sum( size_t size, T a[] ) { 32 30 T total = 0; // initialize by 0 constructor 33 for ( size_t i = 0; i < size; i += 1)31 for ( i; size ) 34 32 total += a[i]; // select appropriate + 35 33 return total; 36 34 } // sum 37 35 38 // Not in prelude.39 unsigned char ?+?( unsigned char t1, unsigned char t2 ) { return (int)t1 + t2; } // cast forces integer addition, otherwise recursion40 unsigned char ?+=?( unsigned char & t1, unsigned char t2 ) { t1 = t1 + t2; return t1; }41 unsigned char ++?( unsigned char & t ) { t += 1; return t; }42 unsigned char ?++( unsigned char & t ) { unsigned char temp = t; t += 1; return temp; }43 44 // Not in prelude.45 void ?{}( unsigned char & c, zero_t ) { c = 0; }46 void ?{}( float & f, zero_t ) { f = 0.0; }47 void ?{}( double & d, zero_t ) { d = 0.0; }48 49 36 int main( void ) { 50 37 const int low = 5, High = 15, size = High - low; 51 38 52 unsigned char s = 0, a[size], v = (char)low;53 for ( int i = 0; i < size; i += 1, v += 1 ) {39 signed char s = 0, a[size], v = (char)low; 40 for ( int i = 0; i < size; i += 1, v += 1hh ) { 54 41 s += v; 55 42 a[i] = v; 56 43 } // for 57 44 sout | "sum from" | low | "to" | High | "is" 58 | sum( size, (unsigned char *)a ) | ", check" | (int)s; 45 | sum( size, (signed char *)a ) | ", check" | (signed char)s; 46 47 unsigned char s = 0, a[size], v = low; 48 for ( int i = 0; i < size; i += 1, v += 1hhu ) { 49 s += (unsigned char)v; 50 a[i] = (unsigned char)v; 51 } // for 52 sout | "sum from" | low | "to" | High | "is" 53 | sum( size, (unsigned char *)a ) | ", check" | (unsigned char)s; 54 55 short int s = 0, a[size], v = low; 56 for ( int i = 0; i < size; i += 1, v += 1h ) { 57 s += (short int)v; 58 a[i] = (short int)v; 59 } // for 60 sout | "sum from" | low | "to" | High | "is" 61 | sum( size, (short int *)a ) | ", check" | (short int)s; 59 62 60 63 int s = 0, a[size], v = low; -
tests/test.py
r6a9d4b4 r933f32f 1 #!/usr/bin/python 2 from __future__ import print_function 1 #!/usr/bin/python3 3 2 4 3 from pybin.tools import * … … 9 8 import re 10 9 import sys 10 import tempfile 11 11 import time 12 12 … … 15 15 ################################################################################ 16 16 17 def find Tests():17 def find_tests(): 18 18 expected = [] 19 19 20 def match Test(path):20 def match_test(path): 21 21 match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path) 22 22 if match : … … 28 28 expected.append(test) 29 29 30 path Walk( matchTest )30 path_walk( match_test ) 31 31 32 32 return expected 33 33 34 34 # reads the directory ./.expect and indentifies the tests 35 def list Tests( includes, excludes ):35 def list_tests( includes, excludes ): 36 36 # tests directly in the .expect folder will always be processed 37 test_list = find Tests()37 test_list = find_tests() 38 38 39 39 # if we have a limited number of includes, filter by them … … 52 52 53 53 # from the found tests, filter all the valid tests/desired tests 54 def valid Tests( options ):54 def valid_tests( options ): 55 55 tests = [] 56 56 … … 59 59 if options.regenerate_expected : 60 60 for testname in options.tests : 61 testname = canonical Path( testname )61 testname = canonical_path( testname ) 62 62 if Test.valid_name(testname): 63 found = [test for test in all Tests if canonicalPath( test.target() ) == testname]63 found = [test for test in all_tests if canonical_path( test.target() ) == testname] 64 64 tests.append( found[0] if len(found) == 1 else Test.from_target(testname) ) 65 65 else : … … 69 69 # otherwise we only need to validate that all tests are present in the complete list 70 70 for testname in options.tests: 71 test = [t for t in all Tests if pathCmp( t.target(), testname )]71 test = [t for t in all_tests if path_cmp( t.target(), testname )] 72 72 73 73 if test : … … 79 79 80 80 # parses the option 81 def getOptions():81 def parse_args(): 82 82 # create a parser with the arguments for the tests script 83 83 parser = argparse.ArgumentParser(description='Script which runs cforall tests') … … 102 102 print('ERROR: invalid arguments', file=sys.stderr) 103 103 parser.print_help(sys.stderr) 104 sys.exit(1)104 sys.exit(1) 105 105 106 106 # script must have at least some tests to run or be listing … … 112 112 # check that exactly one of the booleans is set to true 113 113 if not sum( (listing, all_tests, some_tests, some_dirs) ) > 0 : 114 print(' ERROR: must have option \'--all\', \'--list\', \'--include\', \'-I\' or non-empty test list', file=sys.stderr)114 print('''ERROR: must have option '--all', '--list', '--include', '-I' or non-empty test list''', file=sys.stderr) 115 115 parser.print_help() 116 116 sys.exit(1) … … 124 124 return val == 0 or settings.dry_run 125 125 126 def isExe(file): 127 return settings.dry_run or fileIsExecutable(file) 128 129 def noRule(file, target): 130 return not settings.dry_run and fileContainsOnly(file, "make: *** No rule to make target `%s'. Stop." % target) 126 def no_rule(file, target): 127 return not settings.dry_run and file_contains_only(file, "make: *** No rule to make target `%s'. Stop." % target) 131 128 132 129 # logic to run a single test and return the result (No handling of printing or other test framework logic) … … 145 142 # build, skipping to next test on error 146 143 with Timed() as comp_dur: 147 make_ret, _ = make( test.target(), redirects = ("2> %s 1> /dev/null" % out_file), error_file = err_file ) 148 149 # if the make command succeds continue otherwise skip to diff 144 make_ret, _ = make( test.target(), output=subprocess.DEVNULL, error=out_file, error_file = err_file ) 145 150 146 run_dur = None 151 if success(make_ret): 152 with Timed() as run_dur: 153 if isExe(exe_file): 154 # run test 155 retcode = run(exe_file, out_file, in_file) 147 # run everything in a temp directory to make sure core file are handled properly 148 with tempdir(): 149 # if the make command succeds continue otherwise skip to diff 150 if success(make_ret): 151 with Timed() as run_dur: 152 if settings.dry_run or is_exe(exe_file): 153 # run test 154 retcode, _ = sh(exe_file, output=out_file, input=in_file, timeout=True) 155 else : 156 # simply cat the result into the output 157 retcode = cat(exe_file, out_file) 158 else: 159 retcode = mv(err_file, out_file) 160 161 if success(retcode): 162 if settings.generating : 163 # if we are ounly generating the output we still need to check that the test actually exists 164 if no_rule(out_file, test.target()) : 165 retcode = 1 166 error = "\t\tNo make target for test %s!" % test.target() 167 rm(out_file) 168 else: 169 error = None 156 170 else : 157 # simply cat the result into the output 158 retcode = cat(exe_file, out_file) 159 else: 160 retcode = mv(err_file, out_file) 161 162 if success(retcode): 163 if settings.generating : 164 # if we are ounly generating the output we still need to check that the test actually exists 165 if noRule(out_file, test.target()) : 166 retcode = 1 167 error = "\t\tNo make target for test %s!" % test.target() 168 rm(out_file) 169 else: 170 error = None 171 else : 172 # fetch return code and error from the diff command 173 retcode, error = diff(cmp_file, out_file) 174 175 else: 176 with open (out_file, "r") as myfile: 177 error = myfile.read() 178 179 ret, info = coreInfo(exe_file) 180 error = error + info 171 # fetch return code and error from the diff command 172 retcode, error = diff(cmp_file, out_file) 173 174 else: 175 with open (out_file, "r") as myfile: 176 error = myfile.read() 177 178 ret, info = core_info(exe_file) 179 error = error + info if error else info 181 180 182 181 … … 189 188 # run a single test and handle the errors, outputs, printing, exception handling, etc. 190 189 def run_test_worker(t) : 191 192 with SignalHandling(): 190 try : 193 191 # print formated name 194 name_txt = "%24s " % t.name192 name_txt = '{0:{width}} '.format(t.target(), width=settings.output_width) 195 193 196 194 retcode, error, duration = run_single_test(t) … … 200 198 201 199 #print result with error if needed 202 text = name_txt + result_txt200 text = '\t' + name_txt + result_txt 203 201 out = sys.stdout 204 202 if error : 205 text = text + "\n"+ error203 text = text + '\n' + error 206 204 out = sys.stderr 207 205 … … 210 208 sys.stderr.flush() 211 209 212 return retcode != TestResult.SUCCESS 210 return retcode != TestResult.SUCCESS 211 except KeyboardInterrupt: 212 False 213 213 214 214 # run the given list of tests with the given parameters 215 215 def run_tests(tests, jobs) : 216 216 # clean the sandbox from previous commands 217 make('clean', redirects = '> /dev/null 2>&1')217 make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL) 218 218 219 219 # create the executor for our jobs and handle the signal properly 220 pool = setupPool(jobs)220 pool = multiprocessing.Pool(jobs) 221 221 222 222 # for each test to run … … 233 233 234 234 # clean the workspace 235 make('clean', redirects = '> /dev/null 2>&1')235 make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL) 236 236 237 237 for failed in results: … … 248 248 249 249 # parse the command line arguments 250 options = getOptions()250 options = parse_args() 251 251 252 252 # init global settings … … 254 254 255 255 # fetch the liest of all valid tests 256 all Tests = listTests( options.include, options.exclude )256 all_tests = list_tests( options.include, options.exclude ) 257 257 258 258 259 259 # if user wants all tests than no other treatement of the test list is required 260 260 if options.all or options.list or options.list_comp or options.include : 261 tests = all Tests261 tests = all_tests 262 262 263 263 #otherwise we need to validate that the test list that was entered is valid 264 264 else : 265 tests = valid Tests( options )265 tests = valid_tests( options ) 266 266 267 267 # make sure we have at least some test to run … … 281 281 elif options.list : 282 282 print("Listing for %s:%s"% (settings.arch.string, settings.debug.string)) 283 fancy_print("\n".join(map(lambda t: "%s" % (t.toString()), tests)))283 fancy_print("\n".join(map(lambda t: t.toString(), tests))) 284 284 285 285 else : 286 286 # check the build configuration works 287 settings.prep_output(tests) 287 288 settings.validate() 288 289 289 options.jobs, forceJobs = jobCount( options, tests ) 290 settings.updateMakeCmd(forceJobs, options.jobs) 291 292 print('%s (%s:%s) on %i cores' % ( 293 'Regenerate tests' if settings.generating else 'Running', 290 options.jobs, forceJobs = job_count( options, tests ) 291 settings.update_make_cmd(forceJobs, options.jobs) 292 293 print('%s %i tests on %i cores (%s:%s)' % ( 294 'Regenerating' if settings.generating else 'Running', 295 len(tests), 296 options.jobs, 294 297 settings.arch.string, 295 settings.debug.string, 296 options.jobs 298 settings.debug.string 297 299 )) 298 300 -
tests/warnings/.expect/self-assignment.txt
r6a9d4b4 r933f32f 1 warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Cast of:1 warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Generated Cast of: 2 2 Variable Expression: j: signed int 3 3 ... to: 4 4 reference to signed int 5 warnings/self-assignment.cfa:30:1 warning: self assignment of expression: Cast of:5 warnings/self-assignment.cfa:30:1 warning: self assignment of expression: Generated Cast of: 6 6 Variable Expression: s: instance of struct S with body 1 7 7 ... to: 8 8 reference to instance of struct S with body 1 9 warnings/self-assignment.cfa:31:1 warning: self assignment of expression: Cast of:9 warnings/self-assignment.cfa:31:1 warning: self assignment of expression: Generated Cast of: 10 10 Member Expression, with field: 11 11 i: signed int … … 14 14 ... to: 15 15 reference to signed int 16 warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Cast of:16 warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Generated Cast of: 17 17 Member Expression, with field: 18 18 i: signed int -
tests/warnings/self-assignment.cfa
r6a9d4b4 r933f32f 9 9 // Author : Rob Schluntz 10 10 // Created On : Thu Mar 1 13:53:57 2018 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Thu Mar 1 13:53:57 201813 // Update Count : 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 20 07:56:17 2019 13 // Update Count : 3 14 14 // 15 15 16 16 struct S { 17 int i;17 int i; 18 18 }; 19 19 20 20 struct T { 21 S s;21 S s; 22 22 }; 23 23 24 24 int main() { 25 int j = 0;26 S s = { 0 };27 T t = { { 0 } };25 int j = 0; 26 S s = { 0 }; 27 T t = { { 0 } }; 28 28 29 j = j;30 s = s;31 s.i = s.i;32 t.s.i = t.s.i;29 j = j; 30 s = s; 31 s.i = s.i; 32 t.s.i = t.s.i; 33 33 } 34 34 -
tools/Makefile.in
r6a9d4b4 r933f32f 194 194 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 195 195 ACLOCAL = @ACLOCAL@ 196 ALLOCA = @ALLOCA@197 196 AMTAR = @AMTAR@ 198 197 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -
tools/PrettyGitLogs.sh
r6a9d4b4 r933f32f 27 27 git rev-list --format=short ${GitOldRef}...${GitNewRef} > ${GIT_LOG} 28 28 29 git diff --stat ${GitNewRef} ${GitOldRef}> ${GIT_DIFF}29 git diff --stat --color ${GitNewRef} ${GitOldRef} | sed -e 's/\[32m/<span style\=\"color\: \#00AA00\;\">/g' -e 's/\[31m/<span style\=\"color\: \#AA0000\;\">/g' -e 's/\[m/<\/span>/g' > ${GIT_DIFF} -
tools/prettyprinter/Makefile.in
r6a9d4b4 r933f32f 223 223 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 224 224 ACLOCAL = @ACLOCAL@ 225 ALLOCA = @ALLOCA@226 225 AMTAR = @AMTAR@ 227 226 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
Note:
See TracChangeset
for help on using the changeset viewer.