Changes in / [933f32f:6a9d4b4]
- Files:
-
- 18 added
- 152 deleted
- 224 edited
-
.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 (deleted)
-
benchmark/ctxswitch/cfa_thrd2.cfa (modified) (1 diff)
-
benchmark/fixcsv.sh (deleted)
-
benchmark/jenkins.sh (added)
-
benchmark/tls-fetch_add.c (deleted)
-
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 (deleted)
-
doc/papers/concurrency/examples/Fib.c (deleted)
-
doc/papers/concurrency/examples/Fib.cfa (deleted)
-
doc/papers/concurrency/examples/Fib.cpp (deleted)
-
doc/papers/concurrency/examples/Fib.py (deleted)
-
doc/papers/concurrency/examples/Fib.sim (deleted)
-
doc/papers/concurrency/examples/Fib2.cfa (deleted)
-
doc/papers/concurrency/examples/Fib2.cpp (deleted)
-
doc/papers/concurrency/examples/Fib2.py (deleted)
-
doc/papers/concurrency/examples/FibRefactor.py (deleted)
-
doc/papers/concurrency/examples/Fmt.sim (deleted)
-
doc/papers/concurrency/examples/Format.cc (deleted)
-
doc/papers/concurrency/examples/Format.cfa (deleted)
-
doc/papers/concurrency/examples/Format.cpp (deleted)
-
doc/papers/concurrency/examples/Format.py (deleted)
-
doc/papers/concurrency/examples/Pingpong.cc (deleted)
-
doc/papers/concurrency/examples/Pingpong.cfa (deleted)
-
doc/papers/concurrency/examples/Pingpong.py (deleted)
-
doc/papers/concurrency/examples/ProdCons.cfa (deleted)
-
doc/papers/concurrency/examples/ProdCons.cpp (deleted)
-
doc/papers/concurrency/examples/ProdCons.py (deleted)
-
doc/papers/concurrency/examples/ProdCons.sim (deleted)
-
doc/papers/concurrency/examples/Refactor.py (deleted)
-
doc/papers/concurrency/examples/counter.cpp (deleted)
-
doc/papers/concurrency/mail (modified) (1 diff)
-
doc/proposals/interned_string.cc (deleted)
-
doc/proposals/interned_string.h (deleted)
-
doc/proposals/specialized_casts.md (deleted)
-
doc/proposals/unicode.html (deleted)
-
doc/proposals/virtual.txt (added)
-
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 (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/algo-summary.gp (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/bu-summary.dat (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-bu.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-co.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-dca.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-def.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-cc/cfa-imm.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-mem-by-time.tsv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-mem.tsv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-plots.gp (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/cfa-time.tsv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/data.xlsx (deleted)
-
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 (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/mem-by-max-depth.tsv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/metric-plots.gp (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per-prob-scatter.gp (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per-prob.gp (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per-prob.tsv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/imgui-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/io1-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/io2-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/kernel-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/math1-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/math2-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/math3-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/math4-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/minmax-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/preemption-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/rational-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/searchsort-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/per_prob/swap-per-prob.csv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/time-by-max-assns.tsv (deleted)
-
doc/theses/aaron_moss_PhD/phd/evaluation/time-by-max-depth.tsv (deleted)
-
doc/theses/aaron_moss_PhD/phd/experiments.tex (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/bilson-conv-graph.eps (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/bilson-conv-graph.odg (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/extended-conv-graph.eps (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/extended-conv-graph.odg (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/persistent-union-find.eps (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/persistent-union-find.odg (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/resolution-dag.eps (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/resolution-dag.odg (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/safe-conv-graph.eps (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/safe-conv-graph.odg (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/union-find-with-classes.eps (deleted)
-
doc/theses/aaron_moss_PhD/phd/figures/union-find-with-classes.odg (deleted)
-
doc/theses/aaron_moss_PhD/phd/frontpgs.tex (modified) (6 diffs)
-
doc/theses/aaron_moss_PhD/phd/generic-bench.tex (deleted)
-
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 (deleted)
-
longrun_tests/Makefile.in (deleted)
-
longrun_tests/block.cfa (deleted)
-
longrun_tests/coroutine.cfa (deleted)
-
longrun_tests/create.cfa (deleted)
-
longrun_tests/disjoint.cfa (deleted)
-
longrun_tests/enter.cfa (deleted)
-
longrun_tests/enter3.cfa (deleted)
-
longrun_tests/preempt.cfa (deleted)
-
longrun_tests/processor.cfa (deleted)
-
longrun_tests/stack.cfa (deleted)
-
longrun_tests/update-type (deleted)
-
longrun_tests/wait.cfa (deleted)
-
longrun_tests/yield.cfa (deleted)
-
src/AST/Attribute.cpp (deleted)
-
src/AST/Attribute.hpp (deleted)
-
src/AST/Bitfield.hpp (deleted)
-
src/AST/CVQualifiers.hpp (deleted)
-
src/AST/Convert.cpp (deleted)
-
src/AST/Convert.hpp (deleted)
-
src/AST/Decl.cpp (deleted)
-
src/AST/Decl.hpp (deleted)
-
src/AST/DeclReplacer.cpp (deleted)
-
src/AST/DeclReplacer.hpp (deleted)
-
src/AST/Expr.cpp (deleted)
-
src/AST/Expr.hpp (deleted)
-
src/AST/FunctionSpec.hpp (deleted)
-
src/AST/Fwd.hpp (deleted)
-
src/AST/Init.cpp (deleted)
-
src/AST/Init.hpp (deleted)
-
src/AST/Label.hpp (deleted)
-
src/AST/LinkageSpec.cpp (deleted)
-
src/AST/LinkageSpec.hpp (deleted)
-
src/AST/Node.cpp (deleted)
-
src/AST/Node.hpp (deleted)
-
src/AST/ParseNode.hpp (deleted)
-
src/AST/Pass.hpp (deleted)
-
src/AST/Pass.impl.hpp (deleted)
-
src/AST/Pass.proto.hpp (deleted)
-
src/AST/Stmt.cpp (deleted)
-
src/AST/Stmt.hpp (deleted)
-
src/AST/StorageClasses.hpp (deleted)
-
src/AST/Type.cpp (deleted)
-
src/AST/Type.hpp (deleted)
-
src/AST/TypeSubstitution.cpp (deleted)
-
src/AST/TypeSubstitution.hpp (deleted)
-
src/AST/TypeVar.hpp (deleted)
-
src/AST/Visitor.hpp (deleted)
-
src/AST/module.mk (deleted)
-
src/AST/porting.md (deleted)
-
src/BasicTypes-gen.cc (deleted)
-
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 (deleted)
-
src/CodeGen/module.mk (modified) (1 diff)
-
src/Common/Assert.cc (modified) (1 diff)
-
src/Common/Heap.cc (added)
-
src/Common/Heap.h (added)
-
src/Common/PassVisitor.cc (deleted)
-
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 (deleted)
-
src/Common/SemanticError.h (modified) (1 diff)
-
src/Common/Stats.h (deleted)
-
src/Common/Stats/Base.h (deleted)
-
src/Common/Stats/Counter.cc (deleted)
-
src/Common/Stats/Counter.h (deleted)
-
src/Common/Stats/Heap.cc (deleted)
-
src/Common/Stats/Heap.h (deleted)
-
src/Common/Stats/Stats.cc (deleted)
-
src/Common/Stats/Time.cc (deleted)
-
src/Common/Stats/Time.h (deleted)
-
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) (23 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) (11 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 (deleted)
-
tests/concurrent/examples/.expect/gortn.txt (deleted)
-
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 (deleted)
-
tests/concurrent/examples/matrixSum.cfa (modified) (2 diffs)
-
tests/concurrent/examples/quickSort.cfa (modified) (3 diffs)
-
tests/concurrent/examples/quickSort.generic.cfa (deleted)
-
tests/concurrent/waitfor/parse2.cfa (modified) (2 diffs)
-
tests/config.py.in (modified) (1 diff)
-
tests/coroutine/.expect/devicedriver.txt (deleted)
-
tests/coroutine/.expect/fmtLines.txt (modified) (2 diffs)
-
tests/coroutine/.in/devicedriver.txt (deleted)
-
tests/coroutine/.in/fmtLines.txt (modified) (2 diffs)
-
tests/coroutine/cntparens.cfa (deleted)
-
tests/coroutine/devicedriver.cfa (deleted)
-
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 (deleted)
-
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 (added)
-
tests/preempt_longrun/Makefile.in (added)
-
tests/preempt_longrun/block.c (added)
-
tests/preempt_longrun/coroutine.c (added)
-
tests/preempt_longrun/create.c (added)
-
tests/preempt_longrun/disjoint.c (added)
-
tests/preempt_longrun/enter.c (added)
-
tests/preempt_longrun/enter3.c (added)
-
tests/preempt_longrun/preempt.c (added)
-
tests/preempt_longrun/processor.c (added)
-
tests/preempt_longrun/stack.c (added)
-
tests/preempt_longrun/update-type (added)
-
tests/preempt_longrun/wait.c (added)
-
tests/preempt_longrun/yield.c (added)
-
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 (deleted)
-
tools/prettyprinter/Makefile.in (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
r933f32f r6a9d4b4 10 10 config.py 11 11 stamp-h1 12 libtool13 12 /Makefile 14 13 **/Makefile … … 50 49 libcfa/arm-nolib/ 51 50 51 52 52 # generated by bison and lex from parser.yy and lex.ll 53 53 src/Parser/parser.output -
Jenkins/FullBuild
r933f32f r6a9d4b4 17 17 18 18 parallel ( 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' ) },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 ) }, 25 25 ) 26 26 } 27 28 //Push latest changes to do-lang repo 29 push_build() 27 30 } 28 29 promote_email(true)30 31 } 31 32 … … 42 43 43 44 //Send email to notify the failure 44 promote_ email(false)45 promote_failure_email() 45 46 } 46 47 … … 56 57 //=========================================================================================================== 57 58 58 def trigger_build(String cc, String arch ) {59 def trigger_build(String cc, String arch, Boolean publish) { 59 60 def result = build job: 'Cforall/master', \ 60 61 parameters: [ \ … … 76 77 [$class: 'BooleanParameterValue', \ 77 78 name: 'Publish', \ 78 value: true], \79 value: publish], \ 79 80 [$class: 'BooleanParameterValue', \ 80 81 name: 'Silent', \ … … 88 89 sh("wget -q -O - http://localhost:8084/jenkins/job/Cforall/job/master/${result.number}/consoleText") 89 90 error(result.result) 91 } 92 } 93 94 def push_build() { 95 //Don't use the build_stage function which outputs the compiler 96 stage('Push') { 97 98 status_prefix = 'Push' 99 100 def out_dir = pwd tmp: true 101 sh "mkdir -p ${out_dir}" 102 103 //checkout the code to make sure this is a valid git repo 104 checkout scm 105 106 collect_git_info() 107 108 //parse git logs to find what changed 109 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') 90 119 } 91 120 } … … 112 141 113 142 //Email notification on a full build failure 114 def promote_ email(boolean success) {143 def promote_failure_email() { 115 144 echo('notifying users') 116 117 def result = success ? "PROMOTE - SUCCESS" : "PROMOTE - FAILURE"118 145 119 146 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line 120 147 //Configurations for email format 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> 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". 124 153 125 <p>Check console output at ${env.BUILD_URL} to view the results.</p> 154 Check console output at ${env.BUILD_URL} to view the results. 126 155 127 <p>- Status --------------------------------------------------------------</p> 156 - Status -------------------------------------------------------------- 128 157 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> 158 PROMOTE FAILURE 136 159 """ 137 160 … … 139 162 140 163 //send email notification 141 emailext body: email_body, subject: email_subject, to: email_to, attachLog: !success164 emailext body: email_body, subject: email_subject, to: email_to, attachLog: true 142 165 } -
Jenkinsfile
r933f32f r6a9d4b4 1 1 #!groovy 2 3 import groovy.transform.Field4 2 5 3 //=========================================================================================================== … … 24 22 wrap([$class: 'TimestamperBuildWrapper']) { 25 23 24 notify_server(0) 25 26 26 Settings = prepare_build() 27 27 … … 34 34 checkout() 35 35 36 notify_server(0) 37 36 38 build() 37 39 … … 48 50 BuildDir = pwd tmp: true 49 51 SrcDir = pwd tmp: false 52 53 notify_server(45) 50 54 } 51 55 } … … 68 72 finally { 69 73 //Send email with final results if this is not a full build 70 email(log_needed) 74 if( Settings && !Settings.Silent ) { 75 email(log_needed, Settings.IsSandbox) 76 } 71 77 72 78 echo 'Build Completed' … … 110 116 //Also specify the compiler by hand 111 117 targets="" 112 if( Settings.RunAllTests || Settings.RunBenchmark) {118 if( Settings.RunAllTests ) { 113 119 targets="--with-target-hosts='host:debug,host:nodebug'" 114 120 } else { … … 147 153 dir (BuildDir) { 148 154 //Append bench results 149 sh " make --no-print-directory -C benchmark jenkins"155 sh "${SrcDir}/benchmark/jenkins.sh ${Settings.GitNewRef} ${Settings.Architecture} ${BuildDir}/bench.json" 150 156 } 151 157 } … … 170 176 build_stage('Publish') { 171 177 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) 178 if( !Settings.Publish ) return 176 179 177 180 //Then publish the results 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') 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' 182 182 } 183 183 } … … 196 196 197 197 return """ 198 <pre>199 198 The branch ${env.BRANCH_NAME} has been updated. 200 199 ${gitUpdate} 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> 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 ----------------------------------------------------------------- 212 208 ${gitLog} 213 </pre> 214 215 <p>-----------------------------------------------------------------------</p> 216 <pre> 209 ----------------------------------------------------------------------- 217 210 Summary of changes: 218 211 ${gitDiff} 219 </pre>220 212 """ 221 213 } 222 214 223 215 //Standard build email notification 224 def email(boolean log ) {216 def email(boolean log, boolean bIsSandbox) { 225 217 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line 226 218 //Configurations for email format … … 229 221 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase() 230 222 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}" 231 def email_body = """ <p>This is an automated email from the Jenkins build machine. It was223 def email_body = """This is an automated email from the Jenkins build machine. It was 232 224 generated because of a git hooks/post-receive script following 233 a ref change which was pushed to the C \u2200 repository.</p>225 a ref change which was pushed to the Cforall repository. 234 226 """ + GitLogMessage() 235 227 236 def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"237 238 if( Settings && !Settings. Silent) {228 def email_to = "cforall@lists.uwaterloo.ca" 229 230 if( Settings && !Settings.IsSandbox ) { 239 231 //send email notification 240 232 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log … … 319 311 } 320 312 321 this.IsSandbox = (branch == "jenkins-sandbox")322 313 this.RunAllTests = param.RunAllTests 323 314 this.RunBenchmark = param.RunBenchmark … … 325 316 this.Publish = param.Publish 326 317 this.Silent = param.Silent 318 this.IsSandbox = (branch == "jenkins-sandbox") 327 319 328 320 def full = param.RunAllTests ? " (Full)" : "" … … 341 333 this.GitNewRef = '' 342 334 this.GitOldRef = '' 343 }344 }345 346 class PlotGroup implements Serializable {347 public String name348 public String unit349 public boolean log350 351 PlotGroup(String name, String unit, boolean log) {352 this.name = name353 this.unit = unit354 this.log = log355 335 } 356 336 } … … 418 398 } 419 399 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 return 403 } 404 420 405 def make_doc() { 421 406 def err = null … … 432 417 } 433 418 } 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
r933f32f r6a9d4b4 11 11 ## Created On : Sun May 31 22:14:18 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Sat Feb 2 16:54:42 201914 ## Update Count : 2113 ## Last Modified On : Wed Dec 14 14:20:48 2016 14 ## Update Count : 15 15 15 ############################################################################### 16 16 … … 18 18 ACLOCAL_AMFLAGS = -I automake 19 19 20 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* # order important 20 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* 21 # order important 21 22 22 23 SUBDIRS = driver src . @LIBCFA_TARGET_DIRS@ -
Makefile.in
r933f32f r6a9d4b4 250 250 distcleancheck_listfiles = find . -type f -print 251 251 ACLOCAL = @ACLOCAL@ 252 ALLOCA = @ALLOCA@ 252 253 AMTAR = @AMTAR@ 253 254 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 395 396 AUTOMAKE_OPTIONS = foreign # do not require all the GNU file names 396 397 ACLOCAL_AMFLAGS = -I automake 397 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* # order important398 MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* 398 399 SUBDIRS = driver src . @LIBCFA_TARGET_DIRS@ 399 400 noinst_DATA = @LIBCFA_TARGET_MAKEFILES@ … … 927 928 .PRECIOUS: Makefile 928 929 930 # order important 929 931 930 932 @LIBCFA_TARGET_MAKEFILES@ : Makefile $(srcdir)/libcfa/configure -
automake/cfa.m4
r933f32f r6a9d4b4 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.m484 AC_DEFUN([M4CFA_CHECK_COMPILE_FLAG],85 [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF86 AS_VAR_PUSHDEF([CACHEVAR],[m4cfa_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl87 AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [88 m4cfa_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS89 _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])dnl98 ])dnl M4CFA_CHECK_COMPILE_FLAGS -
benchmark/Makefile.am
r933f32f r6a9d4b4 21 21 include $(top_srcdir)/src/cfa.make 22 22 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 23 24 25 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread 26 AM_CFAFLAGS = -quiet -in-tree -nodebug 27 AM_UPPFLAGS = -quiet -nodebug -multi 49 28 50 29 TOOLSDIR = ${abs_top_builddir}/tools/ … … 67 46 68 47 .NOTPARALLEL: 69 .PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv70 48 71 49 ## ========================================================================================================= … … 82 60 83 61 %.runquiet : 84 @+make $(basename $@) CFLAGS="-w" __quiet=quiet62 @+make $(basename $@) CFLAGS="-w" 85 63 @taskset -c 1 ./a.out 86 64 @rm -f a.out … … 95 73 ## ========================================================================================================= 96 74 97 FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@98 99 75 jenkins$(EXEEXT): 76 @echo "{" 77 @echo -e '\t"githash": "'${githash}'",' 78 @echo -e '\t"arch": "' ${arch} '",' 100 79 @DOifskipcompile@ 101 @+make compile.csv 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},' 102 84 @DOendif@ 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 $@ 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 "}" 144 109 145 110 ## ========================================================================================================= 146 111 loop$(EXEEXT): 147 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c112 $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c 148 113 149 114 function$(EXEEXT): 150 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c115 $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c 151 116 152 117 fetch_add$(EXEEXT): 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 118 $(AM_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 157 119 158 120 ## ========================================================================================================= … … 161 123 function.run \ 162 124 fetch_add.run \ 163 tls-fetch_add.run \164 125 ctxswitch-pthread.run \ 165 126 ctxswitch-cfa_coroutine.run \ … … 178 139 179 140 ctxswitch-kos_fibre$(EXEEXT): 180 $( BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp -I$(LIBFIBRE_DIR) -lfibre141 $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp -I$(LIBFIBRE_DIR) -lfibre 181 142 182 143 ctxswitch-kos_fibre2$(EXEEXT): 183 $( BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre144 $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre 184 145 endif 185 146 … … 187 148 188 149 ctxswitch-pthread$(EXEEXT): 189 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c150 $(AM_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c 190 151 191 152 ctxswitch-cfa_coroutine$(EXEEXT): 192 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa153 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa 193 154 194 155 ctxswitch-cfa_thread$(EXEEXT): 195 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa156 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa 196 157 197 158 ctxswitch-cfa_thread2$(EXEEXT): 198 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa159 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa 199 160 200 161 ctxswitch-upp_coroutine$(EXEEXT): 201 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc162 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc 202 163 203 164 ctxswitch-upp_thread$(EXEEXT): 204 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc165 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc 205 166 206 167 ctxswitch-goroutine$(EXEEXT): 207 $( BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go168 $(AM_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go 208 169 209 170 ctxswitch-java_thread$(EXEEXT): 210 $( BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java171 $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java 211 172 @echo "#!/bin/sh" > a.out 212 173 @echo "java JavaThread" >> a.out … … 226 187 227 188 mutex-pthread_lock$(EXEEXT): 228 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c189 $(AM_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c 229 190 230 191 mutex-upp$(EXEEXT): 231 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc192 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc 232 193 233 194 mutex-cfa1$(EXEEXT): 234 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa1.cfa195 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa1.cfa 235 196 236 197 mutex-cfa2$(EXEEXT): 237 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa2.cfa198 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa2.cfa 238 199 239 200 mutex-cfa4$(EXEEXT): 240 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa4.cfa201 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa4.cfa 241 202 242 203 mutex-java_thread$(EXEEXT): 243 $( BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java204 $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java 244 205 @echo "#!/bin/sh" > a.out 245 206 @echo "java JavaThread" >> a.out … … 256 217 257 218 signal-pthread_cond$(EXEEXT): 258 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=500000 $(srcdir)/schedint/pthreads.c219 $(AM_V_CC)$(COMPILE) -DBENCH_N=500000 $(srcdir)/schedint/pthreads.c 259 220 260 221 signal-upp$(EXEEXT): 261 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc222 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc 262 223 263 224 signal-cfa1$(EXEEXT): 264 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa1.cfa225 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa1.cfa 265 226 266 227 signal-cfa2$(EXEEXT): 267 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa2.cfa228 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa2.cfa 268 229 269 230 signal-cfa4$(EXEEXT): 270 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa4.cfa231 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa4.cfa 271 232 272 233 signal-java_thread$(EXEEXT): 273 $( BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java234 $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java 274 235 @echo "#!/bin/sh" > a.out 275 236 @echo "java JavaThread" >> a.out … … 285 246 286 247 waitfor-upp$(EXEEXT): 287 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc248 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc 288 249 289 250 waitfor-cfa1$(EXEEXT): 290 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa1.cfa251 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa1.cfa 291 252 292 253 waitfor-cfa2$(EXEEXT): 293 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa2.cfa254 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa2.cfa 294 255 295 256 waitfor-cfa4$(EXEEXT): 296 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa4.cfa257 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa4.cfa 297 258 298 259 ## ========================================================================================================= … … 308 269 309 270 creation-cfa_coroutine$(EXEEXT): 310 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa271 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa 311 272 312 273 creation-cfa_coroutine_eager$(EXEEXT): 313 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa -DEAGER274 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa -DEAGER 314 275 315 276 creation-cfa_thread$(EXEEXT): 316 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa277 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa 317 278 318 279 creation-upp_coroutine$(EXEEXT): 319 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc280 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc 320 281 321 282 creation-upp_thread$(EXEEXT): 322 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc283 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc 323 284 324 285 creation-pthread$(EXEEXT): 325 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=250000 $(srcdir)/creation/pthreads.c286 $(AM_V_CC)$(COMPILE) -DBENCH_N=250000 $(srcdir)/creation/pthreads.c 326 287 327 288 creation-goroutine$(EXEEXT): 328 $( BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go289 $(AM_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go 329 290 330 291 creation-java_thread$(EXEEXT): 331 $( BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java292 $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java 332 293 @echo "#!/bin/sh" > a.out 333 294 @echo "java JavaThread" >> a.out … … 350 311 351 312 compile-array$(EXEEXT): 352 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa313 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa 353 314 354 315 compile-attributes$(EXEEXT): 355 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa316 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa 356 317 357 318 compile-empty$(EXEEXT): 358 @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa319 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa 359 320 360 321 compile-expression$(EXEEXT): 361 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa322 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa 362 323 363 324 compile-io$(EXEEXT): 364 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa325 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa 365 326 366 327 compile-monitor$(EXEEXT): 367 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa328 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa 368 329 369 330 compile-operators$(EXEEXT): 370 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa331 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa 371 332 372 333 compile-thread$(EXEEXT): 373 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa334 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa 374 335 375 336 compile-typeof$(EXEEXT): 376 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa377 337 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa 338 -
benchmark/Makefile.in
r933f32f r6a9d4b4 200 200 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 201 201 ACLOCAL = @ACLOCAL@ 202 ALLOCA = @ALLOCA@ 202 203 AMTAR = @AMTAR@ 203 204 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 371 372 372 373 # applies to both programs 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) 374 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread 375 AM_CFAFLAGS = -quiet -in-tree -nodebug 376 AM_UPPFLAGS = -quiet -nodebug -multi 395 377 TOOLSDIR = ${abs_top_builddir}/tools/ 396 378 REPEAT = ${abs_top_builddir}/tools/repeat … … 401 383 PRINT_FORMAT = %20s: #Comments needed for spacing 402 384 dummy_SOURCES = dummyC.c dummyCXX.cpp 403 FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@404 385 CTXSWITCH_DEPEND = loop.run function.run fetch_add.run \ 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)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) 410 391 testdir = $(top_srcdir)/tests 411 392 all: all-am … … 732 713 733 714 .NOTPARALLEL: 734 .PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv735 715 736 716 all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT) … … 746 726 747 727 %.runquiet : 748 @+make $(basename $@) CFLAGS="-w" __quiet=quiet728 @+make $(basename $@) CFLAGS="-w" 749 729 @taskset -c 1 ./a.out 750 730 @rm -f a.out … … 758 738 759 739 jenkins$(EXEEXT): 740 @echo "{" 741 @echo -e '\t"githash": "'${githash}'",' 742 @echo -e '\t"arch": "' ${arch} '",' 760 743 @DOifskipcompile@ 761 @+make compile.csv 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},' 762 748 @DOendif@ 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 $@ 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 "}" 804 773 805 774 loop$(EXEEXT): 806 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c775 $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c 807 776 808 777 function$(EXEEXT): 809 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c778 $(AM_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c 810 779 811 780 fetch_add$(EXEEXT): 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 781 $(AM_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 816 782 817 783 @WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre$(EXEEXT): 818 @WITH_LIBFIBRE_TRUE@ $( BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp -I$(LIBFIBRE_DIR) -lfibre784 @WITH_LIBFIBRE_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp -I$(LIBFIBRE_DIR) -lfibre 819 785 820 786 @WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre2$(EXEEXT): 821 @WITH_LIBFIBRE_TRUE@ $( BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre787 @WITH_LIBFIBRE_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre2.cpp -I$(LIBFIBRE_DIR) -lfibre 822 788 823 789 ctxswitch$(EXEEXT): $(CTXSWITCH_DEPEND) 824 790 825 791 ctxswitch-pthread$(EXEEXT): 826 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c792 $(AM_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c 827 793 828 794 ctxswitch-cfa_coroutine$(EXEEXT): 829 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa795 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa 830 796 831 797 ctxswitch-cfa_thread$(EXEEXT): 832 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa798 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa 833 799 834 800 ctxswitch-cfa_thread2$(EXEEXT): 835 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa801 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa 836 802 837 803 ctxswitch-upp_coroutine$(EXEEXT): 838 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc804 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc 839 805 840 806 ctxswitch-upp_thread$(EXEEXT): 841 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc807 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc 842 808 843 809 ctxswitch-goroutine$(EXEEXT): 844 $( BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go810 $(AM_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go 845 811 846 812 ctxswitch-java_thread$(EXEEXT): 847 $( BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java813 $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java 848 814 @echo "#!/bin/sh" > a.out 849 815 @echo "java JavaThread" >> a.out … … 862 828 863 829 mutex-pthread_lock$(EXEEXT): 864 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c830 $(AM_V_CC)$(COMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c 865 831 866 832 mutex-upp$(EXEEXT): 867 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc833 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc 868 834 869 835 mutex-cfa1$(EXEEXT): 870 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa1.cfa836 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa1.cfa 871 837 872 838 mutex-cfa2$(EXEEXT): 873 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa2.cfa839 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa2.cfa 874 840 875 841 mutex-cfa4$(EXEEXT): 876 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa4.cfa842 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000 $(srcdir)/mutex/cfa4.cfa 877 843 878 844 mutex-java_thread$(EXEEXT): 879 $( BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java845 $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java 880 846 @echo "#!/bin/sh" > a.out 881 847 @echo "java JavaThread" >> a.out … … 891 857 892 858 signal-pthread_cond$(EXEEXT): 893 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=500000 $(srcdir)/schedint/pthreads.c859 $(AM_V_CC)$(COMPILE) -DBENCH_N=500000 $(srcdir)/schedint/pthreads.c 894 860 895 861 signal-upp$(EXEEXT): 896 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc862 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc 897 863 898 864 signal-cfa1$(EXEEXT): 899 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa1.cfa865 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa1.cfa 900 866 901 867 signal-cfa2$(EXEEXT): 902 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa2.cfa868 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa2.cfa 903 869 904 870 signal-cfa4$(EXEEXT): 905 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa4.cfa871 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedint/cfa4.cfa 906 872 907 873 signal-java_thread$(EXEEXT): 908 $( BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java874 $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java 909 875 @echo "#!/bin/sh" > a.out 910 876 @echo "java JavaThread" >> a.out … … 918 884 919 885 waitfor-upp$(EXEEXT): 920 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc886 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc 921 887 922 888 waitfor-cfa1$(EXEEXT): 923 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa1.cfa889 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa1.cfa 924 890 925 891 waitfor-cfa2$(EXEEXT): 926 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa2.cfa892 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa2.cfa 927 893 928 894 waitfor-cfa4$(EXEEXT): 929 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa4.cfa895 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=500000 $(srcdir)/schedext/cfa4.cfa 930 896 931 897 creation$(EXEEXT) :\ … … 940 906 941 907 creation-cfa_coroutine$(EXEEXT): 942 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa908 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa 943 909 944 910 creation-cfa_coroutine_eager$(EXEEXT): 945 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa -DEAGER911 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa -DEAGER 946 912 947 913 creation-cfa_thread$(EXEEXT): 948 $( BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa914 $(AM_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa 949 915 950 916 creation-upp_coroutine$(EXEEXT): 951 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc917 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc 952 918 953 919 creation-upp_thread$(EXEEXT): 954 $( BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc920 $(AM_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc 955 921 956 922 creation-pthread$(EXEEXT): 957 $( BENCH_V_CC)$(COMPILE) -DBENCH_N=250000 $(srcdir)/creation/pthreads.c923 $(AM_V_CC)$(COMPILE) -DBENCH_N=250000 $(srcdir)/creation/pthreads.c 958 924 959 925 creation-goroutine$(EXEEXT): 960 $( BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go926 $(AM_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go 961 927 962 928 creation-java_thread$(EXEEXT): 963 $( BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java929 $(AM_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java 964 930 @echo "#!/bin/sh" > a.out 965 931 @echo "java JavaThread" >> a.out … … 977 943 978 944 compile-array$(EXEEXT): 979 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa945 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa 980 946 981 947 compile-attributes$(EXEEXT): 982 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa948 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa 983 949 984 950 compile-empty$(EXEEXT): 985 @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa951 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa 986 952 987 953 compile-expression$(EXEEXT): 988 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa954 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa 989 955 990 956 compile-io$(EXEEXT): 991 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa957 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa 992 958 993 959 compile-monitor$(EXEEXT): 994 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa960 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa 995 961 996 962 compile-operators$(EXEEXT): 997 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa963 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa 998 964 999 965 compile-thread$(EXEEXT): 1000 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa966 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa 1001 967 1002 968 compile-typeof$(EXEEXT): 1003 @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa969 $(AM_V_CFA)$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa 1004 970 1005 971 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
benchmark/ctxswitch/cfa_cor.cfa
r933f32f r6a9d4b4 11 11 } 12 12 13 void main( __attribute__((unused))GreatSuspender & this ) {13 void main( GreatSuspender & this ) { 14 14 while( true ) { 15 15 suspend(); -
benchmark/ctxswitch/cfa_thrd2.cfa
r933f32f r6a9d4b4 8 8 thread Fibre {}; 9 9 10 void main( __attribute__((unused))Fibre & this) {10 void main(Fibre & this) { 11 11 while(!done) { 12 12 yield(); -
configure
r933f32f r6a9d4b4 637 637 LIBOBJS 638 638 CFA_BACKEND_CC 639 WITH_LIBTCMALLOC_FALSE 640 WITH_LIBTCMALLOC_TRUE 641 WITH_LIBPROFILER_FALSE 642 WITH_LIBPROFILER_TRUE 639 ALLOCA 643 640 WITH_LIBFIBRE_FALSE 644 641 WITH_LIBFIBRE_TRUE … … 1964 1961 } # ac_fn_cxx_try_link 1965 1962 1963 # ac_fn_c_check_type LINENO TYPE VAR INCLUDES 1964 # ------------------------------------------- 1965 # Tests whether TYPE exists after having included INCLUDES, setting cache 1966 # variable VAR accordingly. 1967 ac_fn_c_check_type () 1968 { 1969 as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack 1970 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 1971 $as_echo_n "checking for $2... " >&6; } 1972 if eval \${$3+:} false; then : 1973 $as_echo_n "(cached) " >&6 1974 else 1975 eval "$3=no" 1976 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 1977 /* end confdefs.h. */ 1978 $4 1979 int 1980 main () 1981 { 1982 if (sizeof ($2)) 1983 return 0; 1984 ; 1985 return 0; 1986 } 1987 _ACEOF 1988 if ac_fn_c_try_compile "$LINENO"; then : 1989 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 1990 /* end confdefs.h. */ 1991 $4 1992 int 1993 main () 1994 { 1995 if (sizeof (($2))) 1996 return 0; 1997 ; 1998 return 0; 1999 } 2000 _ACEOF 2001 if ac_fn_c_try_compile "$LINENO"; then : 2002 2003 else 2004 eval "$3=yes" 2005 fi 2006 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 2007 fi 2008 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 2009 fi 2010 eval ac_res=\$$3 2011 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 2012 $as_echo "$ac_res" >&6; } 2013 eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno 2014 2015 } # ac_fn_c_check_type 2016 1966 2017 # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES 1967 2018 # ------------------------------------------------------- … … 2055 2106 } # ac_fn_c_check_header_mongrel 2056 2107 2057 # ac_fn_c_ check_type LINENO TYPE VAR INCLUDES2058 # ----------------------------------- --------2059 # Tests whether TYPE exists after having included INCLUDES, setting cache2060 # variable VARaccordingly.2061 ac_fn_c_ check_type()2108 # ac_fn_c_find_intX_t LINENO BITS VAR 2109 # ----------------------------------- 2110 # Finds a signed integer type with width BITS, setting cache variable VAR 2111 # accordingly. 2112 ac_fn_c_find_intX_t () 2062 2113 { 2063 2114 as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack 2064 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&52065 $as_echo_n "checking for $2... " >&6; }2115 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 2116 $as_echo_n "checking for int$2_t... " >&6; } 2066 2117 if eval \${$3+:} false; then : 2067 2118 $as_echo_n "(cached) " >&6 2068 2119 else 2069 2120 eval "$3=no" 2070 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 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 2071 2126 /* end confdefs.h. */ 2072 $4 2127 $ac_includes_default 2128 enum { N = $2 / 2 - 1 }; 2073 2129 int 2074 2130 main () 2075 2131 { 2076 if (sizeof ($2)) 2077 return 0; 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 2078 2136 ; 2079 2137 return 0; … … 2083 2141 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 2084 2142 /* end confdefs.h. */ 2085 $4 2143 $ac_includes_default 2144 enum { N = $2 / 2 - 1 }; 2086 2145 int 2087 2146 main () 2088 2147 { 2089 if (sizeof (($2))) 2090 return 0; 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 2091 2153 ; 2092 2154 return 0; … … 2096 2158 2097 2159 else 2098 eval "$3=yes" 2160 case $ac_type in #( 2161 int$2_t) : 2162 eval "$3=yes" ;; #( 2163 *) : 2164 eval "$3=\$ac_type" ;; 2165 esac 2099 2166 fi 2100 2167 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 2101 2168 fi 2102 2169 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 2170 if eval test \"x\$"$3"\" = x"no"; then : 2171 2172 else 2173 break 2174 fi 2175 done 2103 2176 fi 2104 2177 eval ac_res=\$$3 … … 2107 2180 eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno 2108 2181 2109 } # ac_fn_c_check_type 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 2110 2237 cat >config.log <<_ACEOF 2111 2238 This file contains any messages produced by compilers while … … 2540 2667 2541 2668 2542 # http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m42543 2544 2669 2545 2670 # don't use the default CFLAGS as they unconditonnaly add -O2 … … 3402 3527 "debug") ;; 3403 3528 "nolib") ;; 3404 "profile") ;;3405 3529 *) 3406 3530 >&2 echo "Configuration must be 'debug', 'nodebug' or 'nolib'" … … 5059 5183 5060 5184 5185 # deprecated 5061 5186 # These are often not installed and people miss seeing the "no", so stop the configure. 5062 5187 for ac_prog in 'bison -y' byacc … … 16609 16734 16610 16735 16736 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 16737 $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) " >&6 16742 else 16743 cat >conftest.make <<\_ACEOF 16744 SHELL = /bin/sh 16745 all: 16746 @echo '@@@%%%=$(MAKE)=@@@%%%' 16747 _ACEOF 16748 # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. 16749 case `${MAKE-make} -f conftest.make 2>/dev/null` in 16750 *@@@%%%=?*=@@@%%%*) 16751 eval ac_cv_prog_make_${ac_make}_set=yes;; 16752 *) 16753 eval ac_cv_prog_make_${ac_make}_set=no;; 16754 esac 16755 rm -f conftest.make 16756 fi 16757 if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then 16758 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 16759 $as_echo "yes" >&6; } 16760 SET_MAKE= 16761 else 16762 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 16763 $as_echo "no" >&6; } 16764 SET_MAKE="MAKE=${MAKE-make}" 16765 fi 16766 16611 16767 16612 16768 # Checks for libraries. … … 16662 16818 16663 16819 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 : 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 : 16667 16837 $as_echo_n "(cached) " >&6 16668 16838 else 16669 ac_check_lib_save_LIBS=$LIBS 16670 LIBS="-lprofiler $LIBS" 16671 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16839 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16672 16840 /* end confdefs.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 (); 16841 #include <alloca.h> 16681 16842 int 16682 16843 main () 16683 16844 { 16684 return ProfilingIsEnabledForAllThreads (); 16845 char *p = (char *) alloca (2 * sizeof (int)); 16846 if (p) return 0; 16685 16847 ; 16686 16848 return 0; … … 16688 16850 _ACEOF 16689 16851 if ac_fn_c_try_link "$LINENO"; then : 16690 ac_cv_ lib_profiler_ProfilingIsEnabledForAllThreads=yes16691 else 16692 ac_cv_ lib_profiler_ProfilingIsEnabledForAllThreads=no16852 ac_cv_working_alloca_h=yes 16853 else 16854 ac_cv_working_alloca_h=no 16693 16855 fi 16694 16856 rm -f core conftest.err conftest.$ac_objext \ 16695 16857 conftest$ac_exeext conftest.$ac_ext 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 : 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 : 16718 16870 $as_echo_n "(cached) " >&6 16719 16871 else 16720 ac_check_lib_save_LIBS=$LIBS 16721 LIBS="-ltcmalloc $LIBS" 16722 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16872 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16723 16873 /* end confdefs.h. */ 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" 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 16730 16893 #endif 16731 char malloc (); 16894 16732 16895 int 16733 16896 main () 16734 16897 { 16735 return malloc (); 16898 char *p = (char *) alloca (1); 16899 if (p) return 0; 16736 16900 ; 16737 16901 return 0; … … 16739 16903 _ACEOF 16740 16904 if ac_fn_c_try_link "$LINENO"; then : 16741 ac_cv_ lib_tcmalloc_malloc=yes16742 else 16743 ac_cv_ lib_tcmalloc_malloc=no16905 ac_cv_func_alloca_works=yes 16906 else 16907 ac_cv_func_alloca_works=no 16744 16908 fi 16745 16909 rm -f core conftest.err conftest.$ac_objext \ 16746 16910 conftest$ac_exeext conftest.$ac_ext 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 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 16768 17019 do : 16769 17020 as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` … … 16774 17025 _ACEOF 16775 17026 16776 else16777 echo "Error: Missing required header"; exit 116778 17027 fi 16779 17028 … … 16782 17031 16783 17032 # Checks for typedefs, structures, and compiler characteristics. 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 : 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 : 16802 17036 $as_echo_n "(cached) " >&6 16803 17037 else 16804 16805 m4cfa_check_save_flags=$CFLAGS 16806 CFLAGS="$CFLAGS -Wcast-function-type" 16807 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 17038 cat confdefs.h - <<_ACEOF >conftest.$ac_ext 16808 17039 /* end confdefs.h. */ 17040 17041 #include <stdbool.h> 17042 #ifndef bool 17043 "error: bool is not defined" 17044 #endif 17045 #ifndef false 17046 "error: false is not defined" 17047 #endif 17048 #if false 17049 "error: false is not 0" 17050 #endif 17051 #ifndef true 17052 "error: true is not defined" 17053 #endif 17054 #if true != 1 17055 "error: true is not 1" 17056 #endif 17057 #ifndef __bool_true_false_are_defined 17058 "error: __bool_true_false_are_defined is not defined" 17059 #endif 17060 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 for 17074 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. See 17079 http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html 17080 http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html 17081 */ 17082 _Bool q = true; 17083 _Bool *pq = &q; 16809 17084 16810 17085 int 16811 17086 main () 16812 17087 { 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 + !!l 17094 + !m + !n + !o + !p + !q + !pq); 16813 17095 16814 17096 ; … … 16817 17099 _ACEOF 16818 17100 if ac_fn_c_try_compile "$LINENO"; then : 16819 m4cfa_cv_check_cflags___Wcast_function_type=yes16820 else 16821 m4cfa_cv_check_cflags___Wcast_function_type=no17101 ac_cv_header_stdbool_h=yes 17102 else 17103 ac_cv_header_stdbool_h=no 16822 17104 fi 16823 17105 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 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 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 16835 17311 16836 17312 … … 16845 17321 16846 17322 #============================================================================== 16847 ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile longrun_tests/Makefile tools/Makefile tools/prettyprinter/Makefile"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" 16848 17324 16849 17325 … … 16996 17472 if test -z "${WITH_LIBFIBRE_TRUE}" && test -z "${WITH_LIBFIBRE_FALSE}"; then 16997 17473 as_fn_error $? "conditional \"WITH_LIBFIBRE\" was never defined. 16998 Usually this means the macro was only invoked conditionally." "$LINENO" 516999 fi17000 if test -z "${WITH_LIBPROFILER_TRUE}" && test -z "${WITH_LIBPROFILER_FALSE}"; then17001 as_fn_error $? "conditional \"WITH_LIBPROFILER\" was never defined.17002 Usually this means the macro was only invoked conditionally." "$LINENO" 517003 fi17004 if test -z "${WITH_LIBTCMALLOC_TRUE}" && test -z "${WITH_LIBTCMALLOC_FALSE}"; then17005 as_fn_error $? "conditional \"WITH_LIBTCMALLOC\" was never defined.17006 17474 Usually this means the macro was only invoked conditionally." "$LINENO" 5 17007 17475 fi … … 17991 18459 "benchmark/Makefile") CONFIG_FILES="$CONFIG_FILES benchmark/Makefile" ;; 17992 18460 "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; 17993 " longrun_tests/Makefile") CONFIG_FILES="$CONFIG_FILES longrun_tests/Makefile" ;;18461 "tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES tests/preempt_longrun/Makefile" ;; 17994 18462 "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;; 17995 18463 "tools/prettyprinter/Makefile") CONFIG_FILES="$CONFIG_FILES tools/prettyprinter/Makefile" ;; -
configure.ac
r933f32f r6a9d4b4 139 139 "debug") ;; 140 140 "nolib") ;; 141 "profile") ;;142 141 *) 143 142 >&2 echo "Configuration must be 'debug', 'nodebug' or 'nolib'" … … 179 178 AC_PROG_CC 180 179 AM_PROG_AS 180 AM_PROG_CC_C_O # deprecated 181 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_SET 188 189 189 190 # Checks for libraries. … … 191 192 AM_CONDITIONAL([WITH_LIBFIBRE], [test "$HAVE_LIBFIBRE" -eq 1]) 192 193 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 199 194 # Checks for header files. 200 AC_CHECK_HEADERS([libintl.h malloc.h unistd.h], [], [echo "Error: Missing required header"; exit 1]) 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]) 201 197 202 198 # Checks for typedefs, structures, and compiler characteristics. 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.])) 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]) 207 212 208 213 #============================================================================== … … 218 223 benchmark/Makefile 219 224 tests/Makefile 220 longrun_tests/Makefile225 tests/preempt_longrun/Makefile 221 226 tools/Makefile 222 227 tools/prettyprinter/Makefile -
doc/LaTeXmacros/lstlang.sty
r933f32f r6a9d4b4 8 8 %% Created On : Sat May 13 16:34:42 2017 9 9 %% Last Modified By : Peter A. Buhr 10 %% Last Modified On : Tue Jan 8 14:40:33 201911 %% Update Count : 2 110 %% Last Modified On : Fri Apr 6 23:44:50 2018 11 %% Update Count : 20 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, exception, __extension__, fallthrough, fallthru, finally,116 coroutine, disable, dtype, enable, __extension__, exception, 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
r933f32f r6a9d4b4 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 Key word 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 } 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}}, 833 {{http://www.boost.org/\-doc/\-libs/1\_61\_0/\-libs/\-coroutine/\-doc/\-html/\-index.html}}}, 834 optnote = {Accessed: 2016-09}, 844 835 } 845 836 … … 948 939 author = {{\textsf{C}{$\mathbf{\forall}$} Features}}, 949 940 howpublished= {\href{https://plg.uwaterloo.ca/~cforall/features}{https://\-plg.uwaterloo.ca/\-$\sim$cforall/\-features}}, 941 optnote = {Accessed: 2018-01-01}, 950 942 } 951 943 … … 967 959 year = 2018, 968 960 howpublished= {\href{https://cforall.uwaterloo.ca/CFAStackEvaluation.zip}{https://cforall.uwaterloo.ca/\-CFAStackEvaluation.zip}}, 961 optnote = {[Accessed May 2018]}, 969 962 } 970 963 … … 973 966 contributer = {pabuhr@plg}, 974 967 author = {Aaron Moss and Robert Schluntz and Peter A. Buhr}, 975 title = {\textsf{C}$\mathbf{\forall}$ : Adding Modern Programming Language Features to {C}},968 title = {\textsf{C}$\mathbf{\forall}$ : Adding Modern Programming Language Features to C}, 976 969 journal = spe, 977 970 volume = 48, … … 1093 1086 } 1094 1087 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 1104 1088 @article{Buhr85, 1105 1089 keywords = {goto, multi-exit loop}, … … 1148 1132 year = 1998, 1149 1133 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/}}1177 1134 } 1178 1135 … … 1277 1234 } 1278 1235 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 1298 1236 @book{sml:commentary, 1299 1237 author = {Robin Milner and Mads Tofte}, … … 1356 1294 journal = sigplan, 1357 1295 year = 1986, 1358 month = oct, 1359 volume = 21, 1360 number = 10, 1361 pages = {19-28}, 1296 month = oct, volume = 21, number = 10, pages = {19-28}, 1362 1297 note = {Object Oriented Programming Workshop} 1363 1298 } … … 1524 1459 title = {concurrent-locking}, 1525 1460 howpublished= {\href{https://github.com/pabuhr/concurrent-locking}{https://\-github.com/\-pabuhr/\-concurrent-locking}}, 1461 optnote = {[Accessed April 2017]}, 1526 1462 } 1527 1463 … … 1685 1621 } 1686 1622 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 1700 1623 @article{Buhr05a, 1701 1624 keywords = {concurrency, myths}, … … 1824 1747 howpublished= {\href{https://www.airs.com/blog/archives/428} 1825 1748 {https://www.airs.com/\-blog/\-archives/\-428}}, 1749 optnote = {Accessed: 2018-05}, 1826 1750 } 1827 1751 … … 1919 1843 year = 1965, 1920 1844 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}},1931 1845 } 1932 1846 … … 2357 2271 } 2358 2272 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 2375 2273 @article{design, 2376 2274 keywords = {Smalltalk, designing classes}, … … 2380 2278 journal = joop, 2381 2279 year = 1988, 2382 volume = 1, 2383 number = 2, 2384 pages = {22-35}, 2280 volume = 1, number = 2, pages = {22-35}, 2385 2281 comment = { 2386 2282 Abstract classes represent standard protocols. ``It is better to … … 2467 2363 year = 1990, 2468 2364 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}2478 2365 } 2479 2366 … … 2583 2470 pages = {325-361}, 2584 2471 } 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 }2606 2472 2607 2473 @book{Eiffel, … … 3040 2906 year = 2014, 3041 2907 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}, 3042 2909 } 3043 2910 … … 3123 2990 } 3124 2991 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 3135 2992 @inproceedings{F-bound, 3136 2993 keywords = {}, … … 3180 3037 } 3181 3038 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 3213 3039 @manual{Fortran95, 3214 3040 keywords = {Fortran 95}, … … 3231 3057 address = {\href{https://www.iso.org/standard/50459.html}{https://\-www.iso.org/\-standard/\-50459.html}}, 3232 3058 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,3244 3059 } 3245 3060 … … 3491 3306 year = 2014, 3492 3307 howpublished= {https://developer.gnome.org/gobject/stable/}, 3308 optnote = {Accessed: 2017-04}, 3493 3309 } 3494 3310 … … 3805 3621 year = {1964}, 3806 3622 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},3831 3623 } 3832 3624 … … 4135 3927 } 4136 3928 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 4150 3929 % J 4151 3930 … … 4169 3948 year = 2015, 4170 3949 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,4192 3950 } 4193 3951 … … 4371 4129 } 4372 4130 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 4384 4131 @book{Weissman67, 4385 4132 keywords = {lisp}, … … 4391 4138 } 4392 4139 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 4415 4140 @article{Sundell08, 4416 4141 keywords = {lock free, deque}, … … 4423 4148 year = 2008, 4424 4149 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},4437 4150 } 4438 4151 … … 4451 4164 } 4452 4165 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 4462 4166 % M 4463 4167 … … 4469 4173 publisher = {Motorola}, 4470 4174 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},4484 4175 } 4485 4176 … … 4800 4491 } 4801 4492 % 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 }4816 4493 4817 4494 @manual{MPI, … … 5240 4917 year = 2014, 5241 4918 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} 5242 4920 } 5243 4921 … … 5249 4927 year = 2015, 5250 4928 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} 5251 4930 } 5252 4931 … … 5383 5062 note = {\href{https://www.openmp.org/wp-content/uploads/openmp-4.5.pdf}{https://\-www.openmp.org/\-wp-content/\-uploads/\-openmp-4.5.pdf}}, 5384 5063 } 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 }5404 5064 5405 5065 @book{Deitel04, … … 5780 5440 year = 2012, 5781 5441 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} 5782 5443 } 5783 5444 … … 6103 5764 address = {\href{https://www.iso.org/standard/64029.html}{https://\-www.iso.org/\-standard/\-64029.html}}, 6104 5765 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,6116 5766 } 6117 5767 … … 6267 5917 institution = {Carnegie Mellon University}, 6268 5918 year = 1991, 6269 month = feb, 6270 number = {CMU-CS-91-106}, 5919 month = feb, number = "CMU-CS-91-106", 6271 5920 annote = { 6272 5921 Discusses a typed lambda calculus with … … 6325 5974 journal = sigplan, 6326 5975 year = 1988, 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}, 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}, 6332 5979 abstract = { 6333 5980 This paper deals with the integration of an efficient asynchronous … … 6379 6026 } 6380 6027 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 6392 6028 @manual{Python, 6393 6029 keywords = {Python}, 6394 6030 contributer = {pabuhr@plg}, 6395 author = {Python},6396 title = {Python Language Reference, Release 3.7.2},6031 title = {Python Reference Manual, Release 2.5}, 6032 author = {Guido van Rossum}, 6397 6033 organization= {Python Software Foundation}, 6398 address = {\href{https://docs.python.org/3/reference/index.html}{https://\-docs.python.org/\-3/\-reference/\-index.html}}, 6399 year = 2018, 6034 month = sep, 6035 year = 2006, 6036 note = {Fred L. Drake, Jr., editor}, 6400 6037 } 6401 6038 6402 6039 % 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 }6414 6040 6415 6041 @article{Grossman06, … … 6448 6074 } 6449 6075 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 6460 6076 % R 6461 6077 … … 6571 6187 number = 10, 6572 6188 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},6584 6189 } 6585 6190 … … 6720 6325 } 6721 6326 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 6732 6327 % S 6733 6328 … … 7466 7061 } 7467 7062 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 7478 7063 % T 7479 7064 … … 7530 7115 author = {{TIOBE Index}}, 7531 7116 howpublished= {\href{http://www.tiobe.com/tiobe_index}{http://\-www.tiobe.com/\-tiobe\_index}}, 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)}}, 7117 optnote = {Accessed: 2018-09}, 7540 7118 } 7541 7119 … … 7699 7277 } 7700 7278 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 7708 7279 @article{Cormack90, 7709 7280 keywords = {polymorphism}, … … 7876 7447 year = 2017, 7877 7448 howpublished= {\url{https://wiki.gnome.org/Projects/Vala/Manual}}, 7449 optnote = {Accessed: 2017-04} 7878 7450 } 7879 7451 … … 8049 7621 % Y 8050 7622 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 8066 7623 % Z 8067 7624 -
doc/papers/concurrency/Paper.tex
r933f32f r6a9d4b4 215 215 {} 216 216 \lstnewenvironment{Go}[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}} 217 {\lstset{#1}} 221 218 {} 222 219 … … 231 228 } 232 229 233 \title{\texorpdfstring{ Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flowin Cforall}}230 \title{\texorpdfstring{Concurrency in \protect\CFA}{Concurrency in Cforall}} 234 231 235 232 \author[1]{Thierry Delisle} … … 241 238 \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}} 242 239 243 %\fundingInfo{Natural Sciences and Engineering Research Council of Canada}240 \fundingInfo{Natural Sciences and Engineering Research Council of Canada} 244 241 245 242 \abstract[Summary]{ 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. 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. 254 250 Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming-languages. 255 251 }% 256 252 257 \keywords{co routines, concurrency, parallelism, threads, monitors, runtime, C, \CFA (Cforall)}253 \keywords{concurrency, parallelism, coroutines, threads, monitors, runtime, C, Cforall} 258 254 259 255 … … 266 262 \section{Introduction} 267 263 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 \item333 expressive language-level coroutines and user-level threading, which respect the expectations of C programmers.334 \item335 monitor synchronization without barging.336 \item337 safely acquiring multiple monitors \emph{simultaneously} (deadlock free), while seamlessly integrating this capability with all monitor synchronization mechanisms.338 \item339 providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features.340 \item341 library extensions for executors, futures, and actors built on the basic mechanisms.342 \item343 a runtime system with no spurious wakeup.344 \item345 experimental results showing comparable performance of the new features with similar mechanisms in other concurrent programming-languages.346 \end{itemize}347 348 \begin{comment}349 264 This paper provides a minimal concurrency \newterm{Application Program Interface} (API) that is simple, efficient and can be used to build other concurrency features. 350 265 While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master. … … 366 281 The proposed concurrency API is implemented in a dialect of C, called \CFA (pronounced C-for-all). 367 282 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. 368 \end{comment} 369 370 371 \begin{comment} 283 284 372 285 \section{\CFA Overview} 373 286 … … 638 551 \end{cfa} 639 552 where the return type supplies the type/size of the allocation, which is impossible in most type systems. 640 \end{comment} 641 642 643 \section{Coroutines: Stepping Stone} 644 \label{coroutine} 645 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). 646 595 Coroutines are generalized routines allowing execution to be temporarily suspended and later resumed. 647 596 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. … … 667 616 \centering 668 617 \newbox\myboxA 669 % \begin{lrbox}{\myboxA}670 % \begin{cfa}[aboveskip=0pt,belowskip=0pt]671 % `int fn1, fn2, state = 1;` // single global variables672 % int fib() {673 % int fn;674 % `switch ( state )` { // explicit execution state675 % 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}689 618 \begin{lrbox}{\myboxA} 690 619 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 691 #define FIB_INIT { 0, 1 } 692 typedef struct { int fn1, fn; } Fib; 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 } 630 int main() { 631 632 for ( int i = 0; i < 10; i += 1 ) { 633 printf( "%d\n", fib() ); 634 } 635 } 636 \end{cfa} 637 \end{lrbox} 638 639 \newbox\myboxB 640 \begin{lrbox}{\myboxB} 641 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 642 #define FIB_INIT `{ 0, 1 }` 643 typedef struct { int f2, f1; } Fib; 693 644 int fib( Fib * f ) { 694 645 695 int ret = f->fn1; 696 f->fn1 = f->fn; 697 f->fn = ret + f->fn; 646 int ret = f->f2; 647 int fn = f->f1 + f->f2; 648 f->f2 = f->f1; f->f1 = fn; 649 698 650 return ret; 699 651 } 700 701 702 703 652 int main() { 704 653 Fib f1 = FIB_INIT, f2 = FIB_INIT; 705 654 for ( int i = 0; i < 10; i += 1 ) { 706 printf( "%d %d\n", 707 fib( &f1 ), fib( &f2 ) ); 655 printf( "%d %d\n", fib( &f1 ), fib( &f2 ) ); 708 656 } 709 657 } … … 711 659 \end{lrbox} 712 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; 684 } 685 int main() { 686 Fib f1, f2; 687 for ( int i = 1; i <= 10; i += 1 ) { 688 sout | next( f1 ) | next( f2 ); 689 } 690 } 691 \end{cfa} 692 \end{lrbox} 713 693 \newbox\myboxB 714 694 \begin{lrbox}{\myboxB} 715 695 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 716 `coroutine` Fib { int fn1; };717 void main( Fib & f ib) with( fib ) {718 int fn ;719 [fn1, fn] = [0, 1];720 for () {721 `suspend();` 722 [fn1, fn] = [fn, fn1 + fn];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();` 723 703 } 724 704 } 725 int ?()( Fib & fib ) with( fib ) {726 `resume( fib );` return fn1;727 } 728 int main() { 729 Fib f1, f2; 730 for ( 10 ) { 731 sout | f1() | f2(); 732 } 705 int next( Fib & fib ) with( fib ) { 706 `resume( fib );` 707 return ret; 708 } 709 710 711 712 733 713 734 714 735 715 \end{cfa} 736 716 \end{lrbox} 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} 761 \end{lrbox} 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} 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} 818 722 \end{figure} 819 723 … … 855 759 \begin{lrbox}{\myboxA} 856 760 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 857 `coroutine` F mt {858 char ch; // communication variables859 int g, b; // needed in destructor761 `coroutine` Format { 762 char ch; // used for communication 763 int g, b; // global because used in destructor 860 764 }; 861 void main( F mt & fmt ) with( fmt ) {862 for ( ) {863 for ( g = 0; g < 5; g += 1 ) { // groups864 for ( b = 0; b < 4; b += 1 ) { // block s765 void main( Format & fmt ) with( fmt ) { 766 for ( ;; ) { 767 for ( g = 0; g < 5; g += 1 ) { // group 768 for ( b = 0; b < 4; b += 1 ) { // block 865 769 `suspend();` 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 )`; } 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 } 875 784 int main() { 876 Fmt fmt; 877 sout | nlOff; // turn off auto newline 878 for ( 41 ) 879 send( fmt, 'a' ); 785 Format fmt; 786 eof: for ( ;; ) { 787 sin | fmt.ch; 788 if ( eof( sin ) ) break eof; 789 format( fmt ); 790 } 880 791 } 881 792 \end{cfa} … … 884 795 \newbox\myboxB 885 796 \begin{lrbox}{\myboxB} 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} 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} 912 830 \end{lrbox} 913 \subfloat[\CFA ]{\label{f:CFAFmt}\usebox\myboxA}831 \subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA} 914 832 \qquad 915 \subfloat[ Python]{\label{f:CFmt}\usebox\myboxB}916 \caption{ Output formatting text}833 \subfloat[C Linearized]{\label{f:CFmt}\usebox\myboxB} 834 \caption{Formatting text into lines of 5 blocks of 4 characters.} 917 835 \label{f:fmt-line} 918 836 \end{figure} … … 935 853 void main( Prod & prod ) with( prod ) { 936 854 // 1st resume starts here 937 for ( i ; N) {855 for ( int i = 0; i < N; i += 1 ) { 938 856 int p1 = random( 100 ), p2 = random( 100 ); 939 857 sout | p1 | " " | p2; … … 951 869 } 952 870 void start( Prod & prod, int N, Cons &c ) { 953 &prod.c = &c; // reassignable reference871 &prod.c = &c; 954 872 prod.[N, receipt] = [N, 0]; 955 873 `resume( prod );` … … 966 884 Prod & p; 967 885 int p1, p2, status; 968 bool done;886 _Bool done; 969 887 }; 970 888 void ?{}( Cons & cons, Prod & p ) { 971 &cons.p = &p; // reassignable reference889 &cons.p = &p; 972 890 cons.[status, done ] = [0, false]; 973 891 } … … 1027 945 @start@ returns and the program main terminates. 1028 946 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 \kill1033 \ldots STX \> \ldots message \ldots \> ESC \> ETX \> \ldots message \ldots \> ETX \> 2-byte crc \> \ldots1034 \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 } // choose1067 if ( lnth >= MaxMsg ) { $\C{// buffer full ?}$1068 status = ELNTH; `suspend();` continue msg; }1069 msg[lnth++] = byte;1070 sum += byte;1071 } // for1072 msg[lnth] = '\0'; $\C{// terminate string}\CRT$1073 `suspend();`1074 crc = (unsigned char)byte << 8; // prevent sign extension for signed char1075 `suspend();`1076 status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;1077 `suspend();`1078 } // for1079 }1080 \end{cfa}1081 \caption{Device driver for simple communication protocol}1082 \end{figure}1083 1084 947 1085 948 \subsection{Coroutine Implementation} … … 1197 1060 \end{cquote} 1198 1061 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.1236 1062 1237 1063 -
doc/papers/concurrency/mail
r933f32f r6a9d4b4 27 27 28 28 Software: Practice and Experience Editorial Office 29 30 31 32 Date: Wed, 3 Oct 2018 21:25:28 +000033 From: Richard Jones <onbehalfof@manuscriptcentral.com>34 Reply-To: R.E.Jones@kent.ac.uk35 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca36 Subject: Software: Practice and Experience - Decision on Manuscript ID37 SPE-18-020538 39 03-Oct-201840 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 Jones53 Editor, Software: Practice and Experience54 R.E.Jones@kent.ac.uk55 56 Referee(s)' Comments to Author:57 58 Reviewing: 159 60 Comments to the Author61 "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: 289 90 Comments to the Author91 This article presents the design and rationale behind the concurrency92 features of C-forall, a new low-level programming language. After an93 introduction that defines a selection of standard terminology, section94 2 gives crucial background on the design of the C-forall language.95 Section 3 then starts the core of the article, discussing the96 language's support for "concurrency" which in this case means97 coroutines and threads; a very brief Section 4 builds on section 398 with a discussion of lower level synchronizations. Section 5 the99 presents the main features of concurrency control in C-forall:100 monitors and mutexes. Section 6 then extends monitors with condition101 variables to to support scheduling, and a very brief section 7102 discusses preemption and pooling. Section 8 discusses the runtime103 conceptual model, section 9 gives implementation detail, and section104 10 briefly evaluates C-forall's performance via five concurrent105 micro benchmarks. Finally section 11 concludes the article, and then106 section 12 presents some future work.107 108 109 At the start of section 7, article lays out its rationale: that while110 "historically, computer performance was about processor speeds" but111 "Now, high-performance applications must care about parallelism,112 which requires concurrency". The doomsayers trumpeting the death of113 Moore's law have been proved correct at last, with CPUs sequential114 performance increasing much more slowly than the number of cores115 within each die. This means programmers --- especially low-level,116 systems programmers --- must somehow manage the essential complexity117 of writing concurrent programs to run in parallel in multiple threads118 across multiple cores. Unfortunately, the most venerable widely used119 systems programming language, C, supports parallelism only via an120 e.g. the threads library. This article aims to integrate concurrent121 programming mechanisms more closely into a novel low-level C-based122 programming language, C-forall. The article gives an outline of much of123 C-forall, presents a series of concurrency mechanisms, and finally124 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 the128 best summary of the problem the design of concurrent C-forall sets129 out to solve is buried more than halfway through the article in section130 7, as above, and then the best overview of the proposed solution is131 given in the 2nd, 4th and 5th sentence of the conclusion:132 133 "The approach provides concurrency based on a preemptive M:N134 user-level threading-system, executing in clusters, which135 encapsulate scheduling of work on multiple kernel threads136 providing parallelism... High-level objects (monitor/task) are the137 core mechanism for mutual exclusion and synchronization. A novel138 aspect is allowing multiple mutex-objects to be accessed139 simultaneously reducing the potential for deadlock for this140 complex scenario."141 142 That is, in my reading of the article, it proceeds bottom up rather143 than top down, and so my main recommendation is to essentially reverse144 the order of the article, proceeding from the problem to be solved,145 the high level architecture of the proposed solutions, and then going146 down to the low-level mechanisms. My biggest problem reading the147 article was for explanations of why a particular decision was taken,148 or why a particular mechanism may be used --- often this description149 is actually later in the article, but at that point it's too late for150 the reader. I have tried to point out most of these places in the151 detailed comments below.152 153 My second concern is that the article makes several claims that are154 not really justified by the design or implementation in the article.155 These include claims that this approach meets the expectations of C156 programmers, is minimal, is implemented in itself, etc. The article157 doesn't generally offer evidence to support these assertions (for many158 of them, that would require empirical studies of programmers, or at159 least corpus studies). The solution here is to talk about motivations160 for the design choices "we made these decisions hoping that C161 programmers would be comfortable" rather than claims of fact "C162 programmers are comfortable". Again I attempt to point these out below.163 164 * abstract: needs to characterize the work top down, and not make165 claims "features respect the expectations of C programmers" that166 are not supported empirically.167 168 * p1 line 14 "integrated"169 170 * introduction needs to introduce the big ideas and scope of the171 article, not define terms. Some of the terms / distinctions are172 non-standard (e.g. the distinction between "concurrency" and173 "parallelism") and can be avoided by using more specific terms174 (mutual exclusion, synchronization, parallel execution. etc).175 176 * to me this article introduces novel language features, not just an177 API. Similarly, it doesn't talk about any additions "to the178 language translator" - i.e compiler changes! - rather about language179 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 a184 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 why187 not.188 189 * 2.2 calling it a "with statement" was confusing, given that a with190 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 not197 so much.198 199 * 2.5 and many places elsewhere. Always first describe the semantics200 of your language constructs, then describe their properties, then201 compare with e.g. related languages (mostly C++ & Java?). E.g in202 this case, something like:203 204 "C-forall includes constructors, which are called to initialize205 newly allocated objects, and constructors, which are called when206 objects are deallocated. Constructors and destructors are written as207 functions returning void, under the special names "?{}" for208 constructors and "^{}" for destructors: constructors may be209 overridden, but destructors may not be. The semantics of C-forall's210 constructors and destructors are essentially those of C++."211 212 this problem repeats many times throughout the article and should be213 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 generics218 etc.219 220 * why special case forward declarations? It's not 1970 any more.221 222 * what are traits? structural interfaces (like Go interfaces) or223 nominal bindings?224 225 * section 3 - lines 2-30, also making very specific global definitions226 as in the introduction. The article does not need to take on this227 fight either, rather make clear that this is the conceptual model in228 C-forall. (If the article starts at the top and works down, that may229 well follow anyway).230 231 * "in modern programming languages... unacceptable"; "in a232 system-level language.. concurrent programs should be written with233 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 support237 coroutines, threads, fibres, etc238 239 * FIG 2B - where's the output?240 syntax "sout | next(f1) | next(f2) | endl" nowhere explained241 why not use C++s' << and >>242 243 * FIG 3 be clearer, earlier about the coroutine" constructor syntax244 245 ** ensure all figures are placed *after* their first mention in the246 text. consider interleaving smaller snippets of text rather than247 just referring to large figures248 249 * sec 3.1 p7 etc,. need more context / comparison e.g. Python250 generators etc.251 252 * FIGURE 4 is this right? should there a constructor for Cons taking253 a Prod?254 255 256 * sec 3.2 order of constructors depends on the language. more257 generally, if the article is going to make arguments against OO258 (e.g. section 2) then the article needs to explain, in detail, why259 e.g. coroutine, thread, etc *cannot* be classes / objects.260 261 * "type coroutine_t must be an abstract handle.. descriptor and is262 stack are non-copyable" - too many assumptions in here (and other263 similar passages) that are not really spelled out in detail.264 265 * p10 line 4 introduces "coroutine" keyword. needs to give its266 semantics. also needs to introduce and define properties and compare267 before all the examples using coroutines.268 269 * p10 again, trait semantics need to be better defined270 271 * 3.3 should be an introduction to this section. Note that section272 titles are not part of the text of the article.273 274 * what's the difference between "coroutines" and "user threads" (and275 "fibres?")276 277 * what's a "task type" or an "interface routine" or "underlying278 thread"279 280 * section 4 - "... meaningless". nope some semantics are possible281 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 order287 288 * 4.1 p12 13-25, again it's not clear where this is going. presenting the model289 top down may hopefully resolve this290 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 to298 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 the305 difference between "a type that is a monitor" and "a type that looks306 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 lock314 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 unclear320 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"? which325 approaches? examined by whom? if this is a novel contribution, needs326 rather more there, and more comparison with related work327 328 * FIG 8 consider e.g. sequence diagrams rather than code to show these329 cases330 331 * 6.2 p19 line 5 "similarly, monitor routines can be added at any332 time" really? I thought C-forall was compiled? there's a big333 difference between "static" and "dynamic" inheritance. which is this334 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 be341 expanded to give enough detail to support that argument342 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 the351 user threads, fibres, etc here;352 353 * sec 8.1 I found these sections hard to follow. how is a cluster a354 "collection of threads and virtual processors... like a virtual355 machine"? Where do the thread pools from 7.3 fit in?356 357 * sec 8.3 is out of place, probably unneeded in the paper358 359 * section 9 dives straight into details with no overview. Section 9360 seems very detailed, and depends on assumptions or details that are361 not in the article.362 363 * section 10 covers only microbenchmarks. are there any moderate sized364 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 written368 in C-forall". The article doesn't369 370 371 * future work should precede conclusion, not follow it372 373 * the article should have a related work section (2-3 pages) comparing374 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: 3380 381 Comments to the Author382 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 design427 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
r933f32f r6a9d4b4 2 2 ================================== 3 3 4 This is an adaptation of the earlier virtual proposal, updating it with new 5 ideas, re-framing it and laying out more design decisions. It should 6 eventually replace the earlier proposal, but not all features and syntax have 7 been converted to the new design. 8 4 9 The basic concept of a virtual table (vtable) is the same here as in most 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. 10 other languages. They will mostly contain function pointers although they 11 should be able to store anything that goes into a trait. 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. 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: 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. 22 20 23 21 trait combiner(otype T) { 24 void combine(T&, int);25 };22 void combine(T&, int); 23 }; 26 24 27 25 struct summation { 28 int sum;29 };26 int sum; 27 }; 30 28 31 void ?{}( struct summation & this ) {32 this.sum = 0;33 }29 void ?{}( struct summation & this ) { 30 this.sum = 0; 31 } 34 32 35 33 void combine( struct summation & this, int num ) { 36 this.sum = this.sum + num;37 }34 this.sum = this.sum + num; 35 } 38 36 39 trait combiner obj = struct summation{};40 combine(obj, 5);37 trait combiner obj = struct summation{}; 38 combine(obj, 5); 41 39 42 40 As with `struct` (and `union` and `enum`), `trait` might be optional when … … 44 42 before. 45 43 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. 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. 49 48 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. 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. 239 52 240 53 Hierarchy 241 54 --------- 242 55 243 We would also like to implement hierarchical relations between types. 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. 244 61 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 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. 255 65 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. 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. 259 70 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. 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. 265 75 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. 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. 272 80 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.) 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. 277 85 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 } 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. 283 91 284 trait expression_node(otype T) virtual(ast_node) { 285 Type eval_type(T const & this); 286 } 92 ### Inline vtables 93 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. 287 97 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 468 Since the structures here are usually made to be turned into trait objects 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. 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. 483 101 484 102 ### Virtual Tables as Types 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. 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. 505 107 506 108 Resolution Scope … … 518 120 the type declaration, including the functions that satisfy the trait, are 519 121 all defined. Currently there are many points where this can happen, not all 520 of them have the same definitions and no way to select one over the other. 122 of them will have the same definitions and no way to select one over the 123 other. 521 124 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. 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. 536 127 537 128 ### Explicit Resolution Points: … … 549 140 However this also means that stack-allocated functions can end up in the 550 141 vtable. 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) is559 used at the binding site to say which one is picked. The default keyword can560 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 if567 there is exactly one vtable name marked with default.568 569 These could also be placed inside functions. In which case both the name and570 the default keyword might be optional. If the name is omitted in an assignment571 the closest vtable is chosen (returning to the global default rule if no572 appropriate local vtable is in scope).573 142 574 143 ### Site Based Resolution: … … 596 165 Stack allocated functions interact badly with this because they are not 597 166 static. There are several ways to try to resolve this, however without a 598 general solution most can keep vtables from making the existing thunk problem 599 worse, they don't do anything to solve it. 167 general solution most can only buy time. 600 168 601 169 Filling in some fields of a static vtable could cause issues on a recursive … … 612 180 shortest lifetime of a function assigned to it. However this still limits the 613 181 lifetime "implicitly" and returns to the original problem with thunks. 614 615 Odds And Ends616 -------------617 618 In addition to the main design there are a few extras that should be619 considered. They are not part of the core design but make the new uses fully620 featured.621 622 ### Extension: Parent-Child Assertion623 For hierarchy types in regular traits, generic functions or generic structures624 we may want to be able to check parent-child relationships between two types625 given. For this we might have to add another primitive assertion. It would626 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 Parent632 to child would be dynamically checked as usual.633 634 However in this form there are two concerns. The first that Parent will635 usually be consistent for a given use, it will not be a variable. Second is636 that we may also need the assertion functions. To do any casting/conversions637 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 usual641 assertions plus this new primitive assertion. There may or may not be use642 cases for accessing just one half and providing easy access to them may be643 required depending on how that turns out.644 645 trait Parent(dtype T | interface(T)) virtual(<grand-parent?>) { }646 647 ### Extension: sizeof Compatablity648 Trait types are always sized, it may even be a fixed size like how pointers649 have the same size regardless of what they point at. However their contents650 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 a653 special syntax would have to be added. Here a special case of `sizeof` is654 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 put663 the value into. The other case `x` checks the saved stored value in the664 virtual table and returns that. -
doc/theses/aaron_moss_PhD/phd/Makefile
r933f32f r6a9d4b4 2 2 BIBDIR = ../../../bibliography 3 3 EVALDIR = evaluation 4 FIGDIR = figures5 4 TEXLIB = .:${BUILD}:${BIBDIR}: 6 5 … … 9 8 BIBTEX = BIBINPUTS=${TEXLIB} && export BIBINPUTS && bibtex 10 9 11 VPATH = ${EVALDIR} ${FIGDIR}10 VPATH = ${EVALDIR} 12 11 13 12 BASE = thesis … … 23 22 background \ 24 23 generic-types \ 24 type-environment \ 25 25 resolution-heuristics \ 26 type-environment \27 experiments \28 26 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 \37 27 } 38 28 39 29 GRAPHS = ${addsuffix .tex, \ 40 30 generic-timing \ 41 tests-completed \42 per-prob-histo \43 per-prob-depth \44 cfa-time \45 31 } 46 32 … … 61 47 dvips ${BUILD}/$< -o ${BUILD}/$@ 62 48 63 ${BASE}.dvi : Makefile ${SOURCES} ${GRAPHS} ${ FIGURES} ${BIBFILE} ${BUILD}49 ${BASE}.dvi : Makefile ${SOURCES} ${GRAPHS} ${BIBFILE} ${BUILD} 64 50 ${LATEX} ${BASE} 65 51 ${BIBTEX} ${BUILD}/${BASE} … … 67 53 ${LATEX} ${BASE} 68 54 69 generic-timing.tex: generic-timing.gp generic-timing.dat ${BUILD}55 ${GRAPHS} : generic-timing.gp generic-timing.dat ${BUILD} 70 56 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.gp74 75 per-prob-histo.tex : per-prob.gp per-prob.tsv ${BUILD}76 gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/per-prob.gp77 78 per-prob-depth.tex : per-prob-scatter.gp ${BUILD}79 gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/per-prob-scatter.gp80 81 cfa-time.tex : cfa-plots.gp cfa-time.tsv cfa-mem.tsv ${BUILD}82 gnuplot -e BUILD="'${BUILD}/'" ${EVALDIR}/cfa-plots.gp83 57 84 58 ${BUILD}: -
doc/theses/aaron_moss_PhD/phd/background.tex
r933f32f r6a9d4b4 1 1 \chapter{\CFA{}} 2 \label{cfa-chap}3 2 4 3 \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. 5 4 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. 6 5 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} 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} 24 20 25 21 It is important to note that \CFA{} is not an object-oriented language. 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 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. 29 26 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. 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. 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. 32 28 33 29 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{}. 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. 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. 41 36 \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: 42 37 … … 55 50 \end{cfa} 56 51 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} 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} 63 56 64 57 C does allow name overloading in one context: operator overloading. 65 58 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. 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}}: 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}}: 68 60 69 61 \begin{cfa} … … 79 71 \end{cfa} 80 72 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 \subs ection{Special Literal Types}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 \subsubsection{Special Literal Types} 84 76 85 77 Literal !0! is also used polymorphically in C; it may be either integer zero or the null value of any pointer type. 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. 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. 92 83 93 84 \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. 94 85 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. 95 86 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 \s ection{Polymorphic Functions} \label{poly-func-sec}101 102 The most significant type-systemfeature \CFA{} adds is parametric-polymorphic functions.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 \subsection{Polymorphic Functions} \label{poly-func-sec} 92 93 The most significant feature \CFA{} adds is parametric-polymorphic functions. 103 94 Such functions are written using a !forall! clause (which gives the language its name): 104 95 … … 111 102 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. 112 103 \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. 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} 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} 116 106 117 107 One benefit of this design is that it allows polymorphic functions to be separately compiled. … … 119 109 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. 120 110 121 \subs ection{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.}:111 \subsubsection{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: 124 114 125 115 \begin{cfa} 126 116 forall(otype T `| { T twice(T); }`) 127 117 T four_times(T x) { return twice( twice(x) ); } 128 double twice $\(_1\)$(double d) { return d * 2.0; }118 double twice(double d) { return d * 2.0; } $\C[2.75in]{// (1)}$ 129 119 130 120 double ans = four_times( 10.5 ); $\C[2.75in]{// T bound to double, ans == 42.0}$ … … 139 129 \begin{cfa} 140 130 forall(otype S | { S ?+?(S, S); }) 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.}. 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. 149 138 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. 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}.}: 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}.}: 155 157 156 158 \begin{cfa} … … 169 171 170 172 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. 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 ofstructural inheritance, similar to interface implementation in Go, as opposed to the nominal inheritance model of Java and \CC{}.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 a structural inheritance, similar to interface implementation in Go, as opposed to the nominal inheritance model of Java and \CC{}. 172 174 Nominal inheritance can be simulated in \CFA{} using marker variables in traits: 173 175 … … 184 186 185 187 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. 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.}.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. 187 189 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}.}: 188 190 … … 204 206 \end{cfa} 205 207 206 In th isexample 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.208 In the 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. 207 209 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!). 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}. 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. 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 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. 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. 231 219 \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!. 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 findingthe 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 thathave either no interpretation or multiple ambiguous minimal-cost interpretations.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 find 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. 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 which have either no interpretation or multiple ambiguous minimal-cost interpretations. 236 224 Note that which subexpression interpretation is minimal-cost may require contextual information to disambiguate. 237 225 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. 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}}.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.}. 239 227 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. 240 228 241 \s ection{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 thathave a smaller effect but are useful for code examples.229 \subsection{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 which have a smaller effect but are useful for code examples. 244 232 These features are described here. 245 233 246 \subs ection{Reference Types}247 248 One of the key ergonomic improvements in \CFA{} is reference types, designed and implemented by Robert Schluntz \cite{Schluntz17}.234 \subsubsection{Reference Types} 235 236 One of the key ergonomic improvements in \CFA{} is reference types, designed and implemented by Robert Schluntz\cite{Schluntz17}. 249 237 Given some type !T!, a !T&! (``reference to !T!'') is essentially an automatically dereferenced pointer. 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: 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: 263 246 264 247 \begin{cfa} 265 248 const int magic = 42; 249 266 250 void inc_print( int& x ) { printf("%d\n", ++x); } 267 251 268 inc_print( magic ); $\C{// legal; implicitly generated code in red below:}$252 print_inc( magic ); $\C{// legal; implicitly generated code in red below:}$ 269 253 270 254 `int tmp = magic;` $\C{// to safely strip const-qualifier}$ 271 ` inc_print( tmp );` $\C{// tmp is incremented, magic is unchanged}$255 `print_inc( tmp );` $\C{// tmp is incremented, magic is unchanged}$ 272 256 \end{cfa} 273 257 … … 275 259 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. 276 260 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. 277 \CFA{} supports all of these use cases without further added syntax.261 \CFA{} supports all of these use cases \TODO{test array} without further added syntax. 278 262 The key to this syntax-free feature support is an observation made by the author that the address of a reference is a lvalue. 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: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: 280 264 281 265 \begin{cfa} … … 286 270 \end{cfa} 287 271 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 \subs ection{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}.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 \subsubsection{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}. 293 277 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. 294 278 A wide variety of conceptual resources may be conveniently managed by this scheme, including heap memory, file handles, and software locks. … … 341 325 \end{cfa} 342 326 343 \subs ection{Tuple Types}327 \subsubsection{Tuple Types} 344 328 345 329 \CFA{} adds \emph{tuple types} to C, a syntactic facility for referring to lists of values anonymously or with a single identifier. 346 330 An identifier may name a tuple, a function may return one, and a tuple may be implicitly \emph{destructured} into its component values. 347 331 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. 348 This reuseallows 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;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)}$ 354 338 355 339 forall(otype T) 356 [T, T] swap $\(_1\)$( T a, T b ) {340 [T, T] swap( T a, T b ) { $\C{// (3)}$ 357 341 return [b, a]; $\C{// one-line swap syntax}$ 358 342 } 359 343 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}$344 x = swap( x ); $\C{// destructure [char, char] x into 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}$ 367 351 \end{cfa} 368 352 369 353 Tuple destructuring breaks the one-to-one relationship between identifiers and values. 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. 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. -
doc/theses/aaron_moss_PhD/phd/conclusion.tex
r933f32f r6a9d4b4 1 1 \chapter{Conclusion} 2 2 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. 3 Wrap it up --- Done, done done. -
doc/theses/aaron_moss_PhD/phd/evaluation/generic-timing.dat
r933f32f r6a9d4b4 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
r933f32f r6a9d4b4 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: \> Doug Lea \\ 68 \> Professor, Computer Science Department, \\ 69 \> State University of New York at Oswego \\ 70 \end{tabbing} 71 \bigskip 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 72 71 73 72 \noindent … … 75 74 Internal-External Member: \= \kill % using longest text to define tab length 76 75 Supervisor: \> Peter Buhr \\ 77 \> Associate Professor, School of Computer Science, \\ 78 \> University of Waterloo \\ 76 \> Professor, School of Computer Science, University of Waterloo \\ 79 77 \end{tabbing} 80 78 \bigskip … … 83 81 \begin{tabbing} 84 82 Internal-External Member: \= \kill % using longest text to define tab length 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 \\ 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 \\ 92 87 \end{tabbing} 93 \bigskip88 % \bigskip 94 89 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 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 103 97 104 98 % \noindent … … 130 124 \begin{center}\textbf{Abstract}\end{center} 131 125 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. 126 This is the abstract. 145 127 146 128 \cleardoublepage … … 149 131 % ------------------------------- 150 132 151 \begin{center}\textbf{Acknowledgements}\end{center}133 % \begin{center}\textbf{Acknowledgements}\end{center} 152 134 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 135 % I would like to thank all the little people who made this thesis possible. 136 % \cleardoublepage 165 137 166 138 % D E D I C A T I O N … … 169 141 % \begin{center}\textbf{Dedication}\end{center} 170 142 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 143 % This is dedicated to the one I love. 173 144 % \cleardoublepage 174 145 -
doc/theses/aaron_moss_PhD/phd/generic-types.tex
r933f32f r6a9d4b4 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 unnecessary.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. 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 19 16 struct int_list { int value; struct int_list* next; }; 20 17 … … 27 24 int int_list_head( const struct int_list* ls ) { return ls->value; } 28 25 29 // all code must be duplicated for every generic instantiation26 $\C[\textwidth]{// all code must be duplicated for every generic instantiation}$ 30 27 31 28 struct string_list { const char* value; struct string_list* next; }; … … 40 37 { return ls->value; } 41 38 42 // use is efficient and idiomatic39 $\C[\textwidth]{// use is efficient and idiomatic}$ 43 40 44 41 int main() { … … 58 55 \begin{figure} 59 56 \begin{cfa} 60 #include <stdlib.h> $\C{// for malloc}$61 #include <stdio.h> $\C{// for printf}$62 63 57 // single code implementation 64 58 65 59 struct list { void* value; struct list* next; }; 66 60 67 // internal memory management requires helper functions61 $\C[\textwidth]{// internal memory management requires helper functions}$ 68 62 69 63 void list_insert( struct list** ls, void* x, void* (*copy)(void*) ) { … … 75 69 void* list_head( const struct list* ls ) { return ls->value; } 76 70 77 // helpers duplicated per type71 $\C[\textwidth]{// helpers duplicated per type}$ 78 72 79 73 void* int_copy(void* x) { … … 102 96 \begin{figure} 103 97 \begin{cfa} 104 #include <stdlib.h> $\C{// for malloc}$ 105 #include <stdio.h> $\C{// for printf}$ 106 107 // code is nested in macros 98 $\C[\textwidth]{// code is nested in macros}$ 108 99 109 100 #define list(N) N ## _list … … 127 118 define_list(string, const char*); $\C[3in]{// defines string\_list}$ 128 119 129 // use is efficient, but syntactically idiosyncratic120 $\C[\textwidth]{// use is efficient, but syntactically idiosyncratic}$ 130 121 131 122 int main() { … … 143 134 \end{figure} 144 135 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 onwhich this chapter is closely based.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 from which this chapter is closely based. 147 138 \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. 148 139 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. 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} .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}. 150 141 151 142 \begin{figure} 152 143 \begin{cfa} 153 #include <stdlib.hfa> $\C{// for alloc}$154 #include <stdio.h> $\C{// for printf}$155 156 144 forall(otype T) struct list { T value; list(T)* next; }; 157 145 158 // single polymorphic implementation of each function159 // overloading reduces need for namespace prefixes146 $\C[\textwidth]{// single polymorphic implementation of each function}$ 147 $\C[\textwidth]{// overloading reduces need for namespace prefixes}$ 160 148 161 149 forall(otype T) void insert( list(T)** ls, T x ) { … … 167 155 forall(otype T) T head( const list(T)* ls ) { return ls->value; } 168 156 169 // use is clear and efficient157 $\C[\textwidth]{// use is clear and efficient}$ 170 158 171 159 int main() { … … 185 173 \section{Design} 186 174 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++}.175 Though a number of languages have some implementation of generic types, backward compatibility with both C and existing \CFA{} polymorphism presented 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++}. 194 182 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. 195 183 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. 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.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. 197 185 The most significant restriction of the \CC{} template model is that it breaks separate compilation and C's translation-unit-based encapsulation mechanisms. 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{}.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{}. 203 191 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. 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 .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. 205 193 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. 206 194 207 Cyclone \cite{Grossman06} extends C and also provides capabilities for polymorphic functions and existential types which aresimilar to \CFA{}'s !forall! functions and generic types.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. 208 196 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. 209 197 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!. … … 212 200 213 201 Many other languages include some form of generic types. 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 param eters.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 paramters. 219 207 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. 220 Rust has powerful abstractions for generic programming, including explicit implemen tation of traits and options for both separately-compiled virtual dispatch and template-instantiated static dispatch in functions.208 Rust has powerful abstractions for generic programming, including explicit implemenation of traits and options for both separately-compiled virtual dispatch and template-instantiated static dispatch in functions. 221 209 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. 222 210 223 211 \subsection{\CFA{} Generics} 224 212 225 The generic types design in \CFA{} draws inspiration from both \CC{} and Java generics, capturing usefulaspects 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.213 The generic types design in \CFA{} draws inspiration from both \CC{} and Java generics, capturing the better aspects 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. 227 215 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. 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 216 As an example, consider the following generic type and function \TODO{test this}: 217 231 218 \begin{cfa} 232 219 forall( otype R, otype S ) struct pair { R first; S second; }; 233 220 234 221 pair(const char*, int) with_len( const char* s ) { 235 return (pair(const char* , int)){ s, strlen(s) };222 return (pair(const char*), int){ s, strlen(s) }; 236 223 } 237 224 \end{cfa} 238 225 239 226 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!. 240 If its return type w ere!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 a ppropriate re-declarationsand 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 principleeliminate any runtime overhead of this polymorphic call.227 If its return type was !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 an appropriate redeclaration and 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. 245 232 246 233 \CFA{} deliberately does not support \CC{}-style partial specializations of generic types. 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.234 A particularly infamous example in the \CC{} standard library is !vector<bool>!, which is represented as a bitstring rather than the array representation of the other !vector! instantiations. 248 235 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. 249 Rather than attempting to plug leaks in the template specialization abstraction with a detailed method interface, \CFA{} takes the more consistentposition 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 usingthe same polymorphic functions.236 Rather than attempting to plug leaks in the template specialization abstraction with a detailed method interface, \CFA{} takes the more principled position 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 in the same polymorphic functions. 251 238 252 239 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. 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{}:240 As an example, the !with_len! function above could be an optimization of the following more general function: 254 241 255 242 \begin{cfa} … … 260 247 \end{cfa} 261 248 262 \CFA{} generic types also support t ype constraints, as in!forall! functions.249 \CFA{} generic types also support the type constraints from !forall! functions. 263 250 For example, the following declaration of a sorted set type ensures that the set key implements equality and relational comparison: 264 251 … … 267 254 \end{cfa} 268 255 269 These constraints are enforced by applying equivalent constraints to the compiler-generated constructors for this type.256 These constraints are implemented by applying equivalent constraints to the compiler-generated constructors for this type. 270 257 271 258 \section{Implementation} \label{generic-impl-sec} 272 259 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 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. 277 263 A \emph{dtype-static} type has polymorphic parameters but is still concrete. 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.264 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. 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. 280 266 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. 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 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 284 269 \begin{cfa} 285 270 //dynamic, layout varies based on T 286 forall(otype T) T value $\(_1\)$( pair(const char*, T) p ) { return p.second; }271 forall(otype T) T value( pair(const char*, T) p ) { return p.second; } 287 272 288 273 // dtype-static, F* and T* are concrete but recursively polymorphic 289 forall(dtype F, otype T) T value $\(_2\)$( pair(F*, T*) ) { return *p.second; }274 forall(dtype F, otype T) T value( pair(F*, T*) ) { return *p.second; } 290 275 291 276 pair(const char*, int) p = {"magic", 42}; $\C[2.5in]{// concrete}$ 292 277 int i = value(p); 293 pair(void*, int*) q = {0, & i}; $\C[2.5in]{// concrete}$278 pair(void*, int*) q = {0, &p.second}; $\C[2.5in]{// concrete}$ 294 279 i = value(q); 295 280 double d = 1.0; … … 300 285 \subsection{Concrete Generic Types} 301 286 302 The \CFACC{} translator template -expands concrete generic types into new structure types, affording maximal inlining.287 The \CFACC{} translator template expands concrete generic types into new structure types, affording maximal inlining. 303 288 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. 304 289 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. 305 290 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. 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}}: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}} 307 292 308 293 \begin{cfa} … … 311 296 312 297 A concrete generic type with dtype-static parameters is also expanded to a structure type, but this type is used for all matching instantiations. 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 :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. 314 299 315 300 \begin{cfa} … … 323 308 The design for generic types presented here adds an \emph{offset array} containing structure-member offsets for dynamic generic !struct! types. 324 309 A dynamic generic !union! needs no such offset array, as all members are at offset 0, but size and alignment are still necessary. 325 Access to members of a dynamic structure is provided at runtime via base -displacement addressing ofthe 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.310 Access to members of a dynamic structure is provided at runtime via base displacement addressing the 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. 328 313 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. 329 As an example, the body of !value!$_2$ above is implemented as:314 As an example, the body of the second !value! function above is implemented as 330 315 331 316 \begin{cfa} … … 333 318 \end{cfa} 334 319 335 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: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 as 337 322 338 323 \begin{cfa} … … 345 330 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. 346 331 \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. 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.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 functions's caller. 348 333 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. 349 Un -!sized! parameters arenot 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 doesnot 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.334 Un!sized! parameters not 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 will not 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{}. 353 338 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. 354 339 Since \CFACC{} generates a distinct layout function for each type, constant-folding and loop unrolling are applied. … … 357 342 forall(dtype T1, dtype T2, ... | sized(T1) | sized(T2) | ...) 358 343 void layout(size_t* size, size_t* align, size_t* offsets) { 344 // initialize values 359 345 *size = 0; *align = 1; 360 346 // set up members … … 374 360 \end{cfa} 375 361 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 implemen tation-hiding constraint of the design.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 implemenation-hiding constraint of the design. 378 364 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. 379 365 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. 380 366 381 Whether a type is concrete, dtype-static, or dynamic is decided solely on the basis of the type arguments and !forall! clause type param eters.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.367 Whether a type is concrete, dtype-static, or dynamic is decided solely on the basis of the type arguments and !forall! clause type paramters. 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. 385 371 386 372 \subsection{Applications of Dtype-static Types} \label{dtype-static-sec} … … 401 387 Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \emph{tag structures}. 402 388 Sometimes, information is only used for type checking and can be omitted at runtime. 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 !?+?!.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 !?+?!. 404 390 These implementations may even be separately compiled, unlike \CC{} template functions. 405 391 However, the \CFA{} type checker ensures matching types are used by all calls to !?+?!, preventing nonsensical computations like adding a length to a volume. … … 422 408 \section{Performance Experiments} \label{generic-performance-sec} 423 409 424 To validate the practicality of this generic type design , microbenchmark-based tests were conductedagainst 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.410 To validate the practicality of this generic type design I have conducted microbenchmark-based tests against 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. 426 412 A more illustrative comparison measures the costs of idiomatic usage of each language's features. 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 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} 432 417 int main() { 433 418 int max = 0, val = 42; … … 450 435 \end{cfa} 451 436 452 The four versions of the benchmark implemented are C with !void*!-based polymorphism, \CFA{} with paramet ric 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.437 The four versions of the benchmark implemented are C with !void*!-based polymorphism, \CFA{} with parameteric 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. 454 439 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. 455 440 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. … … 464 449 \centering 465 450 \input{generic-timing} 466 \caption [Benchmark timing results]{Benchmark timing results (smaller is better)} \label{generic-eval-fig}451 \caption{Benchmark timing results (smaller is better)} \label{generic-eval-fig} 467 452 \end{figure} 468 453 … … 481 466 482 467 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. 483 By contrast, the \CFA{} and \CC{} variants run in noticeably lesstime 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.468 By contrast, the \CFA{} and \CC{} variants run in roughly equivalent 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. 484 469 \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. 485 470 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. 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.471 Finally, the binary size for \CFA{} is larger because of static linking with \CFA{} libraries. 487 472 488 473 \CFA{} is also competitive in terms of source code size, measured as a proxy for programmer effort. … … 490 475 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. 491 476 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. 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.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 reimplementation of such collection types by C programmers. 493 478 \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. 494 479 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. … … 496 481 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. 497 482 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. 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.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 respecified, either as a format specifier, explicit downcast, type-specific function, or by name in a !sizeof!, !struct! literal, or !new! expression. 499 484 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. 500 485 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. … … 502 487 \section{Future Work} 503 488 504 The generic types presented here arealready sufficiently expressive to implement a variety of useful library types.489 The generic types design presented here is already sufficiently expressive to implement a variety of useful library types. 505 490 However, some other features based on this design could further improve \CFA{}. 506 491 507 492 The most pressing addition is the ability to have non-type generic parameters. 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 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. 523 499 Implementation of these field assertions would be based on the same code that supports member access by dynamic offset calculation for dynamic generic types. 524 500 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. 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. 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. 539 504 540 505 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. 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. 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. -
doc/theses/aaron_moss_PhD/phd/introduction.tex
r933f32f r6a9d4b4 1 1 \chapter{Introduction} 2 2 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: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: 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 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, the re is also widespread desire of programmers for languages with more expressive power and programmer-friendly features; accommodating both maintenance of legacy C code anddevelopment 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 procedural control 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, they 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-effort 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 thataims 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 which 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 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. 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. 29 28 30 29 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. 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} 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. 38 33 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}. 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. -
doc/theses/aaron_moss_PhD/phd/macros.tex
r933f32f r6a9d4b4 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.}\@} 21 \newcommand{\vs}{\textit{vs.}\@} 17 \newcommand{\ie}{\textit{i.e.}} 18 \newcommand{\eg}{\textit{e.g.}} 19 \newcommand{\etc}{\textit{etc.}} 20 \newcommand{\etal}{\textit{et~al.}} 22 21 23 22 \newcommand{\myset}[1]{\left\{#1\right\}} -
doc/theses/aaron_moss_PhD/phd/resolution-heuristics.tex
r933f32f r6a9d4b4 1 \chapter{Resolution Algorithms}1 \chapter{Resolution Heuristics} 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 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. 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. 10 8 11 \section{ Expression Resolution}9 \section{Conversion Cost} 12 10 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 11 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 12 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}$ 13 % Discuss changes to cost model, as promised in Ch. 2 25 14 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. 15 % Mention relevance of work to C++20 concepts -
doc/theses/aaron_moss_PhD/phd/thesis.tex
r933f32f r6a9d4b4 29 29 \usepackage{footmisc} % for double refs to the same footnote 30 30 31 \usepackage{caption} % for subfigure32 \usepackage{subcaption}33 34 31 % Hyperlinks make it very easy to navigate an electronic document. 35 32 % In addition, this is where you should specify the thesis title … … 37 34 % Use the "hyperref" package 38 35 % N.B. HYPERREF MUST BE THE LAST PACKAGE LOADED; ADD ADDITIONAL PKGS ABOVE 39 %\usepackage[pdftex,pagebackref=false]{hyperref} % with basic options \40 \usepackage[ breaklinks,pagebackref=false]{hyperref}36 %\usepackage[pdftex,pagebackref=false]{hyperref} % with basic options 37 \usepackage[pagebackref=false]{hyperref} 41 38 % N.B. pagebackref=true provides links back from the References to the body text. This can cause trouble for printing. 42 39 … … 132 129 \input{resolution-heuristics} 133 130 \input{type-environment} 134 \input{experiments}135 131 \input{conclusion} 136 132 … … 160 156 % \nocite{*} 161 157 162 % APPENDICIES163 % -----------164 \appendix165 \input{generic-bench}166 167 158 \end{document} -
doc/theses/aaron_moss_PhD/phd/type-environment.tex
r933f32f r6a9d4b4 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 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. 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. 9 8 10 9 \section{Definitions} \label{env-defn-sec} 11 10 12 11 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|}}$. 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!$\}$. 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). 31 14 32 15 \begin{table} … … 35 18 \centering 36 19 \begin{tabular}{r@{\hskip 0.25em}ll} 37 \hline 38 $find(T, v_{i,j})$ & $\rightarrow T_i~|~\mathsf{fail}$ & Locate class for variable \\ 20 $find(T, v_{i,j})$ & $\rightarrow T_i | \bot$ & Locate class for variable \\ 39 21 $report(T_i)$ & $\rightarrow \{ v_{i,j} \cdots \}$ & List variables for class \\ 40 $bound(T_i)$ & $\rightarrow b_i ~|~\mathsf{fail}$ & Get bound for class \\41 $insert( T, v_{i,1})$ && New single-variable class \\22 $bound(T_i)$ & $\rightarrow b_i | \bot$ & Get bound for class \\ 23 $insert(v_{i,1})$ & & New single-variable class \\ 42 24 $add(T_i, v_{i,j})$ & & Add variable to class \\ 43 25 $bind(T_i, b_i)$ & & Set or update class bound \\ 44 \hline 45 $unify(T, T_i, T_j)$ & $\rightarrow \mathsf{pass}~|~\mathsf{fail}$ & Combine two type classes \\ 26 $unify(T, T_i, T_j)$ & $\rightarrow \top | \bot$ & Combine two type classes \\ 46 27 $split(T, T_i)$ & $\rightarrow T'$ & Revert the last $unify$ operation on $T_i$ \\ 47 $combine(T, T')$ & $\rightarrow \ mathsf{pass}~|~\mathsf{fail}$ & Merge two environments \\28 $combine(T, T')$ & $\rightarrow \top | \bot$ & Merge two environments \\ 48 29 $save(T)$ & $\rightarrow H$ & Get handle for current state \\ 49 $backtrack(T, H)$ & & Return to handle state \\ 50 \hline 30 $backtrack(T, H)$ & & Return to handle state 51 31 \end{tabular} 52 32 \end{table} 53 33 54 Type environments in \CFACC{} need to support eleven basic operations, summarized in Table~\ref{env-op-table}.55 The first s ixoperations 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$ thatcontains variable $v_{i,j}$, or an invalid sentinel value for no such class.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 seven operations 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$ which contains variable $v_{i,j}$, or an invalid sentinel value for no such class. 57 37 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. 58 38 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}$ mustnot belong to any other type class in $T$.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$. 60 40 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$. 61 41 $bind(T_i, b_i)$ mutates the bound for a type class, setting or updating the current bound. 62 42 63 The $unify$ operation is the fundamental non-trivial operation a type -environment data-structure must support.43 The $unify$ operation is the fundamental non-trivial operation a type environment data structure must support. 64 44 $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. 65 45 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. 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.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. 68 48 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. 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*! resultsin a call to $unifyBound$ on !int! and the bound type of the class containing !R!.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 result in a call to $unifyBound$ on !int! and the bound type of the class containing !R!. 70 50 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. 71 51 For more information on \CFA{} unification, see \cite{Bilson03}. 72 The inverse of $unify$ is $split(T, T_i)$, which produces a new environment $T'$ thatis 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 priorcall 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 abacktracking search, caching and concurrency are both useful tools to decrease runtime.52 The inverse of $unify$ is $split(T, T_i)$, which produces a new environment $T'$ which 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$. 53 If there has been no call 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. 76 56 However, both of these approaches may produce multiple distinct descendants of the same initial type environment, which have possibly been mutated in incompatible ways. 77 As such, to effectively employ either c aching 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 resultsin the resolution algorithm backtracking to a different environment.57 As such, to effectively employ either concurrency 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 result in the resolution algorithm backtracking to a different environment. 80 60 $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'$. 81 61 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. … … 84 64 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$. 85 65 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. 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 simpletranslation 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.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 straightforward 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. 93 73 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. 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 removesthe need to check each type class individually to maintain the disjointness property.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 remove the need to check each type class individually to maintain the disjointness property. 95 75 These improvements do not change the fundamental issues with this data structure, however. 96 76 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 thathave been modified with respect to the parent.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 which have been modified with respect to the parent. 100 80 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. 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, ensuringall local changes to the type environment are listed in its index.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 parent until 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 that all local changes to the type environment are listed in its index. 105 85 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. 106 86 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 diff erence, but is correct as long as the ``null parent'' base-case is properly handled.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'' base case is properly handled. 108 88 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. 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.89 These issues can be solved by ``flattening'' parent nodes into their children before the parents 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. 110 90 111 91 \subsection{Union-Find} \label{env-union-find-approach} 112 92 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}.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}. 114 94 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. 115 95 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. 116 96 $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. 117 97 $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. 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}.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$. 119 99 120 100 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. 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 th en 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.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 than 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. 124 104 125 105 \subsection{Union-Find with Classes} \label{env-union-find-classes-approach} … … 127 107 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. 128 108 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. 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. 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} 131 113 132 114 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. … … 135 117 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. 136 118 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. 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}.119 When two classes are unified, the !next! pointers of the representatives of those classes are swapped, splicing the two circularly-linked lists together. 138 120 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. 139 121 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 \centering143 \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}147 122 148 123 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. … … 152 127 153 128 \begin{theorem} \label{env-reverse-thm} 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.129 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. 155 130 \end{theorem} 156 131 … … 158 133 By induction on the height of the tree. \\ 159 134 \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. \\ 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.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. 161 136 \end{proof} 162 137 … … 164 139 165 140 \subsection{Persistent Union-Find} 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. 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. 169 143 Conchon and Filli\^{a}tre~\cite{Conchon07} present a persistent union-find data structure based on the persistent array of Baker~\cite{Baker78,Baker91}. 170 144 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. 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. 174 150 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. 175 176 The mutation algorithm at the root is a special case of the key operation on persistent arrays, $reroot$. 151 The mutation algorithm at the root is in some sense a special case of the key operation on persistent arrays, $reroot$. 152 177 153 A rerooting operation takes any array reference and makes it the root node of the array. 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.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. 179 155 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. 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 itmust be used behind a lock in a concurrent context.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, and must be used behind a lock in a concurrent context. 181 157 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. 182 158 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. 183 159 184 160 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. 185 In particular, an arbitrary number of type variables m aybe 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.161 In particular, an arbitrary number of type variables must be 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. 189 165 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. 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. 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. 202 170 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. 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. 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. 205 172 206 173 The procedure for $combine(T, T')$ based on edit paths is as follows: 207 174 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. 208 175 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. 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. 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. 220 185 221 186 \begin{table} … … 225 190 \begin{tabular}{rllll} 226 191 \hline 227 & \textbf{Na\"{\i}ve} & \textbf{Incremental} & \textbf{Union-Find} & \textbf{Persistent U-F}\\192 & \textbf{Na\"{\i}ve} & \textbf{Incremental} & \textbf{Union-Find} & \textbf{U-F with Classes} \\ 228 193 \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)$ \\ 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)$ \\ 241 205 \hline 242 206 \end{tabular} 243 207 \end{table} 244 208 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. 209 % Future work: design multi-threaded version of C&F persistent map --- core idea is some sort of thread-boundary edit node -
doc/user/user.tex
r933f32f r6a9d4b4 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Sun May 5 18:24:50 201914 %% Update Count : 34 8913 %% Last Modified On : Tue Dec 11 23:19:26 2018 14 %% Update Count : 3400 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 196 195 197 196 \subsection{Background} … … 433 432 which conditionally includes the correct header file, if the program is compiled using \Indexc{gcc} or \Indexc{cfa}. 434 433 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 \item440 \Indexc{-h}\index{translator option!-h@{©-h©}}, \Indexc{--help}\index{translator option!--help@{©--help©}} \, print help message441 \item442 \Indexc{-l}\index{translator option!-l@{©-l©}}, \Indexc{--libcfa}\index{translator option!--libcfa@{©--libcfa©}} \, generate libcfa.c443 \item444 \Indexc{-L}\index{translator option!-L@{©-L©}}, \Indexc{--linemarks}\index{translator option!--linemarks@{©--linemarks©}} \, generate line marks445 \item446 \Indexc{-m}\index{translator option!-m@{©-m©}}, \Indexc{--no-main}\index{translator option!--no-main@{©--no-main©}} \, do not replace main447 \item448 \Indexc{-N}\index{translator option!-N@{©-N©}}, \Indexc{--no-linemarks}\index{translator option!--no-linemarks@{©--no-linemarks©}} \, do not generate line marks449 \item450 \Indexc{-n}\index{translator option!-n@{©-n©}}, \Indexc{--no-prelude}\index{translator option!--no-prelude@{©--no-prelude©}} \, do not read prelude451 \item452 \Indexc{-p}\index{translator option!-p@{©-p©}}, \Indexc{--prototypes}\index{translator option!--prototypes@{©--prototypes©}} \, generate prototypes for prelude functions453 \item454 \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 \item457 \Indexc{altexpr}\index{translator option!-P@{©-P©}!©altexpr©}\index{translator option!--print@{©-print©}!©altexpr©} \, alternatives for expressions458 \item459 \Indexc{ascodegen}\index{translator option!-P@{©-P©}!©ascodegen©}\index{translator option!--print@{©-print©}!©ascodegen©} \, as codegen rather than AST460 \item461 \Indexc{ast}\index{translator option!-P@{©-P©}!©ast©}\index{translator option!--print@{©-print©}!©ast©} \, AST after parsing462 \item463 \Indexc{astdecl}\index{translator option!-P@{©-P©}!©astdecl©}\index{translator option!--print@{©-print©}!©astdecl©} \, AST after declaration validation pass464 \item465 \Indexc{asterr}\index{translator option!-P@{©-P©}!©asterr©}\index{translator option!--print@{©-print©}!©asterr©} \, AST on error466 \item467 \Indexc{astexpr}\index{translator option!-P@{©-P©}!©astexpr©}\index{translator option!--print@{©-print©}!©altexpr©} \, AST after expression analysis468 \item469 \Indexc{astgen}\index{translator option!-P@{©-P©}!©astgen©}\index{translator option!--print@{©-print©}!©astgen©} \, AST after instantiate generics470 \item471 \Indexc{box}\index{translator option!-P@{©-P©}!©box©}\index{translator option!--print@{©-print©}!©box©} \, before box step472 \item473 \Indexc{ctordtor}\index{translator option!-P@{©-P©}!©ctordtor©}\index{translator option!--print@{©-print©}!©ctordtor©} \, after ctor/dtor are replaced474 \item475 \Indexc{codegen}\index{translator option!-P@{©-P©}!©codegen©}\index{translator option!--print@{©-print©}!©codegen©} \, before code generation476 \item477 \Indexc{declstats}\index{translator option!-P@{©-P©}!©declstats©}\index{translator option!--print@{©-print©}!©declstats©} \, code property statistics478 \item479 \Indexc{parse}\index{translator option!-P@{©-P©}!©parse©}\index{translator option!--print@{©-print©}!©parse©} \, yacc (parsing) debug information480 \item481 \Indexc{pretty}\index{translator option!-P@{©-P©}!©pretty©}\index{translator option!--print@{©-print©}!©pretty©} \, prettyprint for ascodegen flag482 \item483 \Indexc{resolver}\index{translator option!-P@{©-P©}!©resolver©}\index{translator option!--print@{©-print©}!©resolver©} \, before resolver step484 \item485 \Indexc{rproto}\index{translator option!-P@{©-P©}!©rproto©}\index{translator option!--print@{©-print©}!©rproto©} \, resolver-proto instance486 \item487 \Indexc{rsteps}\index{translator option!-P@{©-P©}!©rsteps©}\index{translator option!--print@{©-print©}!©rsteps©} \, resolver steps488 \item489 \Indexc{symevt}\index{translator option!-P@{©-P©}!©symevt©}\index{translator option!--print@{©-print©}!©symevt©} \, symbol table events490 \item491 \Indexc{tree}\index{translator option!-P@{©-P©}!©tree©}\index{translator option!--print@{©-print©}!©tree©} \, parse tree492 \item493 \Indexc{tuple}\index{translator option!-P@{©-P©}!©tuple©}\index{translator option!--print@{©-print©}!©tuple©} \, after tuple expansion494 \end{description}495 \item496 \Indexc{--prelude-dir} <directory> \, prelude directory for debug/nodebug497 \item498 \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 \item501 \Indexc{counters,heap,time,all,none}502 \end{description}503 \item504 \Indexc{-t}\index{translator option!-t@{©-t©}}, \Indexc{--tree}\index{translator option!--tree@{©--tree©}} build in tree505 \end{description}506 507 434 508 435 \section{Backquote Identifiers} … … 581 508 582 509 As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types. 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. 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} 592 518 Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©. 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, ©*©. 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. 601 522 602 523 … … 628 549 \subsection{Loop Control} 629 550 630 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}). 631 \begin{itemize} 632 \item 551 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges. 633 552 An empty conditional implies ©1©. 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 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]. 645 557 ©0© is the implicit start value; 646 \item647 558 ©1© is the implicit increment value. 648 \item649 559 The up-to range uses ©+=© for increment; 650 \item 651 The down-to range uses ©-=© for decrement. 652 \item 560 the down-to range uses ©-=© for decrement. 653 561 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}657 562 \begin{cquote} 658 \begin{tabular}{@{}l |l@{}}659 \multicolumn{ 1}{c|}{loop control} & \multicolumn{1}{c}{output} \\563 \begin{tabular}{@{}ll|l@{}} 564 \multicolumn{2}{c|}{loop control} & \multicolumn{1}{c}{output} \\ 660 565 \hline 661 566 \begin{cfa} 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; 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; } 680 584 enum { N = 10 }; 681 for ( ®N® ) { sout | "N"; } sout | nl;682 for ( ®i; N® ) { sout | i; } sout | nl;683 for ( ®i; N -~ 0® ) { sout | i; } sout | nl;585 for ( ®N® ) { sout | "N"; } 586 for ( ®i; N® ) { sout | i; } 587 for ( ®i; N -~ 0® ) { sout | i; } 684 588 const int start = 3, comp = 10, inc = 2; 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; 589 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } 712 590 \end{cfa} 713 591 & 714 592 \begin{cfa} 715 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} 716 619 empty 717 620 empty … … 737 640 738 641 3 6 9 739 740 1 2 3 4 5 6 7 8 9 10741 742 10 9 8 7 6 5 4 3 2 1 0743 744 2 4 6 8 10745 746 2.1 3.8 5.5 7.2 8.9747 748 10 8 6 4 2 0749 750 12.1 10.4 8.7 7 5.3 3.6751 0 -5 1 -4 2 -3 3 -2 4 -1752 0 -5 1 -6 2 -7 3 -8 4 -9753 0 -5 1 -3 2 -1 3 1 4 3754 0 -5 1 -7 2 -9 3 -11 4 -13755 0 -5 1 -4 2 -3 3 -2 4 -1756 0 -5 1 -6 2 -7 3 -8 4 -9757 0 -5 1 -3 2 -1 3 1 4 3758 0 -5 1 -7 2 -9 3 -11 4 -13759 760 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5761 762 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5763 764 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5765 642 \end{cfa} 766 643 \end{tabular} 767 644 \end{cquote} 768 \caption{Loop Control Examples}769 \label{f:LoopControlExamples}770 \end{figure}771 645 772 646 … … 1446 1320 \end{cfa} 1447 1321 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}). 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} 1322 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice. 1452 1323 1453 1324 \CFA provides its own type, variable and routine declarations, using a different syntax. -
driver/Makefile.am
r933f32f r6a9d4b4 19 19 20 20 # applies to both programs 21 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src -I${abs_top_srcdir}/src/include21 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src 22 22 23 23 # don't install cfa directly -
driver/Makefile.in
r933f32f r6a9d4b4 187 187 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 188 188 ACLOCAL = @ACLOCAL@ 189 ALLOCA = @ALLOCA@ 189 190 AMTAR = @AMTAR@ 190 191 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 334 335 335 336 # applies to both programs 336 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src -I${abs_top_srcdir}/src/include337 AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src 337 338 cfa_SOURCES = cfa.cc 338 339 -
driver/cfa.cc
r933f32f r6a9d4b4 10 10 // Created On : Tue Aug 20 13:44:49 2002 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 10 08:28:09201913 // Update Count : 28 112 // Last Modified On : Tue Jan 15 20:56:03 2019 13 // Update Count : 280 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 nolib = false; // -nolib flag 112 bool help = false; // -help flag 109 bool quiet = false; // -quiet flag 110 bool debug = true; // -debug flag 111 bool help = false; // -help flag 113 112 bool CFA_flag = false; // -CFA flag 114 113 bool cpp_flag = false; // -E or -M flag, preprocessor only … … 163 162 debug = true; // strip the debug flag 164 163 } else if ( arg == "-nodebug" ) { 165 debug = false; // strip the debug flag 166 } else if ( arg == "-nolib" ) { 167 nolib = true; // strip the nodebug flag 164 debug = false; // strip the nodebug flag 168 165 } else if ( arg == "-quiet" ) { 169 166 quiet = true; // strip the quiet flag … … 369 366 } // if 370 367 } // if 371 const char * config = nolib ? "nolib" : (debug ? "debug": "nodebug");368 const char * config = debug ? "debug": "nodebug"; 372 369 string libdir = libbase + arch + "-" + config; 373 370 374 if ( ! nolib && !dirExists( libdir ) ) {371 if ( ! dirExists( libdir ) ) { 375 372 cerr << argv[0] << " internal error, configuration " << config << " not installed." << endl; 376 373 cerr << "Was looking for " << libdir << endl; … … 498 495 args[nargs] = "-Wno-deprecated"; 499 496 nargs += 1; 500 #ifdef HAVE_CAST_FUNCTION_TYPE501 args[nargs] = "-Wno-cast-function-type";502 nargs += 1;503 #endif // HAVE_CAST_FUNCTION_TYPE504 497 if ( ! std_flag ) { // default c11, if none specified 505 498 args[nargs] = "-std=gnu11"; -
libcfa/configure
r933f32f r6a9d4b4 2382 2382 2383 2383 2384 # http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_check_compile_flag.m42385 2386 2384 2387 2385 am__api_version='1.15' … … 2959 2957 case $CONFIGURATION in 2960 2958 "debug" ) 2961 CONFIG_CFLAGS="-O g-g"2959 CONFIG_CFLAGS="-O0 -g" 2962 2960 CONFIG_CFAFLAGS="-debug" 2963 2961 CONFIG_BUILDLIB="yes" 2964 2962 ;; 2965 2963 "nodebug" ) 2966 CONFIG_CFLAGS="-O 3-s"2964 CONFIG_CFLAGS="-O2 -s" 2967 2965 CONFIG_CFAFLAGS="-nodebug" 2968 2966 CONFIG_BUILDLIB="yes" 2969 2967 ;; 2970 2968 "nolib" ) 2971 CONFIG_CFLAGS="-O 3-s"2972 CONFIG_CFAFLAGS="-no lib"2969 CONFIG_CFLAGS="-O2 -s" 2970 CONFIG_CFAFLAGS="-nodebug" 2973 2971 CONFIG_BUILDLIB="no" 2974 ;;2975 "profile" )2976 CONFIG_CFLAGS="-O3 -g -fno-omit-frame-pointer"2977 CONFIG_CFAFLAGS="-nodebug"2978 CONFIG_BUILDLIB="yes"2979 2972 ;; 2980 2973 *) … … 2982 2975 ;; 2983 2976 esac 2984 2985 CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}"2986 2977 2987 2978 -
libcfa/configure.ac
r933f32f r6a9d4b4 45 45 case $CONFIGURATION in 46 46 "debug" ) 47 CONFIG_CFLAGS="-O g-g"47 CONFIG_CFLAGS="-O0 -g" 48 48 CONFIG_CFAFLAGS="-debug" 49 49 CONFIG_BUILDLIB="yes" 50 50 ;; 51 51 "nodebug" ) 52 CONFIG_CFLAGS="-O 3-s"52 CONFIG_CFLAGS="-O2 -s" 53 53 CONFIG_CFAFLAGS="-nodebug" 54 54 CONFIG_BUILDLIB="yes" 55 55 ;; 56 56 "nolib" ) 57 CONFIG_CFLAGS="-O 3-s"58 CONFIG_CFAFLAGS="-no lib"57 CONFIG_CFLAGS="-O2 -s" 58 CONFIG_CFAFLAGS="-nodebug" 59 59 CONFIG_BUILDLIB="no" 60 ;;61 "profile" )62 CONFIG_CFLAGS="-O3 -g -fno-omit-frame-pointer"63 CONFIG_CFAFLAGS="-nodebug"64 CONFIG_BUILDLIB="yes"65 60 ;; 66 61 *) … … 68 63 ;; 69 64 esac 70 71 CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}"72 65 73 66 AC_SUBST(CONFIG_CFLAGS) -
libcfa/prelude/builtins.c
r933f32f r6a9d4b4 10 10 // Created On : Fri Jul 21 16:21:03 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Mar 26 23:10:36 201913 // Update Count : 9512 // Last Modified On : Sun Aug 5 21:40:38 2018 13 // Update Count : 20 14 14 // 15 15 … … 42 42 typedef unsigned long long __cfaabi_abi_exception_type_t; 43 43 44 #include <limits.h> // CHAR_BIT45 44 #include "../src/virtual.h" 46 45 #include "../src/exception.h" … … 51 50 // increment/decrement unification 52 51 53 static inline { 54 forall( dtype DT | { DT & ?+=?( DT &, one_t ); } ) 55 DT & ++?( DT & x ) { return x += 1; } 52 static inline forall( dtype T | { T& ?+=?( T&, one_t ); } ) 53 T& ++? ( T& x ) { return x += 1; } 56 54 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; }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; } 59 57 60 forall( dtype DT | { DT & ?-=?( DT&, one_t ); } )61 DT & --?( DT& x ) { return x -= 1; }58 static inline forall( dtype T | { T& ?-=?( T&, one_t ); } ) 59 T& --? ( T& x ) { return x -= 1; } 62 60 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; } 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; } 70 63 71 64 // exponentiation operator implementation … … 80 73 } // extern "C" 81 74 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 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 ); } 90 81 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 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 } // ?\? 94 92 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 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 } // ?\? 106 103 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 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 } // ?\? 114 115 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__() 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 } // ?\? 121 120 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 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. 126 125 127 #undef __CFA_BASE_COMP_1__ 128 #undef __CFA_BASE_COMP_2__ 129 #undef __CFA_EXP_OVERFLOW__ 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 // } // ?\? 130 131 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 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; } 137 136 138 137 // Local Variables: // -
libcfa/prelude/extras.c
r933f32f r6a9d4b4 1 #include <stddef.h> // size_t, ptrdiff_t , intptr_t, uintptr_t1 #include <stddef.h> // size_t, ptrdiff_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
r933f32f r6a9d4b4 1 1 typedef.* size_t; 2 2 typedef.* ptrdiff_t; 3 typedef.* intptr_t;4 typedef.* uintptr_t;5 3 typedef.* __int8_t; 6 4 typedef.* __int16_t; -
libcfa/prelude/prelude-gen.cc
r933f32f r6a9d4b4 1 //2 // Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo3 //4 // The contents of this file are covered under the licence agreement in the5 // file "LICENCE" distributed with Cforall.6 //7 // prelude-gen.cc --8 //9 // Author : Rob Schluntz and Thierry Delisle10 // Created On : Sat Feb 16 08:44:58 201911 // Last Modified By : Peter A. Buhr12 // Last Modified On : Tue Apr 2 17:18:24 201913 // Update Count : 3714 //15 16 1 #include <algorithm> 17 2 #include <array> … … 26 11 bool hasComparison; 27 12 } basicTypes[] = { 28 { "char" , false, true , },29 { "signed char" , false, true , },30 { "unsigned char" , false, true , },13 // { "char" , false, true , }, 14 // { "signed char" , false, true , }, 15 // { "unsigned char" , false, true , }, 31 16 { "signed short" , false, true , }, 32 17 { "unsigned short" , false, true , }, … … 49 34 #if defined(__i386__) || defined(__ia64__) || defined(__x86_64__) 50 35 { "__float80" , true , true , }, 51 { "_ _float128", true , true , },36 { "_Float128" , true , true , }, 52 37 #endif 53 38 }; … … 118 103 { "?!=?", false, "signed int", Normal, "" }, 119 104 { "?=?", true, "", Normal, "" }, // void * LHS, zero_t RHS ??? 120 // { "*?", false, "&", Normal, " | sized(DT)" }, // & ??? 121 { "*?", false, "&", Normal, "" }, // & ??? 105 { "*?", false, "&", Normal, " | sized(DT)" }, // & ??? 122 106 123 107 { "?-?", false, "ptrdiff_t", Normal, " | sized(DT)" }, … … 166 150 cout << endl; 167 151 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;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; 172 156 173 157 for (auto op : arithmeticOperators) { … … 204 188 cout << "// Arithmetic Constructors //" << endl; 205 189 cout << "/////////////////////////////" << endl; 206 cout << endl;207 208 190 auto otype = [](const std::string & type, bool do_volatile = false) { 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 << ")";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 << " )"; 214 196 } 215 197 cout << ";" << endl; 216 cout << "void ^?{}( " << type << " & );" << endl;198 cout << "void \t^?{}( " << type << " & );" << endl; 217 199 }; 218 200 219 201 otype("zero_t"); 220 cout << endl;221 202 otype("one_t"); 222 cout << endl;223 203 otype("_Bool", true); 224 cout << endl; 204 otype("char", true); 205 otype("signed char", true); 206 otype("unsigned char", true); 225 207 226 208 for (auto type : basicTypes) { 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; 209 cout << "void ?{}(" << type.name << " &);" << endl; 210 cout << "void ?{}(" << type.name << " &, " << type.name << ");" << endl; 231 211 cout << "void ^?{}(" << type.name << " &);" << endl; 232 212 cout << endl; … … 237 217 cout << "// Pointer Constructors //" << endl; 238 218 cout << "//////////////////////////" << endl; 239 cout << endl; 240 241 cout << "forall(ftype FT) void ?{}( FT *&, FT * );" << endl; 242 cout << "forall(ftype FT) void ?{}( FT * volatile &, FT * );" << endl; 219 cout << "forall(ftype FT) void ?{}( FT *&, FT * );" << endl; 220 cout << "forall(ftype FT) void ?{}( FT * volatile &, FT * );" << endl; 243 221 244 222 // generate qualifiers … … 264 242 for (auto cvq : qualifiersPair) { 265 243 for (auto is_vol : { " ", "volatile" }) { 266 cout << "forall(dtype DT) void ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl;244 cout << "forall(dtype DT) void ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl; 267 245 } 268 246 } 269 247 for (auto cvq : qualifiersSingle) { 270 248 for (auto is_vol : { " ", "volatile" }) { 271 cout << "forall(dtype DT) void ?{}(" << cvq << type << " * " << is_vol << " &);" << endl;249 cout << "forall(dtype DT) void ?{}(" << cvq << type << " * " << is_vol << " &);" << endl; 272 250 } 273 251 for (auto is_vol : { " ", "volatile" }) { … … 291 269 cout << "forall(ftype FT) FT * ?=?( FT * &, zero_t );" << endl; 292 270 cout << "forall(ftype FT) FT * ?=?( FT * volatile &, zero_t );" << endl; 293 cout << "forall( ftype FT) void ?{}( FT * & );" << endl;294 cout << "forall( ftype FT) void ^?{}( FT * & );" << endl;271 cout << "forall( ftype FT ) void ?{}( FT * & );" << endl; 272 cout << "forall( ftype FT ) void ^?{}( FT * & );" << endl; 295 273 cout << endl; 296 274 … … 299 277 cout << "///////////////////////" << endl; 300 278 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; 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 307 286 308 287 for (auto op : pointerOperators) { … … 408 387 } 409 388 410 // Local Variables: //411 // tab-width: 4 //412 // End: // -
libcfa/prelude/sync-builtins.cf
r933f32f r6a9d4b4 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*, ...);326 325 327 326 char __sync_val_compare_and_swap(volatile char *, char, char,...); … … 349 348 unsigned __int128 __sync_val_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...); 350 349 #endif 351 forall(dtype T) T * __sync_val_compare_and_swap(T * volatile *, T *, T*,...);352 350 353 351 char __sync_lock_test_and_set(volatile char *, char,...); … … 436 434 #endif 437 435 438 char __atomic_exchange_n(volatile char *, char, int);436 char __atomic_exchange_n(volatile char *, volatile char *, int); 439 437 char __atomic_exchange_1(volatile char *, char, int); 440 438 void __atomic_exchange(volatile char *, volatile char *, volatile char *, int); 441 signed char __atomic_exchange_n(volatile signed char *, signed char, int);439 signed char __atomic_exchange_n(volatile signed char *, volatile signed char *, int); 442 440 signed char __atomic_exchange_1(volatile signed char *, signed char, int); 443 441 void __atomic_exchange(volatile signed char *, volatile signed char *, volatile signed char *, int); 444 unsigned char __atomic_exchange_n(volatile unsigned char *, unsigned char, int);442 unsigned char __atomic_exchange_n(volatile unsigned char *, volatile unsigned char *, int); 445 443 unsigned char __atomic_exchange_1(volatile unsigned char *, unsigned char, int); 446 444 void __atomic_exchange(volatile unsigned char *, volatile unsigned char *, volatile unsigned char *, int); 447 signed short __atomic_exchange_n(volatile signed short *, signed short, int);445 signed short __atomic_exchange_n(volatile signed short *, volatile signed short *, int); 448 446 signed short __atomic_exchange_2(volatile signed short *, signed short, int); 449 447 void __atomic_exchange(volatile signed short *, volatile signed short *, volatile signed short *, int); 450 unsigned short __atomic_exchange_n(volatile unsigned short *, unsigned short, int);448 unsigned short __atomic_exchange_n(volatile unsigned short *, volatile unsigned short *, int); 451 449 unsigned short __atomic_exchange_2(volatile unsigned short *, unsigned short, int); 452 450 void __atomic_exchange(volatile unsigned short *, volatile unsigned short *, volatile unsigned short *, int); 453 signed int __atomic_exchange_n(volatile signed int *, signed int, int);451 signed int __atomic_exchange_n(volatile signed int *, volatile signed int *, int); 454 452 signed int __atomic_exchange_4(volatile signed int *, signed int, int); 455 453 void __atomic_exchange(volatile signed int *, volatile signed int *, volatile signed int *, int); 456 unsigned int __atomic_exchange_n(volatile unsigned int *, unsigned int, int);454 unsigned int __atomic_exchange_n(volatile unsigned int *, volatile unsigned int *, int); 457 455 unsigned int __atomic_exchange_4(volatile unsigned int *, unsigned int, int); 458 456 void __atomic_exchange(volatile unsigned int *, volatile unsigned int *, volatile unsigned int *, int); 459 signed long long int __atomic_exchange_n(volatile signed long long int *, signed long long int, int);457 signed long long int __atomic_exchange_n(volatile signed long long int *, volatile signed long long int *, int); 460 458 signed long long int __atomic_exchange_8(volatile signed long long int *, signed long long int, int); 461 459 void __atomic_exchange(volatile signed long long int *, volatile signed long long int *, volatile signed long long int *, int); 462 unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, unsigned long long int, int);460 unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, volatile unsigned long long int *, int); 463 461 unsigned long long int __atomic_exchange_8(volatile unsigned long long int *, unsigned long long int, int); 464 462 void __atomic_exchange(volatile unsigned long long int *, volatile unsigned long long int *, volatile unsigned long long int *, int); 465 463 #if defined(__SIZEOF_INT128__) 466 signed __int128 __atomic_exchange_n(volatile signed __int128 *, signed __int128, int);464 signed __int128 __atomic_exchange_n(volatile signed __int128 *, volatile signed __int128 *, int); 467 465 signed __int128 __atomic_exchange_16(volatile signed __int128 *, signed __int128, int); 468 466 void __atomic_exchange(volatile signed __int128 *, volatile signed __int128 *, volatile signed __int128 *, int); 469 unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, unsigned __int128, int);467 unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, volatile unsigned __int128 *, int); 470 468 unsigned __int128 __atomic_exchange_16(volatile unsigned __int128 *, unsigned __int128, int); 471 469 void __atomic_exchange(volatile unsigned __int128 *, volatile unsigned __int128 *, volatile unsigned __int128 *, int); 472 470 #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);475 471 476 472 _Bool __atomic_load_n(const volatile _Bool *, int); … … 511 507 void __atomic_load(const volatile unsigned __int128 *, volatile unsigned __int128 *, int); 512 508 #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);515 509 516 510 _Bool __atomic_compare_exchange_n(volatile char *, char *, char, _Bool, int, int); … … 549 543 _Bool __atomic_compare_exchange (volatile unsigned __int128 *, unsigned __int128 *, unsigned __int128 *, _Bool, int, int); 550 544 #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);553 545 554 546 void __atomic_store_n(volatile _Bool *, _Bool, int); … … 589 581 void __atomic_store(volatile unsigned __int128 *, unsigned __int128 *, int); 590 582 #endif 591 forall(dtype T) void __atomic_store_n(T * volatile *, T *, int);592 forall(dtype T) void __atomic_store(T * volatile *, T **, int);593 583 594 584 char __atomic_add_fetch (volatile char *, char, int); -
libcfa/src/Makefile.am
r933f32f r6a9d4b4 74 74 75 75 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 76 ${AM_V_GEN} $(CFACOMPILE) -quiet -in-tree-XCFA -l ${<} -c -o ${@}76 ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -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 $(CFACOMPILE) -quiet -in-tree-XCFA -l ${<} -c -o ${@}80 @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@} 81 81 82 82 -
libcfa/src/Makefile.in
r933f32f r6a9d4b4 926 926 927 927 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 928 ${AM_V_GEN} $(CFACOMPILE) -quiet -in-tree-XCFA -l ${<} -c -o ${@}928 ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -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 $(CFACOMPILE) -quiet -in-tree-XCFA -l ${<} -c -o ${@}932 @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@} 933 933 934 934 #---------------------------------------------------------------------------------------------------------------- -
libcfa/src/bits/containers.hfa
r933f32f r6a9d4b4 186 186 187 187 forall(dtype T | is_node(T)) 188 static inline bool ?!=?( __queue(T) & this, __attribute__((unused))zero_t zero ) {188 static inline bool ?!=?( __queue(T) & this, zero_t zero ) { 189 189 return this.head != 0; 190 190 } … … 196 196 //----------------------------------------------------------------------------- 197 197 #ifdef __cforall 198 forall(dtype TYPE )198 forall(dtype TYPE | sized(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, __attribute__((unused))zero_t zero ) {270 static inline bool ?!=?( __dllist(T) & this, zero_t zero ) { 271 271 return this.head != 0; 272 272 } -
libcfa/src/concurrency/CtxSwitch-i386.S
r933f32f r6a9d4b4 41 41 #define PC_OFFSET ( 2 * PTR_BYTE ) 42 42 43 .text43 .text 44 44 .align 2 45 .globl CtxSwitch 46 .type CtxSwitch, @function 45 .globl CtxSwitch 47 46 CtxSwitch: 48 47 … … 51 50 52 51 movl 4(%esp),%eax 52 53 // Save floating & SSE control words on the stack. 54 55 sub $8,%esp 56 stmxcsr 0(%esp) // 4 bytes 57 fnstcw 4(%esp) // 2 bytes 53 58 54 59 // Save volatile registers on the stack. … … 62 67 movl %esp,SP_OFFSET(%eax) 63 68 movl %ebp,FP_OFFSET(%eax) 69 // movl 4(%ebp),%ebx // save previous eip for debugger 70 // movl %ebx,PC_OFFSET(%eax) 64 71 65 72 // Copy the "to" context argument from the stack to register eax … … 67 74 // argument is now at 8 + 12 = 20(%esp) 68 75 69 movl 2 0(%esp),%eax76 movl 28(%esp),%eax 70 77 71 78 // Load new context from the "to" area. … … 80 87 popl %ebx 81 88 89 // Load floating & SSE control words from the stack. 90 91 fldcw 4(%esp) 92 ldmxcsr 0(%esp) 93 add $8,%esp 94 82 95 // Return to thread. 83 96 84 97 ret 85 .size CtxSwitch, .-CtxSwitch86 98 87 99 // Local Variables: // -
libcfa/src/concurrency/CtxSwitch-x86_64.S
r933f32f r6a9d4b4 39 39 #define SP_OFFSET ( 0 * PTR_BYTE ) 40 40 #define FP_OFFSET ( 1 * PTR_BYTE ) 41 #define PC_OFFSET ( 2 * PTR_BYTE ) 41 42 42 //----------------------------------------------------------------------------- 43 // Regular context switch routine which enables switching from one context to anouther 44 .text 43 .text 45 44 .align 2 46 .globl CtxSwitch 47 .type CtxSwitch, @function 45 .globl CtxSwitch 48 46 CtxSwitch: 47 48 // Save floating & SSE control words on the stack. 49 50 subq $8,%rsp 51 stmxcsr 0(%rsp) // 4 bytes 52 fnstcw 4(%rsp) // 2 bytes 49 53 50 54 // Save volatile registers on the stack. … … 74 78 popq %r15 75 79 80 // Load floating & SSE control words from the stack. 81 82 fldcw 4(%rsp) 83 ldmxcsr 0(%rsp) 84 addq $8,%rsp 85 76 86 // Return to thread. 77 87 78 88 ret 79 .size CtxSwitch, .-CtxSwitch80 89 81 //----------------------------------------------------------------------------- 82 // Stub used to create new stacks which are ready to be context switched to 83 .text 90 .text 84 91 .align 2 85 .globl CtxInvokeStub 86 .type CtxInvokeStub, @function 92 .globl CtxInvokeStub 87 93 CtxInvokeStub: 88 94 movq %rbx, %rdi 89 95 jmp *%r12 90 .size CtxInvokeStub, .-CtxInvokeStub91 96 92 97 // Local Variables: // -
libcfa/src/concurrency/coroutine.cfa
r933f32f r6a9d4b4 35 35 36 36 extern "C" { 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__)); 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 } 44 42 } 45 43 … … 49 47 // minimum feasible stack size in bytes 50 48 #define MinStackSize 1000 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 ); 49 static size_t pageSize = 0; // architecture pagesize HACK, should go in proper runtime singleton 54 50 55 51 //----------------------------------------------------------------------------- 56 52 // Coroutine ctors and dtors 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 } 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 } 87 72 } 88 73 89 74 void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) { 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;75 (this.stack){storage, storageSize}; 76 this.name = name; 77 errno_ = 0; 78 state = Start; 79 starter = NULL; 80 last = NULL; 81 cancellation = NULL; 97 82 } 98 83 99 84 void ^?{}(coroutine_desc& this) { 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 }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 } 117 102 } 118 103 … … 121 106 forall(dtype T | is_coroutine(T)) 122 107 void prime(T& cor) { 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; 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; 182 190 } 183 191 … … 185 193 // is not inline (We can't inline Cforall in C) 186 194 extern "C" { 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 } 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 } 207 216 } 208 217 -
libcfa/src/concurrency/coroutine.hfa
r933f32f r6a9d4b4 46 46 //----------------------------------------------------------------------------- 47 47 // Public coroutine API 48 static inline void suspend( void);48 static inline void suspend(); 49 49 50 50 forall(dtype T | is_coroutine(T)) 51 static inline T &resume(T & cor);51 static inline void 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");70 66 } 71 67 72 68 // Private wrappers for context switch and stack creation 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 */); 69 extern void CoroutineCtxSwitch(coroutine_desc * src, coroutine_desc * dst); 70 extern void create_stack( coStack_t * this, unsigned int storageSize ); 95 71 96 72 // Suspend implementation inlined for performance 97 static inline void suspend( void) {73 static inline void suspend() { 98 74 // optimization : read TLS once and reuse it 99 75 // Safety note: this is preemption safe since if … … 101 77 // will also migrate which means this value will 102 78 // stay in syn with the TLS 103 coroutine_desc * src = TL_GET( this_ thread )->curr_cor;79 coroutine_desc * src = TL_GET( this_coroutine ); 104 80 105 81 assertf( src->last != 0, … … 117 93 // Resume implementation inlined for performance 118 94 forall(dtype T | is_coroutine(T)) 119 static inline T &resume(T & cor) {95 static inline void resume(T & cor) { 120 96 // optimization : read TLS once and reuse it 121 97 // Safety note: this is preemption safe since if … … 123 99 // will also migrate which means this value will 124 100 // stay in syn with the TLS 125 coroutine_desc * src = TL_GET( this_ thread )->curr_cor;101 coroutine_desc * src = TL_GET( this_coroutine ); 126 102 coroutine_desc * dst = get_coroutine(cor); 127 103 128 if( unlikely( dst->context.SP == NULL) ) {129 __stack_prepare(&dst->stack, 65000);104 if( unlikely(!dst->stack.base) ) { 105 create_stack(&dst->stack, dst->stack.size); 130 106 CtxStart(&cor, CtxInvokeCoroutine); 131 107 } … … 145 121 // always done for performance testing 146 122 CoroutineCtxSwitch( src, dst ); 147 148 return cor;149 123 } 150 124 … … 155 129 // will also migrate which means this value will 156 130 // stay in syn with the TLS 157 coroutine_desc * src = TL_GET( this_ thread )->curr_cor;131 coroutine_desc * src = TL_GET( this_coroutine ); 158 132 159 133 // not resuming self ? -
libcfa/src/concurrency/invoke.c
r933f32f r6a9d4b4 28 28 29 29 extern void __suspend_internal(void); 30 extern void __leave_coroutine( struct coroutine_desc *);31 extern void __finish_creation( struct thread_desc *);30 extern void __leave_coroutine(void); 31 extern void __finish_creation(void); 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 49 51 main( this ); 50 52 51 53 //Final suspend, should never return 52 __leave_coroutine( cor);54 __leave_coroutine(); 53 55 __cabi_abort( "Resumed dead coroutine" ); 54 56 } … … 60 62 __attribute((__unused__)) struct _Unwind_Exception * unwind_exception, 61 63 __attribute((__unused__)) struct _Unwind_Context * context, 62 void * param64 __attribute((__unused__)) void * param 63 65 ) { 64 66 if( actions & _UA_END_OF_STACK ) { 65 67 // We finished unwinding the coroutine, 66 68 // leave it 67 __leave_coroutine( param);69 __leave_coroutine(); 68 70 __cabi_abort( "Resumed dead coroutine" ); 69 71 } … … 73 75 } 74 76 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);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 ); 78 80 printf("UNWIND ERROR %d after force unwind\n", ret); 79 81 abort(); … … 86 88 void *this 87 89 ) { 90 // First suspend, once the thread arrives here, 91 // the function pointer to main can be invalidated without risk 92 __finish_creation(); 93 88 94 // Fetch the thread handle from the user defined thread structure 89 95 struct thread_desc* thrd = get_thread( this ); 90 91 // First suspend, once the thread arrives here, 92 // the function pointer to main can be invalidated without risk 93 __finish_creation( thrd ); 96 thrd->self_cor.last = NULL; 94 97 95 98 // Officially start the thread by enabling preemption … … 117 120 void (*invoke)(void *) 118 121 ) { 119 struct coroutine_desc * cor = get_coroutine( this ); 120 struct __stack_t * stack = cor->stack.storage; 122 struct coStack_t* stack = &get_coroutine( this )->stack; 121 123 122 124 #if defined( __i386 ) 123 125 124 126 struct FakeStack { 125 void *fixedRegisters[3]; // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant) 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) 126 130 void *rturn; // where to go on return from uSwitch 127 void *dummyReturn; // fake return compiler would have pushed on call to uInvoke128 void *argument[3]; // for 16-byte ABI, 16-byte alignment starts here129 void *padding; // padding to force 16-byte alignment, as "base" is 16-byte aligned131 void *dummyReturn; // fake return compiler would have pushed on call to uInvoke 132 void *argument[3]; // for 16-byte ABI, 16-byte alignment starts here 133 void *padding; // padding to force 16-byte alignment, as "base" is 16-byte aligned 130 134 }; 131 135 132 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );133 cor->context.FP = NULL; // terminate stack with NULL fp136 ((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 fp 134 138 135 struct FakeStack *fs = (struct FakeStack *)cor->context.SP;136 137 fs->dummyReturn = NULL;138 fs->argument[0] = this; // argument to invoke139 fs->rturn = invoke;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-520 143 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 140 144 141 145 #elif defined( __x86_64 ) … … 143 147 struct FakeStack { 144 148 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) 145 151 void *rturn; // where to go on return from uSwitch 146 152 void *dummyReturn; // NULL return address to provide proper alignment 147 153 }; 148 154 149 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );150 cor->context.FP = NULL; // terminate stack with NULL fp155 ((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 fp 151 157 152 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;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-520 163 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 158 164 159 165 #elif defined( __ARM_ARCH ) … … 165 171 }; 166 172 167 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );168 cor->context.FP = NULL;173 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack ); 174 ((struct machine_context_t *)stack->context)->FP = NULL; 169 175 170 struct FakeStack *fs = (struct FakeStack *) cor->context.SP;176 struct FakeStack *fs = (struct FakeStack *)((struct machine_context_t *)stack->context)->SP; 171 177 172 178 fs->intRegs[8] = CtxInvokeStub; -
libcfa/src/concurrency/invoke.h
r933f32f r6a9d4b4 50 50 51 51 extern thread_local struct KernelThreadData { 52 struct coroutine_desc * volatile this_coroutine; 52 53 struct thread_desc * volatile this_thread; 53 54 struct processor * volatile this_processor; … … 60 61 } kernelTLS __attribute__ ((tls_model ( "initial-exec" ))); 61 62 } 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 ); } // UNSAFE 62 67 #endif 63 68 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; 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 93 77 }; 94 78 … … 96 80 97 81 struct coroutine_desc { 98 // context that is switch during a CtxSwitch99 struct __stack_context_t context;100 101 82 // stack information of the coroutine 102 struct __stack_info_t stack;103 104 // textual name for coroutine/task 83 struct coStack_t stack; 84 85 // textual name for coroutine/task, initialized by uC++ generated code 105 86 const char * name; 87 88 // copy of global UNIX variable errno 89 int errno_; 106 90 107 91 // current execution status for coroutine 108 92 enum coroutine_state state; 109 110 93 // first coroutine to resume this one 111 94 struct coroutine_desc * starter; … … 161 144 struct thread_desc { 162 145 // Core threading fields 163 // context that is switch during a CtxSwitch164 struct __stack_context_t context;165 166 // current execution status for coroutine167 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 it170 171 146 // coroutine body used to store context 172 147 struct coroutine_desc self_cor; … … 195 170 struct thread_desc * prev; 196 171 } node; 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 172 }; 173 174 #ifdef __cforall 175 extern "Cforall" { 205 176 static inline thread_desc * & get_next( thread_desc & this ) { 206 177 return this.next; … … 260 231 // assembler routines that performs the context switch 261 232 extern void CtxInvokeStub( void ); 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"); 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 265 253 266 254 #endif //_INVOKE_PRIVATE_H_ -
libcfa/src/concurrency/kernel.cfa
r933f32f r6a9d4b4 36 36 #include "invoke.h" 37 37 38 //-----------------------------------------------------------------------------39 // Some assembly required40 #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 #else103 #error unknown hardware architecture104 #endif105 106 //-----------------------------------------------------------------------------107 38 //Start and stop routine for the kernel, declared first to make sure they run first 108 39 static void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); … … 111 42 //----------------------------------------------------------------------------- 112 43 // Kernel storage 113 KERNEL_STORAGE(cluster, mainCluster);114 KERNEL_STORAGE(processor, mainProcessor);115 KERNEL_STORAGE(thread_desc, mainThread);116 KERNEL_STORAGE( __stack_t,mainThreadCtx);44 KERNEL_STORAGE(cluster, mainCluster); 45 KERNEL_STORAGE(processor, mainProcessor); 46 KERNEL_STORAGE(thread_desc, mainThread); 47 KERNEL_STORAGE(machine_context_t, mainThreadCtx); 117 48 118 49 cluster * mainCluster; … … 123 54 struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters; 124 55 } 125 126 size_t __page_size = 0;127 56 128 57 //----------------------------------------------------------------------------- … … 131 60 NULL, 132 61 NULL, 62 NULL, 133 63 { 1, false, false } 134 64 }; … … 137 67 // Struct to steal stack 138 68 struct current_stack_info_t { 139 __stack_t * storage; // pointer to stack object 69 machine_context_t ctx; 70 unsigned int size; // size of stack 140 71 void *base; // base of stack 72 void *storage; // pointer to stack 141 73 void *limit; // stack grows towards stack limit 142 74 void *context; // address of cfa_context_t 75 void *top; // address of top of storage 143 76 }; 144 77 145 78 void ?{}( current_stack_info_t & this ) { 146 __stack_context_t ctx;147 CtxGet( ctx );148 this. base = ctx.FP;79 CtxGet( this.ctx ); 80 this.base = this.ctx.FP; 81 this.storage = this.ctx.SP; 149 82 150 83 rlimit r; 151 84 getrlimit( RLIMIT_STACK, &r); 152 size_tsize = r.rlim_cur;153 154 this.limit = (void *)(((intptr_t)this.base) - size);85 this.size = r.rlim_cur; 86 87 this.limit = (void *)(((intptr_t)this.base) - this.size); 155 88 this.context = &storage_mainThreadCtx; 89 this.top = this.base; 156 90 } 157 91 158 92 //----------------------------------------------------------------------------- 159 93 // 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 } 160 103 161 104 void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) { 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; 105 stack{ info }; 169 106 name = "Main Thread"; 107 errno_ = 0; 170 108 state = Start; 171 109 starter = NULL; 172 last = NULL;173 cancellation = NULL;174 110 } 175 111 176 112 void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) { 177 state = Start;178 113 self_cor{ info }; 179 114 curr_cor = &self_cor; … … 306 241 } 307 242 308 static int * __volatile_errno() __attribute__((noinline));309 static int * __volatile_errno() { asm(""); return &errno; }310 311 243 // KERNEL ONLY 312 244 // runThread runs a thread by context switching 313 245 // from the processor coroutine to the target thread 314 static void runThread(processor * this, thread_desc * thrd_dst) { 246 static void runThread(processor * this, thread_desc * dst) { 247 assert(dst->curr_cor); 315 248 coroutine_desc * proc_cor = get_coroutine(this->runner); 249 coroutine_desc * thrd_cor = dst->curr_cor; 316 250 317 251 // Reset the terminating actions here … … 319 253 320 254 // Update global state 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; 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 335 260 } 336 261 … … 338 263 static void returnToKernel() { 339 264 coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner); 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; 265 coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine; 266 ThreadCtxSwitch(thrd_cor, proc_cor); 363 267 } 364 268 … … 403 307 processor * proc = (processor *) arg; 404 308 kernelTLS.this_processor = proc; 309 kernelTLS.this_coroutine = NULL; 405 310 kernelTLS.this_thread = NULL; 406 311 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1]; … … 409 314 // to waste the perfectly valid stack create by pthread. 410 315 current_stack_info_t info; 411 __stack_t ctx;412 info. storage= &ctx;316 machine_context_t ctx; 317 info.context = &ctx; 413 318 (proc->runner){ proc, &info }; 414 319 415 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack. storage);320 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.base); 416 321 417 322 //Set global state 323 kernelTLS.this_coroutine = get_coroutine(proc->runner); 418 324 kernelTLS.this_thread = NULL; 419 325 … … 444 350 445 351 // KERNEL_ONLY 446 void kernel_first_resume( processor * this) {447 thread_desc * src = mainThread;352 void kernel_first_resume(processor * this) { 353 coroutine_desc * src = kernelTLS.this_coroutine; 448 354 coroutine_desc * dst = get_coroutine(this->runner); 449 355 450 356 verify( ! kernelTLS.preemption_state.enabled ); 451 357 452 __stack_prepare( &dst->stack, 65000);358 create_stack(&dst->stack, dst->stack.size); 453 359 CtxStart(&this->runner, CtxInvokeCoroutine); 454 360 455 361 verify( ! kernelTLS.preemption_state.enabled ); 456 362 457 dst->last = &src->self_cor;458 dst->starter = dst->starter ? dst->starter : &src->self_cor;363 dst->last = src; 364 dst->starter = dst->starter ? dst->starter : src; 459 365 460 366 // set state of current coroutine to inactive 461 367 src->state = src->state == Halted ? Halted : Inactive; 462 368 369 // set new coroutine that task is executing 370 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 will 376 // stay disabled. 377 disable_interrupts(); 378 463 379 // context switch to specified coroutine 464 verify( dst->context.SP);465 CtxSwitch( &src->context, &dst->context );380 assert( src->stack.context ); 381 CtxSwitch( src->stack.context, dst->stack.context ); 466 382 // when CtxSwitch returns we are back in the src coroutine 467 383 … … 470 386 471 387 verify( ! kernelTLS.preemption_state.enabled ); 472 }473 474 // KERNEL_ONLY475 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 processor484 CtxSwitch( &src->context, &dst->context );485 388 } 486 389 … … 491 394 void ScheduleThread( thread_desc * thrd ) { 492 395 verify( thrd ); 493 verify( thrd->s tate != Halted );396 verify( thrd->self_cor.state != Halted ); 494 397 495 398 verify( ! kernelTLS.preemption_state.enabled ); … … 648 551 __cfaabi_dbg_print_safe("Kernel : Starting\n"); 649 552 650 __page_size = sysconf( _SC_PAGESIZE );651 652 553 __cfa_dbg_global_clusters.list{ __get }; 653 554 __cfa_dbg_global_clusters.lock{}; … … 664 565 mainThread = (thread_desc *)&storage_mainThread; 665 566 current_stack_info_t info; 666 info.storage = (__stack_t*)&storage_mainThreadCtx;667 567 (*mainThread){ &info }; 668 568 … … 699 599 kernelTLS.this_processor = mainProcessor; 700 600 kernelTLS.this_thread = mainThread; 601 kernelTLS.this_coroutine = &mainThread->self_cor; 701 602 702 603 // Enable preemption … … 733 634 // which is currently here 734 635 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 735 kernel_last_resume( kernelTLS.this_processor);636 returnToKernel(); 736 637 mainThread->self_cor.state = Halted; 737 638 … … 819 720 __cfaabi_dbg_bits_write( abort_text, len ); 820 721 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);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 ); 823 724 __cfaabi_dbg_bits_write( abort_text, len ); 824 725 } -
libcfa/src/concurrency/thread.cfa
r933f32f r6a9d4b4 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 };34 33 self_cor{ name, storage, storageSize }; 35 state = Start;34 verify(&self_cor); 36 35 curr_cor = &self_cor; 37 36 self_mon.owner = &this; … … 74 73 forall( dtype T | is_thread(T) ) 75 74 void __thrd_start( T& this ) { 76 thread_desc * this_thrd = get_thread(this); 77 thread_desc * curr_thrd = TL_GET( this_thread ); 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); 78 80 79 81 disable_interrupts(); 82 create_stack(&thrd_c->stack, thrd_c->stack.size); 83 kernelTLS.this_coroutine = thrd_c; 80 84 CtxStart(&this, CtxInvokeThread); 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 ); 85 assert( thrd_c->last->stack.context ); 86 CtxSwitch( thrd_c->last->stack.context, thrd_c->stack.context ); 84 87 85 ScheduleThread(th is_thrd);88 ScheduleThread(thrd_h); 86 89 enable_interrupts( __cfaabi_dbg_ctx ); 87 90 } … … 89 92 extern "C" { 90 93 // KERNEL ONLY 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 ); 94 void __finish_creation(void) { 95 coroutine_desc* thrd_c = kernelTLS.this_coroutine; 96 ThreadCtxSwitch( thrd_c, thrd_c->last ); 97 97 } 98 98 } … … 112 112 } 113 113 114 // KERNEL ONLY 115 void ThreadCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 116 // set state of current coroutine to inactive 117 src->state = src->state == Halted ? Halted : Inactive; 118 dst->state = Active; 119 120 // set new coroutine that the processor is executing 121 // and context switch to it 122 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 active 128 dst->state = dst->state == Halted ? Halted : Inactive; 129 src->state = Active; 130 } 131 114 132 // Local Variables: // 115 133 // mode: c // -
libcfa/src/concurrency/thread.hfa
r933f32f r6a9d4b4 61 61 void ^?{}(thread_desc & this); 62 62 63 static inline void ?{}(thread_desc & this) { this{ "Anonymous Thread", *mainCluster, NULL, 65000 }; }63 static inline void ?{}(thread_desc & this) { this{ "Anonymous Thread", *mainCluster, NULL, 0 }; } 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, 65000 }; }67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize ) { this{ "Anonymous Thread", cl, NULL, stackSize }; }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 }; } 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, 65000 }; }70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl ) { this{ name, cl, NULL, 65000 }; }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 }; } 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
r933f32f r6a9d4b4 10 10 // Created On : Wed May 24 15:40:00 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 17 11:22:03 201913 // Update Count : 312 // Last Modified On : Thu Jul 20 15:23:50 2017 13 // Update Count : 2 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
r933f32f r6a9d4b4 10 10 // Created On : Wed May 24 15:40:00 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 17 11:24:04 201913 // Update Count : 312 // Last Modified On : Thu Jul 20 15:23:58 2017 13 // Update Count : 2 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
r933f32f r6a9d4b4 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu May 16 08:33:28 201913 // Update Count : 3 2812 // Last Modified On : Mon Dec 24 18:33:38 2018 13 // Update Count : 304 14 14 // 15 15 … … 23 23 #include <complex.h> // creal, cimag 24 24 #include <assert.h> 25 #include <errno.h> // errno26 25 27 26 #define IO_MSG "I/O error: " 28 27 29 void ?{}( ofstream & os, void * file ) {28 void ?{}( ofstream & os, void * file, bool sepDefault, bool sepOnOff, bool nlOnOff, bool prt, const char * separator, const char * tupleSeparator ) { 30 29 os.file = file; 31 os.sepDefault = true; 32 os.sepOnOff = false; 33 os.nlOnOff = true; 34 os.prt = false; 35 os.sawNL = false; 36 sepSet( os, " " ); 30 os.sepDefault = sepDefault; 31 os.sepOnOff = sepOnOff; 32 os.nlOnOff = nlOnOff; 33 os.prt = prt; 34 sepSet( os, separator ); 37 35 sepSetCur( os, sepGet( os ) ); 38 sepSetTuple( os, ", ");36 sepSetTuple( os, tupleSeparator ); 39 37 } 40 38 … … 104 102 105 103 void open( ofstream & os, const char * name, const char * mode ) { 106 FILE * file = fopen( name, mode );104 FILE *file = fopen( name, mode ); 107 105 #ifdef __CFA_DEBUG__ 108 106 if ( file == 0 ) { 109 abort( IO_MSG "open output file \"%s\", %s", name, strerror( errno ) ); 107 fprintf( stderr, IO_MSG "open output file \"%s\", ", name ); 108 perror( 0 ); 109 exit( EXIT_FAILURE ); 110 110 } // if 111 111 #endif // __CFA_DEBUG__ 112 (os){ file };112 (os){ file, true, false, true, false, " ", ", " }; 113 113 } // open 114 114 … … 121 121 122 122 if ( fclose( (FILE *)(os.file) ) == EOF ) { 123 abort( IO_MSG "close output %s", strerror( errno ));123 perror( IO_MSG "close output" ); 124 124 } // if 125 125 } // close … … 127 127 ofstream & write( ofstream & os, const char * data, size_t size ) { 128 128 if ( fail( os ) ) { 129 abort( "attempt write I/O on failed stream\n" ); 129 fprintf( stderr, "attempt write I/O on failed stream\n" ); 130 exit( EXIT_FAILURE ); 130 131 } // if 131 132 132 133 if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) { 133 abort( IO_MSG "write %s", strerror( errno ) ); 134 perror( IO_MSG "write" ); 135 exit( EXIT_FAILURE ); 134 136 } // if 135 137 return os; … … 142 144 if ( len == EOF ) { 143 145 if ( ferror( (FILE *)(os.file) ) ) { 144 abort( "invalid write\n" ); 146 fprintf( stderr, "invalid write\n" ); 147 exit( EXIT_FAILURE ); 145 148 } // if 146 149 } // if … … 152 155 } // fmt 153 156 154 static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_) };157 static ofstream soutFile = { (FILE *)(&_IO_2_1_stdout_), true, false, true, false, " ", ", " }; 155 158 ofstream & sout = soutFile; 156 static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_) };159 static ofstream serrFile = { (FILE *)(&_IO_2_1_stderr_), true, false, true, false, " ", ", " }; 157 160 ofstream & serr = serrFile; 158 161 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 only166 else setPrt( os, false ); // turn off167 }168 162 169 163 //--------------------------------------- … … 172 166 void ?{}( ifstream & is, void * file ) { 173 167 is.file = file; 174 is.nlOnOff = false;175 168 } 176 169 … … 184 177 open( is, name, "r" ); 185 178 } 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; }190 179 191 180 int fail( ifstream & is ) { … … 198 187 199 188 void open( ifstream & is, const char * name, const char * mode ) { 200 FILE * file = fopen( name, mode );189 FILE *file = fopen( name, mode ); 201 190 #ifdef __CFA_DEBUG__ 202 191 if ( file == 0 ) { 203 abort( IO_MSG "open input file \"%s\", %s\n", name, strerror( errno ) ); 192 fprintf( stderr, IO_MSG "open input file \"%s\", ", name ); 193 perror( 0 ); 194 exit( EXIT_FAILURE ); 204 195 } // if 205 196 #endif // __CFA_DEBUG__ … … 215 206 216 207 if ( fclose( (FILE *)(is.file) ) == EOF ) { 217 abort( IO_MSG "close input %s", strerror( errno ));208 perror( IO_MSG "close input" ); 218 209 } // if 219 210 } // close … … 221 212 ifstream & read( ifstream & is, char * data, size_t size ) { 222 213 if ( fail( is ) ) { 223 abort( "attempt read I/O on failed stream\n" ); 214 fprintf( stderr, "attempt read I/O on failed stream\n" ); 215 exit( EXIT_FAILURE ); 224 216 } // if 225 217 226 218 if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) { 227 abort( IO_MSG "read %s", strerror( errno ) ); 219 perror( IO_MSG "read" ); 220 exit( EXIT_FAILURE ); 228 221 } // if 229 222 return is; … … 232 225 ifstream &ungetc( ifstream & is, char c ) { 233 226 if ( fail( is ) ) { 234 abort( "attempt ungetc I/O on failed stream\n" ); 227 fprintf( stderr, "attempt ungetc I/O on failed stream\n" ); 228 exit( EXIT_FAILURE ); 235 229 } // if 236 230 237 231 if ( ungetc( c, (FILE *)(is.file) ) == EOF ) { 238 abort( IO_MSG "ungetc %s", strerror( errno ) ); 232 perror( IO_MSG "ungetc" ); 233 exit( EXIT_FAILURE ); 239 234 } // if 240 235 return is; … … 248 243 if ( len == EOF ) { 249 244 if ( ferror( (FILE *)(is.file) ) ) { 250 abort( "invalid read\n" ); 245 fprintf( stderr, "invalid read\n" ); 246 exit( EXIT_FAILURE ); 251 247 } // if 252 248 } // if -
libcfa/src/fstream.hfa
r933f32f r6a9d4b4 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu May 16 08:34:10 201913 // Update Count : 1 5712 // Last Modified On : Mon Dec 24 18:33:41 2018 13 // Update Count : 149 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 75 72 76 73 struct ifstream { 77 74 void * file; 78 bool nlOnOff;79 75 }; // ifstream 80 76 81 77 // public 82 void nlOn( ifstream & );83 void nlOff( ifstream & );84 bool getANL( ifstream & );85 78 int fail( ifstream & is ); 86 79 int eof( ifstream & is ); -
libcfa/src/gmp.hfa
r933f32f r6a9d4b4 10 10 // Created On : Tue Apr 19 08:43:43 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Apr 20 09:01:52 201913 // Update Count : 2 412 // Last Modified On : Tue Dec 4 23:25:51 2018 13 // Update Count : 22 14 14 // 15 15 … … 271 271 272 272 void ?|?( ostype & os, Int mp ) { 273 (ostype)(os | mp); nl( os );273 (ostype)(os | mp); if ( getANL( os ) ) nl( os ); 274 274 } // ?|? 275 275 } // distribution -
libcfa/src/heap.cfa
r933f32f r6a9d4b4 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu May 9 16:29:12 201913 // Update Count : 51 612 // Last Modified On : Thu Sep 6 09:01:30 2018 13 // Update Count : 513 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 237 236 static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; } 238 239 237 // 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; // pointer to new block of storage535 HeapManager.Storage * block; 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 enum { BufferSize = 64 }; 659 char helpText[BufferSize]; 658 char helpText[64]; 660 659 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size ); 661 660 __cfaabi_dbg_bits_write( helpText, len ); … … 854 853 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero. 855 854 if ( ! mapped ) 856 #endif // __CFA_DEBUG__855 #endif // __CFA_DEBUG__ 857 856 memset( (char *)area + usize, '\0', asize - ( (char *)area - (char *)header ) - usize ); // zero-fill back part 858 857 header->kind.real.blockSize |= 2; // mark new request as zero fill … … 1035 1034 // Local Variables: // 1036 1035 // tab-width: 4 // 1037 // compile-command: "cfa -nodebug -O2 heap.c fa" //1036 // compile-command: "cfa -nodebug -O2 heap.c" // 1038 1037 // End: // -
libcfa/src/iostream.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun May 19 10:48:27 201913 // Update Count : 65412 // Last Modified On : Mon Dec 24 18:33:40 2018 13 // Update Count : 589 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> // isfinite26 25 #include <complex.h> // creal, cimag 27 26 } 28 27 29 28 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 48 29 ostype & ?|?( ostype & os, bool b ) { 49 30 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); … … 154 135 } // ?|? 155 136 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 } // for161 } // checkDecPt162 163 137 ostype & ?|?( ostype & os, float f ) { 164 138 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 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 139 fmt( os, "%g", f ); 169 140 return os; 170 141 } // ?|? … … 175 146 ostype & ?|?( ostype & os, double d ) { 176 147 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 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 148 fmt( os, "%.*lg", DBL_DIG, d ); 181 149 return os; 182 150 } // ?|? … … 187 155 ostype & ?|?( ostype & os, long double ld ) { 188 156 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 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 157 fmt( os, "%.*Lg", LDBL_DIG, ld ); 193 158 return os; 194 159 } // ?|? … … 199 164 ostype & ?|?( ostype & os, float _Complex fc ) { 200 165 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 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" ); 166 fmt( os, "%g%+gi", crealf( fc ), cimagf( fc ) ); 212 167 return os; 213 168 } // ?|? … … 218 173 ostype & ?|?( ostype & os, double _Complex dc ) { 219 174 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 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" ); 175 fmt( os, "%.*lg%+.*lgi", DBL_DIG, creal( dc ), DBL_DIG, cimag( dc ) ); 231 176 return os; 232 177 } // ?|? … … 237 182 ostype & ?|?( ostype & os, long double _Complex ldc ) { 238 183 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); 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" ); 184 fmt( os, "%.*Lg%+.*Lgi", LDBL_DIG, creall( ldc ), LDBL_DIG, cimagl( ldc ) ); 250 185 return os; 251 186 } // ?|? … … 443 378 444 379 istype & ?|?( istype & is, char & c ) { 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 380 fmt( is, "%c", &c ); // must pass pointer through varg to fmt 452 381 return is; 453 382 } // ?|? … … 541 470 } // ?|? 542 471 472 543 473 // manipulators 544 474 istype & ?|?( istype & is, istype & (* manip)( istype & ) ) { … … 547 477 548 478 istype & nl( istype & is ) { 549 fmt( is, "%*[ ^\n]" ); // ignore characters to newline479 fmt( is, "%*[ \t\f\n\r\v]" ); // ignore whitespace 550 480 return is; 551 481 } // nl 552 553 istype & nlOn( istype & is ) {554 nlOn( is ); // call void returning555 return is;556 } // nlOn557 558 istype & nlOff( istype & is ) {559 nlOff( is ); // call void returning560 return is;561 } // nlOff562 482 } // distribution 563 483 -
libcfa/src/iostream.hfa
r933f32f r6a9d4b4 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat May 11 10:31:27 201913 // Update Count : 2 3212 // Last Modified On : Mon Dec 24 18:33:40 2018 13 // Update Count : 220 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[], ... ) __attribute__(( format(printf, 2, 3) ));50 int fmt( ostype &, const char format[], ... ); 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 69 64 ostype & ?|?( ostype &, bool ); 70 65 void ?|?( ostype &, bool ); … … 149 144 150 145 trait istream( dtype istype ) { 151 void nlOn( istype & ); // read newline152 void nlOff( istype & ); // scan newline153 bool getANL( istype & ); // get scan newline (on/off)154 146 int fail( istype & ); 155 147 int eof( istype & ); … … 158 150 istype & read( istype &, char *, size_t ); 159 151 istype & ungetc( istype &, char ); 160 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));152 int fmt( istype &, const char format[], ... ); 161 153 }; // istream 162 154 … … 192 184 istype & ?|?( istype &, istype & (*)( istype & ) ); 193 185 istype & nl( istype & is ); 194 istype & nlOn( istype & );195 istype & nlOff( istype & );196 186 } // distribution 197 187 … … 215 205 216 206 // Local Variables: // 207 // mode: c // 217 208 // tab-width: 4 // 218 209 // End: // -
libcfa/src/rational.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed Apr 6 17:54:28 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Mar 28 17:33:03 201913 // Update Count : 1 8112 // Last Modified On : Sun Dec 23 22:56:49 2018 13 // Update Count : 170 14 14 // 15 15 … … 35 35 static RationalImpl simplify( RationalImpl & n, RationalImpl & d ) { 36 36 if ( d == (RationalImpl){0} ) { 37 abort( "Invalid rational number construction: denominator cannot be equal to 0.\n" ); 37 serr | "Invalid rational number construction: denominator cannot be equal to 0."; 38 exit( EXIT_FAILURE ); 38 39 } // exit 39 40 if ( d < (RationalImpl){0} ) { d = -d; n = -n; } // move sign to numerator … … 53 54 void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ) { 54 55 RationalImpl t = simplify( n, d ); // simplify 55 r.[numerator, denominator] = [n / t, d / t]; 56 r.numerator = n / t; 57 r.denominator = d / t; 56 58 } // rational 57 59 … … 76 78 RationalImpl prev = r.numerator; 77 79 RationalImpl t = gcd( abs( n ), r.denominator ); // simplify 78 r.[numerator, denominator] = [n / t, r.denominator / t]; 80 r.numerator = n / t; 81 r.denominator = r.denominator / t; 79 82 return prev; 80 83 } // numerator … … 83 86 RationalImpl prev = r.denominator; 84 87 RationalImpl t = simplify( r.numerator, d ); // simplify 85 r.[numerator, denominator] = [r.numerator / t, d / t]; 88 r.numerator = r.numerator / t; 89 r.denominator = d / t; 86 90 return prev; 87 91 } // denominator … … 116 120 117 121 Rational(RationalImpl) +?( Rational(RationalImpl) r ) { 118 return (Rational(RationalImpl)){ r.numerator, r.denominator }; 122 Rational(RationalImpl) t = { r.numerator, r.denominator }; 123 return t; 119 124 } // +? 120 125 121 126 Rational(RationalImpl) -?( Rational(RationalImpl) r ) { 122 return (Rational(RationalImpl)){ -r.numerator, r.denominator }; 127 Rational(RationalImpl) t = { -r.numerator, r.denominator }; 128 return t; 123 129 } // -? 124 130 125 131 Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 126 132 if ( l.denominator == r.denominator ) { // special case 127 return (Rational(RationalImpl)){ l.numerator + r.numerator, l.denominator }; 133 Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator }; 134 return t; 128 135 } else { 129 return (Rational(RationalImpl)){ l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; 136 Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; 137 return t; 130 138 } // if 131 139 } // ?+? … … 133 141 Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 134 142 if ( l.denominator == r.denominator ) { // special case 135 return (Rational(RationalImpl)){ l.numerator - r.numerator, l.denominator }; 143 Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator }; 144 return t; 136 145 } else { 137 return (Rational(RationalImpl)){ l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; 146 Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; 147 return t; 138 148 } // if 139 149 } // ?-? 140 150 141 151 Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 142 return (Rational(RationalImpl)){ l.numerator * r.numerator, l.denominator * r.denominator }; 152 Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator }; 153 return t; 143 154 } // ?*? 144 155 145 156 Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 146 157 if ( r.numerator < (RationalImpl){0} ) { 147 r.[numerator, denominator] = [-r.numerator, -r.denominator]; 158 r.numerator = -r.numerator; 159 r.denominator = -r.denominator; 148 160 } // if 149 return (Rational(RationalImpl)){ l.numerator * r.denominator, l.denominator * r.numerator }; 161 Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator }; 162 return t; 150 163 } // ?/? 151 164 … … 154 167 forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } ) 155 168 istype & ?|?( istype & is, Rational(RationalImpl) & r ) { 169 RationalImpl t; 156 170 is | r.numerator | r.denominator; 157 RationalImplt = simplify( r.numerator, r.denominator );171 t = simplify( r.numerator, r.denominator ); 158 172 r.numerator /= t; 159 173 r.denominator /= t; … … 171 185 } // distribution 172 186 } // 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 } // if181 }182 187 183 188 // conversion -
libcfa/src/rational.hfa
r933f32f r6a9d4b4 12 12 // Created On : Wed Apr 6 17:56:25 2016 13 13 // Last Modified By : Peter A. Buhr 14 // Last Modified On : Tue Mar 26 23:16:10 201915 // Update Count : 10 914 // Last Modified On : Tue Dec 4 23:07:46 2018 15 // Update Count : 106 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 103 100 // conversion 104 101 forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); } ) -
libcfa/src/stdhdr/stdbool.h
r933f32f r6a9d4b4 10 10 // Created On : Mon Jul 4 23:25:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 25 08:00:08 201913 // Update Count : 1 512 // Last Modified On : Tue Jul 5 20:39:51 2016 13 // Update Count : 12 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/false20 #if defined( true )21 #undef true22 #define true ((_Bool)1)23 #endif // true24 25 #if defined( false )26 #undef false27 #define false ((_Bool)0)28 #endif // false29 18 } // extern "C" 30 19 -
libcfa/src/stdlib.hfa
r933f32f r6a9d4b4 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 24 17:35:43 201913 // Update Count : 3 5212 // Last Modified On : Mon Dec 17 15:37:45 2018 13 // Update Count : 346 14 14 // 15 15 … … 40 40 } // malloc 41 41 42 // T & malloc( void ) { 43 // int & p = *(T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc 44 // printf( "& malloc %p\n", &p ); 45 // return p; 46 // // return (T &)*(T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc 47 // } // malloc 48 42 49 T * calloc( size_t dim ) { 43 50 return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc … … 69 76 T * alloc( char fill ) { 70 77 T * ptr = (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc 71 return (T *)memset( ptr, (int)fill, sizeof(T) ); // initializewith fill value78 return (T *)memset( ptr, (int)fill, sizeof(T) ); // initial with fill value 72 79 } // alloc 73 80 … … 77 84 78 85 T * alloc( size_t dim, char fill ) { 79 T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C calloc80 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); // initializewith fill value86 T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C malloc 87 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); // initial with fill value 81 88 } // alloc 82 89 -
libcfa/src/time.hfa
r933f32f r6a9d4b4 30 30 31 31 static inline { 32 Duration ?=?( Duration & dur, __attribute__((unused))zero_t ) { return dur{ 0 }; }32 Duration ?=?( Duration & dur, 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, __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; }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; } 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, __attribute__((unused))zero_t ) { t{ 0, 0 }; }104 105 timeval ?=?( timeval & t, __attribute__((unused))zero_t ) { return t{ 0 }; }103 void ?{}( timeval & t, zero_t ) { t{ 0, 0 }; } 104 105 timeval ?=?( timeval & t, 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, __attribute__((unused))zero_t ) { t{ 0, 0 }; }119 120 timespec ?=?( timespec & t, __attribute__((unused))zero_t ) { return t{ 0 }; }118 void ?{}( timespec & t, zero_t ) { t{ 0, 0 }; } 119 120 timespec ?=?( timespec & t, 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, __attribute__((unused))zero_t ) { return time{ 0 }; }147 Time ?=?( Time & time, 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
r933f32f r6a9d4b4 24 24 25 25 static inline void ?{}( Duration & dur ) with( dur ) { tv = 0; } 26 static inline void ?{}( Duration & dur, __attribute__((unused))zero_t ) with( dur ) { tv = 0; }26 static inline void ?{}( Duration & dur, 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, __attribute__((unused))zero_t ) with( time ) { tv = 0; }36 static inline void ?{}( Time & time, zero_t ) with( time ) { tv = 0; } 37 37 38 38 // Local Variables: // -
src/CodeGen/CodeGenerator.cc
r933f32f r6a9d4b4 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 : Thr May 2 10:47:00 201913 // Update Count : 49 711 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat May 5 09:08:32 2018 13 // Update Count : 494 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 ( ! options.lineMarks || to.isUnset() ) return;85 if ( !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 ), 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 ) {} 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 ) {} 120 119 121 120 string CodeGenerator::mangleName( DeclarationWithType * decl ) { 122 121 // GCC builtins should always be printed unmangled 123 if ( options.pretty || decl->linkage.is_gcc_builtin ) return decl->name;122 if ( pretty || decl->linkage.is_gcc_builtin ) return decl->name; 124 123 if ( decl->mangleName != "" ) { 125 124 // need to incorporate scope level in order to differentiate names for destructors … … 165 164 previsit( (BaseSyntaxNode *)node ); 166 165 GuardAction( [this, node](){ 167 if ( options.printExprTypes && node->result ) {168 output << " /* " << genType( node->result, "", options) << " */ ";166 if ( printExprTypes && node->result ) { 167 output << " /* " << genType( node->result, "", pretty, genC ) << " */ "; 169 168 } 170 169 } ); … … 174 173 void CodeGenerator::postvisit( FunctionDecl * functionDecl ) { 175 174 // deleted decls should never be used, so don't print them 176 if ( functionDecl->isDeleted && options.genC ) return;175 if ( functionDecl->isDeleted && genC ) return; 177 176 extension( functionDecl ); 178 177 genAttributes( functionDecl->get_attributes() ); … … 181 180 functionDecl->get_funcSpec().print( output ); 182 181 183 Options subOptions = options; 184 subOptions.anonymousUnused = functionDecl->has_body(); 185 output << genType( functionDecl->get_functionType(), mangleName( functionDecl ), subOptions ); 182 output << genType( functionDecl->get_functionType(), mangleName( functionDecl ), pretty, genC ); 186 183 187 184 asmName( functionDecl ); … … 197 194 void CodeGenerator::postvisit( ObjectDecl * objectDecl ) { 198 195 // deleted decls should never be used, so don't print them 199 if ( objectDecl->isDeleted && options.genC ) return;200 if (objectDecl->get_name().empty() && options.genC ) {196 if ( objectDecl->isDeleted && genC ) return; 197 if (objectDecl->get_name().empty() && genC ) { 201 198 // only generate an anonymous name when generating C code, otherwise it clutters the output too much 202 199 static UniqueName name = { "__anonymous_object" }; 203 200 objectDecl->set_name( name.newName() ); 204 // Stops unused parameter warnings.205 if ( options.anonymousUnused ) {206 objectDecl->attributes.push_back( new Attribute( "unused" ) );207 }208 201 } 209 202 … … 212 205 213 206 handleStorageClass( objectDecl ); 214 output << genType( objectDecl->get_type(), mangleName( objectDecl ), options.pretty, options.genC );207 output << genType( objectDecl->get_type(), mangleName( objectDecl ), pretty, genC ); 215 208 216 209 asmName( objectDecl ); … … 231 224 232 225 void CodeGenerator::handleAggregate( AggregateDecl * aggDecl, const std::string & kind ) { 233 if( ! aggDecl->parameters.empty() && ! options.genC ) {226 if( ! aggDecl->parameters.empty() && ! genC ) { 234 227 // assertf( ! genC, "Aggregate type parameters should not reach code generation." ); 235 228 output << "forall("; … … 301 294 302 295 void CodeGenerator::postvisit( TraitDecl * traitDecl ) { 303 assertf( ! options.genC, "TraitDecls should not reach code generation." );296 assertf( ! genC, "TraitDecls should not reach code generation." ); 304 297 extension( traitDecl ); 305 298 handleAggregate( traitDecl, "trait " ); … … 307 300 308 301 void CodeGenerator::postvisit( TypedefDecl * typeDecl ) { 309 assertf( ! options.genC, "Typedefs are removed and substituted in earlier passes." );302 assertf( ! genC, "Typedefs are removed and substituted in earlier passes." ); 310 303 output << "typedef "; 311 output << genType( typeDecl->get_base(), typeDecl->get_name(), options) << endl;304 output << genType( typeDecl->get_base(), typeDecl->get_name(), pretty, genC ) << endl; 312 305 } 313 306 314 307 void CodeGenerator::postvisit( TypeDecl * typeDecl ) { 315 assertf( ! options.genC, "TypeDecls should not reach code generation." );308 assertf( ! genC, "TypeDecls should not reach code generation." ); 316 309 output << typeDecl->genTypeString() << " " << typeDecl->name; 317 310 if ( typeDecl->sized ) { … … 378 371 379 372 void CodeGenerator::postvisit( ConstructorInit * init ){ 380 assertf( ! options.genC, "ConstructorInit nodes should not reach code generation." );373 assertf( ! genC, "ConstructorInit nodes should not reach code generation." ); 381 374 // pseudo-output for constructor/destructor pairs 382 375 output << "<ctorinit>{" << endl << ++indent << "ctor: "; … … 514 507 } else { 515 508 // no constructors with 0 or more than 2 parameters 516 assertf( ! options.genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );509 assertf( ! genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." ); 517 510 output << "("; 518 511 (*arg++)->accept( *visitor ); … … 611 604 // an lvalue cast, this has been taken out. 612 605 output << "("; 613 output << genType( castExpr->get_result(), "", options);606 output << genType( castExpr->get_result(), "", pretty, genC ); 614 607 output << ")"; 615 608 } // if … … 619 612 620 613 void CodeGenerator::postvisit( KeywordCastExpr * castExpr ) { 621 assertf( ! options.genC, "KeywordCast should not reach code generation." );614 assertf( ! genC, "KeywordCast should not reach code generation." ); 622 615 extension( castExpr ); 623 616 output << "((" << castExpr->targetString() << " &)"; … … 627 620 628 621 void CodeGenerator::postvisit( VirtualCastExpr * castExpr ) { 629 assertf( ! options.genC, "VirtualCastExpr should not reach code generation." );622 assertf( ! genC, "VirtualCastExpr should not reach code generation." ); 630 623 extension( castExpr ); 631 624 output << "(virtual "; … … 635 628 636 629 void CodeGenerator::postvisit( UntypedMemberExpr * memberExpr ) { 637 assertf( ! options.genC, "UntypedMemberExpr should not reach code generation." );630 assertf( ! genC, "UntypedMemberExpr should not reach code generation." ); 638 631 extension( memberExpr ); 639 632 memberExpr->get_aggregate()->accept( *visitor ); … … 668 661 output << "sizeof("; 669 662 if ( sizeofExpr->get_isType() ) { 670 output << genType( sizeofExpr->get_type(), "", options);663 output << genType( sizeofExpr->get_type(), "", pretty, genC ); 671 664 } else { 672 665 sizeofExpr->get_expr()->accept( *visitor ); … … 680 673 output << "__alignof__("; 681 674 if ( alignofExpr->get_isType() ) { 682 output << genType( alignofExpr->get_type(), "", options);675 output << genType( alignofExpr->get_type(), "", pretty, genC ); 683 676 } else { 684 677 alignofExpr->get_expr()->accept( *visitor ); … … 688 681 689 682 void CodeGenerator::postvisit( UntypedOffsetofExpr * offsetofExpr ) { 690 assertf( ! options.genC, "UntypedOffsetofExpr should not reach code generation." );683 assertf( ! genC, "UntypedOffsetofExpr should not reach code generation." ); 691 684 output << "offsetof("; 692 output << genType( offsetofExpr->get_type(), "", options);685 output << genType( offsetofExpr->get_type(), "", pretty, genC ); 693 686 output << ", " << offsetofExpr->get_member(); 694 687 output << ")"; … … 698 691 // use GCC builtin 699 692 output << "__builtin_offsetof("; 700 output << genType( offsetofExpr->get_type(), "", options);693 output << genType( offsetofExpr->get_type(), "", pretty, genC ); 701 694 output << ", " << mangleName( offsetofExpr->get_member() ); 702 695 output << ")"; … … 704 697 705 698 void CodeGenerator::postvisit( OffsetPackExpr * offsetPackExpr ) { 706 assertf( ! options.genC, "OffsetPackExpr should not reach code generation." );707 output << "__CFA_offsetpack(" << genType( offsetPackExpr->get_type(), "", options) << ")";699 assertf( ! genC, "OffsetPackExpr should not reach code generation." ); 700 output << "__CFA_offsetpack(" << genType( offsetPackExpr->get_type(), "", pretty, genC ) << ")"; 708 701 } 709 702 … … 735 728 extension( commaExpr ); 736 729 output << "("; 737 if ( options.genC ) {730 if ( genC ) { 738 731 // arg1 of a CommaExpr is never used, so it can be safely cast to void to reduce gcc warnings. 739 732 commaExpr->set_arg1( new CastExpr( commaExpr->get_arg1() ) ); … … 746 739 747 740 void CodeGenerator::postvisit( TupleAssignExpr * tupleExpr ) { 748 assertf( ! options.genC, "TupleAssignExpr should not reach code generation." );741 assertf( ! genC, "TupleAssignExpr should not reach code generation." ); 749 742 tupleExpr->stmtExpr->accept( *visitor ); 750 743 } 751 744 752 745 void CodeGenerator::postvisit( UntypedTupleExpr * tupleExpr ) { 753 assertf( ! options.genC, "UntypedTupleExpr should not reach code generation." );746 assertf( ! genC, "UntypedTupleExpr should not reach code generation." ); 754 747 extension( tupleExpr ); 755 748 output << "["; … … 759 752 760 753 void CodeGenerator::postvisit( TupleExpr * tupleExpr ) { 761 assertf( ! options.genC, "TupleExpr should not reach code generation." );754 assertf( ! genC, "TupleExpr should not reach code generation." ); 762 755 extension( tupleExpr ); 763 756 output << "["; … … 767 760 768 761 void CodeGenerator::postvisit( TupleIndexExpr * tupleExpr ) { 769 assertf( ! options.genC, "TupleIndexExpr should not reach code generation." );762 assertf( ! genC, "TupleIndexExpr should not reach code generation." ); 770 763 extension( tupleExpr ); 771 764 tupleExpr->get_tuple()->accept( *visitor ); … … 774 767 775 768 void CodeGenerator::postvisit( TypeExpr * typeExpr ) { 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);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 ); 780 773 } 781 774 } … … 795 788 void CodeGenerator::postvisit( CompoundLiteralExpr *compLitExpr ) { 796 789 assert( compLitExpr->get_result() && dynamic_cast< ListInit * > ( compLitExpr->get_initializer() ) ); 797 output << "(" << genType( compLitExpr->get_result(), "", options) << ")";790 output << "(" << genType( compLitExpr->get_result(), "", pretty, genC ) << ")"; 798 791 compLitExpr->get_initializer()->accept( *visitor ); 799 792 } 800 793 801 794 void CodeGenerator::postvisit( UniqueExpr * unqExpr ) { 802 assertf( ! options.genC, "Unique expressions should not reach code generation." );795 assertf( ! genC, "Unique expressions should not reach code generation." ); 803 796 output << "unq<" << unqExpr->get_id() << ">{ "; 804 797 unqExpr->get_expr()->accept( *visitor ); … … 836 829 837 830 void CodeGenerator::postvisit( ConstructorExpr * expr ) { 838 assertf( ! options.genC, "Unique expressions should not reach code generation." );831 assertf( ! genC, "Unique expressions should not reach code generation." ); 839 832 expr->callExpr->accept( *visitor ); 840 833 } 841 834 842 835 void CodeGenerator::postvisit( DeletedExpr * expr ) { 843 assertf( ! options.genC, "Deleted expressions should not reach code generation." );836 assertf( ! genC, "Deleted expressions should not reach code generation." ); 844 837 expr->expr->accept( *visitor ); 845 838 } 846 839 847 840 void CodeGenerator::postvisit( DefaultArgExpr * arg ) { 848 assertf( ! options.genC, "Default argument expressions should not reach code generation." );841 assertf( ! genC, "Default argument expressions should not reach code generation." ); 849 842 arg->expr->accept( *visitor ); 850 843 } 851 844 852 845 void CodeGenerator::postvisit( GenericExpr * expr ) { 853 assertf( ! options.genC, "C11 _Generic expressions should not reach code generation." );846 assertf( ! genC, "C11 _Generic expressions should not reach code generation." ); 854 847 output << "_Generic("; 855 848 expr->control->accept( *visitor ); … … 861 854 output << "default: "; 862 855 } else { 863 output << genType( assoc.type, "", options) << ": ";856 output << genType( assoc.type, "", pretty, genC ) << ": "; 864 857 } 865 858 assoc.expr->accept( *visitor ); … … 896 889 void CodeGenerator::postvisit( ExprStmt * exprStmt ) { 897 890 assert( exprStmt ); 898 if ( options.genC ) {891 if ( genC ) { 899 892 // cast the top-level expression to void to reduce gcc warnings. 900 893 exprStmt->set_expr( new CastExpr( exprStmt->get_expr() ) ); … … 1006 999 case BranchStmt::FallThrough: 1007 1000 case BranchStmt::FallThroughDefault: 1008 assertf( ! options.genC, "fallthru should not reach code generation." );1001 assertf( ! genC, "fallthru should not reach code generation." ); 1009 1002 output << "fallthru"; 1010 1003 break; 1011 1004 } // switch 1012 1005 // print branch target for labelled break/continue/fallthru in debug mode 1013 if ( ! options.genC && branchStmt->get_type() != BranchStmt::Goto ) {1006 if ( ! genC && branchStmt->get_type() != BranchStmt::Goto ) { 1014 1007 if ( ! branchStmt->get_target().empty() ) { 1015 1008 output << " " << branchStmt->get_target(); … … 1028 1021 1029 1022 void CodeGenerator::postvisit( ThrowStmt * throwStmt ) { 1030 assertf( ! options.genC, "Throw statements should not reach code generation." );1023 assertf( ! genC, "Throw statements should not reach code generation." ); 1031 1024 1032 1025 output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ? … … 1043 1036 } 1044 1037 void CodeGenerator::postvisit( CatchStmt * stmt ) { 1045 assertf( ! options.genC, "Catch statements should not reach code generation." );1038 assertf( ! genC, "Catch statements should not reach code generation." ); 1046 1039 1047 1040 output << ((stmt->get_kind() == CatchStmt::Terminate) ? … … 1060 1053 1061 1054 void CodeGenerator::postvisit( WaitForStmt * stmt ) { 1062 assertf( ! options.genC, "Waitfor statements should not reach code generation." );1055 assertf( ! genC, "Waitfor statements should not reach code generation." ); 1063 1056 1064 1057 bool first = true; … … 1106 1099 1107 1100 void CodeGenerator::postvisit( WithStmt * with ) { 1108 if ( ! options.genC ) {1101 if ( ! genC ) { 1109 1102 output << "with ( "; 1110 1103 genCommaList( with->exprs.begin(), with->exprs.end() ); … … 1172 1165 1173 1166 void CodeGenerator::postvisit( ImplicitCtorDtorStmt * stmt ) { 1174 assertf( ! options.genC, "ImplicitCtorDtorStmts should not reach code generation." );1167 assertf( ! genC, "ImplicitCtorDtorStmts should not reach code generation." ); 1175 1168 stmt->callStmt->accept( *visitor ); 1176 1169 } -
src/CodeGen/CodeGenerator.h
r933f32f r6a9d4b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Apr 30 12:01:00 201913 // Update Count : 5 712 // Last Modified On : Fri Aug 18 15:40:00 2017 13 // Update Count : 56 14 14 // 15 15 … … 20 20 #include <string> // for string 21 21 22 #include "CodeGen/Options.h" // for Options23 22 #include "Common/Indenter.h" // for Indenter 24 23 #include "Common/PassVisitor.h" // for PassVisitor … … 32 31 33 32 CodeGenerator( std::ostream &os, bool pretty = false, bool genC = false, bool lineMarks = false, bool printExprTypes = false ); 34 CodeGenerator( std::ostream &os, const Options &options );35 33 36 34 //*** Turn off visit_children for all nodes … … 146 144 std::ostream & output; 147 145 LabelPrinter printLabels; 148 Options options; 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; 149 150 public: 150 151 LineEnder endl; -
src/CodeGen/GenType.cc
r933f32f r6a9d4b4 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 : Wed May 1 15:24:00 201913 // Update Count : 2 311 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 17 09:02:28 2017 13 // Update Count : 22 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, const Options &options );30 GenType( const std::string &typeString, bool pretty, bool genC, bool lineMarks ); 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 Options options; 59 bool pretty = false; // pretty print 60 bool genC = false; // generating C code? 61 bool lineMarks = false; // lineMarks on for CodeGenerator? 60 62 }; 61 63 62 std::string genType( Type *type, const std::string &baseString, const Options &options ) {63 PassVisitor<GenType> gt( baseString, options );64 std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) { 65 PassVisitor<GenType> gt( baseString, pretty, genC, lineMarks ); 64 66 std::ostringstream os; 65 67 66 68 if ( ! type->get_attributes().empty() ) { 67 PassVisitor<CodeGenerator> cg( os, options );69 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 68 70 cg.pass.genAttributes( type->get_attributes() ); 69 71 } // if … … 73 75 } 74 76 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 ) {} 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 ) {} 84 82 85 83 // *** BaseSyntaxNode … … 135 133 } // if 136 134 if ( dimension != 0 ) { 137 PassVisitor<CodeGenerator> cg( os, options );135 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 138 136 dimension->accept( cg ); 139 137 } else if ( isVarLen ) { … … 169 167 void GenType::postvisit( ReferenceType * refType ) { 170 168 assert( refType->base != 0); 171 assertf( ! options.genC, "Reference types should not reach code generation." );169 assertf( ! genC, "Reference types should not reach code generation." ); 172 170 handleQualifiers( refType ); 173 171 typeString = "&" + typeString; … … 197 195 } // if 198 196 } else { 199 PassVisitor<CodeGenerator> cg( os, options );197 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 200 198 os << "(" ; 201 199 … … 217 215 218 216 // add forall 219 if( ! funcType->forall.empty() && ! options.genC ) {217 if( ! funcType->forall.empty() && ! genC ) { 220 218 // assertf( ! genC, "Aggregate type parameters should not reach code generation." ); 221 219 std::ostringstream os; 222 PassVisitor<CodeGenerator> cg( os, options );220 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 223 221 os << "forall("; 224 222 cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() ); … … 231 229 if ( ! refType->parameters.empty() ) { 232 230 std::ostringstream os; 233 PassVisitor<CodeGenerator> cg( os, options );231 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 234 232 os << "("; 235 233 cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() ); … … 242 240 void GenType::postvisit( StructInstType * structInst ) { 243 241 typeString = structInst->name + handleGeneric( structInst ) + " " + typeString; 244 if ( options.genC ) typeString = "struct " + typeString;242 if ( genC ) typeString = "struct " + typeString; 245 243 handleQualifiers( structInst ); 246 244 } … … 248 246 void GenType::postvisit( UnionInstType * unionInst ) { 249 247 typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString; 250 if ( options.genC ) typeString = "union " + typeString;248 if ( genC ) typeString = "union " + typeString; 251 249 handleQualifiers( unionInst ); 252 250 } … … 254 252 void GenType::postvisit( EnumInstType * enumInst ) { 255 253 typeString = enumInst->name + " " + typeString; 256 if ( options.genC ) typeString = "enum " + typeString;254 if ( genC ) typeString = "enum " + typeString; 257 255 handleQualifiers( enumInst ); 258 256 } … … 264 262 265 263 void GenType::postvisit( TupleType * tupleType ) { 266 assertf( ! options.genC, "Tuple types should not reach code generation." );264 assertf( ! genC, "Tuple types should not reach code generation." ); 267 265 unsigned int i = 0; 268 266 std::ostringstream os; … … 270 268 for ( Type * t : *tupleType ) { 271 269 i++; 272 os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", ");270 os << genType( t, "", pretty, genC, lineMarks ) << (i == tupleType->size() ? "" : ", "); 273 271 } 274 272 os << "] "; … … 283 281 void GenType::postvisit( ZeroType * zeroType ) { 284 282 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 285 typeString = ( options.pretty ? "zero_t " : "long int ") + typeString;283 typeString = (pretty ? "zero_t " : "long int ") + typeString; 286 284 handleQualifiers( zeroType ); 287 285 } … … 289 287 void GenType::postvisit( OneType * oneType ) { 290 288 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 291 typeString = ( options.pretty ? "one_t " : "long int ") + typeString;289 typeString = (pretty ? "one_t " : "long int ") + typeString; 292 290 handleQualifiers( oneType ); 293 291 } 294 292 295 293 void GenType::postvisit( GlobalScopeType * globalType ) { 296 assertf( ! options.genC, "Global scope type should not reach code generation." );294 assertf( ! genC, "Global scope type should not reach code generation." ); 297 295 handleQualifiers( globalType ); 298 296 } 299 297 300 298 void GenType::postvisit( TraitInstType * inst ) { 301 assertf( ! options.genC, "Trait types should not reach code generation." );299 assertf( ! genC, "Trait types should not reach code generation." ); 302 300 typeString = inst->name + " " + typeString; 303 301 handleQualifiers( inst ); … … 306 304 void GenType::postvisit( TypeofType * typeof ) { 307 305 std::ostringstream os; 308 PassVisitor<CodeGenerator> cg( os, options );306 PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 309 307 os << "typeof("; 310 308 typeof->expr->accept( cg ); … … 315 313 316 314 void GenType::postvisit( QualifiedType * qualType ) { 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;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; 320 318 typeString = os.str(); 321 319 handleQualifiers( qualType ); … … 335 333 typeString = "_Atomic " + typeString; 336 334 } // if 337 if ( type->get_lvalue() && ! options.genC ) {335 if ( type->get_lvalue() && ! genC ) { 338 336 // when not generating C code, print lvalue for debugging. 339 337 typeString = "lvalue " + typeString; -
src/CodeGen/GenType.h
r933f32f r6a9d4b4 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 : Tue Apr 30 11:47:00 201913 // Update Count : 311 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 21 22:17:23 2017 13 // Update Count : 2 14 14 // 15 15 … … 18 18 #include <string> // for string 19 19 20 #include "CodeGen/Options.h" // for Options21 22 20 class Type; 23 21 24 22 namespace CodeGen { 25 std::string genType( Type *type, const std::string &baseString, const Options &options );26 23 std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false ); 27 24 std::string genPrettyType( Type * type, const std::string & baseString ); -
src/CodeGen/module.mk
r933f32f r6a9d4b4 18 18 # ArgTweak/Mutate.cc 19 19 20 SRC _CODEGEN =\20 SRC += CodeGen/Generate.cc \ 21 21 CodeGen/CodeGenerator.cc \ 22 CodeGen/GenType.cc \ 23 CodeGen/FixNames.cc \ 22 24 CodeGen/FixMain.cc \ 23 CodeGen/GenType.cc \24 25 CodeGen/OperatorTable.cc 25 26 27 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/FixNames.cc28 SRCDEMANGLE += $(SRC_CODEGEN) -
src/Common/Assert.cc
r933f32f r6a9d4b4 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 51 41 // Local Variables: // 52 42 // tab-width: 4 // -
src/Common/PassVisitor.h
r933f32f r6a9d4b4 4 4 5 5 #include <stack> 6 #include <type_traits> 7 8 #include "Common/Stats.h" 6 9 7 #include "Common/utility.h" 10 8 … … 155 153 virtual void visit( ConstructorInit * ctorInit ) override final; 156 154 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 257 259 virtual Constant * mutate( Constant * constant ) override final; 258 260 … … 298 300 299 301 300 auto get_env_ptr () -> decltype(env_impl( pass, 0)) { return env_impl( pass, 0); }302 TypeSubstitution ** get_env_ptr () { return env_impl ( pass, 0); } 301 303 std::list< Statement* > * get_beforeStmts() { return stmtsToAddBefore_impl( pass, 0); } 302 304 std::list< Statement* > * get_afterStmts () { return stmtsToAddAfter_impl ( pass, 0); } … … 345 347 }; 346 348 347 class WithConstTypeSubstitution {348 protected:349 WithConstTypeSubstitution() = default;350 ~WithConstTypeSubstitution() = default;351 352 public:353 const TypeSubstitution * env = nullptr;354 };355 356 349 class WithStmtsToAdd { 357 350 protected: … … 433 426 }; 434 427 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 443 428 #include "SynTree/TypeSubstitution.h" 444 429 #include "PassVisitor.impl.h" -
src/Common/PassVisitor.impl.h
r933f32f r6a9d4b4 20 20 21 21 #define MUTATE_END( type, node ) \ 22 auto __return = call_postmutate< type * >( node ); \ 23 assert( __return ); \ 24 return __return; 22 return call_postmutate< type * >( node ); \ 25 23 26 24 … … 69 67 SemanticErrorException errors; 70 68 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);74 69 for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) { 75 76 77 70 // splice in new declarations after previous decl 78 71 if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); } … … 90 83 if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); } 91 84 } 92 pass_visitor_stats.depth--;93 85 if ( ! errors.isEmpty() ) { 94 86 throw errors; … … 102 94 SemanticErrorException errors; 103 95 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);107 96 for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) { 108 97 // splice in new declarations after previous decl … … 120 109 if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); } 121 110 } 122 pass_visitor_stats.depth--;123 111 if ( ! errors.isEmpty() ) { 124 112 throw errors; … … 138 126 if ( ! visitor.get_visit_children() ) return; 139 127 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);144 128 for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) { 145 129 try { … … 151 135 } 152 136 } 153 pass_visitor_stats.depth--;154 137 if ( ! errors.isEmpty() ) { 155 138 throw errors; … … 168 151 template< typename Container, typename pass_type > 169 152 inline void maybeMutate_impl( Container & container, PassVisitor< pass_type > & mutator ) { 170 171 153 if ( ! mutator.get_visit_children() ) return; 172 154 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);177 155 for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) { 178 156 try { … … 185 163 } // try 186 164 } // for 187 pass_visitor_stats.depth--;188 165 if ( ! errors.isEmpty() ) { 189 166 throw errors; … … 208 185 DeclList_t* afterDecls = get_afterDecls(); 209 186 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);213 187 for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) { 214 188 … … 218 192 try { 219 193 func( *i ); 220 assert( *i );221 194 assert(( empty( beforeStmts ) && empty( afterStmts )) 222 195 || ( empty( beforeDecls ) && empty( afterDecls )) ); … … 229 202 if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); } 230 203 } 231 pass_visitor_stats.depth--;232 204 233 205 if ( !empty( afterDecls ) ) { splice( std::back_inserter( statements ), afterDecls); } … … 257 229 258 230 // don't want statements from outer CompoundStmts to be added to this CompoundStmt 259 ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type > oldEnv( get_env_ptr() );231 ValueGuardPtr< TypeSubstitution * > oldEnv ( get_env_ptr () ); 260 232 ValueGuardPtr< DeclList_t > oldBeforeDecls( get_beforeDecls() ); 261 233 ValueGuardPtr< DeclList_t > oldAfterDecls ( get_afterDecls () ); … … 1993 1965 1994 1966 // don't want statements from outer CompoundStmts to be added to this StmtExpr 1995 ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type > oldEnv( get_env_ptr() );1967 ValueGuardPtr< TypeSubstitution * > oldEnv ( get_env_ptr() ); 1996 1968 ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() ); 1997 1969 ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () ); … … 2010 1982 2011 1983 // don't want statements from outer CompoundStmts to be added to this StmtExpr 2012 ValueGuardPtr< typename std::remove_pointer<decltype(get_env_ptr())>::type > oldEnv( get_env_ptr() );1984 ValueGuardPtr< TypeSubstitution * > oldEnv ( get_env_ptr() ); 2013 1985 ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() ); 2014 1986 ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () ); … … 2706 2678 2707 2679 //-------------------------------------------------------------------------- 2680 // Subrange 2681 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 //-------------------------------------------------------------------------- 2708 2696 // Attribute 2709 2697 template< typename pass_type > -
src/Common/PassVisitor.proto.h
r933f32f r6a9d4b4 165 165 static inline type * name##_impl( __attribute__((unused)) pass_type& pass, __attribute__((unused)) long unused ) { return nullptr;} \ 166 166 167 FIELD_PTR( constTypeSubstitution *, env )167 FIELD_PTR( 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_PTR177 178 176 //--------------------------------------------------------- 179 177 // Indexer … … 222 220 INDEXER_FUNC2( addWith , std::list< Expression * > &, BaseSyntaxNode * ); 223 221 224 #undef INDEXER_FUNC1225 #undef INDEXER_FUNC2226 222 227 223 template<typename pass_type> -
src/Common/SemanticError.h
r933f32f r6a9d4b4 17 17 18 18 #include "ErrorObjects.h" 19 #include "AST/Node.hpp"20 19 #include <cstring> 21 20 -
src/Common/module.mk
r933f32f r6a9d4b4 15 15 ############################################################################### 16 16 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) 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 -
src/Common/utility.h
r933f32f r6a9d4b4 463 463 std::pair<long long int, bool> eval(Expression * expr); 464 464 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; 465 // ----------------------------------------------------------------------------- 466 /// Reorders the input range in-place so that the minimal-value elements according to the 467 /// comparator are in front; 474 468 /// returns the iterator after the last minimal-value element. 475 469 template<typename Iter, typename Compare> 476 470 Iter sort_mins( Iter begin, Iter end, Compare& lt ) { 477 471 if ( begin == end ) return end; 478 472 479 473 Iter min_pos = begin; 480 474 for ( Iter i = begin + 1; i != end; ++i ) { -
src/CompilationState.cc
r933f32f r6a9d4b4 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon Ju1 30 10:47:01 2018 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri May 3 13:45:23 201913 // Update Count : 411 // Last Modified By : Rob Schluntz 12 // Last Modified On : Mon Ju1 30 10:46:25 2018 13 // Update Count : 2 14 14 // 15 15 16 int 16 bool 17 17 astp = false, 18 18 bresolvep = false, … … 26 26 libcfap = false, 27 27 nopreludep = false, 28 genproto= false,28 noprotop = false, 29 29 nomainp = false, 30 30 parsep = false, -
src/CompilationState.h
r933f32f r6a9d4b4 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon Ju1 30 10:47:01 2018 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri May 3 13:43:21 201913 // Update Count : 411 // Last Modified By : Rob Schluntz 12 // Last Modified On : Mon Ju1 30 10:46:25 2018 13 // Update Count : 2 14 14 // 15 15 16 16 extern int yydebug; // set for -g flag (Grammar) 17 extern int17 extern bool 18 18 astp, 19 19 bresolvep, … … 27 27 libcfap, 28 28 nopreludep, 29 genproto,29 noprotop, 30 30 nomainp, 31 31 parsep, -
src/Concurrency/Waitfor.cc
r933f32f r6a9d4b4 11 11 // Last Modified By : 12 12 // Last Modified On : 13 // Update Count : 713 // Update Count : 5 14 14 // 15 15 -
src/Concurrency/module.mk
r933f32f r6a9d4b4 15 15 ############################################################################### 16 16 17 SRC += Concurrency/Keywords.cc Concurrency/Waitfor.cc18 SRCDEMANGLE += Concurrency/Keywords.cc17 SRC += Concurrency/Keywords.cc \ 18 Concurrency/Waitfor.cc 19 19 -
src/ControlStruct/ExceptTranslate.cc
r933f32f r6a9d4b4 9 9 // Author : Andrew Beach 10 10 // Created On : Wed Jun 14 16:49:00 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Wed Feb 13 18:15:29 201913 // Update Count : 1111 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Aug 17 17:19:00 2017 13 // Update Count : 9 14 14 // 15 15 … … 617 617 return create_terminate_rethrow( throwStmt ); 618 618 } else { 619 a bort("Invalid throw in %s at %i\n",619 assertf(false, "Invalid throw in %s at %i\n", 620 620 throwStmt->location.filename.c_str(), 621 621 throwStmt->location.first_line); 622 return nullptr; 622 623 } 623 624 } else { … … 627 628 return create_resume_rethrow( throwStmt ); 628 629 } else { 629 a bort("Invalid throwResume in %s at %i\n",630 assertf(false, "Invalid throwResume in %s at %i\n", 630 631 throwStmt->location.filename.c_str(), 631 632 throwStmt->location.first_line); 633 return nullptr; 632 634 } 633 635 } -
src/ControlStruct/ForExprMutator.cc
r933f32f r6a9d4b4 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Mar 11 22:26:52 201913 // Update Count : 1 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Aug 18 10:22:00 2017 13 // Update Count : 12 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
r933f32f r6a9d4b4 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Mar 11 22:26:02 201913 // Update Count : 15 911 // Last Modified By : Rob Schluntz 12 // Last Modified On : Tue Jul 28 13:32:43 2015 13 // Update Count : 156 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 statement for every label in the list78 // parameter. 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 78 // statement for every label in the list 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 temporarily used as the canonical label 102 // produce one of the labels attached to this statement to be 103 // temporarily used as the canonical label 103 104 return labelTable[ llabel.front() ]->get_label(); 104 105 } … … 116 117 117 118 // Builds a table that maps a label to its defining statement. 118 std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {119 std::map<Label, Statement * > *LabelFixer::resolveJumps() throw ( SemanticErrorException ) { 119 120 std::map< Label, Statement * > *ret = new std::map< Label, Statement * >(); 120 121 for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) { -
src/ControlStruct/LabelGenerator.cc
r933f32f r6a9d4b4 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Mar 11 22:23:20 201913 // Update Count : 1 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Aug 14 14:14:00 2015 13 // Update Count : 14 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 31 32 return labelGenerator; 32 33 } … … 37 38 if ( stmt && ! stmt->get_labels().empty() ) { 38 39 os << "_" << stmt->get_labels().front() << "__"; 39 } // if40 } 40 41 std::string ret = os.str(); 41 42 Label l( ret ); -
src/ControlStruct/module.mk
r933f32f r6a9d4b4 15 15 ############################################################################### 16 16 17 SRC_CONTROLSTRUCT = \ 17 SRC += ControlStruct/LabelGenerator.cc \ 18 ControlStruct/LabelFixer.cc \ 19 ControlStruct/MLEMutator.cc \ 20 ControlStruct/Mutate.cc \ 18 21 ControlStruct/ForExprMutator.cc \ 19 ControlStruct/LabelFixer.cc \ 20 ControlStruct/LabelGenerator.cc \ 21 ControlStruct/MLEMutator.cc \ 22 ControlStruct/Mutate.cc 23 24 SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc 25 SRCDEMANGLE += $(SRC_CONTROLSTRUCT) 26 22 ControlStruct/ExceptTranslate.cc -
src/GenPoly/Box.cc
r933f32f r6a9d4b4 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 ConstTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting {78 class Pass1 final : public BoxPass, public WithTypeSubstitution, 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 ConstTypeSubstitution {152 class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithTypeSubstitution { 153 153 public: 154 154 PolyGenericCalculator(); -
src/GenPoly/GenPoly.cc
r933f32f r6a9d4b4 440 440 } 441 441 442 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, constTypeSubstitution * env ) {442 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, 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, constTypeSubstitution * env ) {452 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, 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
r933f32f r6a9d4b4 81 81 82 82 /// true if arg requires boxing given exprTyVars 83 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, constTypeSubstitution * env );83 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, 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, constTypeSubstitution * env );86 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, TypeSubstitution * env ); 87 87 88 88 /// Adds the type variable `tyVar` to `tyVarMap` -
src/GenPoly/InstantiateGeneric.cc
r933f32f r6a9d4b4 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 ConstTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards {170 struct GenericInstantiator final : public WithTypeSubstitution, 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
r933f32f r6a9d4b4 42 42 43 43 namespace GenPoly { 44 struct Specialize final : public With ConstTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {44 struct Specialize final : public WithTypeSubstitution, 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, constTypeSubstitution *env ) {56 bool needsPolySpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) { 57 57 if ( env ) { 58 58 using namespace ResolvExpr; … … 145 145 } 146 146 147 bool needsSpecialization( Type *formalType, Type *actualType, constTypeSubstitution *env ) {147 bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) { 148 148 return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType ); 149 149 } -
src/GenPoly/module.mk
r933f32f r6a9d4b4 22 22 GenPoly/FindFunction.cc \ 23 23 GenPoly/InstantiateGeneric.cc 24 25 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/Lvalue.cc26 -
src/InitTweak/FixInit.cc
r933f32f r6a9d4b4 10 10 // Created On : Wed Jan 13 16:29:30 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 13 18:15:56 201913 // Update Count : 7 612 // Last Modified On : Wed Jun 21 17:35:05 2017 13 // Update Count : 74 14 14 // 15 15 #include "FixInit.h" … … 72 72 }; 73 73 74 struct InsertImplicitCalls : public With ConstTypeSubstitution {74 struct InsertImplicitCalls : public WithTypeSubstitution { 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
r933f32f r6a9d4b4 5 5 #include <memory> // for __shared_ptr 6 6 7 #include "AST/Expr.hpp"8 #include "AST/Stmt.hpp"9 #include "AST/Type.hpp"10 7 #include "Common/PassVisitor.h" 11 8 #include "Common/SemanticError.h" // for SemanticError … … 29 26 #include "Tuples/Tuples.h" // for Tuples::isTtype 30 27 28 class UntypedValofExpr; 29 31 30 namespace InitTweak { 32 31 namespace { … … 433 432 assert( false ); 434 433 } 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 // }448 434 } 449 435 … … 465 451 assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() ); 466 452 } 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.cpp472 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 // }490 453 } 491 454 … … 550 513 } 551 514 } 552 const ast::Type* getPointerBase( const ast::Type* t ) {553 (void)t;554 #warning needs to build Type.cpp before inclusion555 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 }564 515 565 516 Type * isPointerType( Type * type ) { -
src/InitTweak/InitTweak.h
r933f32f r6a9d4b4 20 20 #include <string> // for string, allocator 21 21 22 #include "AST/Fwd.hpp" // for AST nodes23 22 #include "SynTree/SynTree.h" // for Visitor Nodes 24 23 … … 81 80 /// returns the argument to a call expression in position N indexed from 0 82 81 Expression *& getCallArg( Expression * callExpr, unsigned int pos ); 83 const ast::Expr * getCallArg( const ast::Expr * call, unsigned pos );84 82 85 83 /// returns the base type of a PointerType or ArrayType, else returns NULL 86 84 Type * getPointerBase( Type * ); 87 const ast::Type* getPointerBase( const ast::Type* );88 85 89 86 /// returns the argument if it is a PointerType or ArrayType, else returns NULL -
src/InitTweak/module.mk
r933f32f r6a9d4b4 20 20 InitTweak/InitTweak.cc 21 21 22 SRCDEMANGLE += InitTweak/GenInit.cc \23 InitTweak/InitTweak.cc24 -
src/MakeLibCfa.cc
r933f32f r6a9d4b4 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sat May 16 10:33:33 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sun Feb 17 21:08:09 201913 // Update Count : 4 111 // Last Modified By : Rob Schluntz 12 // Last Modified On : Fri Apr 22 13:54:15 2016 13 // Update Count : 40 14 14 // 15 15 … … 146 146 } // namespace 147 147 } // namespace LibCfa 148 149 // Local Variables: //150 // tab-width: 4 //151 // End: // -
src/Makefile.am
r933f32f r6a9d4b4 10 10 ## Author : Peter A. Buhr 11 11 ## Created On : Sun May 31 08:51:46 2015 12 ## Last Modified By : Peter A. Buhr13 ## Last Modified On : Fri Feb 15 09:44:09 201914 ## Update Count : 9712 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tus Jul 25 10:34:00 2017 14 ## Update Count : 76 15 15 ############################################################################### 16 16 … … 20 20 21 21 SRC = main.cc \ 22 MakeLibCfa.cc \ 23 CompilationState.cc 24 25 SRCDEMANGLE = CompilationState.cc 22 MakeLibCfa.cc \ 23 CompilationState.cc 26 24 27 25 MAINTAINERCLEANFILES = 28 MOSTLYCLEANFILES = 26 MOSTLYCLEANFILES = Parser/gcc-flags.h 29 27 30 if WITH_LIBPROFILER 31 LIBPROFILER = -lprofiler 32 endif 28 Parser/gcc-flags.h : 29 ${AM_V_GEN}$(CC) -dM -E - < /dev/null | sed 's/define /define __GCC__/' > $(@) 33 30 34 if WITH_LIBTCMALLOC 35 LIBTCMALLOC = -ltcmalloc 36 TCMALLOCFLAG = -DTCMALLOC 37 endif 31 Parser/lex.ll : Parser/gcc-flags.h 38 32 39 33 include CodeGen/module.mk … … 52 46 include Virtual/module.mk 53 47 54 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h55 56 $(srcdir)/SynTree/Type.h : BasicTypes-gen.cc57 ${AM_V_GEN}${CXXCOMPILE} $< -o BasicTypes-gen -Wall -Wextra58 @./BasicTypes-gen59 @rm BasicTypes-gen60 61 48 # put into lib for now 62 49 cfa_cpplibdir = $(CFA_LIBDIR) 63 50 cfa_cpplib_PROGRAMS = ../driver/cfa-cpp demangler 64 51 ___driver_cfa_cpp_SOURCES = $(SRC) 65 ___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC)52 ___driver_cfa_cpp_LDADD = -ldl # yywrap 66 53 67 AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O 3 -g -std=c++14 $(TCMALLOCFLAG)54 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 68 55 AM_LDFLAGS = @HOST_FLAGS@ -Xlinker -export-dynamic 69 56 ARFLAGS = cr … … 71 58 demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete 72 59 73 demangler_LDADD = libdemangle.a -ldl# yywrap60 demangler_LDADD = libdemangle.a # yywrap 74 61 75 62 noinst_LIBRARIES = libdemangle.a 76 libdemangle_a_SOURCES = $(SRCDEMANGLE) 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 77 152 78 153 MAINTAINERCLEANFILES += ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}} -
src/Makefile.in
r933f32f r6a9d4b4 162 162 libdemangle_a_LIBADD = 163 163 am__dirstamp = $(am__leading_dot)dirstamp 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) \ 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) \ 173 191 ControlStruct/LabelFixer.$(OBJEXT) \ 174 192 ControlStruct/LabelGenerator.$(OBJEXT) \ 175 193 ControlStruct/MLEMutator.$(OBJEXT) \ 176 ControlStruct/Mutate.$(OBJEXT) 177 am__objects_4 = ResolvExpr/AdjustExprType.$(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) \ 178 198 ResolvExpr/Alternative.$(OBJEXT) \ 179 199 ResolvExpr/AlternativeFinder.$(OBJEXT) \ 200 ResolvExpr/ExplodedActual.$(OBJEXT) \ 180 201 ResolvExpr/CastCost.$(OBJEXT) ResolvExpr/CommonType.$(OBJEXT) \ 181 202 ResolvExpr/ConversionCost.$(OBJEXT) \ 182 203 ResolvExpr/CurrentObject.$(OBJEXT) \ 183 ResolvExpr/ExplodedActual.$(OBJEXT) \184 204 ResolvExpr/FindOpenVars.$(OBJEXT) ResolvExpr/Occurs.$(OBJEXT) \ 185 205 ResolvExpr/PolyCost.$(OBJEXT) \ … … 192 212 ResolvExpr/SpecCost.$(OBJEXT) \ 193 213 ResolvExpr/TypeEnvironment.$(OBJEXT) \ 194 ResolvExpr/Unify.$(OBJEXT) 195 am__objects_5 = SymTab/Autogen.$(OBJEXT) SymTab/FixFunction.$(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) \ 196 271 SymTab/Indexer.$(OBJEXT) SymTab/Mangler.$(OBJEXT) \ 197 SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT) 198 am__objects_6 = SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \ 272 SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT) \ 273 SymTab/FixFunction.$(OBJEXT) SymTab/Autogen.$(OBJEXT) \ 274 SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \ 199 275 SynTree/BasicType.$(OBJEXT) SynTree/PointerType.$(OBJEXT) \ 200 276 SynTree/ArrayType.$(OBJEXT) SynTree/ReferenceType.$(OBJEXT) \ … … 215 291 SynTree/Initializer.$(OBJEXT) \ 216 292 SynTree/TypeSubstitution.$(OBJEXT) SynTree/Attribute.$(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) \ 293 SynTree/DeclReplacer.$(OBJEXT) \ 255 294 Tuples/TupleAssignment.$(OBJEXT) \ 256 295 Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \ … … 258 297 Validate/FindSpecialDecls.$(OBJEXT) \ 259 298 Virtual/ExpandCasts.$(OBJEXT) 260 am____driver_cfa_cpp_OBJECTS = $(am__objects_ 8)299 am____driver_cfa_cpp_OBJECTS = $(am__objects_1) 261 300 ___driver_cfa_cpp_OBJECTS = $(am____driver_cfa_cpp_OBJECTS) 262 am__DEPENDENCIES_1 = 263 ___driver_cfa_cpp_DEPENDENCIES = $(am__DEPENDENCIES_1) \ 264 $(am__DEPENDENCIES_1) 301 ___driver_cfa_cpp_DEPENDENCIES = 265 302 AM_V_lt = $(am__v_lt_@AM_V@) 266 303 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) … … 381 418 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 382 419 ACLOCAL = @ACLOCAL@ 420 ALLOCA = @ALLOCA@ 383 421 AMTAR = @AMTAR@ 384 422 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 528 566 AUTOMAKE_OPTIONS = foreign subdir-objects 529 567 ACLOCAL_AMFLAGS = -I automake 530 SRC = main.cc MakeLibCfa.cc CompilationState.cc $(SRC_CODEGEN) \ 531 CodeGen/Generate.cc CodeGen/FixNames.cc CodeTools/DeclStats.cc \ 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 \ 532 572 CodeTools/ResolvProtoDump.cc CodeTools/TrackLoc.cc \ 533 Concurrency/Keywords.cc Concurrency/Waitfor.cc $(SRC_COMMON) \ 534 Common/DebugMalloc.cc $(SRC_CONTROLSTRUCT) \ 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 \ 535 579 ControlStruct/ExceptTranslate.cc GenPoly/Box.cc \ 536 580 GenPoly/GenPoly.cc GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc \ … … 543 587 Parser/StatementNode.cc Parser/InitializerNode.cc \ 544 588 Parser/TypeData.cc Parser/LinkageSpec.cc \ 545 Parser/parserutility.cc $(SRC_RESOLVEXPR) \ 546 ResolvExpr/AlternativePrinter.cc $(SRC_SYMTAB) $(SRC_SYNTREE) \ 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 \ 547 618 Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \ 548 619 Tuples/Explode.cc Validate/HandleAttributes.cc \ 549 620 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.cc558 621 MAINTAINERCLEANFILES = ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}} 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 = \ 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 \ 565 675 CodeGen/CodeGenerator.cc \ 566 676 CodeGen/FixMain.cc \ 677 CodeGen/Generate.cc \ 567 678 CodeGen/GenType.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 = \ 679 CodeGen/OperatorTable.cc \ 680 Common/Assert.cc \ 681 Common/Eval.cc \ 682 Common/SemanticError.cc \ 683 Common/UniqueName.cc \ 684 Concurrency/Keywords.cc \ 582 685 ControlStruct/ForExprMutator.cc \ 583 686 ControlStruct/LabelFixer.cc \ 584 687 ControlStruct/LabelGenerator.cc \ 585 688 ControlStruct/MLEMutator.cc \ 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) 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 668 726 all: $(BUILT_SOURCES) 669 727 $(MAKE) $(AM_MAKEFLAGS) all-am … … 704 762 clean-noinstLIBRARIES: 705 763 -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) 764 SymTab/$(am__dirstamp): 765 @$(MKDIR_P) SymTab 766 @: > 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) SynTree 776 @: > 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) 706 848 CodeGen/$(am__dirstamp): 707 849 @$(MKDIR_P) CodeGen … … 714 856 CodeGen/FixMain.$(OBJEXT): CodeGen/$(am__dirstamp) \ 715 857 CodeGen/$(DEPDIR)/$(am__dirstamp) 858 CodeGen/Generate.$(OBJEXT): CodeGen/$(am__dirstamp) \ 859 CodeGen/$(DEPDIR)/$(am__dirstamp) 716 860 CodeGen/GenType.$(OBJEXT): CodeGen/$(am__dirstamp) \ 717 861 CodeGen/$(DEPDIR)/$(am__dirstamp) 718 862 CodeGen/OperatorTable.$(OBJEXT): CodeGen/$(am__dirstamp) \ 719 863 CodeGen/$(DEPDIR)/$(am__dirstamp) 720 Concurrency/$(am__dirstamp):721 @$(MKDIR_P) Concurrency722 @: > 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)728 864 Common/$(am__dirstamp): 729 865 @$(MKDIR_P) Common … … 736 872 Common/Eval.$(OBJEXT): Common/$(am__dirstamp) \ 737 873 Common/$(DEPDIR)/$(am__dirstamp) 738 Common/PassVisitor.$(OBJEXT): Common/$(am__dirstamp) \739 Common/$(DEPDIR)/$(am__dirstamp)740 874 Common/SemanticError.$(OBJEXT): Common/$(am__dirstamp) \ 741 875 Common/$(DEPDIR)/$(am__dirstamp) 742 Common/Stats/$(am__dirstamp):743 @$(MKDIR_P) Common/Stats744 @: > 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)756 876 Common/UniqueName.$(OBJEXT): Common/$(am__dirstamp) \ 757 877 Common/$(DEPDIR)/$(am__dirstamp) 878 Concurrency/$(am__dirstamp): 879 @$(MKDIR_P) Concurrency 880 @: > 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) 758 886 ControlStruct/$(am__dirstamp): 759 887 @$(MKDIR_P) ControlStruct … … 812 940 ResolvExpr/AlternativeFinder.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 813 941 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 942 ResolvExpr/ExplodedActual.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 943 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 814 944 ResolvExpr/CastCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 815 945 ResolvExpr/$(DEPDIR)/$(am__dirstamp) … … 820 950 ResolvExpr/CurrentObject.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 821 951 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 822 ResolvExpr/ExplodedActual.$(OBJEXT): ResolvExpr/$(am__dirstamp) \823 ResolvExpr/$(DEPDIR)/$(am__dirstamp)824 952 ResolvExpr/FindOpenVars.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 825 953 ResolvExpr/$(DEPDIR)/$(am__dirstamp) … … 846 974 ResolvExpr/Unify.$(OBJEXT): ResolvExpr/$(am__dirstamp) \ 847 975 ResolvExpr/$(DEPDIR)/$(am__dirstamp) 848 SymTab/$(am__dirstamp):849 @$(MKDIR_P) SymTab850 @: > SymTab/$(am__dirstamp)851 SymTab/$(DEPDIR)/$(am__dirstamp):852 @$(MKDIR_P) SymTab/$(DEPDIR)853 @: > SymTab/$(DEPDIR)/$(am__dirstamp)854 976 SymTab/Autogen.$(OBJEXT): SymTab/$(am__dirstamp) \ 855 977 SymTab/$(DEPDIR)/$(am__dirstamp) … … 860 982 SymTab/Mangler.$(OBJEXT): SymTab/$(am__dirstamp) \ 861 983 SymTab/$(DEPDIR)/$(am__dirstamp) 862 SymTab/ManglerCommon.$(OBJEXT): SymTab/$(am__dirstamp) \863 SymTab/$(DEPDIR)/$(am__dirstamp)864 984 SymTab/Validate.$(OBJEXT): SymTab/$(am__dirstamp) \ 865 985 SymTab/$(DEPDIR)/$(am__dirstamp) 866 SymTab/Demangle.$(OBJEXT): SymTab/$(am__dirstamp) \867 SymTab/$(DEPDIR)/$(am__dirstamp)868 SynTree/$(am__dirstamp):869 @$(MKDIR_P) SynTree870 @: > 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)942 986 Tuples/$(am__dirstamp): 943 987 @$(MKDIR_P) Tuples … … 946 990 @$(MKDIR_P) Tuples/$(DEPDIR) 947 991 @: > Tuples/$(DEPDIR)/$(am__dirstamp) 992 Tuples/Explode.$(OBJEXT): Tuples/$(am__dirstamp) \ 993 Tuples/$(DEPDIR)/$(am__dirstamp) 948 994 Tuples/TupleAssignment.$(OBJEXT): Tuples/$(am__dirstamp) \ 949 995 Tuples/$(DEPDIR)/$(am__dirstamp) 950 996 Tuples/TupleExpansion.$(OBJEXT): Tuples/$(am__dirstamp) \ 951 Tuples/$(DEPDIR)/$(am__dirstamp)952 Tuples/Explode.$(OBJEXT): Tuples/$(am__dirstamp) \953 997 Tuples/$(DEPDIR)/$(am__dirstamp) 954 998 Validate/$(am__dirstamp): … … 1016 1060 echo " rm -f" $$list; \ 1017 1061 rm -f $$list 1018 CodeGen/Generate.$(OBJEXT): CodeGen/$(am__dirstamp) \1019 CodeGen/$(DEPDIR)/$(am__dirstamp)1020 1062 CodeGen/FixNames.$(OBJEXT): CodeGen/$(am__dirstamp) \ 1021 1063 CodeGen/$(DEPDIR)/$(am__dirstamp) … … 1035 1077 Concurrency/$(DEPDIR)/$(am__dirstamp) 1036 1078 Common/DebugMalloc.$(OBJEXT): Common/$(am__dirstamp) \ 1079 Common/$(DEPDIR)/$(am__dirstamp) 1080 Common/Heap.$(OBJEXT): Common/$(am__dirstamp) \ 1037 1081 Common/$(DEPDIR)/$(am__dirstamp) 1038 1082 ControlStruct/ExceptTranslate.$(OBJEXT): \ … … 1105 1149 -rm -f CodeTools/*.$(OBJEXT) 1106 1150 -rm -f Common/*.$(OBJEXT) 1107 -rm -f Common/Stats/*.$(OBJEXT)1108 1151 -rm -f Concurrency/*.$(OBJEXT) 1109 1152 -rm -f ControlStruct/*.$(OBJEXT) … … 1136 1179 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/DebugMalloc.Po@am__quote@ 1137 1180 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/Eval.Po@am__quote@ 1138 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/ PassVisitor.Po@am__quote@1181 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/Heap.Po@am__quote@ 1139 1182 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/SemanticError.Po@am__quote@ 1140 1183 @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@1145 1184 @AMDEP_TRUE@@am__include@ @am__quote@Concurrency/$(DEPDIR)/Keywords.Po@am__quote@ 1146 1185 @AMDEP_TRUE@@am__include@ @am__quote@Concurrency/$(DEPDIR)/Waitfor.Po@am__quote@ … … 1405 1444 -rm -f Common/$(DEPDIR)/$(am__dirstamp) 1406 1445 -rm -f Common/$(am__dirstamp) 1407 -rm -f Common/Stats/$(DEPDIR)/$(am__dirstamp)1408 -rm -f Common/Stats/$(am__dirstamp)1409 1446 -rm -f Concurrency/$(DEPDIR)/$(am__dirstamp) 1410 1447 -rm -f Concurrency/$(am__dirstamp) … … 1444 1481 1445 1482 distclean: distclean-am 1446 -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Co mmon/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)1483 -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR) 1447 1484 -rm -f Makefile 1448 1485 distclean-am: clean-am distclean-compile distclean-generic \ … … 1490 1527 1491 1528 maintainer-clean: maintainer-clean-am 1492 -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Co mmon/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)1529 -rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR) 1493 1530 -rm -f Makefile 1494 1531 maintainer-clean-am: distclean-am maintainer-clean-generic … … 1530 1567 1531 1568 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 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 1538 1573 1539 1574 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
src/Parser/DeclarationNode.cc
r933f32f r6a9d4b4 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Feb 1 16:49:17 201913 // Update Count : 11 1312 // Last Modified On : Thu Nov 1 20:54:26 2018 13 // Update Count : 1108 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", "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 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" }; 47 45 const char * DeclarationNode::signednessNames[] = { "signed", "unsigned", "NoSignednessNames" }; 48 46 const char * DeclarationNode::lengthNames[] = { "short", "long", "long long", "NoLengthNames" }; -
src/Parser/ExpressionNode.cc
r933f32f r6a9d4b4 10 10 // Created On : Sat May 16 13:17:07 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Mar 10 16:10:32 201913 // Update Count : 97612 // Last Modified On : Mon Jun 4 21:24:45 2018 13 // Update Count : 802 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 checkZ( char c ) { return c == 'z' || c == 'Z'; } 55 // 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 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'; } 56 57 static inline bool checkF( char c ) { return c == 'f' || c == 'F'; } 57 58 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'; }61 59 static inline bool checkI( char c ) { return c == 'i' || c == 'I'; } 62 60 static inline bool checkB( char c ) { return c == 'b' || c == 'B'; } 63 61 static inline bool checkX( char c ) { return c == 'x' || c == 'X'; } 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; 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; 82 79 } else { // 128 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 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 109 95 110 96 Expression * build_constantInteger( string & str ) { 111 static const BasicType::Kind kind[2][ 7] = {112 // short (h) must be before char (hh) because shorter type has the longer suffix97 static const BasicType::Kind kind[2][6] = { 98 // short (h) must be before char (hh) 113 99 { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, BasicType::SignedInt128, }, 114 100 { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::UnsignedInt128, }, 115 101 }; 116 102 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 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 121 106 122 107 unsigned long long int v; // converted integral value 123 108 size_t last = str.length() - 1; // last subscript of constant 124 109 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 => int128128 int ltype = -1; // 0 => 16 bits, 1 => 8 bits, 2 => 32 bits, 3 => 64 bits, 4 => size_t, 5 => intptr, 6 => pointer129 bool dec = true, Unsigned = false; // decimal, unsigned constant130 110 131 111 // special constants … … 139 119 } // if 140 120 141 // Cannot be just "0"/"1"; sscanf stops at the suffix, if any; value goes over the wall => always generate121 // Cannot be "0" 142 122 143 123 if ( str[0] == '0' ) { // radix character ? … … 147 127 //printf( "%llx %llu\n", v, v ); 148 128 } else if ( checkB( str[1] ) ) { // binary constant ? 149 v = 0; // compute value150 for ( unsigned int i = 2;; ) { // ignore prefix129 v = 0; 130 for ( unsigned int i = 2;; i += 1 ) { // compute value 151 131 if ( str[i] == '1' ) v |= 1; 152 i += 1; 153 if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break; 132 if ( i == last ) break; 154 133 v <<= 1; 155 134 } // for 156 //printf( "% #llx %llu\n", v, v );135 //printf( "%llx %llu\n", v, v ); 157 136 } else { // octal constant 158 137 sscanf( (char *)str.c_str(), "%llo", &v ); 159 //printf( "% #llo %llu\n", v, v );138 //printf( "%llo %llu\n", v, v ); 160 139 } // if 161 140 } else { // decimal constant ? 162 141 sscanf( (char *)str.c_str(), "%llu", &v ); 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 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; 170 } // 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 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 ?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 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 ) ); 221 } // if 222 } // if 223 } // if 224 225 CLEANUP: ; 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 226 224 delete &str; // created by lex 227 225 return ret; … … 229 227 230 228 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 229 static inline void checkLNFloat( string & str, int & lnth, int & size ) { 230 string::size_type posn = str.find_first_of( "lL" ), start = posn; 240 231 if ( posn == string::npos ) return; 241 explnth = true; 232 size = 2; // assume largest size 233 lnth = 0; 242 234 posn += 1; // advance to size 243 235 if ( str[posn] == '3' ) { // 32 244 if ( str[last] != 'x' ) type = 6; 245 else type = 7; 236 size = 0; 246 237 } else if ( str[posn] == '6' ) { // 64 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 238 size = 1; 239 } else if ( str[posn] == '8' || str[posn] == '1' ) { // 80, 128 240 size = 2; 241 if ( str[posn] == '1' ) posn += 1; 258 242 } else { 259 243 assertf( false, "internal error, bad floating point length %s", str.c_str() ); 260 244 } // if 261 } // checkFnxFloat 245 posn += 1; 246 str.erase( start, posn - start + 1 ); // remove length suffix 247 } // checkLNFloat 262 248 263 249 264 250 Expression * build_constantFloat( string & str ) { 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},251 static const BasicType::Kind kind[2][3] = { 252 { BasicType::Float, BasicType::Double, BasicType::LongDouble }, 253 { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex }, 268 254 }; 269 255 270 // floating-point constant has minimum of 2 characters 1. or .1 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 271 260 size_t last = str.length() - 1; 272 261 double v; 273 int type; // 0 => float, 1 => double, 3 => long double, ...274 bool complx = false; // real, complex275 bool explnth = false; // explicit literal length276 262 277 263 sscanf( str.c_str(), "%lg", &v ); … … 283 269 284 270 if ( checkF( str[last] ) ) { // float ? 285 type = 0;271 size = 0; 286 272 } else if ( checkD( str[last] ) ) { // double ? 287 type = 1;273 size = 1; 288 274 } else if ( checkL( str[last] ) ) { // long double ? 289 type = 2; 290 } else if ( checkF80( str[last] ) ) { // __float80 ? 291 type = 3; 292 } else if ( checkF128( str[last] ) ) { // __float128 ? 293 type = 4; 275 size = 2; 294 276 } else { 295 type = 1; // double (default if no suffix) 296 checkFnxFloat( str, last, explnth, type ); 297 } // if 298 277 size = 1; // double (default) 278 checkLNFloat( str, lnth, size ); 279 } // if 299 280 if ( ! complx && checkI( str[last - 1] ) ) { // imaginary ? 300 281 complx = true; 301 282 } // if 302 283 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 );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 ); 307 288 } // if 308 289 -
src/Parser/ParseNode.h
r933f32f r6a9d4b4 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 15 14:22:39 201913 // Update Count : 8 7412 // Last Modified On : Thu Nov 1 20:54:53 2018 13 // Update Count : 854 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(); } 134 135 template<typename T> 135 136 bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); } 136 137 137 138 Expression * build() const { return const_cast<ExpressionNode *>(this)->expr.release(); } 138 139 std::unique_ptr<Expression> expr; // public because of lifetime implications140 139 private: 141 140 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 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 }; 208 // These enumerations must harmonize with their names. 209 enum BasicType { Void, Bool, Char, Int, Float, Double, LongDouble, Int128, Float80, Float128, NoBasicType }; 212 210 static const char * basicTypeNames[]; 213 enum ComplexType { Complex, NoComplexType, Imaginary }; // Imaginary unsupported => parse, but make invisible and print error message211 enum ComplexType { Complex, Imaginary, NoComplexType }; 214 212 static const char * complexTypeNames[]; 215 213 enum Signedness { Signed, Unsigned, NoSignedness }; -
src/Parser/TypeData.cc
r933f32f r6a9d4b4 10 10 // Created On : Sat May 16 15:12:51 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 13 18:16:23 201913 // Update Count : 6 4912 // Last Modified On : Fri Nov 2 07:54:26 2018 13 // Update Count : 624 14 14 // 15 15 … … 666 666 667 667 case DeclarationNode::Float: 668 case DeclarationNode::Float80: 669 case DeclarationNode::Float128: 668 670 case DeclarationNode::Double: 669 671 case DeclarationNode::LongDouble: // not set until below 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, }, 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 }, 682 676 }; 683 677 … … 692 686 genTSError( DeclarationNode::lengthNames[ td->length ], td->basictype ); 693 687 } // if 694 if ( td->complextype == DeclarationNode::Imaginary ) {695 genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype );696 } // if697 if ( (td->basictype == DeclarationNode::uuFloat80 || td->basictype == DeclarationNode::uuFloat128) && td->complextype == DeclarationNode::Complex ) { // gcc unsupported698 genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype );699 } // if700 688 if ( td->length == DeclarationNode::Long ) { 701 689 const_cast<TypeData *>(td)->basictype = DeclarationNode::LongDouble; 702 690 } // if 703 691 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 704 701 ret = floattype[ td->complextype ][ td->basictype - DeclarationNode::Float ]; 705 //printf( "XXXX %d %d %d %d\n", td->complextype, td->basictype, DeclarationNode::Float, ret );706 702 break; 707 703 -
src/Parser/TypeData.h
r933f32f r6a9d4b4 31 31 struct Aggregate_t { 32 32 DeclarationNode::Aggregate kind; 33 const std::string * name = nullptr;34 DeclarationNode * params = nullptr;35 ExpressionNode * actuals = nullptr; // holds actual parameters later applied to AggInst36 DeclarationNode * fields = nullptr;33 const std::string * name; 34 DeclarationNode * params; 35 ExpressionNode * actuals; // holds actual parameters later applied to AggInst 36 DeclarationNode * fields; 37 37 bool body; 38 38 bool anon; 39 39 40 40 bool tagged; 41 const std::string * parent = nullptr;41 const std::string * parent; 42 42 }; 43 43 44 44 struct AggInst_t { 45 TypeData * aggregate = nullptr;46 ExpressionNode * params = nullptr;45 TypeData * aggregate; 46 ExpressionNode * params; 47 47 bool hoistType; 48 48 }; 49 49 50 50 struct Array_t { 51 ExpressionNode * dimension = nullptr;51 ExpressionNode * dimension; 52 52 bool isVarLen; 53 53 bool isStatic; … … 55 55 56 56 struct Enumeration_t { 57 const std::string * name = nullptr;58 DeclarationNode * constants = nullptr;57 const std::string * name; 58 DeclarationNode * constants; 59 59 bool body; 60 60 bool anon; … … 62 62 63 63 struct Function_t { 64 mutable DeclarationNode * params = nullptr; // mutables modified in buildKRFunction65 mutable DeclarationNode * idList = nullptr; // old-style66 mutable DeclarationNode * oldDeclList = nullptr;67 StatementNode * body = nullptr;68 ExpressionNode * withExprs = nullptr; // expressions from function's with_clause64 mutable DeclarationNode * params; // mutables modified in buildKRFunction 65 mutable DeclarationNode * idList; // old-style 66 mutable DeclarationNode * oldDeclList; 67 StatementNode * body; 68 ExpressionNode * withExprs; // expressions from function's with_clause 69 69 }; 70 70 71 71 struct Symbolic_t { 72 const std::string * name = nullptr;72 const std::string * name; 73 73 bool isTypedef; // false => TYPEGENname, true => TYPEDEFname 74 DeclarationNode * params = nullptr;75 ExpressionNode * actuals = nullptr;76 DeclarationNode * assertions = nullptr;74 DeclarationNode * params; 75 ExpressionNode * actuals; 76 DeclarationNode * assertions; 77 77 }; 78 78 79 79 struct Qualified_t { // qualified type S.T 80 TypeData * parent = nullptr;81 TypeData * child = nullptr;80 TypeData * parent; 81 TypeData * child; 82 82 }; 83 83 … … 93 93 94 94 Type::Qualifiers qualifiers; 95 DeclarationNode * forall = nullptr;95 DeclarationNode * forall; 96 96 97 97 Aggregate_t aggregate; … … 102 102 Symbolic_t symbolic; 103 103 Qualified_t qualified; 104 DeclarationNode * tuple = nullptr;105 ExpressionNode * typeexpr = nullptr;104 DeclarationNode * tuple; 105 ExpressionNode * typeexpr; 106 106 107 107 TypeData( Kind k = Unknown ); -
src/Parser/lex.ll
r933f32f r6a9d4b4 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Wed May 15 21:25:27 201913 * Update Count : 70812 * Last Modified On : Thu Nov 1 20:57:35 2018 13 * Update Count : 687 14 14 */ 15 15 … … 39 39 using namespace std; 40 40 41 #include "config.h" // configure info42 41 #include "ParseNode.h" 43 42 #include "TypedefTable.h" … … 60 59 #define IDENTIFIER_RETURN() RETURN_VAL( typedefTable.isKind( yytext ) ) 61 60 #define ATTRIBUTE_RETURN() RETURN_VAL( ATTR_IDENTIFIER ) 62 63 #ifdef HAVE_KEYWORDS_FLOATXX // GCC >= 7 => keyword, otherwise typedef64 #define FLOATXX(v) KEYWORD_RETURN(v);65 #else66 #define FLOATXX(v) IDENTIFIER_RETURN();67 #endif // HAVE_KEYWORDS_FLOATXX68 61 69 62 void rm_underscore() { … … 99 92 hex_quad {hex}("_"?{hex}){3} 100 93 size_opt (8|16|32|64|128)? 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]))? 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]))? 105 96 106 97 octal_digits ({octal})|({octal}({octal}|"_")*{octal}) … … 121 112 // GCC: D (double) and iI (imaginary) suffixes, and DL (long double) 122 113 exponent "_"?[eE]"_"?[+-]?{decimal_digits} 123 floating_size 16|32|32x|64|64x|80|128|128x124 floating_length ([fFdDlL wWqQ]|[fF]{floating_size})114 floating_size 32|64|80|128 115 floating_length ([fFdDlL]|[lL]{floating_size}) 125 116 floating_suffix ({floating_length}?[iI]?)|([iI]{floating_length}) 126 117 floating_suffix_opt ("_"?({floating_suffix}|"DL"))? … … 226 217 char { KEYWORD_RETURN(CHAR); } 227 218 choose { KEYWORD_RETURN(CHOOSE); } // CFA 228 coerce { KEYWORD_RETURN(COERCE); } // CFA229 219 _Complex { KEYWORD_RETURN(COMPLEX); } // C99 230 220 __complex { KEYWORD_RETURN(COMPLEX); } // GCC … … 250 240 finally { KEYWORD_RETURN(FINALLY); } // CFA 251 241 float { KEYWORD_RETURN(FLOAT); } 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 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 263 252 for { KEYWORD_RETURN(FOR); } 264 253 forall { KEYWORD_RETURN(FORALL); } // CFA 265 254 fortran { KEYWORD_RETURN(FORTRAN); } 266 255 ftype { KEYWORD_RETURN(FTYPE); } // CFA 267 generator { KEYWORD_RETURN(GENERATOR); } // CFA268 256 _Generic { KEYWORD_RETURN(GENERIC); } // C11 269 257 goto { KEYWORD_RETURN(GOTO); } -
src/Parser/module.mk
r933f32f r6a9d4b4 31 31 Parser/parserutility.cc 32 32 33 SRCDEMANGLE += \34 Parser/LinkageSpec.cc35 36 37 33 MOSTLYCLEANFILES += Parser/lex.cc Parser/parser.cc Parser/parser.hh Parser/parser.output -
src/Parser/parser.yy
r933f32f r6a9d4b4 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 15 21:25:27 201913 // Update Count : 4 29612 // Last Modified On : Thu Nov 8 18:08:23 2018 13 // Update Count : 4052 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 for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) { 101 //cur->addType( specifier ); 102 for ( cur = dynamic_cast< DeclarationNode * >( cur->get_next() ); cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) { 102 103 cl->cloneBaseType( cur ); 103 104 } // for 104 105 declList->addType( cl ); 106 // delete cl; 105 107 return declList; 106 108 } // distAttr … … 173 175 DeclarationNode * fieldDecl( DeclarationNode * typeSpec, DeclarationNode * fieldList ) { 174 176 if ( ! fieldList ) { // field declarator ? 175 if ( ! ( typeSpec->type && (typeSpec->type->kind == TypeData::Aggregate || typeSpec->type->kind == TypeData::Enum)) ) {177 if ( ! ( typeSpec->type && typeSpec->type->kind == TypeData::Aggregate ) ) { 176 178 stringstream ss; 177 179 typeSpec->type->print( ss ); … … 185 187 186 188 ForCtrl * forCtrl( ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 187 ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type-> expr.get());189 ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->get_expr()); 188 190 if ( constant && (constant->get_constant()->get_value() == "0" || constant->get_constant()->get_value() == "1") ) { 189 191 type = new ExpressionNode( new CastExpr( maybeMoveBuild< Expression >(type), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ) ); … … 191 193 return new ForCtrl( 192 194 distAttr( DeclarationNode::newTypeof( type, true ), DeclarationNode::newName( index )->addInitializer( new InitializerNode( start ) ) ), 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 ); 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 ) ) ); 197 198 } // forCtrl 198 199 199 200 ForCtrl * forCtrl( ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 200 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index-> expr.get()) ) {201 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->get_expr()) ) { 201 202 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 } // if208 203 } else { 209 204 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr; … … 265 260 %token RESTRICT // C99 266 261 %token ATOMIC // C11 267 %token FORALL MUTEX VIRTUAL COERCE// CFA262 %token FORALL MUTEX VIRTUAL // CFA 268 263 %token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED 269 264 %token BOOL COMPLEX IMAGINARY // C99 270 %token INT128 uuFLOAT80 uuFLOAT128 // GCC 271 %token uFLOAT16 uFLOAT32 uFLOAT32X uFLOAT64 uFLOAT64X uFLOAT128 // GCC 265 %token INT128 FLOAT80 FLOAT128 // GCC 272 266 %token ZERO_T ONE_T // CFA 273 267 %token VALIST // GCC … … 275 269 %token ENUM STRUCT UNION 276 270 %token EXCEPTION // CFA 277 %token GENERATOR COROUTINE MONITOR THREAD// CFA271 %token COROUTINE MONITOR THREAD // CFA 278 272 %token OTYPE FTYPE DTYPE TTYPE TRAIT // CFA 279 273 %token SIZEOF OFFSETOF … … 330 324 %type<en> argument_expression_list argument_expression default_initialize_opt 331 325 %type<ifctl> if_control_expression 332 %type<fctl> for_control_expression for_control_expression_list326 %type<fctl> for_control_expression 333 327 %type<compop> inclexcl 334 328 %type<en> subrange 335 329 %type<decl> asm_name_opt 336 %type<en> asm_operands_opt asm_operands_listasm_operand330 %type<en> asm_operands_opt asm_operands_list asm_operand 337 331 %type<label> label_list 338 332 %type<en> asm_clobbers_list_opt 339 333 %type<flag> asm_volatile_opt 340 334 %type<en> handler_predicate_opt 341 %type<genexpr> generic_association generic_assoc_list335 %type<genexpr> generic_association generic_assoc_list 342 336 343 337 // statements … … 677 671 // empty 678 672 { $$ = nullptr; } 679 | ' @' // CFA, default parameter673 | '?' // CFA, default parameter 680 674 { SemanticError( yylloc, "Default parameter for argument is currently unimplemented." ); $$ = nullptr; } 681 675 // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); } … … 795 789 | '(' type_no_function ')' cast_expression 796 790 { $$ = new ExpressionNode( build_cast( $2, $4 ) ); } 797 // keyword cast cannot be grouped because of reduction in aggregate_key798 | '(' GENERATOR '&' ')' cast_expression // CFA799 { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }800 791 | '(' COROUTINE '&' ')' cast_expression // CFA 801 792 { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); } … … 809 800 | '(' VIRTUAL type_no_function ')' cast_expression // CFA 810 801 { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild< Expression >( $5 ), maybeMoveBuildType( $3 ) ) ); } 811 | '(' RETURN type_no_function ')' cast_expression // CFA812 { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; }813 | '(' COERCE type_no_function ')' cast_expression // CFA814 { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; }815 | '(' qualifier_cast_list ')' cast_expression // CFA816 { SemanticError( yylloc, "Qualifier cast is currently unimplemented." ); $$ = nullptr; }817 802 // | '(' type_no_function ')' tuple 818 803 // { $$ = new ExpressionNode( build_cast( $2, $4 ) ); } 819 ;820 821 qualifier_cast_list:822 cast_modifier type_qualifier_name823 | cast_modifier MUTEX824 | qualifier_cast_list cast_modifier type_qualifier_name825 | qualifier_cast_list cast_modifier MUTEX826 ;827 828 cast_modifier:829 '-'830 | '+'831 804 ; 832 805 … … 1011 984 // labels cannot be identifiers 0 or 1 or ATTR_IDENTIFIER 1012 985 identifier_or_type_name ':' attribute_list_opt statement 1013 { $$ = $4->add_label( $1, $3 ); } 986 { 987 $$ = $4->add_label( $1, $3 ); 988 } 1014 989 ; 1015 990 … … 1027 1002 statement_decl 1028 1003 | statement_decl_list statement_decl 1029 { assert( $1 ); $1->set_last( $2 ); $$ = $1;}1004 { if ( $1 != 0 ) { $1->set_last( $2 ); $$ = $1; } } 1030 1005 ; 1031 1006 … … 1034 1009 { $$ = new StatementNode( $1 ); } 1035 1010 | EXTENSION declaration // GCC 1036 { distExt( $2 ); $$ = new StatementNode( $2 ); } 1011 { 1012 distExt( $2 ); 1013 $$ = new StatementNode( $2 ); 1014 } 1037 1015 | function_definition 1038 1016 { $$ = new StatementNode( $1 ); } 1039 1017 | EXTENSION function_definition // GCC 1040 { distExt( $2 ); $$ = new StatementNode( $2 ); } 1018 { 1019 distExt( $2 ); 1020 $$ = new StatementNode( $2 ); 1021 } 1041 1022 | statement 1042 1023 ; … … 1045 1026 statement 1046 1027 | statement_list_nodecl statement 1047 { assert( $1 ); $1->set_last( $2 ); $$ = $1;}1028 { if ( $1 != 0 ) { $1->set_last( $2 ); $$ = $1; } } 1048 1029 ; 1049 1030 … … 1157 1138 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1158 1139 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2 ) ); } 1159 | FOR '(' push for_control_expression _list')' statement pop1140 | FOR '(' push for_control_expression ')' statement pop 1160 1141 { $$ = new StatementNode( build_for( $4, $6 ) ); } 1161 1142 | FOR '(' ')' statement // CFA => for ( ;; ) … … 1163 1144 ; 1164 1145 1165 for_control_expression_list:1166 for_control_expression1167 | for_control_expression_list ':' for_control_expression1168 // ForCtrl + ForCtrl:1169 // init + init => multiple declaration statements that are hoisted1170 // 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 } // if1178 } 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 } // if1183 } else $1->change = $3->change;1184 $$ = $1;1185 }1186 ;1187 1188 1146 for_control_expression: 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 1147 comma_expression // CFA 1197 1148 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ), 1198 1149 OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1199 | co mma_expression inclexcl comma_expression// CFA1150 | constant_expression inclexcl constant_expression // CFA 1200 1151 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1201 | co mma_expression inclexcl comma_expression '~' comma_expression // CFA1152 | constant_expression inclexcl constant_expression '~' constant_expression // CFA 1202 1153 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, $5 ); } 1203 1154 | comma_expression ';' comma_expression // CFA 1204 1155 { $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ), 1205 1156 OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1206 | comma_expression ';' co mma_expression inclexcl comma_expression // CFA1157 | comma_expression ';' constant_expression inclexcl constant_expression // CFA 1207 1158 { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1208 | comma_expression ';' co mma_expression inclexcl comma_expression '~' comma_expression // CFA1159 | comma_expression ';' constant_expression inclexcl constant_expression '~' constant_expression // CFA 1209 1160 { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); } 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 ); } 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 ); } 1222 1167 ; 1223 1168 … … 1826 1771 | FLOAT 1827 1772 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float ); } 1773 | FLOAT80 1774 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float80 ); } 1775 | FLOAT128 1776 { $$ = DeclarationNode::newBasicType( DeclarationNode::Float128 ); } 1828 1777 | DOUBLE 1829 1778 { $$ = DeclarationNode::newBasicType( DeclarationNode::Double ); } 1830 | uuFLOAT801831 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat80 ); }1832 | uuFLOAT1281833 { $$ = DeclarationNode::newBasicType( DeclarationNode::uuFloat128 ); }1834 | uFLOAT161835 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat16 ); }1836 | uFLOAT321837 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32 ); }1838 | uFLOAT32X1839 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat32x ); }1840 | uFLOAT641841 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64 ); }1842 | uFLOAT64X1843 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat64x ); }1844 | uFLOAT1281845 { $$ = DeclarationNode::newBasicType( DeclarationNode::uFloat128 ); }1846 1779 | COMPLEX // C99 1847 1780 { $$ = DeclarationNode::newComplexType( DeclarationNode::Complex ); } … … 2063 1996 | EXCEPTION 2064 1997 { yyy = true; $$ = DeclarationNode::Exception; } 2065 | GENERATOR2066 { yyy = true; $$ = DeclarationNode::Coroutine; }2067 1998 | COROUTINE 2068 1999 { yyy = true; $$ = DeclarationNode::Coroutine; } -
src/ResolvExpr/AlternativeFinder.cc
r933f32f r6a9d4b4 258 258 // - necessary pre-requisite to pruning 259 259 AltList candidates; 260 std::list<std::string> errors;261 260 for ( unsigned i = 0; i < alternatives.size(); ++i ) { 262 resolveAssertions( alternatives[i], indexer, candidates , errors);261 resolveAssertions( alternatives[i], indexer, candidates ); 263 262 } 264 263 // fail early if none such 265 264 if ( mode.failFast && candidates.empty() ) { 266 265 std::ostringstream stream; 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 } 266 stream << "No resolvable alternatives for expression " << expr << "\n" 267 << "Alternatives with failing assertions are:\n"; 268 printAlts( alternatives, stream, 1 ); 273 269 SemanticError( expr->location, stream.str() ); 274 270 } -
src/ResolvExpr/CommonType.cc
r933f32f r6a9d4b4 10 10 // Created On : Sun May 17 06:59:27 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Feb 14 17:10:10 201913 // Update Count : 2412 // Last Modified On : Mon Sep 25 15:18:17 2017 13 // Update Count : 9 14 14 // 15 15 … … 176 176 } 177 177 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 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 }; 480 207 static_assert( 481 sizeof(com monTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,208 sizeof(combinedType)/sizeof(combinedType[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES, 482 209 "Each basic type kind should have a corresponding row in the combined type matrix" 483 210 ); … … 491 218 void CommonType::postvisit( BasicType *basicType ) { 492 219 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) { 493 BasicType::Kind newType = com monTypes[ basicType->get_kind() ][ otherBasic->get_kind() ];220 BasicType::Kind newType = combinedType[ basicType->get_kind() ][ otherBasic->get_kind() ]; 494 221 if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= otherBasic->get_qualifiers() ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->get_qualifiers() <= otherBasic->get_qualifiers() ) || widenSecond ) ) { 495 222 result = new BasicType( basicType->get_qualifiers() | otherBasic->get_qualifiers(), newType ); … … 497 224 } else if ( dynamic_cast< EnumInstType * > ( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) { 498 225 // use signed int in lieu of the enum/zero/one type 499 BasicType::Kind newType = com monTypes[ basicType->get_kind() ][ BasicType::SignedInt ];226 BasicType::Kind newType = combinedType[ basicType->get_kind() ][ BasicType::SignedInt ]; 500 227 if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= type2->get_qualifiers() ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->get_qualifiers() <= type2->get_qualifiers() ) || widenSecond ) ) { 501 228 result = new BasicType( basicType->get_qualifiers() | type2->get_qualifiers(), newType ); -
src/ResolvExpr/ConversionCost.cc
r933f32f r6a9d4b4 10 10 // Created On : Sun May 17 07:06:19 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon May 6 14:18:22 201913 // Update Count : 2512 // Last Modified On : Mon Sep 25 15:43:34 2017 13 // Update Count : 10 14 14 // 15 15 … … 28 28 29 29 namespace ResolvExpr { 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 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 }; 41 38 42 39 #if 0 … … 45 42 #define PRINT(x) 46 43 #endif 47 48 44 Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 49 45 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { … … 183 179 } 184 180 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 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 }; 253 263 static_assert( 254 264 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES, 255 " Missing row in the cost matrix"265 "Each basic type kind should have a corresponding row in the cost matrix" 256 266 ); 257 267 258 // GENERATED START, DO NOT EDIT259 // GENERATED BY BasicTypes-gen.cc260 static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion261 /* 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 }; // signMatrix299 // GENERATED END300 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 );304 268 305 269 void ConversionCost::postvisit( VoidType * ) { … … 315 279 cost = Cost::zero; 316 280 cost.incSafe( tableResult ); 317 cost.incSign( signMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ] );318 281 } // if 319 282 } else if ( dynamic_cast< EnumInstType *>( dest ) ) { … … 337 300 // types are the same, except otherPointer has more qualifiers 338 301 cost = Cost::safe; 339 } // if302 } 340 303 } else { 341 304 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env ); … … 459 422 cost = Cost::zero; 460 423 cost.incSafe( tableResult + 1 ); 461 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] ); 462 } // if 424 } 463 425 } else if ( dynamic_cast< PointerType* >( dest ) ) { 464 cost = Cost::zero; 465 cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation 466 } // if 426 cost = Cost::safe; 427 } 467 428 } 468 429 … … 478 439 cost = Cost::zero; 479 440 cost.incSafe( tableResult + 1 ); 480 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] ); 481 } // if 482 } // if 441 } 442 } 483 443 } 484 444 } // namespace ResolvExpr -
src/ResolvExpr/Cost.h
r933f32f r6a9d4b4 7 7 // Cost.h -- 8 8 // 9 // Author : Peter Buhr and Aaron Moss9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 09:39:50 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Apr 29 18:33:44 201913 // Update Count : 4911 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Fri Oct 05 14:32:00 2018 13 // Update Count : 7 14 14 // 15 15 … … 17 17 18 18 #include <iostream> 19 #include <cassert>20 #include <climits>21 19 22 20 namespace ResolvExpr { 23 #if 024 25 //*************************** OLD ***************************26 27 21 class Cost { 28 22 private: 29 Cost( int unsafeCost, int polyCost, int safeCost, int signCost, 30 int varCost, int specCost, int referenceCost ); 23 Cost( int unsafeCost, int polyCost, int safeCost, int varCost, int specCost, 24 int referenceCost ); 25 31 26 public: 32 27 Cost & incUnsafe( int inc = 1 ); 33 28 Cost & incPoly( int inc = 1 ); 34 29 Cost & incSafe( int inc = 1 ); 35 Cost & incSign( int inc = 1 );36 30 Cost & incVar( int inc = 1 ); 37 31 Cost & decSpec( int inc = 1 ); … … 41 35 int get_polyCost() const { return polyCost; } 42 36 int get_safeCost() const { return safeCost; } 43 int get_signCost() const { return signCost; }44 37 int get_varCost() const { return varCost; } 45 38 int get_specCost() const { return specCost; } … … 47 40 48 41 Cost operator+( const Cost &other ) const; 42 Cost operator-( const Cost &other ) const; 49 43 Cost &operator+=( const Cost &other ); 50 44 bool operator<( const Cost &other ) const; … … 61 55 static const Cost poly; 62 56 static const Cost safe; 63 static const Cost sign;64 57 static const Cost var; 65 58 static const Cost spec; … … 70 63 int polyCost; ///< Count of parameters and return values bound to some poly type 71 64 int safeCost; ///< Safe (widening) conversions 72 int signCost; ///< Count of safe sign conversions73 65 int varCost; ///< Count of polymorphic type variables 74 66 int specCost; ///< Polymorphic type specializations (type assertions), negative cost … … 76 68 }; 77 69 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 ) {}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 ) {} 82 74 83 75 inline Cost & Cost::incUnsafe( int inc ) { … … 96 88 if ( *this == infinity ) return *this; 97 89 safeCost += inc; 98 return *this;99 }100 101 inline Cost & Cost::incSign( int inc ) {102 if ( *this == infinity ) return *this;103 signCost += inc;104 90 return *this; 105 91 } … … 125 111 inline Cost Cost::operator+( const Cost &other ) const { 126 112 if ( *this == infinity || other == infinity ) return infinity; 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 }; 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 }; 131 125 } 132 126 … … 140 134 polyCost += other.polyCost; 141 135 safeCost += other.safeCost; 142 signCost += other.signCost;143 136 varCost += other.varCost; 144 137 specCost += other.specCost; … … 163 156 } else if ( safeCost < other.safeCost ) { 164 157 return true; 165 } else if ( signCost > other.signCost ) {166 return false;167 } else if ( signCost < other.signCost ) {168 return true;169 158 } else if ( varCost > other.varCost ) { 170 159 return false; … … 191 180 c = polyCost - other.polyCost; if ( c ) return c; 192 181 c = safeCost - other.safeCost; if ( c ) return c; 193 c = signCost - other.signCost; if ( c ) return c;194 182 c = varCost - other.varCost; if ( c ) return c; 195 183 c = specCost - other.specCost; if ( c ) return c; … … 201 189 && polyCost == other.polyCost 202 190 && safeCost == other.safeCost 203 && signCost == other.signCost204 191 && varCost == other.varCost 205 192 && specCost == other.specCost … … 212 199 213 200 inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) { 214 return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " 215 << cost.safeCost << ", " << cost.signCost << ", " 216 << cost.varCost << ", " << cost.specCost << ", " 201 return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " 202 << cost.safeCost << ", " << cost.varCost << ", " << cost.specCost << ", " 217 203 << cost.referenceCost << " )"; 218 204 } 219 220 #else221 222 //*************************** NEW ***************************223 224 // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the225 // 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; ///< unused233 unsigned char referenceCost; ///< reference conversions234 unsigned char specCost; ///< Polymorphic type specializations (type assertions), negative cost235 unsigned char varCost; ///< Count of polymorphic type variables236 unsigned char signCost; ///< Count of safe sign conversions237 unsigned char safeCost; ///< Safe (widening) conversions238 unsigned char polyCost; ///< Count of parameters and return values bound to some poly type239 unsigned char unsafeCost; ///< Unsafe (narrowing) conversions240 #else241 #error Cost BIG_ENDIAN unsupported242 #endif243 } v;244 uint64_t all;245 };246 static const unsigned char correctb = 0xff; // byte correction for negative spec cost247 static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost248 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, // padding268 (unsigned char)referenceCost, // low priority269 (unsigned char)(specCost + correctb), // correct for signedness270 (unsigned char)varCost,271 (unsigned char)signCost,272 (unsigned char)safeCost,273 (unsigned char)polyCost,274 (unsigned char)unsafeCost, // high priority275 #else276 #error Cost BIG_ENDIAN unsupported277 #endif278 };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 > rhs292 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 cost308 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 cost366 }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 // 0374 205 } // namespace ResolvExpr 375 206 -
src/ResolvExpr/RenameVars.cc
r933f32f r6a9d4b4 10 10 // Created On : Sun May 17 12:05:18 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 30 17:07:57 201913 // Update Count : 712 // Last Modified On : Wed Mar 2 17:36:32 2016 13 // Update Count : 5 14 14 // 15 15 … … 39 39 private: 40 40 int level, resetCount; 41 std::list< std:: unordered_map< std::string, std::string > > mapStack;41 std::list< std::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:: unordered_map< std::string, std::string >() );57 mapStack.push_front( std::map< std::string, std::string >() ); 58 58 } 59 59 … … 65 65 void RenameVars::previsit( TypeInstType * instType ) { 66 66 previsit( (Type *)instType ); 67 std:: unordered_map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name );67 std::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
r933f32f r6a9d4b4 20 20 #include <list> // for list 21 21 #include <memory> // for unique_ptr 22 #include <sstream> // for ostringstream 23 #include <string> // for string 22 #include <string> 24 23 #include <unordered_map> // for unordered_map, unordered_multimap 25 24 #include <utility> // for move … … 28 27 #include "Alternative.h" // for Alternative, AssertionItem, AssertionList 29 28 #include "Common/FilterCombos.h" // for filterCombos 30 #include "Common/Indenter.h" // for Indenter31 29 #include "Common/utility.h" // for sort_mins 32 30 #include "ResolvExpr/RenameVars.h" // for renameTyVars … … 35 33 #include "SynTree/Expression.h" // for InferredParams 36 34 #include "TypeEnvironment.h" // for TypeEnvironment, etc. 37 #include "typeops.h" // for adjustExprType , specCost35 #include "typeops.h" // for adjustExprType 38 36 #include "Unify.h" // for unify 39 37 … … 58 56 using CandidateList = std::vector<AssnCandidate>; 59 57 58 /// Unique identifier for a yet-to-be-resolved assertion 59 struct AssnId { 60 DeclarationWithType* decl; ///< Declaration of assertion 61 AssertionSetValue info; ///< Information about assertion 62 63 AssnId(DeclarationWithType* decl, const AssertionSetValue& info) : decl(decl), info(info) {} 64 }; 65 66 /// Cached assertion items 67 struct AssnCacheItem { 68 CandidateList matches; ///< Possible matches for this assertion 69 std::vector<AssnId> deferIds; ///< Deferred assertions which resolve to this item 70 71 AssnCacheItem( CandidateList&& m ) : matches(std::move(m)), deferIds() {} 72 }; 73 74 /// Cache of resolved assertions 75 using AssnCache = std::unordered_map<std::string, AssnCacheItem>; 76 60 77 /// Reference to single deferred item 61 78 struct DeferRef { 62 const DeclarationWithType* decl; 63 const AssertionSetValue& info; 79 const AssnCacheItem& item; 64 80 const AssnCandidate& match; 65 81 }; … … 68 84 /// Acts like indexed list of DeferRef 69 85 struct DeferItem { 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] }; } 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; } 82 105 }; 83 106 … … 154 177 for ( const auto& assn : x.assns ) { 155 178 k += computeConversionCost( 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 } 179 assn.match.adjType, assn.item.deferIds[0].decl->get_type(), indexer, 180 x.env ); 171 181 } 172 182 it = cache.emplace_hint( it, &x, k ); … … 239 249 240 250 /// Resolve a single assertion, in context 241 bool resolveAssertion( AssertionItem& assn, ResnState& resn ) {251 bool resolveAssertion( AssertionItem& assn, ResnState& resn, AssnCache& cache ) { 242 252 // skip unused assertions 243 253 if ( ! assn.info.isUsed ) return true; 244 254 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; 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 } 271 288 } 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;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 } 278 295 } 279 } 296 297 it = cache.emplace_hint( it, assnKey, AssnCacheItem{ std::move(matches) } ); 298 } 299 300 CandidateList& matches = it->second.matches; 280 301 281 302 // break if no suitable assertion … … 284 305 // defer if too many suitable assertions 285 306 if ( matches.size() > 1 ) { 286 resn.deferred.emplace_back( assn.decl, assn.info, std::move(matches) ); 307 it->second.deferIds.emplace_back( assn.decl, assn.info ); 308 resn.deferred.emplace_back( cache, assnKey ); 287 309 return true; 288 310 } … … 292 314 addToIndexer( match.have, resn.indexer ); 293 315 resn.newNeed.insert( match.need.begin(), match.need.end() ); 294 resn.alt.env = std::move(match.env);295 resn.alt.openVars = std::move(match.openVars);316 resn.alt.env = match.env; 317 resn.alt.openVars = match.openVars; 296 318 297 319 bindAssertion( assn.decl, assn.info, resn.alt, match, resn.inferred ); … … 342 364 static const int recursionLimit = /* 10 */ 4; 343 365 344 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out , std::list<std::string>& errors) {366 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ) { 345 367 // finish early if no assertions to resolve 346 368 if ( alt.need.empty() ) { … … 354 376 ResnList resns{ ResnState{ alt, root_indexer } }; 355 377 ResnList new_resns{}; 378 AssnCache assnCache; 356 379 357 380 // resolve assertions in breadth-first-order up to a limited number of levels deep … … 362 385 for ( auto& assn : resn.need ) { 363 386 // fail early if any assertion is not resolvable 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 } 387 if ( ! resolveAssertion( assn, resn, assnCache ) ) goto nextResn; 375 388 } 376 389 … … 383 396 } 384 397 } else { 398 // only resolve each deferred assertion once 399 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() ); 385 402 // resolve deferred assertions by mutual compatibility 386 403 std::vector<CandidateEnvMerger::OutType> compatible = filterCombos( 387 404 resn.deferred, 388 405 CandidateEnvMerger{ resn.alt.env, resn.alt.openVars, resn.indexer } ); 389 // fail early if no mutually-compatible assertion satisfaction390 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 }404 406 // sort by cost 405 407 CandidateCost coster{ resn.indexer }; … … 427 429 new_resn.newNeed.insert( match.need.begin(), match.need.end() ); 428 430 429 bindAssertion( r.decl, r.info, new_resn.alt, match, new_resn.inferred ); 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 } 430 436 } 431 437 -
src/ResolvExpr/ResolveAssertions.h
r933f32f r6a9d4b4 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 , std::list<std::string>& errors);26 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ); 27 27 } // namespace ResolvExpr 28 28 -
src/ResolvExpr/Resolver.cc
r933f32f r6a9d4b4 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:17:01 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Tue Feb 19 18:09:56 201913 // Update Count : 2 4011 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Fri Oct 05 09:43:00 2018 13 // Update Count : 214 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 CastExpr * untyped = new CastExpr( expr ); // cast to void293 untyped ->location = expr->location;292 static CastExpr untyped( nullptr ); // cast to void 293 untyped.location = expr->location; 294 294 295 295 // set up and resolve expression cast to void 296 untyped.arg = expr; 296 297 Alternative choice; 297 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );298 findUnfinishedKindExpression( &untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() ); 298 299 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
r933f32f r6a9d4b4 10 10 // Created On : Sun May 17 12:18:34 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Feb 18 20:40:38 201913 // Update Count : 412 // Last Modified On : Sat Jul 22 09:36:57 2017 13 // Update Count : 3 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
r933f32f r6a9d4b4 386 386 } 387 387 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 ) { 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 ) { 391 389 392 390 auto class1 = internal_lookup( var1->get_name() ); … … 430 428 class1->set_type( common ); 431 429 } 432 class1->data.isComplete |= data.isComplete;433 430 env.erase( class2 ); 434 431 } else return false; … … 438 435 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 439 436 class1->allowWidening = widen1; 440 class1->data.isComplete |= data.isComplete;441 437 env.erase( class2 ); 442 438 } else { 443 439 class2->vars.insert( class1->vars.begin(), class1->vars.end() ); 444 440 class2->allowWidening = widen2; 445 class2->data.isComplete |= data.isComplete;446 441 env.erase( class1 ); 447 442 } // if … … 450 445 class1->vars.insert( var2->get_name() ); 451 446 class1->allowWidening = widen1; 452 class1->data.isComplete |= data.isComplete;453 447 } else if ( class2 != env.end() ) { 454 448 // var1 unbound, add to class2 455 449 class2->vars.insert( var1->get_name() ); 456 450 class2->allowWidening = widen2; 457 class2->data.isComplete |= data.isComplete;458 451 } else { 459 452 // neither var bound, create new class -
src/ResolvExpr/TypeEnvironment.h
r933f32f r6a9d4b4 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 12:24:58 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Tue Apr 30 23:04:10 201913 // Update Count : 911 // Last Modified By : Aaron B. Moss 12 // Last Modified On : Mon Jun 18 11:58:00 2018 13 // Update Count : 4 14 14 // 15 15 … … 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 <unordered_map> 22 #include <set> // for set 20 #include <map> // for map, map<>::value_compare 21 #include <set> // for set 23 22 #include <string> // for string 24 23 #include <utility> // for move, swap … … 65 64 AssertionSetValue() : isUsed(false), resnSlot(0) {} 66 65 }; 67 typedef std::map< DeclarationWithType *, AssertionSetValue, AssertCompare > AssertionSet;68 typedef std:: unordered_map< std::string, TypeDecl::Data > OpenVarSet;66 typedef std::map< DeclarationWithType*, AssertionSetValue, AssertCompare > AssertionSet; 67 typedef std::map< std::string, TypeDecl::Data > OpenVarSet; 69 68 70 69 /// merges one set of open vars into another … … 140 139 /// Binds the type classes represented by `var1` and `var2` together; will add 141 140 /// one or both classes if needed. Returns false on failure. 142 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );141 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ); 143 142 144 143 /// Disallows widening for all bindings in the environment -
src/ResolvExpr/Unify.cc
r933f32f r6a9d4b4 21 21 #include <string> // for string, operator==, operator!=, bas... 22 22 #include <utility> // for pair, move 23 #include <vector> 24 25 #include "AST/Node.hpp" 26 #include "AST/Type.hpp" 23 27 24 #include "Common/PassVisitor.h" // for PassVisitor 28 25 #include "FindOpenVars.h" // for findOpenVars … … 175 172 bool isopen2 = var2 && ( entry2 != openVars.end() ); 176 173 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 } 174 if ( isopen1 && isopen2 && entry1->second == entry2->second ) { 175 result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer ); 185 176 } else if ( isopen1 ) { 186 177 result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer ); … … 633 624 } 634 625 626 // xxx - compute once and store in the FunctionType? 635 627 Type * extractResultType( FunctionType * function ) { 636 628 if ( function->get_returnVals().size() == 0 ) { … … 646 638 } 647 639 } 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 }660 640 } // namespace ResolvExpr 661 641 -
src/ResolvExpr/module.mk
r933f32f r6a9d4b4 15 15 ############################################################################### 16 16 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) 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 -
src/ResolvExpr/typeops.h
r933f32f r6a9d4b4 10 10 // Created On : Sun May 17 07:28:22 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Feb 8 09:30:34 201913 // Update Count : 412 // Last Modified On : Sat Jul 22 09:36:18 2017 13 // Update Count : 3 14 14 // 15 15 … … 18 18 #include <vector> 19 19 20 #include "AST/Node.hpp"21 #include "AST/Type.hpp"22 20 #include "SynTree/SynTree.h" 23 21 #include "SynTree/Type.h" … … 101 99 /// creates the type represented by the list of returnVals in a FunctionType. The caller owns the return value. 102 100 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 );105 101 106 102 // in CommonType.cc 107 Type * commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );103 Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ); 108 104 109 105 // in PolyCost.cc -
src/SymTab/Indexer.cc
r933f32f r6a9d4b4 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:37:33 2015 11 // Last Modified By : Aaron B. Moss12 // Last Modified On : Fri Mar 8 13:55:00 201913 // Update Count : 2 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Aug 17 16:08:40 2017 13 // Update Count : 20 14 14 // 15 15 … … 17 17 18 18 #include <cassert> // for assert, strict_dynamic_cast 19 #include <iostream> // for operator<<, basic_ostream, ostream 19 20 #include <string> // for string, operator<<, operator!= 20 #include <memory> // for shared_ptr, make_shared21 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 vector25 24 26 25 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign 27 26 #include "Common/SemanticError.h" // for SemanticError 28 27 #include "Common/utility.h" // for cloneAll 29 #include "Common/Stats/Counter.h" // for counters 30 #include "GenPoly/GenPoly.h" // for getFunctionType 28 #include "GenPoly/GenPoly.h" 31 29 #include "InitTweak/InitTweak.h" // for isConstructor, isCopyFunction, isC... 32 30 #include "Mangler.h" // for Mangler … … 40 38 #include "SynTree/Type.h" // for Type, StructInstType, UnionInstType 41 39 40 #define debugPrint(x) if ( doDebug ) { std::cerr << x; } 41 42 42 namespace SymTab { 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) 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; 71 114 }; 72 return ret; 73 } 74 } 75 76 Indexer::Indexer() 77 : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(), 78 prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; } 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 } 79 206 80 207 Indexer::~Indexer() { 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; 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; 109 231 } 110 232 111 233 void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const { 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 } 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 ); 122 258 } 123 259 124 260 NamedTypeDecl *Indexer::lookupType( const std::string &id ) const { 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; 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 ); 130 265 } 131 266 132 267 StructDecl *Indexer::lookupStruct( const std::string &id ) const { 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; 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 ); 272 } 273 274 NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const { 275 return lookupTypeAtScope( id, 0 ); 276 } 277 278 StructDecl *Indexer::globalLookupStruct( const std::string &id ) const { 279 return lookupStructAtScope( id, 0 ); 280 } 281 282 UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const { 283 return lookupUnionAtScope( id, 0 ); 284 } 285 286 EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const { 287 return lookupEnumAtScope( id, 0 ); 138 288 } 139 289 140 290 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; 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 ); 146 295 } 147 296 148 297 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; 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 ); 154 302 } 155 303 156 304 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; 172 } 173 174 NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const { 175 return atScope( 0 )->lookupType( id ); 176 } 177 178 StructDecl *Indexer::globalLookupStruct( const std::string &id ) const { 179 return atScope( 0 )->lookupStruct( id ); 180 } 181 182 UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const { 183 return atScope( 0 )->lookupUnion( id ); 184 } 185 186 EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const { 187 return atScope( 0 )->lookupEnum( id ); 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 ); 188 405 } 189 406 … … 207 424 } 208 425 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 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 215 428 assert( (isObject( added ) && isObject( existing.id ) ) 216 429 || ( isFunction( added ) && isFunction( existing.id ) ) ); 217 430 218 if ( LinkageSpec::isOverridable( existing.id-> linkage) ) {431 if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) { 219 432 // new definition shadows the autogenerated one, even at the same scope 220 433 return false; 221 } else if ( LinkageSpec::isMangled( added->linkage ) 222 || ResolvExpr::typesCompatible( 223 added->get_type(), existing.id->get_type(), Indexer() ) ) { 434 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) { 224 435 225 436 // it is a conflict if one declaration is deleted and the other is not 226 437 if ( deleteStmt && ! existing.deleteStmt ) { 227 if ( handleConflicts.mode == OnConflict::Error ) { 228 SemanticError( added, "deletion of defined identifier " ); 229 } 230 return true; 438 return handleConflicts( existing, "deletion of defined identifier " ); 231 439 } else if ( ! deleteStmt && existing.deleteStmt ) { 232 if ( handleConflicts.mode == OnConflict::Error ) { 233 SemanticError( added, "definition of deleted identifier " ); 234 } 235 return true; 440 return handleConflicts( existing, "definition of deleted identifier " ); 236 441 } 237 442 238 443 if ( isDefinition( added ) && isDefinition( existing.id ) ) { 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; 444 if ( isFunction( added ) ) { 445 return handleConflicts( existing, "duplicate function definition for " ); 446 } else { 447 return handleConflicts( existing, "duplicate object definition for " ); 448 } // if 246 449 } // if 247 450 } else { 248 if ( handleConflicts.mode == OnConflict::Error ) { 249 SemanticError( added, "duplicate definition for " ); 250 } 251 return true; 451 return handleConflicts( existing, "duplicate definition for " ); 252 452 } // if 253 453 … … 255 455 } 256 456 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 } 358 } else { 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 432 return true; 433 } 434 435 void Indexer::addId( 436 DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr, 437 BaseSyntaxNode * deleteStmt ) { 438 ++*stats().add_calls; 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 439 462 const std::string &name = decl->name; 440 if ( name == "" ) return;441 442 463 std::string mangleName; 443 464 if ( LinkageSpec::isOverridable( decl->linkage ) ) { 444 // mangle the name without including the appropriate suffix, so overridable routines 445 // are placed into thesame "bucket" as their user defined versions.465 // mangle the name without including the appropriate suffix, so overridable routines are placed into the 466 // same "bucket" as their user defined versions. 446 467 mangleName = Mangler::mangle( decl, false ); 447 468 } else { … … 449 470 } // if 450 471 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 ) ) { 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 ) ) { 480 SemanticError( decl, "conflicting overload of C function " ); 481 } 482 } else { 454 483 // Check that a Cforall declaration doesn't override any C declaration 455 if ( hasCompatibleCDecl( name, mangleName ) ) {484 if ( hasCompatibleCDecl( name, mangleName, scope ) ) { 456 485 SemanticError( decl, "Cforall declaration hides C function " ); 457 486 } 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 ) ) { 462 SemanticError( decl, "conflicting overload of C function " ); 463 } 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) ) ); 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; 508 496 } 509 497 510 498 void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) { 511 499 // default handling of conflicts is to raise an error 512 addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );500 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr ); 513 501 } 514 502 515 503 void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) { 516 504 // default handling of conflicts is to raise an error 517 addId( decl, OnConflict::error(), nullptr, deleteStmt );505 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt ); 518 506 } 519 507 … … 530 518 } 531 519 } 532 // does not need to be added to the table if both existing and added have a base that are 533 // the same 520 // does not need to be added to the table if both existing and added have a base that are the same 534 521 return true; 535 522 } 536 523 537 524 void Indexer::addType( NamedTypeDecl *decl ) { 538 ++*stats().add_calls; 525 debugPrint( "Adding type " << decl->name << std::endl ); 526 makeWritable(); 527 539 528 const std::string &id = decl->name; 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 } ); 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 } 554 541 } 555 542 … … 564 551 565 552 void Indexer::addStruct( const std::string &id ) { 553 debugPrint( "Adding fwd decl for struct " << id << std::endl ); 566 554 addStruct( new StructDecl( id ) ); 567 555 } 568 556 569 557 void Indexer::addStruct( StructDecl *decl ) { 570 ++*stats().add_calls; 558 debugPrint( "Adding struct " << decl->name << std::endl ); 559 makeWritable(); 560 571 561 const std::string &id = decl->name; 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 } ); 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 } 586 574 } 587 575 588 576 void Indexer::addEnum( EnumDecl *decl ) { 589 ++*stats().add_calls; 577 debugPrint( "Adding enum " << decl->name << std::endl ); 578 makeWritable(); 579 590 580 const std::string &id = decl->name; 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 } ); 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 } 605 593 } 606 594 607 595 void Indexer::addUnion( const std::string &id ) { 596 debugPrint( "Adding fwd decl for union " << id << std::endl ); 608 597 addUnion( new UnionDecl( id ) ); 609 598 } 610 599 611 600 void Indexer::addUnion( UnionDecl *decl ) { 612 ++*stats().add_calls; 601 debugPrint( "Adding union " << decl->name << std::endl ); 602 makeWritable(); 603 613 604 const std::string &id = decl->name; 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 } ); 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 } 628 617 } 629 618 630 619 void Indexer::addTrait( TraitDecl *decl ) { 631 ++*stats().add_calls; 620 debugPrint( "Adding trait " << decl->name << std::endl ); 621 makeWritable(); 622 632 623 const std::string &id = decl->name; 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 ) { 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 ) { 651 639 for ( Declaration * decl : aggr->members ) { 652 640 if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) { … … 654 642 if ( dwt->name == "" ) { 655 643 Type * t = dwt->get_type()->stripReferences(); 656 if ( dynamic_cast< StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {644 if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) { 657 645 Expression * base = expr->clone(); 658 646 ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost? … … 671 659 assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() ); 672 660 673 addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) ); 661 addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) { 662 // on conflict, delete the identifier 663 existing.deleteStmt = withStmt; 664 return true; 665 }); 674 666 } 675 667 } … … 693 685 addIds( ftype->returnVals ); 694 686 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 scope 717 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 695 747 } 696 748 -
src/SymTab/Indexer.h
r933f32f r6a9d4b4 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:38:55 2015 11 // Last Modified By : Aaron B. Moss12 // Last Modified On : Fri Mar 8 13:55:00 201913 // Update Count : 911 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Aug 17 16:09:12 2017 13 // Update Count : 8 14 14 // 15 15 16 16 #pragma once 17 17 18 #include < functional> // for function19 #include <list> // for list20 #include < memory> // for shared_ptr, enable_shared_from_this21 #include < string> // for string18 #include <iosfwd> // for ostream 19 #include <list> // for list 20 #include <string> // for string 21 #include <functional> // for function 22 22 23 #include " Common/PersistentMap.h" // for PersistentMap24 #include "SynTree/SynTree.h" // for AST nodes23 #include "SynTree/Visitor.h" // for Visitor 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 : public std::enable_shared_from_this<SymTab::Indexer>{32 public:31 class Indexer { 32 public: 33 33 explicit Indexer(); 34 35 Indexer( const Indexer &that ); 36 Indexer( Indexer &&that ); 34 37 virtual ~Indexer(); 38 Indexer& operator= ( const Indexer &that ); 39 Indexer& operator= ( Indexer &&that ); 35 40 36 // when using an indexer manually (e.g., within a mutator traversal), it is necessary to 37 // tell the indexerexplicitly when scopes begin and end41 // 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 38 43 void enterScope(); 39 44 void leaveScope(); … … 45 50 /// non-null if this declaration is deleted 46 51 BaseSyntaxNode * deleteStmt = nullptr; 47 /// scope of identifier48 unsigned long scope = 0;49 52 50 53 // NOTE: shouldn't need either of these constructors, but gcc-4 does not properly support initializer lists with default members. 51 54 IdData() = default; 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 ) {} 55 IdData( DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ) {} 58 56 59 57 Expression * combine( ResolvExpr::Cost & cost ) const; … … 82 80 EnumDecl *globalLookupEnum( const std::string &id ) const; 83 81 82 void print( std::ostream &os, int indent = 0 ) const; 83 84 /// looks up a specific mangled ID at the given scope 85 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 name 88 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 name 90 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 84 100 void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr ); 85 101 void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ); … … 96 112 void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt ); 97 113 114 /// adds all of the members of the Aggregate (addWith helper) 115 void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction ); 116 98 117 /// convenience function for adding a list of Ids to the indexer 99 118 void addIds( const std::list< DeclarationWithType * > & decls ); … … 105 124 void addFunctionType( FunctionType * ftype ); 106 125 126 bool doDebug = false; ///< Display debugging trace? 107 127 private: 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 128 struct Impl; 113 129 114 Scoped(Decl* d, unsigned long s) : decl(d), scope(s) {}115 };130 Impl *tables; ///< Copy-on-write instance of table data structure 131 unsigned long scope; ///< Scope index of this pointer 116 132 117 using Ptr = std::shared_ptr<const Indexer>; 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 ); 118 137 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> >; 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; 126 142 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 ); 143 /// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope) 144 void makeWritable(); 170 145 171 146 /// common code for addId, addDeletedId, etc. 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; 147 void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr ); 183 148 }; 184 149 } // namespace SymTab -
src/SymTab/Mangler.cc
r933f32f r6a9d4b4 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 ); 40 41 Mangler( const Mangler & ) = delete; 41 42 … … 66 67 private: 67 68 std::ostringstream mangleName; ///< Mangled name being constructed 68 typedef std::map< std::string, std::pair< int, int > > VarMapType;69 typedef std::map< std::string, std::pair< std::string, int > > VarMapType; 69 70 VarMapType varNums; ///< Map of type variables to indices 70 71 int nextVarNum; ///< Next type variable index 72 const ResolvExpr::TypeEnvironment* env; ///< optional environment for substitutions 71 73 bool isTopLevel; ///< Is the Mangler at the top level 72 74 bool mangleOverridable; ///< Specially mangle overridable built-in methods … … 78 80 public: 79 81 Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 80 int nextVarNum, const VarMapType& varNums ); 82 int nextVarNum, const ResolvExpr::TypeEnvironment* env, 83 const VarMapType& varNums ); 81 84 82 85 private: … … 106 109 } 107 110 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 108 118 namespace { 109 119 Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams ) 110 : nextVarNum( 0 ), isTopLevel( true ),120 : nextVarNum( 0 ), env(nullptr), isTopLevel( true ), 111 121 mangleOverridable( mangleOverridable ), typeMode( typeMode ), 112 122 mangleGenericParams( mangleGenericParams ) {} 113 123 124 Mangler::Mangler( const ResolvExpr::TypeEnvironment& env ) 125 : nextVarNum( 0 ), env( &env ), isTopLevel( true ), mangleOverridable( false ), 126 typeMode( false ), mangleGenericParams( true ) {} 127 114 128 Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 115 int nextVarNum, const VarMapType& varNums ) 116 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ), 129 int nextVarNum, const ResolvExpr::TypeEnvironment* env, 130 const VarMapType& varNums ) 131 : varNums( varNums ), nextVarNum( nextVarNum ), env( env ), isTopLevel( false ), 117 132 mangleOverridable( mangleOverridable ), typeMode( typeMode ), 118 133 mangleGenericParams( mangleGenericParams ) {} … … 343 358 assert( false ); 344 359 } // switch 345 varNums[ (*i)->name ] = std::make_pair( nextVarNum, (int)(*i)->get_kind() ); 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() ); 346 377 for ( std::list< DeclarationWithType* >::iterator assert = (*i)->assertions.begin(); assert != (*i)->assertions.end(); ++assert ) { 347 378 PassVisitor<Mangler> sub_mangler( 348 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ); 379 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, env, 380 varNums ); 349 381 (*assert)->accept( sub_mangler ); 350 382 assertionNames.push_back( sub_mangler.pass.get_mangleName() ); -
src/SymTab/Mangler.h
r933f32f r6a9d4b4 44 44 /// Mangle ignoring generic type parameters 45 45 std::string mangleConcrete( Type* ty ); 46 /// Mangle for assertion key 47 std::string mangleAssnKey( DeclarationWithType* decl, 48 const ResolvExpr::TypeEnvironment& env ); 46 49 47 50 namespace Encoding { -
src/SymTab/ManglerCommon.cc
r933f32f r6a9d4b4 10 10 // Created On : Sun May 17 21:44:03 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Feb 14 17:06:37 201913 // Update Count : 2612 // Last Modified On : Sat Jul 22 09:45:30 2017 13 // Update Count : 15 14 14 // 15 15 … … 23 23 const std::string manglePrefix = "_X"; 24 24 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 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 }; 80 61 static_assert( 81 62 sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES, -
src/SymTab/Validate.cc
r933f32f r6a9d4b4 49 49 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign 50 50 #include "ControlStruct/Mutate.h" // for ForExprMutator 51 #include "Common/Stats.h" // for Stats::Heap52 51 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd 53 52 #include "Common/ScopedMap.h" // for ScopedMap … … 299 298 PassVisitor<FixQualifiedTypes> fixQual; 300 299 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 } 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 ); 384 325 } 385 326 -
src/SymTab/module.mk
r933f32f r6a9d4b4 15 15 ############################################################################### 16 16 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 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 -
src/SynTree/AddressExpr.cc
r933f32f r6a9d4b4 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 23:54:44 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : T hu Feb 28 13:13:38 201913 // Update Count : 1011 // Last Modified By : Rob Schluntz 12 // Last Modified On : Tue Apr 26 12:35:13 2016 13 // Update Count : 6 14 14 // 15 15 … … 47 47 } else { 48 48 // taking address of non-lvalue -- must be a reference, loses one layer of reference 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 49 ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( arg->result ); 50 set_result( addrType( refType->base ) ); 54 51 } 55 52 // result of & is never an lvalue -
src/SynTree/Attribute.cc
r933f32f r6a9d4b4 21 21 #include "Expression.h" // for Expression 22 22 23 Attribute::Attribute( const Attribute &other ) : BaseSyntaxNode( other ),name( other.name ) {23 Attribute::Attribute( const Attribute &other ) : name( other.name ) { 24 24 cloneAll( other.parameters, parameters ); 25 25 } -
src/SynTree/BaseSyntaxNode.h
r933f32f r6a9d4b4 18 18 #include "Common/CodeLocation.h" 19 19 #include "Common/Indenter.h" 20 #include "Common/Stats.h"21 22 20 class Visitor; 23 21 class Mutator; … … 25 23 class BaseSyntaxNode { 26 24 public: 27 static Stats::Counters::SimpleCounter* new_nodes;28 29 25 CodeLocation location; 30 31 BaseSyntaxNode() { ++*new_nodes; }32 BaseSyntaxNode( const BaseSyntaxNode& o ) : location(o.location) { ++*new_nodes; }33 26 34 27 virtual ~BaseSyntaxNode() {} -
src/SynTree/BasicType.cc
r933f32f r6a9d4b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jan 31 21:37:36 201913 // Update Count : 1 212 // Last Modified On : Mon Sep 25 14:14:03 2017 13 // Update Count : 11 14 14 // 15 15 … … 30 30 31 31 bool BasicType::isInteger() const { 32 return kind <= UnsignedInt128;33 #if 034 32 switch ( kind ) { 35 33 case Bool: … … 65 63 assert( false ); 66 64 return false; 67 #endif68 65 } 69 66 -
src/SynTree/Constant.cc
r933f32f r6a9d4b4 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 : Wed Feb 13 18:11:22 201913 // Update Count : 3 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Spt 28 14:49:00 2018 13 // Update Count : 30 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 ) : BaseSyntaxNode( other ),rep( other.rep ), val( other.val ) {27 Constant::Constant( const Constant &other ) : rep( other.rep ), val( other.val ) { 28 28 type = other.type->clone(); 29 29 } -
src/SynTree/Declaration.cc
r933f32f r6a9d4b4 31 31 32 32 Declaration::Declaration( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage ) 33 : name( name ), linkage( linkage ), uniqueId( 0 ), storageClasses( scs) {33 : name( name ), linkage( linkage ), storageClasses( scs ), uniqueId( 0 ) { 34 34 } 35 35 36 36 Declaration::Declaration( const Declaration &other ) 37 : BaseSyntaxNode( other ), name( other.name ), linkage( other.linkage ), extension( other.extension ), uniqueId( other.uniqueId ), storageClasses( other.storageClasses) {37 : BaseSyntaxNode( other ), name( other.name ), linkage( other.linkage ), extension( other.extension ), storageClasses( other.storageClasses ), uniqueId( other.uniqueId ) { 38 38 } 39 39 -
src/SynTree/Declaration.h
r933f32f r6a9d4b4 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 : Thr May 2 10:47:00 201913 // Update Count : 13 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Sep 3 19:24:06 2017 13 // Update Count : 131 14 14 // 15 15 … … 19 19 #include <iosfwd> // for ostream 20 20 #include <list> // for list 21 #include <unordered_map> // for unordered_map22 21 #include <string> // for string, operator+, allocator, to_string 23 22 … … 71 70 static Declaration *declFromId( UniqueId id ); 72 71 72 private: 73 Type::StorageClasses storageClasses; 73 74 UniqueId uniqueId; 74 Type::StorageClasses storageClasses;75 private:76 75 }; 77 76 … … 167 166 CompoundStmt *get_statements() const { return statements; } 168 167 void set_statements( CompoundStmt *newValue ) { statements = newValue; } 169 bool has_body() const { return NULL != statements; }170 168 171 169 static FunctionDecl * newFunction( const std::string & name, FunctionType * type, CompoundStmt * statements ); … … 213 211 TypeDecl::Kind kind; 214 212 bool isComplete; 215 216 213 Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {} 217 214 Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {} 218 215 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 222 216 bool operator==(const Data & other) const { return kind == other.kind && isComplete == other.isComplete; } 223 217 bool operator!=(const Data & other) const { return !(*this == other);} … … 245 239 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 246 240 241 private: 247 242 Kind kind; 248 243 }; … … 305 300 virtual void accept( Visitor &v ) override { v.visit( this ); } 306 301 virtual Declaration *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 302 private: 307 303 DeclarationNode::Aggregate kind; 308 private:309 304 virtual std::string typeString() const override; 310 305 }; … … 335 330 virtual Declaration *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 336 331 private: 337 std:: unordered_map< std::string, long long int > enumValues;332 std::map< std::string, long long int > enumValues; 338 333 virtual std::string typeString() const override; 339 334 }; -
src/SynTree/Expression.cc
r933f32f r6a9d4b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Feb 19 18:10:55 201913 // Update Count : 6012 // Last Modified On : Tue Jul 25 14:15:47 2017 13 // Update Count : 54 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 ) :arg(arg), isGenerated( isGenerated ) {280 CastExpr::CastExpr( Expression *arg, Type *toType, bool isGenerated ) : Expression(), arg(arg), isGenerated( isGenerated ) { 281 281 set_result(toType); 282 282 } 283 283 284 CastExpr::CastExpr( Expression * arg, bool isGenerated ) :arg(arg), isGenerated( isGenerated ) {284 CastExpr::CastExpr( Expression *arg, bool isGenerated ) : Expression(), 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 << (isGenerated ? "Generated " : "Explicit ") <<"Cast of:" << std::endl << indent+1;295 void CastExpr::print( std::ostream &os, Indenter indent ) const { 296 os << "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
r933f32f r6a9d4b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Feb 18 18:29:51 201913 // Update Count : 4 912 // Last Modified On : Sun Sep 3 19:23:46 2017 13 // Update Count : 48 14 14 // 15 15 … … 195 195 public: 196 196 Expression * arg; 197 bool isGenerated = true; // cast generated implicitly by code generation or explicit inprogram197 bool isGenerated = true; // whether this cast appeared in the source program 198 198 199 199 CastExpr( Expression * arg, bool isGenerated = true ); -
src/SynTree/Label.h
r933f32f r6a9d4b4 35 35 operator std::string() const { return name; } 36 36 bool empty() { return name.empty(); } 37 37 private: 38 38 std::string name; 39 39 Statement * labelled; -
src/SynTree/Mutator.h
r933f32f r6a9d4b4 121 121 virtual Initializer * mutate( ConstructorInit * ctorInit ) = 0 ; 122 122 123 virtual Subrange * mutate( Subrange * subrange ) = 0; 124 123 125 virtual Constant * mutate( Constant * constant ) = 0; 124 126 -
src/SynTree/Statement.h
r933f32f r6a9d4b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Mar 12 09:01:53 201913 // Update Count : 8312 // Last Modified On : Thu Mar 8 14:53:02 2018 13 // Update Count : 78 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, Statement * body, std::list<Statement *> & initialization, bool isDoWhile = false ); 226 WhileStmt( const WhileStmt & other ); 225 WhileStmt( Expression *condition, 226 Statement *body, std::list<Statement *> & initialization, bool isDoWhile = false ); 227 WhileStmt( const WhileStmt &other ); 227 228 virtual ~WhileStmt(); 228 229 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; }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; } 233 234 bool get_isDoWhile() { return isDoWhile; } 234 235 void set_isDoWhile( bool newValue ) { isDoWhile = newValue; } 235 236 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;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; 240 241 }; 241 242 … … 243 244 public: 244 245 std::list<Statement *> initialization; 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 ); 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 ); 251 253 virtual ~ForStmt(); 252 254 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;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; 265 267 }; 266 268 … … 272 274 const Label originalTarget; 273 275 Label target; 274 Expression * computedTarget;276 Expression *computedTarget; 275 277 Type type; 276 278 277 279 BranchStmt( Label target, Type ) throw (SemanticErrorException); 278 BranchStmt( Expression * computedTarget, Type ) throw (SemanticErrorException);280 BranchStmt( Expression *computedTarget, Type ) throw (SemanticErrorException); 279 281 280 282 Label get_originalTarget() { return originalTarget; } … … 282 284 void set_target( Label newValue ) { target = newValue; } 283 285 284 Expression * get_computedTarget() { return computedTarget; }286 Expression *get_computedTarget() { return computedTarget; } 285 287 void set_target( Expression * newValue ) { computedTarget = newValue; } 286 288 287 289 Type get_type() { return type; } 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;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; 294 296 private: 295 static const char * brType[];297 static const char *brType[]; 296 298 }; 297 299 298 300 class ReturnStmt : public Statement { 299 301 public: 300 Expression * expr;301 302 ReturnStmt( Expression * expr );303 ReturnStmt( const ReturnStmt & other );302 Expression *expr; 303 304 ReturnStmt( Expression *expr ); 305 ReturnStmt( const ReturnStmt &other ); 304 306 virtual ~ReturnStmt(); 305 307 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;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; 313 315 }; 314 316 … … 322 324 323 325 ThrowStmt( Kind kind, Expression * expr, Expression * target = nullptr ); 324 ThrowStmt( const ThrowStmt & other );326 ThrowStmt( const ThrowStmt &other ); 325 327 virtual ~ThrowStmt(); 326 328 … … 331 333 void set_target( Expression * newTarget ) { target = newTarget; } 332 334 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;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; 337 339 }; 338 340 … … 343 345 FinallyStmt * finallyBlock; 344 346 345 TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt *finallyBlock = 0 );346 TryStmt( const TryStmt & other );347 TryStmt( CompoundStmt *tryBlock, std::list<CatchStmt *> &handlers, FinallyStmt *finallyBlock = 0 ); 348 TryStmt( const TryStmt &other ); 347 349 virtual ~TryStmt(); 348 350 349 CompoundStmt * get_block() const { return block; }350 void set_block( CompoundStmt * newValue ) { block = newValue; }351 CompoundStmt *get_block() const { return block; } 352 void set_block( CompoundStmt *newValue ) { block = newValue; } 351 353 std::list<CatchStmt *>& get_catchers() { return handlers; } 352 354 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;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; 360 362 }; 361 363 … … 365 367 366 368 const Kind kind; 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 );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 ); 374 376 virtual ~CatchStmt(); 375 377 376 378 Kind get_kind() { return kind; } 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;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; 388 390 }; 389 391 390 392 class FinallyStmt : public Statement { 391 393 public: 392 CompoundStmt * block;393 394 FinallyStmt( CompoundStmt * block );395 FinallyStmt( const FinallyStmt & other );394 CompoundStmt *block; 395 396 FinallyStmt( CompoundStmt *block ); 397 FinallyStmt( const FinallyStmt &other ); 396 398 virtual ~FinallyStmt(); 397 399 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;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; 405 407 }; 406 408 … … 436 438 } orelse; 437 439 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;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; 442 444 443 445 }; … … 462 464 class DeclStmt : public Statement { 463 465 public: 464 Declaration * decl;465 466 DeclStmt( Declaration * decl );467 DeclStmt( const DeclStmt & other );466 Declaration *decl; 467 468 DeclStmt( Declaration *decl ); 469 DeclStmt( const DeclStmt &other ); 468 470 virtual ~DeclStmt(); 469 471 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. 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. 482 485 class ImplicitCtorDtorStmt : public Statement { 483 486 public: … … 489 492 virtual ~ImplicitCtorDtorStmt(); 490 493 491 Statement * get_callStmt() const { return callStmt; }494 Statement *get_callStmt() const { return callStmt; } 492 495 void set_callStmt( Statement * newValue ) { callStmt = newValue; } 493 496 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;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; 498 501 }; 499 502 -
src/SynTree/SynTree.h
r933f32f r6a9d4b4 34 34 class NamedTypeDecl; 35 35 class TypeDecl; 36 class FtypeDecl; 37 class DtypeDecl; 36 38 class TypedefDecl; 37 39 class AsmDecl; … … 88 90 class ConstructorExpr; 89 91 class CompoundLiteralExpr; 92 class UntypedValofExpr; 90 93 class RangeExpr; 91 94 class UntypedTupleExpr; … … 129 132 class ConstructorInit; 130 133 134 class Subrange; 135 131 136 //template <class T> // emulate a union with templates? 132 137 class Constant; -
src/SynTree/Type.cc
r933f32f r6a9d4b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jan 31 21:54:16 201913 // Update Count : 4312 // Last Modified On : Fri Jun 22 10:17:19 2018 13 // Update Count : 39 14 14 // 15 15 #include "Type.h" … … 25 25 26 26 const char *BasicType::typeNames[] = { 27 #if 028 27 "_Bool", 29 28 "char", … … 50 49 "unsigned __int128", 51 50 "__float80", 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", 51 "__float128" 107 52 }; 108 53 static_assert( -
src/SynTree/Type.h
r933f32f r6a9d4b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Feb 14 17:11:24 201913 // Update Count : 1 6912 // Last Modified On : Mon Sep 25 14:14:01 2017 13 // Update Count : 154 14 14 // 15 15 … … 207 207 class BasicType : public Type { 208 208 public: 209 // GENERATED START, DO NOT EDIT210 // GENERATED BY BasicTypes-gen.cc211 209 enum Kind { 212 210 Bool, … … 222 220 LongLongSignedInt, 223 221 LongLongUnsignedInt, 222 Float, 223 Double, 224 LongDouble, 225 FloatComplex, 226 DoubleComplex, 227 LongDoubleComplex, 228 FloatImaginary, 229 DoubleImaginary, 230 LongDoubleImaginary, 224 231 SignedInt128, 225 232 UnsignedInt128, 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, 233 Float80, 234 Float128, 248 235 NUMBER_OF_BASIC_TYPES 249 236 } kind; 250 // GENERATED END251 237 252 238 static const char *typeNames[]; // string names for basic types, MUST MATCH with Kind -
src/SynTree/TypeSubstitution.cc
r933f32f r6a9d4b4 64 64 } 65 65 66 void TypeSubstitution::addVar( std::string formalExpr, Expression *actualExpr ) {67 varEnv[ formalExpr ] = actualExpr;68 }69 70 66 void TypeSubstitution::remove( std::string formalType ) { 71 67 TypeEnvType::iterator i = typeEnv.find( formalType ); … … 112 108 namespace { 113 109 struct EnvTrimmer { 114 const TypeSubstitution * env; 115 TypeSubstitution * newEnv; 116 EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){} 110 TypeSubstitution * env, * newEnv; 111 EnvTrimmer( TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){} 117 112 void previsit( TypeDecl * tyDecl ) { 118 113 // transfer known bindings for seen type variables … … 125 120 126 121 /// reduce environment to just the parts that are referenced in a given expression 127 TypeSubstitution * TypeSubstitution::newFromExpr( Expression * expr, constTypeSubstitution * env ) {122 TypeSubstitution * TypeSubstitution::newFromExpr( Expression * expr, TypeSubstitution * env ) { 128 123 if ( env ) { 129 124 TypeSubstitution * newEnv = new TypeSubstitution(); -
src/SynTree/TypeSubstitution.h
r933f32f r6a9d4b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 30 22:52:47 201913 // Update Count : 912 // Last Modified On : Sat Jul 22 09:52:24 2017 13 // Update Count : 3 14 14 // 15 15 … … 19 19 #include <iosfwd> // for ostream 20 20 #include <list> // for list<>::iterator, _List_iterator 21 #include < unordered_map>22 #include < unordered_set>21 #include <map> // for _Rb_tree_iterator, map, map<>::val... 22 #include <set> // for 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 ) const;42 template< typename SynTreeClass > int applyFree( SynTreeClass *&input ) const;41 template< typename SynTreeClass > int apply( SynTreeClass *&input ); 42 template< typename SynTreeClass > int applyFree( SynTreeClass *&input ); 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 52 50 template< typename FormalIterator, typename ActualIterator > 53 51 void add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ); … … 58 56 59 57 /// create a new TypeSubstitution using bindings from env containing all of the type variables in expr 60 static TypeSubstitution * newFromExpr( Expression * expr, constTypeSubstitution * env );58 static TypeSubstitution * newFromExpr( Expression * expr, TypeSubstitution * env ); 61 59 62 60 void normalize(); … … 80 78 friend class PassVisitor; 81 79 82 typedef std:: unordered_map< std::string, Type* > TypeEnvType;83 typedef std:: unordered_map< std::string, Expression* > VarEnvType;80 typedef std::map< std::string, Type* > TypeEnvType; 81 typedef std::map< std::string, Expression* > VarEnvType; 84 82 TypeEnvType typeEnv; 85 83 VarEnvType varEnv; … … 91 89 auto begin() const -> decltype( typeEnv.begin() ) { return typeEnv.begin(); } 92 90 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(); }98 91 }; 99 92 … … 105 98 ActualIterator actualIt = actualBegin; 106 99 for ( ; formalIt != formalEnd; ++formalIt, ++actualIt ) { 107 if ( TypeDecl *formal = dynamic_cast< TypeDecl * >( *formalIt ) ) {108 if ( TypeExpr *actual = dynamic_cast< TypeExpr * >( *actualIt ) ) {100 if ( TypeDecl *formal = dynamic_cast< TypeDecl* >( *formalIt ) ) { 101 if ( TypeExpr *actual = dynamic_cast< TypeExpr* >( *actualIt ) ) { 109 102 if ( formal->get_name() != "" ) { 110 103 TypeEnvType::iterator i = typeEnv.find( formal->get_name() ); … … 137 130 // definitition must happen after PassVisitor is included so that WithGuards can be used 138 131 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> { 139 Substituter( constTypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}132 Substituter( TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {} 140 133 141 134 Type * postmutate( TypeInstType * aggregateUseType ); … … 150 143 void premutate( UnionInstType * aggregateUseType ); 151 144 152 constTypeSubstitution & sub;145 TypeSubstitution & sub; 153 146 int subCount = 0; 154 147 bool freeOnly; 155 typedef std:: unordered_set< std::string > BoundVarsType;148 typedef std::set< std::string > BoundVarsType; 156 149 BoundVarsType boundVars; 157 150 }; 158 151 159 152 template< typename SynTreeClass > 160 int TypeSubstitution::apply( SynTreeClass *&input ) const{153 int TypeSubstitution::apply( SynTreeClass *&input ) { 161 154 assert( input ); 162 155 PassVisitor<Substituter> sub( *this, false ); … … 170 163 171 164 template< typename SynTreeClass > 172 int TypeSubstitution::applyFree( SynTreeClass *&input ) const{165 int TypeSubstitution::applyFree( SynTreeClass *&input ) { 173 166 assert( input ); 174 167 PassVisitor<Substituter> sub( *this, true ); -
src/SynTree/Visitor.h
r933f32f r6a9d4b4 123 123 virtual void visit( ConstructorInit * ctorInit ) = 0; 124 124 125 virtual void visit( Subrange * subrange ) = 0; 126 125 127 virtual void visit( Constant * constant ) = 0; 126 128 -
src/SynTree/module.mk
r933f32f r6a9d4b4 15 15 ############################################################################### 16 16 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 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 52 51 53 SRC += $(SRC_SYNTREE)54 SRCDEMANGLE += $(SRC_SYNTREE) -
src/Tuples/TupleExpansion.cc
r933f32f r6a9d4b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 13 18:14:12 201913 // Update Count : 2112 // Last Modified On : Wed Jun 21 17:35:04 2017 13 // Update Count : 19 14 14 // 15 15 … … 17 17 #include <cassert> // for assert 18 18 #include <list> // for list 19 #include <vector> 20 21 #include "AST/CVQualifiers.hpp" 22 #include "AST/Expr.hpp" 23 #include "AST/Node.hpp" 24 #include "AST/Type.hpp" 19 25 20 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd, WithGu... 26 21 #include "Common/ScopedMap.h" // for ScopedMap … … 63 58 }; 64 59 65 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public With ConstTypeSubstitution {60 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithTypeSubstitution { 66 61 Type * postmutate( TupleType * tupleType ); 67 62 … … 319 314 return new TupleType( qualifiers, types ); 320 315 } 321 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {322 (void) exprs;323 #warning Not implemented; needs Type.cpp in build324 assertf(false, "Not implemented; needs Type.cpp in build");325 // // produce the TupleType which aggregates the types of the exprs326 // 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 void334 // if ( expr->result->isVoid() ) return new ast::VoidType{};335 336 // // qualifiers on the tuple type are the qualifiers that exist on all components337 // 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 }345 316 346 317 TypeInstType * isTtype( Type * type ) { -
src/Tuples/Tuples.h
r933f32f r6a9d4b4 19 19 #include <vector> 20 20 21 #include "AST/Fwd.hpp"22 #include "AST/Node.hpp"23 21 #include "SynTree/Expression.h" 24 22 #include "SynTree/Declaration.h" … … 29 27 namespace Tuples { 30 28 // TupleAssignment.cc 31 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 29 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 32 30 std::vector< ResolvExpr::AlternativeFinder >& args ); 33 31 34 32 // TupleExpansion.cc 35 33 /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate … … 44 42 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types 45 43 Type * makeTupleType( const std::list< Expression * > & exprs ); 46 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );47 44 48 45 /// returns a TypeInstType if `type` is a ttype, nullptr otherwise 49 46 TypeInstType * isTtype( Type * type ); 50 const ast::TypeInstType * isTtype( const ast::Type * type );51 47 52 48 /// returns true if the expression may contain side-effects. -
src/Tuples/module.mk
r933f32f r6a9d4b4 15 15 ############################################################################### 16 16 17 SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc 18 SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc 17 SRC += Tuples/TupleAssignment.cc \ 18 Tuples/TupleExpansion.cc \ 19 Tuples/Explode.cc -
src/Validate/module.mk
r933f32f r6a9d4b4 15 15 ############################################################################### 16 16 17 SRC += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc18 SRCDEMANGLE += Validate/HandleAttributes.ccValidate/FindSpecialDecls.cc17 SRC += Validate/HandleAttributes.cc \ 18 Validate/FindSpecialDecls.cc -
src/config.h.in
r933f32f r6a9d4b4 52 52 #undef CFA_VERSION_SHORT 53 53 54 /* Have compiler warning cast-function-type. */ 55 #undef HAVE_CAST_FUNCTION_TYPE 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 56 68 57 69 /* Define to 1 if you have the <dlfcn.h> header file. */ 58 70 #undef HAVE_DLFCN_H 59 71 72 /* Define to 1 if you have the <fenv.h> header file. */ 73 #undef HAVE_FENV_H 74 75 /* Define to 1 if you have the <float.h> header file. */ 76 #undef HAVE_FLOAT_H 77 60 78 /* Define to 1 if you have the <inttypes.h> header file. */ 61 79 #undef HAVE_INTTYPES_H 62 80 63 /* Have keywords _FloatXX. */64 #undef HAVE_KEYWORDS_FLOATXX65 66 81 /* Define to 1 if you have the <libintl.h> header file. */ 67 82 #undef HAVE_LIBINTL_H 68 83 84 /* Define to 1 if you have the <limits.h> header file. */ 85 #undef HAVE_LIMITS_H 86 69 87 /* Define to 1 if you have the <malloc.h> header file. */ 70 88 #undef HAVE_MALLOC_H … … 73 91 #undef HAVE_MEMORY_H 74 92 93 /* Define to 1 if you have the `memset' function. */ 94 #undef HAVE_MEMSET 95 96 /* Define to 1 if you have the `putenv' function. */ 97 #undef HAVE_PUTENV 98 99 /* Define to 1 if stdbool.h conforms to C99. */ 100 #undef HAVE_STDBOOL_H 101 102 /* Define to 1 if you have the <stddef.h> header file. */ 103 #undef HAVE_STDDEF_H 104 75 105 /* Define to 1 if you have the <stdint.h> header file. */ 76 106 #undef HAVE_STDINT_H … … 79 109 #undef HAVE_STDLIB_H 80 110 111 /* Define to 1 if you have the `strchr' function. */ 112 #undef HAVE_STRCHR 113 81 114 /* Define to 1 if you have the <strings.h> header file. */ 82 115 #undef HAVE_STRINGS_H … … 85 118 #undef HAVE_STRING_H 86 119 120 /* Define to 1 if you have the `strtol' function. */ 121 #undef HAVE_STRTOL 122 87 123 /* Define to 1 if you have the <sys/stat.h> header file. */ 88 124 #undef HAVE_SYS_STAT_H … … 94 130 #undef HAVE_UNISTD_H 95 131 96 /* Define to 1 if the system has the type `_ Float32'. */97 #undef HAVE__ FLOAT32132 /* Define to 1 if the system has the type `_Bool'. */ 133 #undef HAVE__BOOL 98 134 99 135 /* Define to the sub-directory where libtool stores uninstalled libraries. */ … … 120 156 /* Define to the version of this package. */ 121 157 #undef PACKAGE_VERSION 158 159 /* If using the C implementation of alloca, define if you know the 160 direction of stack growth for your system; otherwise it will be 161 automatically deduced at runtime. 162 STACK_DIRECTION > 0 => grows toward higher addresses 163 STACK_DIRECTION < 0 => grows toward lower addresses 164 STACK_DIRECTION = 0 => direction of growth unknown */ 165 #undef STACK_DIRECTION 122 166 123 167 /* Define to 1 if you have the ANSI C header files. */ … … 136 180 `char[]'. */ 137 181 #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, the 185 #define below would cause a syntax error. */ 186 #undef _UINT32_T 187 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, the 190 #define below would cause a syntax error. */ 191 #undef _UINT8_T 192 193 /* Define to `__inline__' or `__inline' if that's what the C compiler 194 calls it, or to nothing if 'inline' is not supported under any name. */ 195 #ifndef __cplusplus 196 #undef inline 197 #endif 198 199 /* Define to the type of a signed integer type of width exactly 16 bits if 200 such a type exists and the standard includes do not define it. */ 201 #undef int16_t 202 203 /* Define to the type of a signed integer type of width exactly 32 bits if 204 such a type exists and the standard includes do not define it. */ 205 #undef int32_t 206 207 /* Define to the type of a signed integer type of width exactly 8 bits if such 208 a type exists and the standard includes do not define it. */ 209 #undef int8_t 210 211 /* Define to the equivalent of the C99 'restrict' keyword, or to 212 nothing if this is not supported. Do not define if restrict is 213 supported directly. */ 214 #undef restrict 215 /* Work around a bug in Sun C++: it does not support _Restrict or 216 __restrict__, even though the corresponding Sun C compiler ends up with 217 "#define restrict _Restrict" or "#define restrict __restrict__" in the 218 previous line. Perhaps some future version of Sun C++ will work with 219 restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ 220 #if defined __SUNPRO_CC && !defined __RESTRICT 221 # define _Restrict 222 # define __restrict__ 223 #endif 224 225 /* Define to `unsigned int' if <sys/types.h> does not define. */ 226 #undef size_t 227 228 /* Define to the type of an unsigned integer type of width exactly 16 bits if 229 such a type exists and the standard includes do not define it. */ 230 #undef uint16_t 231 232 /* Define to the type of an unsigned integer type of width exactly 32 bits if 233 such a type exists and the standard includes do not define it. */ 234 #undef uint32_t 235 236 /* Define to the type of an unsigned integer type of width exactly 8 bits if 237 such a type exists and the standard includes do not define it. */ 238 #undef uint8_t -
src/include/cassert
r933f32f r6a9d4b4 45 45 } 46 46 47 extern void abort(const char *fmt, ... ) noexcept __attribute__((noreturn, format(printf, 1, 2)));48 47 // Local Variables: // 49 48 // tab-width: 4 // -
src/main.cc
r933f32f r6a9d4b4 7 7 // main.cc -- 8 8 // 9 // Author : Peter Buhr and Rob Schluntz9 // Author : Richard C. Bilson 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri May 3 16:10:52 201913 // Update Count : 59912 // Last Modified On : Wed Dec 26 08:11:19 2018 13 // Update Count : 499 14 14 // 15 15 … … 24 24 #include <fstream> // for ofstream 25 25 #include <iostream> // for operator<<, basic_ostream 26 #include <iomanip>27 26 #include <iterator> // for back_inserter 28 27 #include <list> // for list … … 38 37 #include "CodeTools/TrackLoc.h" // for fillLocations 39 38 #include "Common/CompilerError.h" // for CompilerError 40 #include "Common/ Stats.h"39 #include "Common/Heap.h" 41 40 #include "Common/PassVisitor.h" 42 // #include "AST/Pass.hpp"43 41 #include "Common/SemanticError.h" // for SemanticError 44 42 #include "Common/UnimplementedError.h" // for UnimplementedError … … 67 65 using namespace std; 68 66 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 ) \ 67 #define PASS(name, pass) \ 87 68 if ( errorp ) { cerr << name << endl; } \ 88 NewPass(name); \ 89 Stats::Time::StartBlock(name); \ 90 pass; \ 91 Stats::Time::StopBlock(); 69 HeapStats::newPass(name); \ 70 pass; 92 71 93 72 LinkageSpec::Spec linkage = LinkageSpec::Cforall; … … 95 74 DeclarationNode * parseTree = nullptr; // program parse tree 96 75 97 st atic std::string PreludeDirector = "";76 std::string PreludeDirector = ""; 98 77 99 78 static void parse_cmdline( int argc, char *argv[], const char *& filename ); … … 151 130 } // backtrace 152 131 153 staticvoid sigSegvBusHandler( int sig_num ) {132 void sigSegvBusHandler( int sig_num ) { 154 133 cerr << "*CFA runtime error* program cfa-cpp terminated with " 155 134 << (sig_num == SIGSEGV ? "segment fault" : "bus error") … … 157 136 backtrace( 2 ); // skip first 2 stack frames 158 137 //_exit( EXIT_FAILURE ); 159 abort(); // cause core dump for debugging138 abort(); 160 139 } // sigSegvBusHandler 161 140 162 staticvoid sigAbortHandler( __attribute__((unused)) int sig_num ) {141 void sigAbortHandler( __attribute__((unused)) int sig_num ) { 163 142 backtrace( 6 ); // skip first 6 stack frames 164 143 signal( SIGABRT, SIG_DFL); // reset default signal handler 165 raise( SIGABRT ); // reraise SIGABRT144 raise( SIGABRT ); // reraise SIGABRT 166 145 } // sigAbortHandler 167 146 … … 169 148 int main( int argc, char * argv[] ) { 170 149 FILE * input; // use FILE rather than istream because yyin is FILE 171 ostream * output = & cout;172 const char * filename = nullptr;150 ostream *output = & cout; 151 const char *filename = nullptr; 173 152 list< Declaration * > translationUnit; 174 153 … … 202 181 } // if 203 182 204 Stats::Time::StartGlobal();205 NewPass("Parse");206 Stats::Time::StartBlock("Parse");207 208 183 // read in the builtins, extras, and the prelude 209 184 if ( ! nopreludep ) { // include gcc builtins … … 240 215 parseTree->printList( cout ); 241 216 delete parseTree; 242 return EXIT_SUCCESS;217 return 0; 243 218 } // if 244 219 … … 249 224 if ( astp ) { 250 225 dump( translationUnit ); 251 return EXIT_SUCCESS;226 return 0; 252 227 } // if 253 228 … … 256 231 // works okay for now. 257 232 CodeTools::fillLocations( translationUnit ); 258 Stats::Time::StopBlock();259 233 260 234 // add the assignment statement after the initialization of a type parameter 261 PASS( " Validate", SymTab::validate( translationUnit, symtabp ) );235 PASS( "validate", SymTab::validate( translationUnit, symtabp ) ); 262 236 if ( symtabp ) { 263 237 deleteAll( translationUnit ); 264 return EXIT_SUCCESS;238 return 0; 265 239 } // if 266 240 … … 268 242 PassVisitor<ResolvExpr::AlternativePrinter> printer( cout ); 269 243 acceptAll( translationUnit, printer ); 270 return EXIT_SUCCESS;244 return 0; 271 245 } // if 272 246 273 247 if ( validp ) { 274 248 dump( translationUnit ); 275 return EXIT_SUCCESS;276 } // if 277 278 PASS( " FixLabels", ControlStruct::fixLabels( translationUnit ) );279 PASS( " FixNames", CodeGen::fixNames( translationUnit ) );280 PASS( " GenInit", InitTweak::genInit( translationUnit ) );281 PASS( " Expand MemberTuples" , Tuples::expandMemberTuples( 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 ) ); 282 256 if ( libcfap ) { 283 257 // generate the bodies of cfa library functions … … 288 262 CodeTools::printDeclStats( translationUnit ); 289 263 deleteAll( translationUnit ); 290 return EXIT_SUCCESS;291 } // if264 return 0; 265 } 292 266 293 267 if ( bresolvep ) { 294 268 dump( translationUnit ); 295 return EXIT_SUCCESS;269 return 0; 296 270 } // if 297 271 … … 300 274 if ( resolvprotop ) { 301 275 CodeTools::dumpAsResolvProto( translationUnit ); 302 return EXIT_SUCCESS;303 } // if304 305 PASS( " Resolve", ResolvExpr::resolve( translationUnit ) );276 return 0; 277 } 278 279 PASS( "resolve", ResolvExpr::resolve( translationUnit ) ); 306 280 if ( exprp ) { 307 281 dump( translationUnit ); 308 return EXIT_SUCCESS;282 return 0; 309 283 } // if 310 284 311 285 // fix ObjectDecl - replaces ConstructorInit nodes 312 PASS( " FixInit", InitTweak::fix( translationUnit, buildingLibrary() ) );286 PASS( "fixInit", InitTweak::fix( translationUnit, buildingLibrary() ) ); 313 287 if ( ctorinitp ) { 314 288 dump ( translationUnit ); 315 return EXIT_SUCCESS;316 } // if 317 318 PASS( " Expand UniqueExpr", 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 reused319 320 PASS( " TranslateEHM" , ControlStruct::translateEHM( translationUnit ) );321 322 PASS( " GenWaitfor" , Concurrency::generateWaitFor( translationUnit ) );323 324 PASS( " ConvertSpecializations", GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded325 326 PASS( " ExpandTuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this?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 reused 293 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 expanded 299 300 PASS( "expandTuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this? 327 301 328 302 if ( tuplep ) { 329 303 dump( translationUnit ); 330 return EXIT_SUCCESS;331 } // if332 333 PASS( " Virtual ExpandCasts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM334 335 PASS( " InstantiateGenerics", GenPoly::instantiateGeneric( translationUnit ) );304 return 0; 305 } 306 307 PASS( "virtual expandCasts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM 308 309 PASS( "instantiateGenerics", GenPoly::instantiateGeneric( translationUnit ) ); 336 310 if ( genericsp ) { 337 311 dump( translationUnit ); 338 return EXIT_SUCCESS;339 } // if340 PASS( " Convert L-Value", GenPoly::convertLvalue( translationUnit ) );312 return 0; 313 } 314 PASS( "convertLvalue", GenPoly::convertLvalue( translationUnit ) ); 341 315 342 316 343 317 if ( bboxp ) { 344 318 dump( translationUnit ); 345 return EXIT_SUCCESS;346 } // if 347 PASS( " Box", GenPoly::box( translationUnit ) );319 return 0; 320 } // if 321 PASS( "box", GenPoly::box( translationUnit ) ); 348 322 349 323 if ( bcodegenp ) { 350 324 dump( translationUnit ); 351 return EXIT_SUCCESS;352 } // if325 return 0; 326 } 353 327 354 328 if ( optind < argc ) { // any commands after the flags and input file ? => output file name … … 357 331 358 332 CodeTools::fillLocations( translationUnit ); 359 PASS( " Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );333 PASS( "codegen", CodeGen::generate( translationUnit, *output, ! noprotop, prettycodegenp, true, linemarks ) ); 360 334 361 335 CodeGen::FixMain::fix( *output, (PreludeDirector + "/bootloader.c").c_str() ); … … 373 347 delete output; 374 348 } // if 375 return EXIT_FAILURE;349 return 1; 376 350 } catch ( UnimplementedError &e ) { 377 351 cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl; … … 379 353 delete output; 380 354 } // if 381 return EXIT_FAILURE;355 return 1; 382 356 } catch ( CompilerError &e ) { 383 357 cerr << "Compiler Error: " << e.get_what() << endl; … … 386 360 delete output; 387 361 } // if 388 return EXIT_FAILURE;389 } catch ( ...) {362 return 1; 363 } catch(...) { 390 364 std::exception_ptr eptr = std::current_exception(); 391 365 try { 392 366 if (eptr) { 393 367 std::rethrow_exception(eptr); 394 } else { 395 std::cerr << "Exception Uncaught and Unknown" << std::endl; 396 } // if 368 } 369 else { 370 std::cerr << "Exception Uncaught and Unkown" << std::endl; 371 } 397 372 } catch(const std::exception& e) { 398 373 std::cerr << "Uncaught Exception \"" << e.what() << "\"\n"; 399 } // try400 return EXIT_FAILURE;401 } // try374 } 375 return 1; 376 }// try 402 377 403 378 deleteAll( translationUnit ); 404 Stats::print();405 return EXIT_SUCCESS;379 if(!libcfap && !treep) HeapStats::printStats(); 380 return 0; 406 381 } // main 407 382 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 ) { 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 507 412 opterr = 0; // (global) prevent getopt from printing error messages 508 413 509 414 bool Wsuppress = false, Werror = false; 510 415 int c; 511 while ( (c = getopt_long( argc, argv, optstring, long_opts, nullptr)) != -1 ) {416 while ( (c = getopt_long( argc, argv, "abBcCdefgGlLmnNpqrRstTvwW:yzZD:F:", long_opts, &long_index )) != -1 ) { 512 417 switch ( c ) { 513 case 'h': // help message 514 usage( argv ); // no return 515 break; 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: 516 456 case 'l': // generate libcfa.c 517 457 libcfap = true; 518 458 break; 519 case 'L': // generate line marks 459 case Linemarks: 460 case 'L': // print lines marks 520 461 linemarks = true; 521 462 break; 522 case 'm': // do not replace main 523 nomainp = true; 524 break; 525 case 'N': // do not generate line marks 463 case Nopreamble: 464 case 'n': // do not read preamble 465 nopreludep = true; 466 break; 467 case Nolinemarks: 468 case 'N': // suppress line marks 526 469 linemarks = false; 527 470 break; 528 case 'n': // do not read prelude 529 nopreludep = true; 530 break; 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; 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: 552 497 case 't': // build in tree 553 498 treep = true; 554 499 break; 555 case 'w': // suppress all warnings, hidden 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': 556 508 Wsuppress = true; 557 509 break; 558 case 'W': // coordinate gcc -W with CFA, hidden510 case 'W': 559 511 if ( strcmp( optarg, "all" ) == 0 ) { 560 512 SemanticWarning_EnableAll(); … … 573 525 } // if 574 526 break; 575 case 'D': // ignore -Dxxx, forwarded by cpp, hidden 576 break; 577 case 'F': // source file-name without suffix, hidden 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 578 539 filename = optarg; 579 540 break; 580 case '?': // unknown option541 case '?': 581 542 if ( optopt ) { // short option ? 582 cout << "Unknown option -" << (char)optopt << endl;543 assertf( false, "Unknown option: -%c\n", (char)optopt ); 583 544 } else { 584 cout << "Unknown option " << argv[optind - 1] << endl;545 assertf( false, "Unknown option: %s\n", argv[optind - 1] ); 585 546 } // 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: 547 #if defined(__GNUC__) && __GNUC__ >= 7 548 __attribute__((fallthrough)); 549 #endif 595 550 default: 596 usage( argv ); // no return551 abort(); 597 552 } // switch 598 553 } // while … … 632 587 list< Declaration * > decls; 633 588 634 if ( genproto) {589 if ( noprotop ) { 635 590 filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), notPrelude ); 636 591 } else { … … 640 595 // depending on commandline options, either generate code or dump the AST 641 596 if ( codegenp ) { 642 CodeGen::generate( decls, out, ! genproto, prettycodegenp );597 CodeGen::generate( decls, out, ! noprotop, prettycodegenp ); 643 598 } else { 644 599 printAll( decls, out ); 645 } // if600 } 646 601 deleteAll( translationUnit ); 647 602 } // dump -
tests/.expect/KRfunctions.x64.txt
r933f32f r6a9d4b4 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))( __attribute__ ((unused))signed int __anonymous_object0){64 signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(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_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))); 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))); 108 113 } 109 114 -
tests/.expect/KRfunctions.x86.txt
r933f32f r6a9d4b4 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))( __attribute__ ((unused))signed int __anonymous_object0){64 signed int (*_X2f6FFi_i__iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))(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_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))); 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))); 108 113 } 109 114 -
tests/.expect/abs.txt
r933f32f r6a9d4b4 3 3 signed long int -65 abs 65 4 4 signed long long int -65 abs 65 5 float -65 . abs 65.6 double -65 . abs 65.7 long double -65 . abs 65.8 float _Complex -65 .-2.i abs 65.03089 double _Complex -65 .-2.i abs 65.030761951556410 long double _Complex -65 .-2.i abs 65.03076195155643425 float -65 abs 65 6 double -65 abs 65 7 long double -65 abs 65 8 float _Complex -65-2i abs 65.0308 9 double _Complex -65-2i abs 65.0307619515564 10 long double _Complex -65-2i abs 65.0307619515564342 -
tests/.expect/ato.txt
r933f32f r6a9d4b4 22 22 -123.456789012345679 -123.45678901234567890123456789 23 23 -123.456-123.456i -123.456-123.456i 24 0 .+0.i 2 324 0+0i 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
r933f32f r6a9d4b4 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())( __attribute__ ((unused))signed int __anonymous_object2){642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(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
r933f32f r6a9d4b4 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())( __attribute__ ((unused))signed int __anonymous_object2){642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(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
r933f32f r6a9d4b4 1 castError.cfa: 21:1 error: Cannot choose between 3 alternatives for expression2 ExplicitCast of:1 castError.cfa:7:1 error: Cannot choose between 3 alternatives for expression 2 Cast of: 3 3 Name: f 4 4 ... to: 5 5 char Alternatives are: 6 Cost ( 1, 0, 0, 0, 0, 0 , 0 ): ExplicitCast of:6 Cost ( 1, 0, 0, 0, 0, 0 ): 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 , 0 ): ExplicitCast of:18 Cost ( 1, 0, 0, 0, 0, 0 ): Cast of: 19 19 Variable Expression: f: double 20 20 ... to: … … 25 25 Environment: 26 26 27 Cost ( 1, 0, 0, 0, 0, 0 , 0 ): ExplicitCast of:27 Cost ( 1, 0, 0, 0, 0, 0 ): 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 expression38 Generated Cast of:39 Comma Expression:40 constant expression (3 3: signed int)41 Name: v42 ... 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 char47 ... to: nothing48 (types:49 void50 )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 int57 ... to: nothing58 (types:59 void60 )61 Environment:62 63 -
tests/.expect/completeTypeError.txt
r933f32f r6a9d4b4 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 1 completeTypeError.cfa:33:1 error: No reasonable alternatives for expression Applying untyped: 2 Name: *? 3 ...to: 4 Name: v 7 5 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 6 completeTypeError.cfa:34:1 error: No reasonable alternatives for expression Applying untyped: 7 Name: *? 8 ...to: 9 Name: y 55 10 56 11 completeTypeError.cfa:35:1 error: No reasonable alternatives for expression Applying untyped: … … 69 24 Name: v 70 25 71 completeTypeError.cfa:5 9:1 error: No reasonable alternatives for expression Applying untyped:26 completeTypeError.cfa:58:1 error: No reasonable alternatives for expression Applying untyped: 72 27 Name: baz 73 28 ...to: 74 29 Name: y 75 30 76 completeTypeError.cfa: 60:1 error: No reasonable alternatives for expression Applying untyped:31 completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped: 77 32 Name: quux 78 33 ...to: 79 34 Name: y 80 35 81 completeTypeError.cfa:72:1 error: No alternatives with satisfiable assertions for Applying untyped: 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: 82 42 Name: baz 83 43 ...to: 84 44 Name: z 85 45 86 Unsatisfiable alternative:87 Cost ( 0, 1, 0, 0,1, -5, 0 ): Application of88 Variable Expression: baz: forall89 T: sized object type90 ... with assertions91 ?=?: pointer to function92 ... with parameters93 reference to instance of type T (not function type)94 instance of type T (not function type)95 ... returning96 _retval__operator_assign: instance of type T (not function type)97 ... with attributes:98 Attribute with name: unused46 Alternatives with failing assertions are: 47 Cost ( 0, 1, 0, 1, -5, 0 ): Application of 48 Variable Expression: baz: forall 49 T: sized object type 50 ... with assertions 51 ?=?: pointer to function 52 ... with parameters 53 reference to instance of type T (not function type) 54 instance of type T (not function type) 55 ... returning 56 _retval__operator_assign: instance of type T (not function type) 57 ... with attributes: 58 Attribute with name: unused 99 59 100 60 101 ?{}: pointer to function102 ... with parameters103 reference to instance of type T (not function type)104 ... returning nothing61 ?{}: pointer to function 62 ... with parameters 63 reference to instance of type T (not function type) 64 ... returning nothing 105 65 106 ?{}: pointer to function107 ... with parameters108 reference to instance of type T (not function type)109 instance of type T (not function type)110 ... returning nothing66 ?{}: 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 111 71 112 ^?{}: pointer to function113 ... with parameters114 reference to instance of type T (not function type)115 ... returning nothing72 ^?{}: pointer to function 73 ... with parameters 74 reference to instance of type T (not function type) 75 ... returning nothing 116 76 117 77 118 function119 ... with parameters120 pointer to instance of type T (not function type)121 ... returning nothing78 function 79 ... with parameters 80 pointer to instance of type T (not function type) 81 ... returning nothing 122 82 123 ... to arguments124 Variable Expression: z: pointer to instance of type T (not function type)83 ... to arguments 84 Variable Expression: z: pointer to instance of type T (not function type) 125 85 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 86 (types: 87 void 88 ) 89 Environment:( _73_0_T ) -> instance of type T (not function type) (no widening) 140 90 141 91 92 -
tests/.expect/complex.txt
r933f32f r6a9d4b4 1 1 x:3+2i y:4+5i z:7+7i 2 x:3 .+2.i y:4.+5.i z:7.+7.i2 x:3+2i y:4+5i z:7+7i 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
r933f32f r6a9d4b4 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 { 1124 1129 ((void)(_X12_retval_maini_1=0) /* ?{} */); 1125 1130 } … … 1132 1137 __attribute__ ((unused)) signed int _X12_retval_maini_1; 1133 1138 { 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)) /* ?{} */); 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)) /* ?{} */); 1136 1143 } 1137 1144 -
tests/.expect/declarationSpecifier.x86.txt
r933f32f r6a9d4b4 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 { 1124 1129 ((void)(_X12_retval_maini_1=0) /* ?{} */); 1125 1130 } … … 1132 1137 __attribute__ ((unused)) signed int _X12_retval_maini_1; 1133 1138 { 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)) /* ?{} */); 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)) /* ?{} */); 1136 1143 } 1137 1144 -
tests/.expect/extension.x64.txt
r933f32f r6a9d4b4 457 457 458 458 { 459 signed int _tmp_cp_ret4; 460 ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4)); 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)); 461 463 } 462 464 -
tests/.expect/extension.x86.txt
r933f32f r6a9d4b4 457 457 458 458 { 459 signed int _tmp_cp_ret4; 460 ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4)); 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)); 461 463 } 462 464 -
tests/.expect/functions.x64.txt
r933f32f r6a9d4b4 1 1 void _X1hFv___1(void){ 2 2 } 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)){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)){ 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( __attribute__ ((unused))signed int __anonymous_object7){101 signed int _X1fFi_i__1(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( __attribute__ ((unused))signed int __anonymous_object9, signed int _X1xi_1){132 struct _conc__tuple2_0 _X1fFT2ii_ii__1(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( __attribute__ ((unused)) signed int __anonymous_object12, signed int _X1xi_1, __attribute__ ((unused))signed int __anonymous_object13){169 struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object12, signed int _X1xi_1, 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( __attribute__ ((unused))signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){182 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(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( __attribute__ ((unused))double __anonymous_object20){192 const double _X3fooFd_d__1(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( __attribute__ ((unused))signed int __anonymous_object21){244 struct S _X3rtnFS1S_i__1(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( __attribute__ ((unused)) signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1), __attribute__ ((unused))signed int (*__anonymous_object24)(signed int __anonymous_object25)){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)){ 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( __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)]){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)]){ 274 274 __attribute__ ((unused)) signed int _X9_retval_fi_1; 275 275 } -
tests/.expect/functions.x86.txt
r933f32f r6a9d4b4 1 1 void _X1hFv___1(void){ 2 2 } 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)){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)){ 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( __attribute__ ((unused))signed int __anonymous_object7){101 signed int _X1fFi_i__1(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( __attribute__ ((unused))signed int __anonymous_object9, signed int _X1xi_1){132 struct _conc__tuple2_0 _X1fFT2ii_ii__1(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( __attribute__ ((unused)) signed int __anonymous_object12, signed int _X1xi_1, __attribute__ ((unused))signed int __anonymous_object13){169 struct _conc__tuple3_1 _X1fFT3iii_iii__1(signed int __anonymous_object12, signed int _X1xi_1, 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( __attribute__ ((unused))signed int __anonymous_object15, signed int _X1xi_1, signed int *_X1yPi_1){182 struct _conc__tuple3_2 _X1fFT3iiPi_iiPi__1(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( __attribute__ ((unused))double __anonymous_object20){192 const double _X3fooFd_d__1(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( __attribute__ ((unused))signed int __anonymous_object21){244 struct S _X3rtnFS1S_i__1(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( __attribute__ ((unused)) signed int (*__anonymous_object22)(signed int __anonymous_object23, signed int _X1pi_1), __attribute__ ((unused))signed int (*__anonymous_object24)(signed int __anonymous_object25)){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)){ 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( __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)]){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)]){ 274 274 __attribute__ ((unused)) signed int _X9_retval_fi_1; 275 275 } -
tests/.expect/gccExtensions.x64.txt
r933f32f r6a9d4b4 292 292 signed int _X2m3A0A0i_2[((unsigned long int )10)][((unsigned long int )10)]; 293 293 { 294 ((void)(_X12_retval_maini_1= 0) /* ?{} */);294 ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */); 295 295 } 296 296 … … 307 307 __attribute__ ((unused)) signed int _X12_retval_maini_1; 308 308 { 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)) /* ?{} */); 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)) /* ?{} */); 311 313 } 312 314 -
tests/.expect/gccExtensions.x86.txt
r933f32f r6a9d4b4 292 292 signed int _X2m3A0A0i_2[((unsigned int )10)][((unsigned int )10)]; 293 293 { 294 ((void)(_X12_retval_maini_1= 0) /* ?{} */);294 ((void)(_X12_retval_maini_1=((signed int )0)) /* ?{} */); 295 295 } 296 296 … … 307 307 __attribute__ ((unused)) signed int _X12_retval_maini_1; 308 308 { 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)) /* ?{} */); 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)) /* ?{} */); 311 313 } 312 314 -
tests/.expect/identity.txt
r933f32f r6a9d4b4 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-2i 12 double _Complex -4.1-2i 13 long double _Complex -4.1-2i -
tests/.expect/io1.txt
r933f32f r6a9d4b4 1 1 9 6 28 0 7 1 2 2 01 2 33 01234 01232 1 2 3 3 123 4 123 5 5 6 6 opening delimiters -
tests/.expect/loopctrl.txt
r933f32f r6a9d4b4 19 19 10 8 6 4 2 20 20 21 1 2 3 4 5 6 7 8 9 1022 10 9 8 7 6 5 4 3 2 1 023 2 4 6 8 1024 2.1 3.8 5.5 7.2 8.925 10 8 6 4 2 026 12.1 10.4 8.7 7. 5.3 3.627 21 28 22 N N N N N N N N N N … … 30 24 10 9 8 7 6 5 4 3 2 1 31 25 26 32 27 3 6 9 28 33 29 34 30 (0 0)(1 1)(2 2)(3 3)(4 4)(5 5)(6 6)(7 7)(8 8)(9 9) … … 44 40 (10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0) 45 41 (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 448 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -1449 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 1350 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -2351 52 0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 453 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -1454 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 1355 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -2356 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.558 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.559 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
r933f32f r6a9d4b4 1 fmod:1 . 1. 1. 1. 1. 1.2 remainder:-1 . -1. -1.1 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. -2.6 fdim:2 . 2. 2.4 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. 2.9 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 \ 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 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 -
tests/.expect/math2.txt
r933f32f r6a9d4b4 1 log:0 . 0. 0.0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i2 log2:3 . 3. 3.3 log10:2 . 2. 2.1 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. 3.7 sqrt:1 . 1. 1.1.09868+0.45509i 1.09868411346781+0.455089860562227i 1.09868411346780997+0.455089860562227341i8 cbrt:3 . 3. 3.6 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. 0.0.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
r933f32f r6a9d4b4 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. 0.1.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. 6.11 tgamma:6 6 6 -
tests/.expect/math4.txt
r933f32f r6a9d4b4 1 floor:1 . 1. 1.2 ceil:2 . 2. 2.3 trunc:3 . 3. 3.4 rint:2 . 2. 2.1 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. 4.10 round:2 . 2. 2.9 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. -1.15 copysign:-1 -1 -1 16 16 frexp:0.5 3 0.5 3 0.5 3 17 ldexp:8 . 8. 8.18 modf:2 . 0.3 2. 0.3 2.0.319 modf:2 ., 0.3 2., 0.3 2., 0.320 nextafter:2 . 2. 2.21 nexttoward:2 . 2. 2.22 scalbn:16 . 16. 16.23 scalbln:16 . 16. 16.17 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
r933f32f r6a9d4b4 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 4.20 double 4 . 3.1 max 4.21 long double 4 . 3.1 max 4.19 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
r933f32f r6a9d4b4 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
r933f32f r6a9d4b4 1 sum from 5 to 15 is 95, check 952 sum from 5 to 15 is 95, check 953 1 sum from 5 to 15 is 95, check 95 4 2 sum from 5 to 15 is 95, check 95 -
tests/Makefile.am
r933f32f r6a9d4b4 23 23 installed=no 24 24 25 INSTALL_FLAGS=-in-tree26 DEBUG_FLAGS=-debug -O027 28 25 quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes 29 26 … … 31 28 timeouts= 32 29 33 TEST_PY = python 3${builddir}/test.py30 TEST_PY = python ${builddir}/test.py 34 31 35 32 # applies to both programs … … 39 36 -Wno-unused-function \ 40 37 -quiet @CFA_FLAGS@ \ 41 -DIN_DIR="${ abs_srcdir}/.in/"38 -DIN_DIR="${srcdir}/.in/" 42 39 43 40 AM_CFLAGS += ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS} 44 41 CC = @CFACC@ 45 42 46 PRETTY_PATH= mkdir -p $(dir $(abspath ${@})) &&cd ${srcdir} &&43 PRETTY_PATH=cd ${srcdir} && 47 44 48 45 .PHONY: list .validate … … 51 48 52 49 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 53 # automake doesn't know we still need C /CPPrules so pretend like we have a C program54 _dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp50 # automake doesn't know we still need C rules so pretend like we have a C program 51 _dummy_hack_SOURCES = .dummy_hack.c 55 52 56 53 #---------------------------------------------------------------------------------------------------------------- … … 77 74 @echo "int main() { return 0; }" > ${@} 78 75 79 .dummy_hackxx.cpp:80 @echo "int bar() { return 0; }" > ${@}81 82 76 concurrency : 83 77 @+${TEST_PY} --debug=${debug} --install=${installed} -Iconcurrent … … 85 79 #---------------------------------------------------------------------------------------------------------------- 86 80 87 # Use for all tests, make sure the path are correct and all flags are added88 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 fail91 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 stderr94 CFATEST_STDERR=$(CFACOMPILETEST) 2> $(abspath ${@})95 96 #----------------------------------------------------------------------------------------------------------------97 98 81 # implicit rule so not all test require a rule 99 82 % : %.cfa $(CFACC) 100 $( CFATEST_STDOUT)83 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 101 84 102 % : %.cpp 103 $(PRETTY_PATH) $(C XXCOMPILE)$(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})85 declarationSpecifier: declarationSpecifier.cfa $(CFACC) 86 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 104 87 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 88 gccExtensions : gccExtensions.cfa $(CFACC) 89 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 116 90 117 #------------------------------------------------------------------------------ 118 # Expected failures 119 completeTypeError_FLAGS= -DERR1 91 extension : extension.cfa $(CFACC) 92 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 120 93 121 #------------------------------------------------------------------------------ 122 # CUSTOM TARGET 123 #------------------------------------------------------------------------------ 124 typedefRedef-ERR1: typedefRedef.cfa $(CFACC) 125 $(CFATEST_STDOUT) -DERR1 94 attributes : attributes.cfa $(CFACC) 95 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 126 96 127 alloc-ERROR: alloc.cfa $(CFACC)128 $( CFATEST_STDOUT) -DERR197 functions: functions.cfa $(CFACC) 98 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 129 99 130 nested-types-ERR1: nested-types.cfa $(CFACC)131 $( CFATEST_STDOUT) -DERR1100 KRfunctions : KRfunctions.cfa $(CFACC) 101 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 132 102 133 nested-types-ERR2: nested-types.cfa$(CFACC)134 $( CFATEST_STDOUT) -DERR2103 sched-ext-parse : sched-ext-parse.c $(CFACC) 104 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 135 105 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 106 gmp : gmp.cfa $(CFACC) 107 $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 147 108 148 109 #builtins 149 110 builtins/sync: builtins/sync.cfa $(CFACC) 150 $(CFATEST_STDERR) -fsyntax-only 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 ${@}) 151 146 152 147 # Warnings 153 148 warnings/self-assignment: warnings/self-assignment.cfa $(CFACC) 154 $( CFATEST_STDERR) -fsyntax-only149 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only -
tests/Makefile.in
r933f32f r6a9d4b4 107 107 CONFIG_CLEAN_FILES = config.py 108 108 CONFIG_CLEAN_VPATH_FILES = test.py 109 am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT) .dummy_hackxx.$(OBJEXT)109 am__dummy_hack_OBJECTS = .dummy_hack.$(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 =175 157 SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES) 176 158 DIST_SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES) … … 204 186 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 205 187 ACLOCAL = @ACLOCAL@ 188 ALLOCA = @ALLOCA@ 206 189 AMTAR = @AMTAR@ 207 190 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ … … 375 358 debug = yes 376 359 installed = no 377 INSTALL_FLAGS = -in-tree378 DEBUG_FLAGS = -debug -O0379 360 quick_test = avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes 380 361 concurrent = 381 362 timeouts = 382 TEST_PY = python 3${builddir}/test.py363 TEST_PY = python ${builddir}/test.py 383 364 384 365 # applies to both programs 385 366 AM_CFLAGS = $(if $(test), 2> $(test), ) -g -Wall -Wno-unused-function \ 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} &&367 -quiet @CFA_FLAGS@ -DIN_DIR="${srcdir}/.in/" ${DEBUG_FLAGS} \ 368 ${INSTALL_FLAGS} ${ARCH_FLAGS} 369 PRETTY_PATH = cd ${srcdir} && 389 370 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 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 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 419 373 all: all-am 420 374 421 375 .SUFFIXES: 422 .SUFFIXES: .c .cfa . cpp .dummy_hack .dummy_hackxx.lo .o .obj .validate376 .SUFFIXES: .c .cfa .dummy_hack .lo .o .obj .validate 423 377 $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/src/cfa.make $(am__configure_deps) 424 378 @for dep in $?; do \ … … 456 410 .dummy_hack$(EXEEXT): $(_dummy_hack_OBJECTS) $(_dummy_hack_DEPENDENCIES) $(EXTRA__dummy_hack_DEPENDENCIES) 457 411 @rm -f .dummy_hack$(EXEEXT) 458 $(AM_V_C XXLD)$(CXXLINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)412 $(AM_V_CCLD)$(LINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS) 459 413 avltree/$(am__dirstamp): 460 414 @$(MKDIR_P) avltree … … 490 444 491 445 @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@493 446 494 447 .c.o: … … 515 468 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 516 469 @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.Po522 @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.Po530 @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.Plo538 @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 $@ $<541 470 542 471 mostlyclean-libtool: … … 789 718 @echo "int main() { return 0; }" > ${@} 790 719 791 .dummy_hackxx.cpp:792 @echo "int bar() { return 0; }" > ${@}793 794 720 concurrency : 795 721 @+${TEST_PY} --debug=${debug} --install=${installed} -Iconcurrent … … 799 725 # implicit rule so not all test require a rule 800 726 % : %.cfa $(CFACC) 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 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 ${@}) 832 752 833 753 #builtins 834 754 builtins/sync: builtins/sync.cfa $(CFACC) 835 $(CFATEST_STDERR) -fsyntax-only 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 ${@}) 836 790 837 791 # Warnings 838 792 warnings/self-assignment: warnings/self-assignment.cfa $(CFACC) 839 $( CFATEST_STDERR) -fsyntax-only793 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only 840 794 841 795 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
tests/array.cfa
r933f32f r6a9d4b4 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 1 //Testing array declarations 17 2 int a1[]; 18 3 //int a2[*]; … … 49 34 } 50 35 51 int main() {} 52 53 // Local Variables: // 54 // tab-width: 4 // 55 // compile-command: "cfa array.cfa" // 56 // End: // 36 //Dummy main 37 int main(int argc, char const *argv[]) 38 { 39 return 0; 40 } -
tests/builtins/sync.cfa
r933f32f r6a9d4b4 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;14 13 15 14 { char ret; ret = __sync_fetch_and_add(vp1, v1); } … … 181 180 { _Bool ret; ret = __sync_bool_compare_and_swap_16(vp16, v16,v16); } 182 181 #endif 183 { _Bool ret; ret = __sync_bool_compare_and_swap(vpp, vp, vp); }184 182 185 183 { char ret; ret = __sync_val_compare_and_swap(vp1, v1, v1); } … … 195 193 { __int128 ret; ret = __sync_val_compare_and_swap_16(vp16, v16,v16); } 196 194 #endif 197 { struct type * ret; ret = __sync_val_compare_and_swap(vpp, vp, vp); }198 199 195 200 196 { char ret; ret = __sync_lock_test_and_set(vp1, v1); } … … 234 230 { __atomic_clear(vp1, v1); } 235 231 236 { char ret; ret = __atomic_exchange_n(vp1, v1, __ATOMIC_SEQ_CST); }232 { char ret; ret = __atomic_exchange_n(vp1, &v1, __ATOMIC_SEQ_CST); } 237 233 { char ret; ret = __atomic_exchange_1(vp1, v1, __ATOMIC_SEQ_CST); } 238 234 { char ret; __atomic_exchange(vp1, &v1, &ret, __ATOMIC_SEQ_CST); } 239 { short ret; ret = __atomic_exchange_n(vp2, v2, __ATOMIC_SEQ_CST); }235 { short ret; ret = __atomic_exchange_n(vp2, &v2, __ATOMIC_SEQ_CST); } 240 236 { short ret; ret = __atomic_exchange_2(vp2, v2, __ATOMIC_SEQ_CST); } 241 237 { short ret; __atomic_exchange(vp2, &v2, &ret, __ATOMIC_SEQ_CST); } 242 { int ret; ret = __atomic_exchange_n(vp4, v4, __ATOMIC_SEQ_CST); }238 { int ret; ret = __atomic_exchange_n(vp4, &v4, __ATOMIC_SEQ_CST); } 243 239 { int ret; ret = __atomic_exchange_4(vp4, v4, __ATOMIC_SEQ_CST); } 244 240 { int ret; __atomic_exchange(vp4, &v4, &ret, __ATOMIC_SEQ_CST); } 245 { long long int ret; ret = __atomic_exchange_n(vp8, v8, __ATOMIC_SEQ_CST); }241 { long long int ret; ret = __atomic_exchange_n(vp8, &v8, __ATOMIC_SEQ_CST); } 246 242 { long long int ret; ret = __atomic_exchange_8(vp8, v8, __ATOMIC_SEQ_CST); } 247 243 { long long int ret; __atomic_exchange(vp8, &v8, &ret, __ATOMIC_SEQ_CST); } 248 244 #if defined(__SIZEOF_INT128__) 249 { __int128 ret; ret = __atomic_exchange_n(vp16, v16, __ATOMIC_SEQ_CST); }245 { __int128 ret; ret = __atomic_exchange_n(vp16, &v16, __ATOMIC_SEQ_CST); } 250 246 { __int128 ret; ret = __atomic_exchange_16(vp16, v16, __ATOMIC_SEQ_CST); } 251 247 { __int128 ret; __atomic_exchange(vp16, &v16, &ret, __ATOMIC_SEQ_CST); } 252 248 #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); }255 249 256 250 { char ret; ret = __atomic_load_n(vp1, __ATOMIC_SEQ_CST); } … … 271 265 { __int128 ret; __atomic_load(vp16, &ret, __ATOMIC_SEQ_CST); } 272 266 #endif 273 { struct type * ret; ret = __atomic_load_n(vpp, __ATOMIC_SEQ_CST); }274 { struct type * ret; __atomic_load(vpp, &ret, __ATOMIC_SEQ_CST); }275 267 276 268 { _Bool ret; ret = __atomic_compare_exchange_n(vp1, rp1, v1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } … … 291 283 { _Bool ret; ret = __atomic_compare_exchange(vp16, rp16, &v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } 292 284 #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); }295 285 296 286 { __atomic_store_n(vp1, v1, __ATOMIC_SEQ_CST); } … … 311 301 { __atomic_store(vp16, &v16, __ATOMIC_SEQ_CST); } 312 302 #endif 313 { __atomic_store_n(vpp, vp, __ATOMIC_SEQ_CST); }314 { __atomic_store(vpp, &vp, __ATOMIC_SEQ_CST); }315 303 316 304 { char ret; ret = __atomic_add_fetch(vp1, v1, __ATOMIC_SEQ_CST); } -
tests/castError.cfa
r933f32f r6a9d4b4 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 1 //Testing some of the invalid casts of chars 16 2 int f; 17 3 … … 21 7 (char)f; 22 8 (int(*)())f; 23 24 unsigned char v;25 short int v;26 3, v; // implicit void cast27 9 } 28 10 29 int main() {} 30 31 // Local Variables: // 32 // tab-width: 4 // 33 // compile-command: "cfa castError.cfa" // 34 // End: // 11 //Dummy main 12 int main(int argc, char const *argv[]) 13 { 14 return 0; 15 } -
tests/completeTypeError.cfa
r933f32f r6a9d4b4 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 * y;21 *x; // picks B 22 22 *z; 23 23 foo(i); … … 32 32 // bad 33 33 *v; 34 * x; // ambiguous34 *y; 35 35 foo(v); 36 36 baz(v); … … 52 52 void qux(T * y) { 53 53 // okay 54 *y;55 54 bar(y); 56 55 qux(y); … … 59 58 baz(y); 60 59 quux(y); 60 *y; 61 61 } 62 62 -
tests/concurrent/examples/boundedBufferEXT.cfa
r933f32f r6a9d4b4 1 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo3 //4 2 // The contents of this file are covered under the licence agreement in the 5 3 // file "LICENCE" distributed with Cforall. … … 10 8 // Created On : Wed Apr 18 22:52:12 2018 11 9 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:33 201913 // Update Count : 1210 // Last Modified On : Tue Dec 11 21:55:02 2018 11 // Update Count : 9 14 12 // 15 13 16 #include <stdlib.hfa> // random14 #include <stdlib.hfa> // random 17 15 #include <fstream.hfa> 18 16 #include <kernel.hfa> … … 122 120 // Local Variables: // 123 121 // tab-width: 4 // 124 // compile-command: "cfa boundedBufferEXT.c fa" //122 // compile-command: "cfa boundedBufferEXT.c" // 125 123 // End: // -
tests/concurrent/examples/boundedBufferINT.cfa
r933f32f r6a9d4b4 1 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo3 //4 2 // The contents of this file are covered under the licence agreement in the 5 3 // file "LICENCE" distributed with Cforall. … … 10 8 // Created On : Mon Oct 30 12:45:13 2017 11 9 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:52 201913 // Update Count : 8 810 // Last Modified On : Tue Dec 11 21:55:45 2018 11 // Update Count : 84 14 12 // 15 13 16 #include <stdlib.hfa> // random14 #include <stdlib.hfa> // random 17 15 #include <fstream.hfa> 18 16 #include <kernel.hfa> … … 123 121 // Local Variables: // 124 122 // tab-width: 4 // 125 // compile-command: "cfa boundedBufferINT.c fa" //123 // compile-command: "cfa boundedBufferINT.c" // 126 124 // End: // -
tests/concurrent/examples/datingService.cfa
r933f32f r6a9d4b4 1 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo3 //4 2 // The contents of this file are covered under the licence agreement in the 5 3 // file "LICENCE" distributed with Cforall. … … 10 8 // Created On : Mon Oct 30 12:56:20 2017 11 9 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:39 201913 // Update Count : 3110 // Last Modified On : Tue Dec 11 21:55:34 2018 11 // Update Count : 28 14 12 // 15 13 16 #include <stdlib.hfa> // random14 #include <stdlib.hfa> // random 17 15 #include <fstream.hfa> 18 16 #include <kernel.hfa> … … 112 110 // Local Variables: // 113 111 // tab-width: 4 // 114 // compile-command: "cfa datingService.c fa" //112 // compile-command: "cfa datingService.c" // 115 113 // End: // -
tests/concurrent/examples/matrixSum.cfa
r933f32f r6a9d4b4 1 // -*- Mode: C -*- 1 2 // 2 3 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo … … 10 11 // Created On : Mon Oct 9 08:29:28 2017 11 12 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 20 08:37:53 201913 // Update Count : 1 613 // Last Modified On : Tue Dec 11 21:54:55 2018 14 // Update Count : 15 14 15 // 15 16 -
tests/concurrent/examples/quickSort.cfa
r933f32f r6a9d4b4 1 //2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo3 1 // 4 2 // The contents of this file are covered under the licence agreement in the … … 11 9 // Created On : Wed Dec 6 12:15:52 2017 12 10 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Fri Mar 22 13:42:01 201914 // Update Count : 1 7011 // Last Modified On : Sat Dec 22 08:44:27 2018 12 // Update Count : 168 15 13 // 16 14 … … 180 178 // Local Variables: // 181 179 // tab-width: 4 // 182 // compile-command: "cfa quickSort.c fa" //180 // compile-command: "cfa quickSort.c" // 183 181 // End: // -
tests/concurrent/waitfor/parse2.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed Aug 30 17:53:29 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:42:11 201913 // Update Count : 312 // Last Modified On : Wed Aug 30 17:55:17 2017 13 // Update Count : 2 14 14 // 15 15 … … 246 246 // Local Variables: // 247 247 // tab-width: 4 // 248 // compile-command: "cfa waitfor.c fa" //248 // compile-command: "cfa waitfor.c" // 249 249 // End: // -
tests/config.py.in
r933f32f r6a9d4b4 1 #!/usr/bin/env python 31 #!/usr/bin/env python 2 2 # encoding: utf-8 3 3 """ -
tests/coroutine/.expect/fmtLines.txt
r933f32f r6a9d4b4 16 16 difi ed B y : Pete r A. 17 17 Buh r// Last Mod ifie 18 d On : F ri M ar 2 2 1319 : 41: 03 2 019/ / Up date20 Cou nt : 3 3/ /#in18 d On : T ue D ec 1 1 23 19 :31: 12 2 018/ / Up date 20 Cou nt : 32/ /#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 f a" / /// End: //78 s.c" /// / En d: / / -
tests/coroutine/.in/fmtLines.txt
r933f32f r6a9d4b4 10 10 // Created On : Sun Sep 17 21:56:15 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:03 201913 // Update Count : 3 312 // Last Modified On : Tue Dec 11 23:31:12 2018 13 // Update Count : 32 14 14 // 15 15 … … 64 64 // Local Variables: // 65 65 // tab-width: 4 // 66 // compile-command: "cfa fmtLines.c fa" //66 // compile-command: "cfa fmtLines.c" // 67 67 // End: // -
tests/coroutine/fibonacci.cfa
r933f32f r6a9d4b4 10 10 // Created On : Thu Jun 8 07:29:37 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:40:35 201913 // Update Count : 2 612 // Last Modified On : Tue Dec 11 21:57:33 2018 13 // Update Count : 25 14 14 // 15 15 … … 45 45 // Local Variables: // 46 46 // tab-width: 4 // 47 // compile-command: "cfa fibonacci.c fa" //47 // compile-command: "cfa fibonacci.c" // 48 48 // End: // -
tests/coroutine/fibonacci_1.cfa
r933f32f r6a9d4b4 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // fibonacci_1.c fa -- 1-state finite-state machine: precomputed first two states returning f(n - 1)7 // fibonacci_1.c -- 1-state finite-state machine: precomputed first two states returning f(n - 2) 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 hu Mar 21 08:10:45 201913 // Update Count : 2512 // Last Modified On : Tue Dec 11 21:57:54 2018 13 // Update Count : 14 14 14 // 15 15 … … 17 17 #include <coroutine.hfa> 18 18 19 coroutine Fibonacci { int fn1; }; // used for communication19 coroutine Fibonacci { int ret; }; // used for communication 20 20 21 21 void main( Fibonacci & fib ) with( fib ) { // called on first resume 22 int fn; 23 [fn1, fn] = [0, 1]; // precompute first two states 22 int fn, fn1 = 1, fn2 = 0; // precompute first two states 24 23 for () { 24 ret = fn2; 25 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; // general case 25 26 suspend(); // restart last resume 26 [fn1, fn] = [fn, fn1 + fn]; // general case27 27 } // for 28 28 } … … 30 30 int next( Fibonacci & fib ) with( fib ) { 31 31 resume( fib ); // restart last suspend 32 return fn1;32 return ret; 33 33 } 34 34 … … 42 42 // Local Variables: // 43 43 // tab-width: 4 // 44 // compile-command: "cfa fibonacci_1.c fa" //44 // compile-command: "cfa fibonacci_1.c" // 45 45 // End: // -
tests/coroutine/fmtLines.cfa
r933f32f r6a9d4b4 10 10 // Created On : Sun Sep 17 21:56:15 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:16 201913 // Update Count : 5 812 // Last Modified On : Sat Dec 22 18:27:00 2018 13 // Update Count : 57 14 14 // 15 15 … … 63 63 // Local Variables: // 64 64 // tab-width: 4 // 65 // compile-command: "cfa fmtLines.c fa" //65 // compile-command: "cfa fmtLines.c" // 66 66 // End: // -
tests/coroutine/pingpong.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed Sep 20 11:55:23 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Mar 26 17:54:14 201913 // Update Count : 3512 // Last Modified On : Tue Dec 11 21:58:06 2018 13 // Update Count : 29 14 14 // 15 15 … … 20 20 const char * name; 21 21 /* const */ unsigned int N; 22 PingPong ∂22 PingPong * part; 23 23 }; 24 24 25 25 void ?{}( PingPong & this, const char * name, unsigned int N, PingPong & part ) { 26 this.[name, N] = [name, N]; &this.part = ∂ 26 (this.__cor){name}; 27 this.name = name; 28 this.N = N; 29 this.part = ∂ 27 30 } 28 31 void ?{}( PingPong & this, const char * name, unsigned int N ) { 29 this{ name, N, * 0p }; // call first constructor32 this{ name, N, *(PingPong *)0 }; 30 33 } 31 34 void cycle( PingPong & pingpong ) { … … 33 36 } 34 37 void partner( PingPong & this, PingPong & part ) { 35 &this.part = ∂38 this.part = ∂ 36 39 resume( this ); 37 40 } 38 void main( PingPong & pingpong ) with(pingpong) {// ping's starter ::main, pong's starter ping39 for ( N ) {// N ping-pongs40 sout | name;41 cycle( part );41 void main( PingPong & pingpong ) { // ping's starter ::main, pong's starter ping 42 for ( pingpong.N ) { // N ping-pongs 43 sout | pingpong.name; 44 cycle( *pingpong.part ); 42 45 } // for 43 46 } … … 50 53 // Local Variables: // 51 54 // tab-width: 4 // 52 // compile-command: "cfa pingpong.c fa" //55 // compile-command: "cfa pingpong.c" // 53 56 // End: // -
tests/coroutine/prodcons.cfa
r933f32f r6a9d4b4 10 10 // Created On : Mon Sep 18 12:23:39 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:10 201913 // Update Count : 5 412 // Last Modified On : Wed Dec 12 23:04:49 2018 13 // Update Count : 53 14 14 // 15 15 … … 91 91 // Local Variables: // 92 92 // tab-width: 4 // 93 // compile-command: "cfa prodcons.c fa" //93 // compile-command: "cfa prodcons.c" // 94 94 // End: // -
tests/coroutine/runningTotal.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed Dec 6 08:05:27 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:40:49 201913 // Update Count : 512 // Last Modified On : Tue Dec 11 21:59:00 2018 13 // Update Count : 4 14 14 // 15 15 … … 48 48 // Local Variables: // 49 49 // tab-width: 4 // 50 // compile-command: "cfa runningTotal.c fa" //50 // compile-command: "cfa runningTotal.c" // 51 51 // End: // -
tests/declarationSpecifier.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed Aug 17 08:21:04 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 30 18:20:36 201913 // Update Count : 412 // Last Modified On : Tue Nov 6 17:52:59 2018 13 // Update Count : 3 14 14 // 15 15 … … 89 89 90 90 //Dummy main 91 int main( int argc, char const * argv[] ) {} 91 int main(int argc, char const *argv[]) 92 { 93 return 0; 94 } 92 95 93 96 // Local Variables: // -
tests/forall.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed May 9 08:48:15 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Mar 19 08:29:38 201913 // Update Count : 3 212 // Last Modified On : Tue Nov 6 17:53:43 2018 13 // Update Count : 31 14 14 // 15 15 … … 53 53 right = temp; 54 54 } 55 56 void ?{}( int & c, zero_t ) { c = 0; } // not in prelude 55 57 56 58 trait sumable( otype T ) { -
tests/function-operator.cfa
r933f32f r6a9d4b4 10 10 // Created On : Fri Aug 25 15:21:11 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Apr 11 18:27:45 201913 // Update Count : 1012 // Last Modified On : Tue Dec 4 21:37:09 2018 13 // Update Count : 9 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
r933f32f r6a9d4b4 10 10 // Created On : Wed Mar 2 16:56:02 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 4 21:42:47 201913 // Update Count : 11 512 // Last Modified On : Fri Dec 21 16:02:55 2018 13 // Update Count : 114 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 | 0 |1 | 2 | 3;22 sout | ' 0' | '1' | '2' | '3';23 sout | 0 | "" |1 | "" | 2 | "" | 3;21 sout | 1 | 2 | 3; 22 sout | '1' | '2' | '3'; 23 sout | 1 | "" | 2 | "" | 3; 24 24 sout | nl; 25 25 -
tests/io2.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed Mar 2 16:56:02 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Apr 18 08:03:30 201913 // Update Count : 11 312 // Last Modified On : Fri Dec 21 08:20:14 2018 13 // Update Count : 112 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
r933f32f r6a9d4b4 10 10 // Created On : Sat Sep 9 16:34:38 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Feb 12 08:07:39 2019 13 // Update Count : 224 14 // 15 16 #include <features.h> // __GNUC_PREREQ 12 // Last Modified On : Tue Dec 4 21:44:01 2018 13 // Update Count : 139 14 // 15 17 16 #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 >= 7154 // floating with length, gcc f16/f128x unsupported and no prelude code for any _FloatXXx, so they work by conversion to long double155 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 197 153 #ifdef __CFA__ 198 154 // fixed-size length … … 211 167 // octal 212 168 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;169 +01234567_l8; +01234567_l16; +01234567_l32; +01234567_l64; +01234567_l8u; +01234567_ul16; +01234567_l32u; +01234567_ul64; 214 170 -01234567_l8; -01234567_l16; -01234567_l32; -01234567_l64; -01234567_l8u; -01234567_ul16; -01234567_l32u; -01234567_ul64; 215 171 … … 247 203 +0X0123456789ABCDEF_l8; +0X0123456789ABCDEF_l16; +0X0123456789ABCDEFl32; +0X0123456789ABCDEFl64; +0X0123456789ABCDEF_ul8; +0X0123456789ABCDEF_l16u; +0X0123456789ABCDEFul32; +0X0123456789ABCDEFl64u; 248 204 -0X0123456789ABCDEF_l8; -0X0123456789ABCDEF_l16; -0X0123456789ABCDEFl32; -0X0123456789ABCDEFl64; -0X0123456789ABCDEF_ul8; -0X0123456789ABCDEF_l16u; -0X0123456789ABCDEFul32; -0X0123456789ABCDEFl64u; 205 206 // floating 207 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; 249 231 250 232 // char, short, int suffix overloading -
tests/loopctrl.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed Aug 8 18:32:59 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S at Apr 13 11:03:09 201913 // Update Count : 10412 // Last Modified On : Sun Dec 23 23:00:29 2018 13 // Update Count : 79 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 ;56 for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; } sout | nl | nl | nl; 57 57 58 // @ means do nothing59 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 86 58 enum { N = 10 }; 87 59 for ( N ) { sout | "N"; } sout | nl; 88 60 for ( i; N ) { sout | i; } sout | nl; 89 for ( i; N -~ 0 ) { sout | i; } sout | nl | nl ;61 for ( i; N -~ 0 ) { sout | i; } sout | nl | nl | nl; 90 62 91 63 const int start = 3, comp = 10, inc = 2; 92 64 for ( i; start ~ comp ~ inc + 1 ) { sout | i; } sout | nl | nl; 93 65 66 sout | nl; 94 67 for ( S s = (S){0}; s < (S){10,10}; s += (S){1} ) { sout | s; } sout | nl; 95 68 for ( s; (S){10,10} ) { sout | s; } sout | nl; … … 103 76 for ( s; (S){10,10} -~ (S){0} ~ (S){1} ) { sout | s; } sout | nl; 104 77 for ( s; (S){10,10} -~= (S){0} ) { 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; 78 for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl; 120 79 } 121 80 -
tests/math1.cfa
r933f32f r6a9d4b4 10 10 // Created On : Fri Apr 22 14:59:21 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 25 22:56:47 201913 // Update Count : 10912 // Last Modified On : Wed Dec 12 16:28:49 2018 13 // Update Count : 89 14 14 // 15 15 … … 49 49 unsigned int e = 2; 50 50 b \= e; 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); 51 sout | "\\" | b | b \ e; 52 sout | "\\" | 'a' \ 3u | 2 \ 8u | 4 \ 3u | -4 \ 3u | nonl; 54 53 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;66 54 } // main 67 55 -
tests/numericConstants.cfa
r933f32f r6a9d4b4 10 10 // Created On : Wed May 24 22:10:36 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Feb 5 08:58:16 201913 // Update Count : 512 // Last Modified On : Tue Nov 6 17:59:53 2018 13 // Update Count : 3 14 14 // 15 15 … … 67 67 // Local Variables: // 68 68 // tab-width: 4 // 69 // compile-command: "cfa numericConstants.cfa" //69 // compile-command: "cfa minmax.cfa" // 70 70 // End: // -
tests/pybin/settings.py
r933f32f r6a9d4b4 1 from __future__ import print_function 2 1 3 import os 2 import subprocess3 4 import sys 4 from .import tools5 import tools 5 6 6 7 try : … … 38 39 def __init__(self, arch): 39 40 try: 40 canonical_host = Architecture.make _canonical( config.HOSTARCH )41 canonical_host = Architecture.makeCanonical( config.HOSTARCH ) 41 42 except KeyError: 42 43 print("Unkown host architecture %s" % config.HOSTARCH, file=sys.stderr) … … 45 46 if arch: 46 47 try: 47 arch = Architecture.make _canonical( arch )48 arch = Architecture.makeCanonical( arch ) 48 49 except KeyError: 49 50 print("Unkown architecture %s" % arch, file=sys.stderr) … … 76 77 77 78 @classmethod 78 def make _canonical(_, arch):79 def makeCanonical(_, arch): 79 80 return Architecture.KnownArchitectures[arch] 80 81 … … 83 84 def __init__(self, value): 84 85 self.string = "debug" if value else "no debug" 85 self.flags = """DEBUG_FLAGS= %s""" % ("-debug -O0" if value else "-nodebug -O2")86 self.flags = """DEBUG_FLAGS="%s" """ % ("-debug -O0" if value else "-nodebug -O2") 86 87 87 88 class Install: 88 89 def __init__(self, value): 89 90 self.string = "installed" if value else "in-tree" 90 self.flags = """INSTALL_FLAGS= %s""" % ("" if value else "-in-tree")91 self.flags = """INSTALL_FLAGS="%s" """ % ("" if value else "-in-tree") 91 92 92 93 class Timeouts: … … 111 112 global install 112 113 global timeout 113 global output_width114 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) 122 output_width = 24 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) 123 122 124 123 125 def update _make_cmd(force, jobs):124 def updateMakeCmd(force, jobs): 126 125 global make 127 126 128 make = ['make'] if not force else ['make', "-j%i" % jobs]127 make = "make" if not force else ("make -j%i" % jobs) 129 128 130 129 def validate(): 131 130 errf = os.path.join(BUILDDIR, ".validate.err") 132 make_ret, out = tools.make( ".validate", error_file = errf, output=subprocess.DEVNULL, error=subprocess.DEVNULL)131 make_ret, _ = tools.make( ".validate", error_file = errf, redirects = "2> /dev/null 1> /dev/null", ) 133 132 if make_ret != 0: 134 133 with open (errf, "r") as myfile: … … 140 139 141 140 tools.rm(errf) 142 143 def prep_output(tests):144 global output_width145 output_width = max(map(lambda t: len(t.target()), tests)) -
tests/pybin/test_run.py
r933f32f r6a9d4b4 4 4 5 5 import pybin.settings 6 import datetime 7 8 from string import Template 9 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) 6 18 7 19 # Test class that defines what a test is -
tests/pybin/tools.py
r933f32f r6a9d4b4 1 from __future__ import print_function 2 1 3 import __main__ 2 4 import argparse 3 import contextlib4 5 import fileinput 5 6 import multiprocessing … … 9 10 import signal 10 11 import stat 11 import subprocess12 12 import sys 13 import tempfile14 13 import time 15 import types16 14 17 15 from pybin import settings 16 from subprocess import Popen, PIPE, STDOUT 18 17 19 18 ################################################################################ … … 22 21 23 22 # helper functions to run terminal commands 24 def sh(*cmd, timeout = False, output = None, input = None, error = subprocess.STDOUT): 25 cmd = list(cmd) 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 26 27 27 28 # if this is a dry_run, only print the commands that would be ran 28 29 if settings.dry_run : 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) 30 print("cmd: %s" % cmd) 43 31 return 0, None 44 32 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) 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 67 38 68 39 def is_ascii(fname): … … 74 45 return False 75 46 76 code, out = sh("file %s" % fname, output=subprocess.PIPE)47 code, out = sh("file %s" % fname, print2stdout = False) 77 48 if code != 0: 78 49 return False … … 84 55 85 56 return match.group(1).startswith("ASCII text") 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 file93 94 if isinstance(file, int):95 return file96 97 if checkfile and not os.path.isfile(file):98 return None99 100 file = open(file, mode)101 exitstack.push(file)102 return file103 57 104 58 # Remove 1 or more files silently 105 59 def rm( files ): 106 if isinstance(files, str ): files = [ files ] 107 for file in files: 108 sh( 'rm', '-f', file, output=subprocess.DEVNULL, error=subprocess.DEVNULL ) 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 ) 109 65 110 66 # Create 1 or more directory 111 67 def mkdir( files ): 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)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) ) 117 73 118 74 … … 124 80 # diff two files 125 81 def diff( lhs, rhs ): 82 # diff the output of the files 83 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 126 100 # fetch return code and error from the diff command 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 ) 101 return sh(diff_cmd % (lhs, rhs), False) 141 102 142 103 # call make 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 None145 cmd = [146 *settings.make,147 '-s' if silent else None,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 '', 148 109 test_param, 149 110 settings.arch.flags, … … 151 112 settings.install.flags, 152 113 flags, 153 target 154 ]155 cmd = [s for s in cmd if s]156 return sh( *cmd, output=output, error=error)114 target, 115 redirects 116 ]) 117 return sh(cmd) 157 118 158 119 def which(program): 120 import os 121 def is_exe(fpath): 122 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 123 159 124 fpath, fname = os.path.split(program) 160 125 if fpath: … … 169 134 return None 170 135 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) 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 180 139 181 140 ################################################################################ … … 184 143 # move a file 185 144 def mv(source, dest): 186 ret, _ = sh("mv ", source, dest)145 ret, _ = sh("mv %s %s" % (source, dest)) 187 146 return ret 188 147 189 148 # cat one file into the other 190 149 def cat(source, dest): 191 ret, _ = sh("cat ", source, output=dest)150 ret, _ = sh("cat %s > %s" % (source, dest)) 192 151 return ret 193 152 … … 204 163 205 164 # helper function to check if a files contains only a specific string 206 def file _contains_only(file, text) :165 def fileContainsOnly(file, text) : 207 166 with open(file) as f: 208 167 ff = f.read().strip() 209 168 result = ff == text.strip() 210 169 211 return result 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 212 182 213 183 # transform path to canonical form 214 def canonical _path(path):184 def canonicalPath(path): 215 185 abspath = os.path.abspath(__main__.__file__) 216 186 dname = os.path.dirname(abspath) … … 218 188 219 189 # compare path even if form is different 220 def path _cmp(lhs, rhs):221 return canonical _path( lhs ) == canonical_path( rhs )190 def pathCmp(lhs, rhs): 191 return canonicalPath( lhs ) == canonicalPath( rhs ) 222 192 223 193 # walk all files in a path 224 def path_walk( op ): 225 dname = settings.SRCDIR 226 for dirname, _, names in os.walk(dname): 194 def pathWalk( op ): 195 def step(_, dirname, names): 227 196 for name in names: 228 197 path = os.path.join(dirname, name) 229 198 op( path ) 230 199 200 # Start the walk 201 dname = settings.SRCDIR 202 os.path.walk(dname, step, '') 203 231 204 ################################################################################ 232 205 # system 233 206 ################################################################################ 234 207 # count number of jobs to create 235 def job _count( options, tests ):208 def jobCount( options, tests ): 236 209 # check if the user already passed in a number of jobs for multi-threading 237 210 if not options.jobs: … … 255 228 return min( options.jobs, len(tests) ), force 256 229 230 # setup a proper processor pool with correct signal handling 231 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 pool 237 238 # handle signals in scope 239 class SignalHandling(): 240 def __enter__(self): 241 # enable signal handling 242 signal.signal(signal.SIGINT, signal.SIG_DFL) 243 244 def __exit__(self, type, value, traceback): 245 # disable signal handling 246 signal.signal(signal.SIGINT, signal.SIG_IGN) 247 248 257 249 # enable core dumps for all the test children 258 250 resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY)) … … 269 261 return False 270 262 raise argparse.ArgumentTypeError(msg) 263 return False 271 264 272 265 def fancy_print(text): 273 266 column = which('column') 274 267 if column: 275 subprocess.run(column, input=bytes(text + "\n", "UTF-8")) 268 cmd = "%s 2> /dev/null" % column 269 proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True) 270 proc.communicate(input=text + "\n") 276 271 else: 277 272 print(text) 278 273 279 274 280 def core_info(path): 281 if not os.path.isfile(path): 282 return 1, "ERR Executable path is wrong" 283 275 def coreInfo(path): 284 276 cmd = os.path.join(settings.SRCDIR, "pybin/print-core.gdb") 285 277 if not os.path.isfile(cmd): 286 278 return 1, "ERR Printing format for core dumps not found" 287 279 288 core = os.path.join(os.getcwd(), "core" ) 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" 289 284 290 285 if not os.path.isfile(core): 291 286 return 1, "ERR No core dump" 292 287 293 return sh( 'gdb', '-n', path, core, '-batch', '-x', cmd, output=subprocess.PIPE)288 return sh("gdb -n %s %s -batch -x %s" % (path, core, cmd), print2stdout=False) 294 289 295 290 class Timed: -
tests/raii/.expect/ctor-autogen-ERR1.txt
r933f32f r6a9d4b4 1 raii/ctor-autogen.cfa:102:1 error: Unique best alternative includes deleted identifier in GeneratedCast of:1 raii/ctor-autogen.cfa:102:1 error: Unique best alternative includes deleted identifier in Cast of: 2 2 Application of 3 3 Deleted Expression … … 27 27 28 28 ... to arguments 29 GeneratedCast of:29 Cast of: 30 30 Member Expression, with field: 31 31 x: signed int 32 32 ... from aggregate: 33 GeneratedCast of:33 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 GeneratedCast of:39 Cast of: 40 40 constant expression (0 0: zero_t) 41 41 ... to: … … 48 48 49 49 ... to arguments 50 GeneratedCast of:50 Cast of: 51 51 Variable Expression: x: instance of struct Managed with body 1 52 52 ... to: -
tests/raii/init_once.cfa
r933f32f r6a9d4b4 10 10 // Created On : Tue Jun 14 15:43:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:26 201913 // Update Count : 412 // Last Modified On : Sat Jul 9 11:30:29 2016 13 // Update Count : 3 14 14 // 15 15 … … 192 192 // Local Variables: // 193 193 // tab-width: 4 // 194 // compile-command: "cfa init_once.c fa" //194 // compile-command: "cfa init_once.c" // 195 195 // End: // -
tests/rational.cfa
r933f32f r6a9d4b4 10 10 // Created On : Mon Mar 28 08:43:12 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Mar 27 07:37:17 201913 // Update Count : 8012 // Last Modified On : Tue Dec 4 21:46:42 2018 13 // Update Count : 69 14 14 // 15 15 … … 19 19 #include <fstream.hfa> 20 20 21 // UNNECESSARY, FIX ME 22 void ?{}( int & this ) { this = 0; } 23 void ?{}( int & this, zero_t ) { this = 0; } 24 void ?{}( int & this, one_t ) { this = 1; } 21 25 double convert( int i ) { return (double)i; } 22 26 int convert( double d ) { return (int)d; } … … 54 58 sout | a * b; 55 59 sout | a / b; 56 // sout | a \ 2 | b \ 2; // FIX ME57 // sout | a \ -2 | b \ -2;58 60 59 61 sout | "conversion"; -
tests/sum.cfa
r933f32f r6a9d4b4 11 11 // Created On : Wed May 27 17:56:53 2015 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Sun May 19 11:21:02 201914 // Update Count : 33013 // Last Modified On : Sun Dec 23 23:00:38 2018 14 // Update Count : 287 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 prelude 19 21 20 22 trait sumable( otype T ) { … … 29 31 T sum( size_t size, T a[] ) { 30 32 T total = 0; // initialize by 0 constructor 31 for ( i; size)33 for ( size_t i = 0; i < size; i += 1 ) 32 34 total += a[i]; // select appropriate + 33 35 return total; 34 36 } // sum 35 37 38 // Not in prelude. 39 unsigned char ?+?( unsigned char t1, unsigned char t2 ) { return (int)t1 + t2; } // cast forces integer addition, otherwise recursion 40 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 36 49 int main( void ) { 37 50 const int low = 5, High = 15, size = High - low; 38 51 39 signed char s = 0, a[size], v = (char)low;40 for ( int i = 0; i < size; i += 1, v += 1 hh) {52 unsigned char s = 0, a[size], v = (char)low; 53 for ( int i = 0; i < size; i += 1, v += 1 ) { 41 54 s += v; 42 55 a[i] = v; 43 56 } // for 44 57 sout | "sum from" | low | "to" | High | "is" 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; 58 | sum( size, (unsigned char *)a ) | ", check" | (int)s; 62 59 63 60 int s = 0, a[size], v = low; -
tests/test.py
r933f32f r6a9d4b4 1 #!/usr/bin/python3 1 #!/usr/bin/python 2 from __future__ import print_function 2 3 3 4 from pybin.tools import * … … 8 9 import re 9 10 import sys 10 import tempfile11 11 import time 12 12 … … 15 15 ################################################################################ 16 16 17 def find _tests():17 def findTests(): 18 18 expected = [] 19 19 20 def match _test(path):20 def matchTest(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( match_test )30 pathWalk( matchTest ) 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 listTests( includes, excludes ): 36 36 # tests directly in the .expect folder will always be processed 37 test_list = find _tests()37 test_list = findTests() 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 validTests( 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 = canonicalPath( testname ) 62 62 if Test.valid_name(testname): 63 found = [test for test in all _tests if canonical_path( test.target() ) == testname]63 found = [test for test in allTests if canonicalPath( 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 path_cmp( t.target(), testname )]71 test = [t for t in allTests if pathCmp( t.target(), testname )] 72 72 73 73 if test : … … 79 79 80 80 # parses the option 81 def parse_args():81 def getOptions(): 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 no_rule(file, target): 127 return not settings.dry_run and file_contains_only(file, "make: *** No rule to make target `%s'. Stop." % target) 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) 128 131 129 132 # logic to run a single test and return the result (No handling of printing or other test framework logic) … … 142 145 # build, skipping to next test on error 143 146 with Timed() as comp_dur: 144 make_ret, _ = make( test.target(), output=subprocess.DEVNULL, error=out_file, error_file = err_file ) 145 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 146 150 run_dur = None 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 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) 170 156 else : 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 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 180 181 181 182 … … 188 189 # run a single test and handle the errors, outputs, printing, exception handling, etc. 189 190 def run_test_worker(t) : 190 try : 191 192 with SignalHandling(): 191 193 # print formated name 192 name_txt = '{0:{width}} '.format(t.target(), width=settings.output_width)194 name_txt = "%24s " % t.name 193 195 194 196 retcode, error, duration = run_single_test(t) … … 198 200 199 201 #print result with error if needed 200 text = '\t' +name_txt + result_txt202 text = name_txt + result_txt 201 203 out = sys.stdout 202 204 if error : 203 text = text + '\n'+ error205 text = text + "\n" + error 204 206 out = sys.stderr 205 207 … … 208 210 sys.stderr.flush() 209 211 210 return retcode != TestResult.SUCCESS 211 except KeyboardInterrupt: 212 False 212 return retcode != TestResult.SUCCESS 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', output=subprocess.DEVNULL, error=subprocess.DEVNULL)217 make('clean', redirects = '> /dev/null 2>&1') 218 218 219 219 # create the executor for our jobs and handle the signal properly 220 pool = multiprocessing.Pool(jobs)220 pool = setupPool(jobs) 221 221 222 222 # for each test to run … … 233 233 234 234 # clean the workspace 235 make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)235 make('clean', redirects = '> /dev/null 2>&1') 236 236 237 237 for failed in results: … … 248 248 249 249 # parse the command line arguments 250 options = parse_args()250 options = getOptions() 251 251 252 252 # init global settings … … 254 254 255 255 # fetch the liest of all valid tests 256 all _tests = list_tests( options.include, options.exclude )256 allTests = listTests( 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 = allTests 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 = validTests( 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: t.toString(), tests)))283 fancy_print("\n".join(map(lambda t: "%s" % (t.toString()), tests))) 284 284 285 285 else : 286 286 # check the build configuration works 287 settings.prep_output(tests)288 287 settings.validate() 289 288 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, 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', 297 294 settings.arch.string, 298 settings.debug.string 295 settings.debug.string, 296 options.jobs 299 297 )) 300 298 -
tests/warnings/.expect/self-assignment.txt
r933f32f r6a9d4b4 1 warnings/self-assignment.cfa:29:1 warning: self assignment of expression: GeneratedCast of:1 warnings/self-assignment.cfa:29:1 warning: self assignment of expression: 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: GeneratedCast of:5 warnings/self-assignment.cfa:30:1 warning: self assignment of expression: 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: GeneratedCast of:9 warnings/self-assignment.cfa:31:1 warning: self assignment of expression: 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: GeneratedCast of:16 warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Cast of: 17 17 Member Expression, with field: 18 18 i: signed int -
tests/warnings/self-assignment.cfa
r933f32f r6a9d4b4 9 9 // Author : Rob Schluntz 10 10 // Created On : Thu Mar 1 13:53:57 2018 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Wed Feb 20 07:56:17 201913 // Update Count : 311 // Last Modified By : Rob Schluntz 12 // Last Modified On : Thu Mar 1 13:53:57 2018 13 // Update Count : 2 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
r933f32f r6a9d4b4 194 194 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 195 195 ACLOCAL = @ACLOCAL@ 196 ALLOCA = @ALLOCA@ 196 197 AMTAR = @AMTAR@ 197 198 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -
tools/PrettyGitLogs.sh
r933f32f r6a9d4b4 27 27 git rev-list --format=short ${GitOldRef}...${GitNewRef} > ${GIT_LOG} 28 28 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}29 git diff --stat ${GitNewRef} ${GitOldRef} > ${GIT_DIFF} -
tools/prettyprinter/Makefile.in
r933f32f r6a9d4b4 223 223 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 224 224 ACLOCAL = @ACLOCAL@ 225 ALLOCA = @ALLOCA@ 225 226 AMTAR = @AMTAR@ 226 227 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
Note:
See TracChangeset
for help on using the changeset viewer.