Changes in / [fc12f05:0030b508]
- Files:
-
- 117 added
- 8 deleted
- 134 edited
-
doc/bibliography/pl.bib (modified) (3 diffs)
-
driver/as.cc (modified) (3 diffs)
-
libcfa/prelude/Makefile.am (modified) (5 diffs)
-
libcfa/prelude/bootloader.cf (added)
-
libcfa/prelude/bootloader.cfa (deleted)
-
libcfa/prelude/prelude.old.cf (added)
-
libcfa/prelude/prelude.old.cfa (deleted)
-
libcfa/prelude/prototypes.awk (modified) (2 diffs)
-
libcfa/prelude/sync-builtins.cf (added)
-
libcfa/prelude/sync-builtins.cfa (deleted)
-
libcfa/src/Makefile.am (modified) (3 diffs)
-
libcfa/src/collections/string.cfa (modified) (2 diffs)
-
libcfa/src/collections/string_res.cfa (modified) (5 diffs)
-
libcfa/src/concurrency/channel.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/cofor.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/cofor.hfa (modified) (3 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (1 diff)
-
libcfa/src/concurrency/locks.hfa (modified) (1 diff)
-
libcfa/src/fstream.cfa (modified) (3 diffs)
-
libcfa/src/fstream.hfa (modified) (2 diffs)
-
libcfa/src/iostream.cfa (modified) (30 diffs)
-
libcfa/src/iostream.hfa (modified) (10 diffs)
-
src/AST/Convert.cpp (added)
-
src/AST/Convert.hpp (added)
-
src/AST/Decl.hpp (modified) (6 diffs)
-
src/AST/Fwd.hpp (modified) (1 diff)
-
src/AST/Node.cpp (modified) (1 diff)
-
src/AST/Pass.cpp (modified) (1 diff)
-
src/AST/Pass.hpp (modified) (1 diff)
-
src/AST/Pass.impl.hpp (modified) (1 diff)
-
src/AST/Print.cpp (modified) (1 diff)
-
src/AST/Stmt.hpp (modified) (7 diffs)
-
src/AST/Type.hpp (modified) (1 diff)
-
src/AST/Visitor.hpp (modified) (1 diff)
-
src/AST/module.mk (modified) (1 diff)
-
src/BasicTypes-gen.cc (modified) (11 diffs)
-
src/CodeGen/CodeGenerator.cc (added)
-
src/CodeGen/CodeGenerator.h (added)
-
src/CodeGen/CodeGeneratorNew.cpp (deleted)
-
src/CodeGen/CodeGeneratorNew.hpp (deleted)
-
src/CodeGen/FixMain.cc (modified) (7 diffs)
-
src/CodeGen/FixMain.h (modified) (2 diffs)
-
src/CodeGen/FixMain2.cc (added)
-
src/CodeGen/FixNames.cc (modified) (3 diffs)
-
src/CodeGen/FixNames.h (modified) (2 diffs)
-
src/CodeGen/GenType.cc (modified) (1 diff)
-
src/CodeGen/GenType.h (modified) (2 diffs)
-
src/CodeGen/Generate.cc (modified) (1 diff)
-
src/CodeGen/Generate.h (modified) (1 diff)
-
src/CodeGen/LinkOnce.cc (modified) (2 diffs)
-
src/CodeGen/LinkOnce.h (modified) (2 diffs)
-
src/CodeGen/OperatorTable.cc (modified) (1 diff)
-
src/CodeGen/OperatorTable.h (modified) (2 diffs)
-
src/CodeGen/module.mk (modified) (1 diff)
-
src/CodeTools/DeclStats.cc (added)
-
src/CodeTools/DeclStats.h (added)
-
src/CodeTools/ResolvProtoDump.cc (added)
-
src/CodeTools/ResolvProtoDump.h (added)
-
src/CodeTools/TrackLoc.cc (added)
-
src/CodeTools/TrackLoc.h (added)
-
src/CodeTools/module.mk (added)
-
src/Common/CodeLocationTools.cpp (modified) (1 diff)
-
src/Common/Eval.cc (modified) (2 diffs)
-
src/Common/Eval.h (modified) (1 diff)
-
src/Common/Examine.cc (modified) (3 diffs)
-
src/Common/Examine.h (modified) (2 diffs)
-
src/Common/PassVisitor.cc (added)
-
src/Common/PassVisitor.h (added)
-
src/Common/PassVisitor.impl.h (added)
-
src/Common/PassVisitor.proto.h (added)
-
src/Common/UniqueName.cc (modified) (2 diffs)
-
src/Common/UniqueName.h (modified) (2 diffs)
-
src/Common/module.mk (modified) (1 diff)
-
src/Concurrency/Corun.cpp (modified) (2 diffs)
-
src/Concurrency/Keywords.cc (added)
-
src/Concurrency/Waitfor.cc (added)
-
src/Concurrency/module.mk (modified) (1 diff)
-
src/ControlStruct/ExceptDecl.cc (added)
-
src/ControlStruct/ExceptTranslate.cc (added)
-
src/ControlStruct/ForExprMutator.cc (added)
-
src/ControlStruct/ForExprMutator.h (added)
-
src/ControlStruct/LabelFixer.cc (added)
-
src/ControlStruct/LabelFixer.h (added)
-
src/ControlStruct/LabelGenerator.cc (added)
-
src/ControlStruct/LabelGenerator.h (added)
-
src/ControlStruct/MLEMutator.cc (added)
-
src/ControlStruct/MLEMutator.h (added)
-
src/ControlStruct/Mutate.cc (added)
-
src/ControlStruct/Mutate.h (added)
-
src/ControlStruct/module.mk (modified) (1 diff)
-
src/GenPoly/Box.cc (added)
-
src/GenPoly/BoxNew.cpp (modified) (26 diffs)
-
src/GenPoly/FindFunction.cc (modified) (4 diffs)
-
src/GenPoly/FindFunction.h (modified) (1 diff)
-
src/GenPoly/GenPoly.cc (modified) (22 diffs)
-
src/GenPoly/GenPoly.h (modified) (3 diffs)
-
src/GenPoly/InstantiateGeneric.cc (added)
-
src/GenPoly/Lvalue.cc (added)
-
src/GenPoly/ScrubTyVars.cc (modified) (1 diff)
-
src/GenPoly/ScrubTyVars.h (modified) (1 diff)
-
src/GenPoly/Specialize.cc (added)
-
src/GenPoly/SpecializeNew.cpp (modified) (2 diffs)
-
src/GenPoly/module.mk (modified) (2 diffs)
-
src/InitTweak/FixGlobalInit.cc (modified) (4 diffs)
-
src/InitTweak/FixInit.cc (added)
-
src/InitTweak/FixInitNew.cpp (modified) (3 diffs)
-
src/InitTweak/GenInit.cc (modified) (4 diffs)
-
src/InitTweak/GenInit.h (modified) (1 diff)
-
src/InitTweak/InitTweak.cc (modified) (19 diffs)
-
src/InitTweak/InitTweak.h (modified) (3 diffs)
-
src/InitTweak/module.mk (modified) (1 diff)
-
src/MakeLibCfa.cc (added)
-
src/MakeLibCfa.h (modified) (1 diff)
-
src/Makefile.am (modified) (3 diffs)
-
src/Parser/RunParser.cpp (modified) (1 diff)
-
src/Parser/StatementNode.cc (modified) (1 diff)
-
src/Parser/StatementNode.h (modified) (1 diff)
-
src/Parser/parser.yy (modified) (8 diffs)
-
src/ResolvExpr/AdjustExprType.cc (modified) (1 diff)
-
src/ResolvExpr/Alternative.cc (added)
-
src/ResolvExpr/Alternative.h (added)
-
src/ResolvExpr/AlternativeFinder.cc (added)
-
src/ResolvExpr/AlternativeFinder.h (added)
-
src/ResolvExpr/AlternativePrinter.cc (added)
-
src/ResolvExpr/AlternativePrinter.h (added)
-
src/ResolvExpr/CandidateFinder.cpp (modified) (2 diffs)
-
src/ResolvExpr/CastCost.cc (modified) (3 diffs)
-
src/ResolvExpr/CommonType.cc (modified) (5 diffs)
-
src/ResolvExpr/CommonType.hpp (modified) (1 diff)
-
src/ResolvExpr/ConversionCost.cc (modified) (6 diffs)
-
src/ResolvExpr/ConversionCost.h (modified) (2 diffs)
-
src/ResolvExpr/CurrentObject.cc (modified) (4 diffs)
-
src/ResolvExpr/ExplodedActual.cc (added)
-
src/ResolvExpr/ExplodedActual.h (added)
-
src/ResolvExpr/FindOpenVars.cc (modified) (1 diff)
-
src/ResolvExpr/FindOpenVars.h (modified) (2 diffs)
-
src/ResolvExpr/Occurs.cc (added)
-
src/ResolvExpr/PolyCost.cc (modified) (1 diff)
-
src/ResolvExpr/PtrsAssignable.cc (modified) (1 diff)
-
src/ResolvExpr/PtrsCastable.cc (modified) (1 diff)
-
src/ResolvExpr/RenameVars.cc (modified) (4 diffs)
-
src/ResolvExpr/RenameVars.h (modified) (2 diffs)
-
src/ResolvExpr/ResolveAssertions.cc (added)
-
src/ResolvExpr/ResolveAssertions.h (added)
-
src/ResolvExpr/ResolveTypeof.cc (modified) (2 diffs)
-
src/ResolvExpr/Resolver.cc (modified) (4 diffs)
-
src/ResolvExpr/SatisfyAssertions.cpp (modified) (2 diffs)
-
src/ResolvExpr/SpecCost.cc (modified) (1 diff)
-
src/ResolvExpr/TypeEnvironment.cc (added)
-
src/ResolvExpr/TypeEnvironment.h (added)
-
src/ResolvExpr/Unify.cc (modified) (4 diffs)
-
src/ResolvExpr/Unify.h (modified) (3 diffs)
-
src/ResolvExpr/module.mk (modified) (5 diffs)
-
src/ResolvExpr/typeops.h (modified) (3 diffs)
-
src/SymTab/Autogen.cc (added)
-
src/SymTab/Autogen.h (added)
-
src/SymTab/Demangle.cc (modified) (3 diffs)
-
src/SymTab/Demangle.h (modified) (2 diffs)
-
src/SymTab/FixFunction.cc (modified) (1 diff)
-
src/SymTab/FixFunction.h (modified) (2 diffs)
-
src/SymTab/Indexer.cc (added)
-
src/SymTab/Indexer.h (added)
-
src/SymTab/Mangler.cc (modified) (9 diffs)
-
src/SymTab/Mangler.h (modified) (2 diffs)
-
src/SymTab/ManglerCommon.cc (modified) (4 diffs)
-
src/SymTab/Validate.cc (added)
-
src/SymTab/Validate.h (added)
-
src/SymTab/ValidateType.cc (added)
-
src/SymTab/ValidateType.h (added)
-
src/SymTab/demangler.cc (modified) (1 diff)
-
src/SymTab/module.mk (modified) (1 diff)
-
src/SynTree/AddressExpr.cc (added)
-
src/SynTree/AggregateDecl.cc (added)
-
src/SynTree/ApplicationExpr.cc (added)
-
src/SynTree/ArrayType.cc (added)
-
src/SynTree/AttrType.cc (added)
-
src/SynTree/Attribute.cc (added)
-
src/SynTree/Attribute.h (added)
-
src/SynTree/BaseSyntaxNode.cc (added)
-
src/SynTree/BaseSyntaxNode.h (added)
-
src/SynTree/BasicType.cc (added)
-
src/SynTree/CommaExpr.cc (added)
-
src/SynTree/CompoundStmt.cc (added)
-
src/SynTree/Constant.cc (added)
-
src/SynTree/Constant.h (added)
-
src/SynTree/DeclReplacer.cc (added)
-
src/SynTree/DeclReplacer.h (added)
-
src/SynTree/DeclStmt.cc (added)
-
src/SynTree/Declaration.cc (added)
-
src/SynTree/Declaration.h (added)
-
src/SynTree/DeclarationWithType.cc (added)
-
src/SynTree/Expression.cc (added)
-
src/SynTree/Expression.h (added)
-
src/SynTree/FunctionDecl.cc (added)
-
src/SynTree/FunctionType.cc (added)
-
src/SynTree/Initializer.cc (added)
-
src/SynTree/Initializer.h (added)
-
src/SynTree/InlineMemberDecl.cc (added)
-
src/SynTree/Label.h (added)
-
src/SynTree/LinkageSpec.cc (added)
-
src/SynTree/LinkageSpec.h (added)
-
src/SynTree/Makefile (added)
-
src/SynTree/Mutator.h (added)
-
src/SynTree/NamedTypeDecl.cc (added)
-
src/SynTree/ObjectDecl.cc (added)
-
src/SynTree/PointerType.cc (added)
-
src/SynTree/ReferenceToType.cc (added)
-
src/SynTree/ReferenceType.cc (added)
-
src/SynTree/Statement.cc (added)
-
src/SynTree/Statement.h (added)
-
src/SynTree/SynTree.h (added)
-
src/SynTree/TupleExpr.cc (added)
-
src/SynTree/TupleType.cc (added)
-
src/SynTree/Type.cc (added)
-
src/SynTree/Type.h (added)
-
src/SynTree/TypeDecl.cc (added)
-
src/SynTree/TypeExpr.cc (added)
-
src/SynTree/TypeSubstitution.cc (added)
-
src/SynTree/TypeSubstitution.h (added)
-
src/SynTree/TypeofType.cc (added)
-
src/SynTree/VarArgsType.cc (added)
-
src/SynTree/Visitor.h (added)
-
src/SynTree/VoidType.cc (added)
-
src/SynTree/ZeroOneType.cc (added)
-
src/SynTree/module.mk (added)
-
src/Tuples/Explode.cc (modified) (1 diff)
-
src/Tuples/Explode.h (modified) (2 diffs)
-
src/Tuples/TupleAssignment.cc (modified) (3 diffs)
-
src/Tuples/TupleExpansion.cc (modified) (2 diffs)
-
src/Tuples/Tuples.cc (modified) (3 diffs)
-
src/Tuples/Tuples.h (modified) (2 diffs)
-
src/Validate/FindSpecialDecls.cc (added)
-
src/Validate/FindSpecialDecls.h (modified) (2 diffs)
-
src/Validate/FixReturnTypes.cpp (modified) (1 diff)
-
src/Validate/HandleAttributes.cc (added)
-
src/Validate/HandleAttributes.h (added)
-
src/Validate/module.mk (modified) (2 diffs)
-
src/Virtual/ExpandCasts.cc (modified) (4 diffs)
-
src/Virtual/Tables.cc (modified) (7 diffs)
-
src/Virtual/Tables.h (modified) (6 diffs)
-
src/main.cc (modified) (17 diffs)
-
tests/.expect/attr-priority.txt (deleted)
-
tests/attr-priority.cfa (deleted)
-
tests/collections/.expect/string-istream-manip.txt (modified) (2 diffs)
-
tests/collections/string-istream-manip.cfa (modified) (7 diffs)
-
tests/concurrency/actors/.expect/dynamic.txt (modified) (1 diff)
-
tests/concurrency/actors/.expect/static.txt (modified) (1 diff)
-
tests/concurrency/actors/dynamic.cfa (modified) (1 diff)
-
tests/concurrency/actors/static.cfa (modified) (1 diff)
-
tests/concurrency/cofor.cfa (modified) (2 diffs)
-
tests/concurrency/waitfor/parse.cfa (modified) (2 diffs)
-
tests/concurrency/waituntil/channel_close.cfa (modified) (2 diffs)
-
tests/genericUnion.cfa (modified) (2 diffs)
-
tests/in-demangle.txt (deleted)
-
tests/io/.expect/manipulatorsInput.arm64.txt (modified) (1 diff)
-
tests/io/.expect/manipulatorsInput.x64.txt (modified) (1 diff)
-
tests/io/.expect/manipulatorsInput.x86.txt (modified) (1 diff)
-
tests/io/.expect/manipulatorsOutput4.txt (modified) (1 diff)
-
tests/io/manipulatorsOutput4.cfa (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
doc/bibliography/pl.bib
rfc12f05 r0030b508 4108 4108 } 4109 4109 4110 @article{Buhr2 3,4110 @article{Buhr22, 4111 4111 contributer = {pabuhr@plg}, 4112 4112 author = {Peter A. Buhr and Colby A. Parsons and Thierry Delisle and He Nan Li}, … … 4114 4114 journal = spe, 4115 4115 year = 2023, 4116 month = dec, 4117 volume = 53, 4118 number = 12, 4119 pages = {2463-2500}, 4120 note = {\url{https://onlinelibrary.wiley.com/doi/10.1002/spe.3262}, 4116 month = sep, 4117 note = {\url{https://onlinelibrary.wiley.com/doi/pdf/10.1002/spe.3262}} 4121 4118 } 4122 4119 … … 4136 4133 journal = spe, 4137 4134 year = 1983, 4138 month = jul,4139 4135 volume = 13, 4140 4136 number = 7, 4141 4137 pages = {577-596}, 4138 month = jul 4142 4139 } 4143 4140 -
driver/as.cc
rfc12f05 r0030b508 11 11 // Created On : Wed Aug 1 10:49:42 2018 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Tue Oct 24 20:45:06 202314 // Update Count : 1 5913 // Last Modified On : Wed Dec 8 07:56:12 2021 14 // Update Count : 136 15 15 // 16 16 … … 45 45 char * dcursor; 46 46 if ( (dcursor = strstr( start, ".Ldebug_info0:" ) ) ) { // debug information ? 47 // fprintf( stderr, "found .Ldebug_info0:\n" ); 48 #if defined( __i386 ) || defined( __x86_64 ) 47 49 48 if ( char * cursor = strstr( dcursor, ".long\t.LASF" ) ) { // language code ? 50 // fprintf( stderr, ".long\t.LASF\n" );51 #elif defined( __aarch64__ )52 if ( char * cursor = strstr( dcursor, ".4byte\t.LASF" ) ) { // language code ?53 // fprintf( stderr, ".4byte\t.LASF\n" );54 #else55 #error unsupported architecture56 #endif57 49 for ( int i = 0; i < 2; i += 1 ) { // move N (magic) lines forward 58 50 cursor = strstr( cursor, "\n" ) + 1; … … 63 55 if ( *(cursor - 2) == '0' && *(cursor - 1) == 'x' && 64 56 (*cursor == 'c' || *cursor == '1' || *cursor == '2') ) { // C99/C89/C 65 // fprintf( stderr, "language code C99/C89/C %c\n", *cursor );66 57 // Expand file by one byte to hold 2 character Cforall language code. 67 58 if ( ftruncate( fd, size + 1 ) ) { perror( "ftruncate" ); exit( EXIT_FAILURE ); }; 68 59 memmove( cursor + 2, cursor + 1, start + size - cursor - 1 ); // move remaining text 1 character right 69 60 } else if ( *(cursor - 3) == '0' && *(cursor - 2) == 'x' && *(cursor - 1) == '1' && *cursor == 'd' ) { // C11 70 // fprintf( stderr, "language code C11 %c\n", *cursor );71 61 } else { 72 62 for ( int i = 0; i < 6; i += 1 ) { // move N (magic) lines forward -
libcfa/prelude/Makefile.am
rfc12f05 r0030b508 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Wed Nov 1 21:09:25 202314 ## Update Count : 2 2113 ## Last Modified On : Thu Jan 13 17:06:27 2022 14 ## Update Count : 215 15 15 ############################################################################### 16 16 … … 21 21 # put into lib for now 22 22 cfalibdir = ${CFA_LIBDIR} 23 cfalib_DATA = gcc-builtins.cf a builtins.cfa extras.cfaprelude.cfa bootloader.c defines.hfa23 cfalib_DATA = gcc-builtins.cf builtins.cf extras.cf prelude.cfa bootloader.c defines.hfa 24 24 25 EXTRA_DIST = bootloader.cf a builtins.c builtins.def extras.c extras.regx extras.regx2 prelude-gen.cc prototypes.awk prototypes.c prototypes.sed sync-builtins.cfa25 EXTRA_DIST = bootloader.cf builtins.c builtins.def extras.c extras.regx extras.regx2 prelude-gen.cc prototypes.awk prototypes.c prototypes.sed sync-builtins.cf 26 26 27 27 CC = @LOCAL_CFACC@ … … 36 36 37 37 # create extra forward types/declarations to reduce inclusion of library files 38 extras.cf a: ${srcdir}/extras.regx ${srcdir}/extras.c38 extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c 39 39 @echo '# 2 "${@}" // needed for error messages from this file' > ${@} 40 40 ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx >> ${@} … … 42 42 43 43 # create forward declarations for gcc builtins 44 gcc-builtins.cf a: gcc-builtins.c ${srcdir}/prototypes.sed44 gcc-builtins.cf : gcc-builtins.c ${srcdir}/prototypes.sed 45 45 @echo '# 2 "${@}" // needed for error messages from this file' > ${@} 46 46 ${AM_V_GEN}gcc -I${srcdir} -E -P $< | sed -r -f ${srcdir}/prototypes.sed >> ${@} 47 47 48 gcc-builtins.c : ${srcdir}/builtins.def ${srcdir}/prototypes.awk ${srcdir}/sync-builtins.cf a${srcdir}/prototypes.c48 gcc-builtins.c : ${srcdir}/builtins.def ${srcdir}/prototypes.awk ${srcdir}/sync-builtins.cf ${srcdir}/prototypes.c 49 49 ${AM_V_GEN}gcc -I${srcdir} -E ${srcdir}/prototypes.c | awk -f ${srcdir}/prototypes.awk > ${@} 50 50 … … 59 59 60 60 # create forward declarations for cfa builtins 61 builtins.cf a: builtins.c @LOCAL_CFACC@61 builtins.cf : builtins.c @LOCAL_CFACC@ 62 62 ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${<} -o ${@} -MD -MP -MF $(DEPDIR)/builtins.Po -D__cforall 63 ${AM_V_at}sed -i 's/builtins.o/builtins.cf a/g' $(DEPDIR)/builtins.Po63 ${AM_V_at}sed -i 's/builtins.o/builtins.cf/g' $(DEPDIR)/builtins.Po 64 64 65 65 include $(DEPDIR)/builtins.Po 66 66 67 bootloader.c : ${srcdir}/bootloader.cf a prelude.cfa extras.cfa gcc-builtins.cfa builtins.cfa@CFACPP@68 ${AM_V_GEN}@CFACPP@ --prelude-dir=${builddir} -tpm ${srcdir}/bootloader.cf a${@} # use src/cfa-cpp as not in lib until after install67 bootloader.c : ${srcdir}/bootloader.cf prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACPP@ 68 ${AM_V_GEN}@CFACPP@ --prelude-dir=${builddir} -tpm ${srcdir}/bootloader.cf ${@} # use src/cfa-cpp as not in lib until after install 69 69 70 70 maintainer-clean-local : 71 71 rm -rf $(DEPDIR) 72 72 73 MOSTLYCLEANFILES = bootloader.c builtins.cf a extras.cfa gcc-builtins.c gcc-builtins.cfaprelude.cfa73 MOSTLYCLEANFILES = bootloader.c builtins.cf extras.cf gcc-builtins.c gcc-builtins.cf prelude.cfa 74 74 DISTCLEANFILES = $(DEPDIR)/builtins.Po 75 75 MAINTAINERCLEANFILES = ${addprefix ${libdir}/,${cfalib_DATA}} ${addprefix ${libdir}/,${lib_LIBRARIES}} 76 76 77 77 if ENABLE_DISTCC 78 distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ defines.hfa gcc-builtins.cf a builtins.cfa extras.cfaprelude.cfa bootloader.c $(srcdir)/../../tools/build/push2dist.sh78 distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ defines.hfa gcc-builtins.cf builtins.cf extras.cf prelude.cfa bootloader.c $(srcdir)/../../tools/build/push2dist.sh 79 79 ${AM_V_GEN}$(srcdir)/../../tools/build/push2dist.sh @CFADIR_HASH@ @DIST_BWLIMIT@ 80 80 @echo "Dummy file to track distribution to remote hosts" > ${@} -
libcfa/prelude/prototypes.awk
rfc12f05 r0030b508 10 10 # Created On : Sat May 16 07:57:37 2015 11 11 # Last Modified By : Peter A. Buhr 12 # Last Modified On : Wed Nov 1 20:44:04 202313 # Update Count : 3 712 # Last Modified On : Sat Feb 8 09:46:58 2020 13 # Update Count : 36 14 14 # 15 15 … … 150 150 # extras 151 151 printf( "\n#include \"builtins.def\"\n\n" ); 152 printf( "\n#include \"sync-builtins.cf a\"\n\n" );152 printf( "\n#include \"sync-builtins.cf\"\n\n" ); 153 153 printf( "extern const char *__PRETTY_FUNCTION__;\n" ); 154 154 printf( "float _Complex __builtin_complex( float, float );\n" ); -
libcfa/src/Makefile.am
rfc12f05 r0030b508 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Wed Nov 1 19:03:42202314 ## Update Count : 26 613 ## Last Modified On : Mon Sep 18 17:06:56 2023 14 ## Update Count : 264 15 15 ############################################################################### 16 16 … … 195 195 if ENABLE_DISTCC 196 196 197 ../prelude/distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ ../prelude/defines.hfa ../prelude/gcc-builtins.cf a ../prelude/builtins.cfa ../prelude/extras.cfa../prelude/prelude.cfa ../prelude/bootloader.c $(srcdir)/../../tools/build/push2dist.sh197 ../prelude/distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ ../prelude/defines.hfa ../prelude/gcc-builtins.cf ../prelude/builtins.cf ../prelude/extras.cf ../prelude/prelude.cfa ../prelude/bootloader.c $(srcdir)/../../tools/build/push2dist.sh 198 198 @+make -C ../prelude distribution 199 199 … … 202 202 endif ENABLE_DISTCC 203 203 204 prelude.o : prelude.cfa extras.cf a gcc-builtins.cfa builtins.cfa@LOCAL_CFACC@ @CFACPP@204 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@ 205 205 ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@} 206 206 207 prelude.lo: prelude.cfa extras.cf a gcc-builtins.cfa builtins.cfa@LOCAL_CFACC@ @CFACPP@207 prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@ 208 208 ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \ 209 209 $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@} -
libcfa/src/collections/string.cfa
rfc12f05 r0030b508 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Oct 18 21:52:09202313 // Update Count : 20 812 // Last Modified On : Sat Sep 2 12:05:57 2023 13 // Update Count : 206 14 14 // 15 15 … … 138 138 139 139 void ?|?( ifstream & in, _Istream_Sstr f ) { 140 (ifstream &)(in | f); 140 (ifstream &)(in | f); ends( in ); 141 141 } 142 142 -
libcfa/src/collections/string_res.cfa
rfc12f05 r0030b508 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Oct 18 21:54:54202313 // Update Count : 1 512 // Last Modified On : Mon Aug 14 18:06:01 2023 13 // Update Count : 12 14 14 // 15 15 … … 236 236 // get bytes 237 237 try { 238 *(temp.Handle.ulink->EndVbyte) = '\0'; // pre-assign empty cstring239 238 in | wdi( lenReadable, temp.Handle.ulink->EndVbyte ); 240 239 } catch (cstring_length*) { … … 248 247 } 249 248 250 if ( temp.Handle.lnth > 0 )s = temp;249 s = temp; 251 250 return in; 252 251 } 253 252 254 253 void ?|?( ifstream & in, string_res & this ) { 255 (ifstream &)(in | this); 254 (ifstream &)(in | this); ends( in ); 256 255 } 257 256 … … 269 268 cstr[wd] = '\0'; // guard null terminate string 270 269 try { 271 cstr[0] = '\0'; // pre-assign as empty cstring272 270 is | cf; 273 271 } catch( cstring_length * ) { 274 272 cont = true; 275 273 } finally { 276 if ( ! cf.flags.ignore && // ok to initialize string 277 cstr[0] != '\0' ) { // something was read 278 *(f.s) = cstr; 279 } 274 if ( ! cf.flags.ignore ) *(f.s) = cstr; // ok to initialize string 280 275 } // try 281 276 for ( ; cont; ) { // overflow read ? 282 277 cont = false; 283 278 try { 284 cstr[0] = '\0'; // pre-assign as empty cstring285 279 is | cf; 286 280 } catch( cstring_length * ) { 287 281 cont = true; // continue not allowed 288 282 } finally { 289 if ( ! cf.flags.ignore && 290 cstr[0] != '\0' ) { // something was read 291 *(f.s) += cstr; // build string chunk at a time 292 } 283 if ( ! cf.flags.ignore ) *(f.s) += cstr; // build string chunk at a time 293 284 } // try 294 285 } // for … … 297 288 298 289 void ?|?( ifstream & in, _Istream_Rstr f ) { 299 (ifstream &)(in | f); 290 (ifstream &)(in | f); ends( in ); 300 291 } 301 292 -
libcfa/src/concurrency/channel.hfa
rfc12f05 r0030b508 130 130 static inline void __cons_handoff( channel(T) & chan, T & elem ) with(chan) { 131 131 memcpy( cons`first.extra, (void *)&elem, sizeof(T) ); // do waiting consumer work 132 __atomic_thread_fence( __ATOMIC_SEQ_CST ); 132 133 wake_one( cons ); 133 134 } … … 136 137 static inline void __prods_handoff( channel(T) & chan, T & retval ) with(chan) { 137 138 memcpy( (void *)&retval, prods`first.extra, sizeof(T) ); 139 __atomic_thread_fence( __ATOMIC_SEQ_CST ); 138 140 wake_one( prods ); 139 141 } -
libcfa/src/concurrency/cofor.cfa
rfc12f05 r0030b508 4 4 // cofor ( uC++ COFOR ) 5 5 6 thread cofor_ task{6 thread cofor_runner { 7 7 ssize_t low, high; 8 8 __cofor_body_t loop_body; 9 9 }; 10 10 11 static void ?{}( cofor_ task& this, ssize_t low, ssize_t high, __cofor_body_t loop_body ) {11 static void ?{}( cofor_runner & this, ssize_t low, ssize_t high, __cofor_body_t loop_body ) { 12 12 this.low = low; 13 13 this.high = high; … … 15 15 } 16 16 17 void main( cofor_ task& this ) with( this ) {17 void main( cofor_runner & this ) with( this ) { 18 18 for ( ssize_t i = low; i < high; i++ ) 19 19 loop_body(i); … … 29 29 ssize_t i = 0; 30 30 ssize_t stride_iter = low; 31 cofor_ task* runners[ threads ];31 cofor_runner * runners[ threads ]; 32 32 for ( i; threads ) { 33 33 runners[i] = alloc(); -
libcfa/src/concurrency/cofor.hfa
rfc12f05 r0030b508 1 1 #include <thread.hfa> 2 #include <locks.hfa>3 #include <list.hfa>4 2 5 3 ////////////////////////////////////////////////////////////////////////////////////////// … … 16 14 __Cofor__( low, high, __CFA_loopLambda__ ); \ 17 15 } 18 19 struct runner_node {20 void * value;21 inline dlink(runner_node);22 };23 P9_EMBEDDED( runner_node, dlink(runner_node) )24 25 thread cofor_runner {26 go_mutex mutex_lock; // MX lock27 dlist( runner_node ) items;28 void (*func)(void *);29 volatile bool done;30 };31 32 void ?{}( cofor_runner & this ) { this.done = false; }33 34 void main( cofor_runner & this ) with(this) {35 while ( !done || !items`isEmpty ) {36 lock( mutex_lock );37 runner_node * node = &try_pop_front( items );38 unlock( mutex_lock );39 func( node->value );40 free( node->value );41 free( node );42 }43 }44 45 void start_runners( cofor_runner * thds, unsigned nprocs, void (*func)(void *) ) {46 for ( i; nprocs ) {47 thds[i].func = func;48 }49 }50 51 void end_runners( cofor_runner * thds, unsigned nprocs ) {52 for ( i; nprocs ) {53 thds[i].done = true;54 }55 }56 57 void send_work( cofor_runner * thds, unsigned nprocs, unsigned & curr_proc, void * value ) {58 runner_node * node = malloc();59 (*node){};60 node->value = value;61 lock( thds[curr_proc].mutex_lock );62 insert_last( thds[curr_proc].items, *node );63 unlock( thds[curr_proc].mutex_lock );64 curr_proc = ( curr_proc + 1 ) % nprocs;65 }66 16 67 17 ////////////////////////////////////////////////////////////////////////////////////////// … … 92 42 delete( this.runner ); 93 43 } 44 -
libcfa/src/concurrency/kernel.hfa
rfc12f05 r0030b508 303 303 // gets the number of constructed processors on the cluster 304 304 static inline unsigned get_proc_count( cluster & this ) { return this.procs.constructed; } 305 static inline unsigned get_proc_count() { return publicTLS_get( this_processor )->cltr->procs.constructed; }306 305 307 306 // set the number of internal processors -
libcfa/src/concurrency/locks.hfa
rfc12f05 r0030b508 182 182 static inline void lock( mcs_spin_lock & l, mcs_spin_node & n ) { 183 183 n.locked = true; 184 185 #if defined(__ARM_ARCH)186 __asm__ __volatile__ ( "DMB ISH" ::: );187 #endif188 189 184 mcs_spin_node * prev = __atomic_exchange_n(&l.queue.tail, &n, __ATOMIC_SEQ_CST); 190 185 if( prev == 0p ) return; 191 186 prev->next = &n; 192 193 #if defined(__ARM_ARCH)194 __asm__ __volatile__ ( "DMB ISH" ::: );195 #endif196 197 187 while( __atomic_load_n(&n.locked, __ATOMIC_RELAXED) ) Pause(); 198 199 #if defined(__ARM_ARCH)200 __asm__ __volatile__ ( "DMB ISH" ::: );201 #endif202 188 } 203 189 204 190 static inline void unlock(mcs_spin_lock & l, mcs_spin_node & n) { 205 #if defined(__ARM_ARCH)206 __asm__ __volatile__ ( "DMB ISH" ::: );207 #endif208 209 191 mcs_spin_node * n_ptr = &n; 210 192 if (__atomic_compare_exchange_n(&l.queue.tail, &n_ptr, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) return; 211 193 while (__atomic_load_n(&n.next, __ATOMIC_RELAXED) == 0p) Pause(); 212 213 #if defined(__ARM_ARCH)214 __asm__ __volatile__ ( "DMB ISH" ::: );215 #endif216 217 194 n.next->locked = false; 218 195 } -
libcfa/src/fstream.cfa
rfc12f05 r0030b508 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Oct 18 22:05:54202313 // Update Count : 54 912 // Last Modified On : Fri Aug 18 10:41:17 2023 13 // Update Count : 541 14 14 // 15 15 … … 230 230 void nlOff( ifstream & os ) { os.nlOnOff$ = false; } 231 231 232 void ends( ifstream & is ) {} 233 232 234 bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; } 233 235 … … 309 311 } // if 310 312 va_end( args ); 311 // if ( len == 0 ) throw ExceptionInst( missing_data );312 313 return len; 313 314 } // fmt -
libcfa/src/fstream.hfa
rfc12f05 r0030b508 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Oct 18 20:30:12202313 // Update Count : 2 6112 // Last Modified On : Fri Aug 18 10:41:15 2023 13 // Update Count : 258 14 14 // 15 15 … … 117 117 void nlOn( ifstream & ); 118 118 void nlOff( ifstream & ); 119 void ends( ifstream & ); 119 120 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 120 ifstream & ungetc( ifstream & is, char c );121 bool eof( ifstream & is );122 121 123 122 bool fail( ifstream & is ); 124 123 void clear( ifstream & ); 124 bool eof( ifstream & is ); 125 125 void open( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r" 126 126 void open( ifstream & is, const char name[] ); 127 127 void close( ifstream & is ); 128 128 129 ifstream & read( ifstream & is, char data[], size_t size ); 130 ifstream & ungetc( ifstream & is, char c ); 129 131 130 132 void ?{}( ifstream & is ); -
libcfa/src/iostream.cfa
rfc12f05 r0030b508 1 1 2 // 2 3 // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo … … 10 11 // Created On : Wed May 27 17:56:53 2015 11 12 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S at Nov 11 07:06:27202313 // Update Count : 1 80313 // Last Modified On : Sun Oct 8 12:10:21 2023 14 // Update Count : 1564 14 15 // 15 16 … … 784 785 return is; 785 786 } // ?|? 787 ISTYPE_VOID_IMPL( bool & ) 786 788 787 789 istype & ?|?( istype & is, char & c ) { … … 795 797 return is; 796 798 } // ?|? 799 ISTYPE_VOID_IMPL( char & ) 797 800 798 801 istype & ?|?( istype & is, signed char & sc ) { … … 800 803 return is; 801 804 } // ?|? 805 ISTYPE_VOID_IMPL( signed char & ) 802 806 803 807 istype & ?|?( istype & is, unsigned char & usc ) { … … 805 809 return is; 806 810 } // ?|? 811 ISTYPE_VOID_IMPL( unsigned char & ) 807 812 808 813 istype & ?|?( istype & is, short int & si ) { … … 810 815 return is; 811 816 } // ?|? 817 ISTYPE_VOID_IMPL( short int & ) 812 818 813 819 istype & ?|?( istype & is, unsigned short int & usi ) { … … 815 821 return is; 816 822 } // ?|? 823 ISTYPE_VOID_IMPL( unsigned short int & ) 817 824 818 825 istype & ?|?( istype & is, int & i ) { … … 820 827 return is; 821 828 } // ?|? 829 ISTYPE_VOID_IMPL( int & ) 822 830 823 831 istype & ?|?( istype & is, unsigned int & ui ) { … … 825 833 return is; 826 834 } // ?|? 835 ISTYPE_VOID_IMPL( unsigned int & ) 827 836 828 837 istype & ?|?( istype & is, long int & li ) { … … 830 839 return is; 831 840 } // ?|? 841 ISTYPE_VOID_IMPL( long int & ) 832 842 833 843 istype & ?|?( istype & is, unsigned long int & ulli ) { … … 835 845 return is; 836 846 } // ?|? 847 ISTYPE_VOID_IMPL( unsigned long int & ) 837 848 838 849 istype & ?|?( istype & is, long long int & lli ) { … … 840 851 return is; 841 852 } // ?|? 853 ISTYPE_VOID_IMPL( long long int & ) 842 854 843 855 istype & ?|?( istype & is, unsigned long long int & ulli ) { … … 845 857 return is; 846 858 } // ?|? 859 ISTYPE_VOID_IMPL( unsigned long long int & ) 847 860 848 861 #if defined( __SIZEOF_INT128__ ) … … 850 863 return (istype &)(is | (unsigned int128 &)llli); 851 864 } // ?|? 865 ISTYPE_VOID_IMPL( int128 & ) 852 866 853 867 istype & ?|?( istype & is, unsigned int128 & ullli ) { … … 866 880 return is; 867 881 } // ?|? 882 ISTYPE_VOID_IMPL( unsigned int128 & ) 868 883 #endif // __SIZEOF_INT128__ 869 884 … … 872 887 return is; 873 888 } // ?|? 889 ISTYPE_VOID_IMPL( float & ) 874 890 875 891 istype & ?|?( istype & is, double & d ) { … … 877 893 return is; 878 894 } // ?|? 895 ISTYPE_VOID_IMPL( double & ) 879 896 880 897 istype & ?|?( istype & is, long double & ld ) { … … 882 899 return is; 883 900 } // ?|? 901 ISTYPE_VOID_IMPL( long double & ) 884 902 885 903 istype & ?|?( istype & is, float _Complex & fc ) { … … 889 907 return is; 890 908 } // ?|? 909 ISTYPE_VOID_IMPL( float _Complex & ) 891 910 892 911 istype & ?|?( istype & is, double _Complex & dc ) { … … 896 915 return is; 897 916 } // ?|? 917 ISTYPE_VOID_IMPL( double _Complex & ) 898 918 899 919 istype & ?|?( istype & is, long double _Complex & ldc ) { … … 903 923 return is; 904 924 } // ?|? 925 ISTYPE_VOID_IMPL( long double _Complex & ) 905 926 906 927 istype & ?|?( istype & is, const char fmt[] ) { … … 908 929 return is; 909 930 } // ?|? 931 ISTYPE_VOID_IMPL( const char * ) 910 932 911 933 // manipulators … … 915 937 916 938 void ?|?( istype & is, istype & (* manip)( istype & ) ) { 917 manip( is ); 939 manip( is ); ends( is ); 918 940 } // ?|? 919 941 … … 944 966 char fmtstr[ sizeof("%*[]") + nscanset ]; 945 967 int pos = 0; 946 strcpy( &fmtstr[pos], "%*[" ); pos += 3; 968 fmtstr[pos] = '%'; pos += 1; 969 fmtstr[pos] = '*'; pos += 1; 970 fmtstr[pos] = '['; pos += 1; 947 971 strcpy( &fmtstr[pos], f.scanset ); pos += nscanset; 948 strcpy( &fmtstr[pos], "]" ); 949 fmt( is, fmtstr, "" ); // skip scanset 950 } else { 951 char ch; 952 // fprintf( stderr, "skip " ); 953 for ( f.wd ) { // skip N characters 954 if ( eof( is ) ) break; 955 fmt( is, "%c", &ch ); 956 // fprintf( stderr, "`%c' ", ch ); 957 } // for 958 } // if 972 fmtstr[pos] = ']'; pos += 1; 973 fmtstr[pos] = '\0'; 974 fmt( is, fmtstr, (void*)0 ); // last arg is dummy: suppress gcc warning 975 } 976 else for ( f.wd ) fmt( is, "%*c" ); 959 977 return is; 960 978 } 979 ISTYPE_VOID_IMPL( _Istream_Cskip ) 961 980 962 981 istype & ?|?( istype & is, _Istream_Cstr f ) { 963 const char * scanset; 964 size_t nscanset = 0; 982 const char * scanset = f.scanset; 965 983 if ( f.flags.delimiter ) scanset = f.delimiter; // getline ? 966 else scanset = f.scanset; 967 if ( scanset ) nscanset = strlen( scanset ); 968 969 char fmtstr[nscanset + 32]; // storage for scanset and format codes 984 985 size_t len = 0; 986 if ( scanset ) len = strlen( scanset ); 987 char fmtstr[len + 16]; 988 int start = 1; 970 989 fmtstr[0] = '%'; 971 972 int pos = 1; 973 int args; 974 bool check = true; 975 976 if ( f.flags.ignore ) { check = false; fmtstr[1] = '*'; pos += 1; } 977 int rwd = f.wd; 978 if ( f.wd != -1 ) { // => just ignore versus ignore with width 990 if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; } 991 // no maximum width necessary because text ignored => width is read width 992 if ( f.wd != -1 ) { 979 993 // wd is buffer bytes available (for input chars + null terminator) 980 994 // rwd is count of input chars 981 // no maximum width necessary because text ignored => width is read width 982 if ( f.flags.rwd ) check = false; 983 else rwd = f.wd - 1; 984 pos += sprintf( &fmtstr[pos], "%d", rwd ); 995 int rwd; 996 if (f.flags.rwd) { 997 verify (f.wd >= 0); 998 rwd = f.wd; 999 } else { 1000 verify (f.wd >= 1); 1001 rwd = f.wd - 1; 1002 } // if 1003 start += sprintf( &fmtstr[start], "%d", rwd ); 1004 } 1005 1006 if ( ! scanset ) { 1007 // %s, %*s, %ws, %*ws 1008 fmtstr[start] = 's'; fmtstr[start + 1] = '\0'; 1009 // printf( "cstr %s\n", fmtstr ); 1010 } else { 1011 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx] 1012 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx] 1013 fmtstr[start] = '['; start += 1; 1014 if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; } 1015 strcpy( &fmtstr[start], scanset ); // copy includes '\0' 1016 len += start; 1017 fmtstr[len] = ']'; fmtstr[len + 1] = '\0'; 1018 // printf( "incl/excl %s\n", fmtstr ); 985 1019 } // if 986 1020 987 if ( ! scanset ) { // %s, %*s, %ws, %*ws 988 // fprintf( stderr, "cstr %s\n", f.s ); 989 strcpy( &fmtstr[pos], "s%n" ); 990 int len = 0; // may not be set in fmt 991 if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*' 992 else args = fmt( is, fmtstr, f.s, &len ); 993 // fprintf( stderr, "cstr %s %d %d %d %s\n", fmtstr, args, len, f.wd, f.s ); 994 if ( check && len >= rwd && ! eof( is ) ) { // might not fit 1021 int check = f.wd - 2; 1022 if (! f.flags.ignore ) { 1023 f.s[0] = '\0'; 1024 if ( ! f.flags.rwd ) f.s[check] = '\0'; // insert sentinel 1025 } 1026 len = fmt( is, fmtstr, f.s ); 1027 //fprintf( stderr, "KK %s %zd %d %c %s\n", fmtstr, len, check, f.s[check], f.s ); 1028 1029 if ( ! f.flags.ignore && ! f.flags.rwd && f.s[check] != '\0' ) { // sentinel overwritten ? 1030 // buffer filled, but would we have kept going? 1031 if ( ! eof( is ) ) { 995 1032 char peek; 996 fmt( is, "%c", &peek ); // check for whitespace terminator 997 // fprintf( stderr, "peek %d '%c'\n", args, peek ); 998 if ( ! eof( is ) ) { 999 ungetc( is, peek ); 1000 if ( ! isspace( peek ) ) throw ExceptionInst( cstring_length ); 1001 } // if 1033 fmt( is, "%c", &peek ); 1034 ungetc( is, peek ); 1035 bool hasMore; 1036 if (f.flags.delimiter) { // getline 1037 hasMore = (peek != f.delimiter[0]); 1038 } else if (f.scanset) { // incl/excl 1039 bool peekMatch = strchr(f.scanset, peek) != 0p; 1040 hasMore = f.flags.inex ? (!peekMatch) : (peekMatch); 1041 } else { // %s 1042 hasMore = !isspace(peek); 1043 } 1044 if (hasMore) throw (cstring_length){ &cstring_length_vt }; 1002 1045 } // if 1003 // FIX ME: CFA strings need to be modified to NOT change the argument for this case, then this can be removed. 1004 if ( rwd > 0 && args == 0 ) f.s[0]= '\0'; // read failed => no pattern match => set string to null 1005 } else { 1006 if ( f.flags.delimiter ) { // getline 1007 // fprintf( stderr, "getline\n" ); 1008 sprintf( &fmtstr[pos], "[%s%s]%%n", f.flags.inex ? "^" : "", scanset ); 1009 // fprintf( stderr, "getline %s %d\n", fmtstr, f.wd ); 1010 int len = 0; // may not be set in fmt 1011 if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*' 1012 else args = fmt( is, fmtstr, f.s, &len ); 1013 // fprintf( stderr, "getline %s %d %d %d\n", fmtstr, args, f.wd, eof( is ) ); 1014 if ( check && len == rwd && ! eof( is ) ) { // might not fit 1015 char peek; 1016 fmt( is, "%c", &peek ); // check for delimiter 1017 // fprintf( stderr, "peek %d '%c'\n", args, peek ); 1018 if ( ! eof( is ) ) { 1019 if ( peek != f.delimiter[0] ) { 1020 ungetc( is, peek ); 1021 throw ExceptionInst( cstring_length ); 1022 } // if 1023 } // if 1024 } else fmt( is, "%*c" ); // remove delimiter 1025 } else { 1026 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx] 1027 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx] 1028 sprintf( &fmtstr[pos], "[%s%s]%%n", f.flags.inex ? "^" : "", scanset ); 1029 // fprintf( stderr, "incl/excl %s %d\n", fmtstr, f.wd ); 1030 int len = 0; // may not be set in fmt 1031 if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*' 1032 else args = fmt( is, fmtstr, f.s, &len ); 1033 // fprintf( stderr, "incl/excl %s \"%s\" %d %d %d %d %d %c\n", fmtstr, f.s, args, f.wd, len, eof( is ), check, f.s[f.wd] ); 1034 if ( check && len == rwd && ! eof( is ) ) { // might not fit 1035 // fprintf( stderr, "overflow\n" ); 1036 char peek; 1037 fmt( is, "%c", &peek ); // check for whitespace terminator 1038 // fprintf( stderr, "peek %d '%c'\n", args, peek ); 1039 if ( ! eof( is ) ) { 1040 ungetc( is, peek ); 1041 if ( f.flags.inex ^ strchr( f.scanset, peek ) != 0p ) throw ExceptionInst( cstring_length ); 1042 } // if 1043 } // if 1046 } // if 1047 1048 if ( f.flags.delimiter ) { // getline ? 1049 if ( len == 0 ) f.s[0] = '\0'; // empty read => argument unchanged => set empty 1050 if ( ! eof( is ) ) { // ignore delimiter, may not be present because of width 1051 char delimiter; 1052 fmt( is, "%c", &delimiter ); 1053 if ( delimiter != f.delimiter[0] ) ungetc( is, delimiter ); 1044 1054 } // if 1045 if ( rwd > 0 && args == 0 ) f.s[0]= '\0'; // read failed => no pattern match => set string to null 1046 } // if 1047 if ( args == 1 && eof( is ) ) { // data but scan ended at EOF 1048 // fprintf( stderr, "clear\n" ); 1049 clear( is ); // => reset EOF => detect again on next read 1050 } // if 1051 return is; 1052 } // ?|? 1055 } //if 1056 return is; 1057 } // ?|? 1058 ISTYPE_VOID_IMPL( _Istream_Cstr ) 1053 1059 1054 1060 istype & ?|?( istype & is, _Istream_Char f ) { … … 1056 1062 return is; 1057 1063 } // ?|? 1064 ISTYPE_VOID_IMPL( _Istream_Char ) 1058 1065 } // distribution 1059 1066 … … 1072 1079 return is; \ 1073 1080 } /* ?|? */ \ 1081 ISTYPE_VOID_IMPL( _Istream_Manip(T) ) \ 1074 1082 } // distribution 1075 1083 … … 1099 1107 return is; 1100 1108 } // ?|? 1109 ISTYPE_VOID_IMPL( _Istream_Manip(float _Complex) ) 1101 1110 1102 1111 istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) { … … 1109 1118 return is; 1110 1119 } // ?|? 1120 ISTYPE_VOID_IMPL( _Istream_Manip(double _Complex) ) 1111 1121 1112 1122 istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) { … … 1119 1129 return is; 1120 1130 } // ?|? 1131 ISTYPE_VOID_IMPL( _Istream_Manip(long double _Complex) ) 1121 1132 } // distribution 1122 1133 -
libcfa/src/iostream.hfa
rfc12f05 r0030b508 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Oct 18 21:21:20202313 // Update Count : 5 8312 // Last Modified On : Sun Oct 8 12:02:55 2023 13 // Update Count : 568 14 14 // 15 15 … … 306 306 // *********************************** istream *********************************** 307 307 308 #define ISTYPE_VOID( T ) void ?|?( istype &, T ) 309 #define ISTYPE_VOID_IMPL( T ) \ 310 void ?|?( istype & is, T t ) { \ 311 (istype &)(is | t); ends( is ); \ 312 } // ?|? 313 308 314 forall( istype & ) 309 315 trait basic_istream { … … 314 320 void nlOn( istype & ); // read newline 315 321 void nlOff( istype & ); // scan newline 322 void ends( istype & os ); // end of output statement 316 323 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 317 324 istype & ungetc( istype &, char ); 318 325 bool eof( istype & ); 319 void clear( istype & );320 326 }; // basic_istream 321 327 … … 323 329 trait istream { 324 330 bool fail( istype & ); 325 void open( istype & is, const char name[], const char mode[]);331 void clear( istype & ); 326 332 void open( istype & is, const char name[] ); 327 333 void close( istype & is ); … … 336 342 forall( istype & | basic_istream( istype ) ) { 337 343 istype & ?|?( istype &, bool & ); 344 ISTYPE_VOID( bool & ); 338 345 339 346 istype & ?|?( istype &, char & ); 347 ISTYPE_VOID( char & ); 340 348 istype & ?|?( istype &, signed char & ); 349 ISTYPE_VOID( signed char & ); 341 350 istype & ?|?( istype &, unsigned char & ); 351 ISTYPE_VOID( unsigned char & ); 342 352 343 353 istype & ?|?( istype &, short int & ); 354 ISTYPE_VOID( short int & ); 344 355 istype & ?|?( istype &, unsigned short int & ); 356 ISTYPE_VOID( unsigned short int & ); 345 357 istype & ?|?( istype &, int & ); 358 ISTYPE_VOID( int & ); 346 359 istype & ?|?( istype &, unsigned int & ); 360 ISTYPE_VOID( unsigned int & ); 347 361 istype & ?|?( istype &, long int & ); 362 ISTYPE_VOID( long int & ); 348 363 istype & ?|?( istype &, unsigned long int & ); 364 ISTYPE_VOID( unsigned long int & ); 349 365 istype & ?|?( istype &, long long int & ); 366 ISTYPE_VOID( long long int & ); 350 367 istype & ?|?( istype &, unsigned long long int & ); 368 ISTYPE_VOID( unsigned long long int & ); 351 369 #if defined( __SIZEOF_INT128__ ) 352 370 istype & ?|?( istype &, int128 & ); 371 ISTYPE_VOID( int128 & ); 353 372 istype & ?|?( istype &, unsigned int128 & ); 373 ISTYPE_VOID( unsigned int128 & ); 354 374 #endif // __SIZEOF_INT128__ 355 375 356 376 istype & ?|?( istype &, float & ); 377 ISTYPE_VOID( float & ); 357 378 istype & ?|?( istype &, double & ); 379 ISTYPE_VOID( double & ); 358 380 istype & ?|?( istype &, long double & ); 381 ISTYPE_VOID( long double & ); 359 382 360 383 istype & ?|?( istype &, float _Complex & ); 384 ISTYPE_VOID( float _Complex & ); 361 385 istype & ?|?( istype &, double _Complex & ); 386 ISTYPE_VOID( double _Complex & ); 362 387 istype & ?|?( istype &, long double _Complex & ); 388 ISTYPE_VOID( long double _Complex & ); 363 389 364 390 istype & ?|?( istype &, const char [] ); 391 ISTYPE_VOID( const char [] ); 365 392 366 393 // manipulators 367 394 istype & ?|?( istype &, istype & (*)( istype & ) ); 395 ISTYPE_VOID( istype & (*)( istype & ) ); 368 396 istype & nl( istype & is ); 369 397 istype & nlOn( istype & ); … … 374 402 375 403 ExceptionDecl( cstring_length ); 376 ExceptionDecl( missing_data );377 404 378 405 // *********************************** manipulators *********************************** 379 406 380 // skip does not compose with other C string manipulators.381 407 struct _Istream_Cskip { 382 408 const char * scanset; … … 390 416 forall( istype & | basic_istream( istype ) ) { 391 417 istype & ?|?( istype & is, _Istream_Cskip f ); 418 ISTYPE_VOID( _Istream_Cskip ); 392 419 } 393 420 … … 431 458 forall( istype & | basic_istream( istype ) ) { 432 459 istype & ?|?( istype & is, _Istream_Cstr f ); 460 ISTYPE_VOID( _Istream_Cstr ); 433 461 } 434 462 … … 443 471 forall( istype & | basic_istream( istype ) ) { 444 472 istype & ?|?( istype & is, _Istream_Char f ); 473 ISTYPE_VOID( _Istream_Char ); 445 474 } 446 475 … … 461 490 forall( istype & | basic_istream( istype ) ) { \ 462 491 istype & ?|?( istype & is, _Istream_Manip(T) f ); \ 492 ISTYPE_VOID( _Istream_Manip(T) ); \ 463 493 } // ?|? 464 494 -
src/AST/Decl.hpp
rfc12f05 r0030b508 125 125 126 126 /// Object declaration `int foo()` 127 class FunctionDecl final: public DeclWithType {127 class FunctionDecl : public DeclWithType { 128 128 public: 129 129 std::vector<ptr<TypeDecl>> type_params; … … 314 314 class EnumDecl final : public AggregateDecl { 315 315 public: 316 // isTyped indicated if the enum has a declaration like:316 bool isTyped; // isTyped indicated if the enum has a declaration like: 317 317 // enum (type_optional) Name {...} 318 bool isTyped; 319 // if isTyped == true && base.get() == nullptr, it is a "void" type enum 320 ptr<Type> base; 318 ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum 321 319 enum class EnumHiding { Visible, Hide } hide; 322 320 … … 376 374 377 375 /// Assembly declaration: `asm ... ( "..." : ... )` 378 class AsmDecl final: public Decl {376 class AsmDecl : public Decl { 379 377 public: 380 378 ptr<AsmStmt> stmt; 381 379 382 380 AsmDecl( const CodeLocation & loc, AsmStmt * stmt ) 383 : Decl( loc, "", {}, Linkage::C), stmt(stmt) {}381 : Decl( loc, "", {}, {} ), stmt(stmt) {} 384 382 385 383 const AsmDecl * accept( Visitor & v ) const override { return v.visit( this ); } … … 390 388 391 389 /// C-preprocessor directive `#...` 392 class DirectiveDecl final: public Decl {390 class DirectiveDecl : public Decl { 393 391 public: 394 392 ptr<DirectiveStmt> stmt; 395 393 396 394 DirectiveDecl( const CodeLocation & loc, DirectiveStmt * stmt ) 397 : Decl( loc, "", {}, Linkage::C), stmt(stmt) {}395 : Decl( loc, "", {}, {} ), stmt(stmt) {} 398 396 399 397 const DirectiveDecl * accept( Visitor & v ) const override { return v.visit( this ); } … … 404 402 405 403 /// Static Assertion `_Static_assert( ... , ... );` 406 class StaticAssertDecl final: public Decl {404 class StaticAssertDecl : public Decl { 407 405 public: 408 406 ptr<Expr> cond; … … 410 408 411 409 StaticAssertDecl( const CodeLocation & loc, const Expr * condition, const ConstantExpr * msg ) 412 : Decl( loc, "", {}, Linkage::C), cond( condition ), msg( msg ) {}410 : Decl( loc, "", {}, {} ), cond( condition ), msg( msg ) {} 413 411 414 412 const StaticAssertDecl * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Fwd.hpp
rfc12f05 r0030b508 68 68 class MutexStmt; 69 69 class CorunStmt; 70 class CoforStmt;71 70 72 71 class Expr; -
src/AST/Node.cpp
rfc12f05 r0030b508 194 194 template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::weak >; 195 195 template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::strong >; 196 template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::weak >;197 template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::strong >;198 196 template class ast::ptr_base< ast::Expr, ast::Node::ref_type::weak >; 199 197 template class ast::ptr_base< ast::Expr, ast::Node::ref_type::strong >; -
src/AST/Pass.cpp
rfc12f05 r0030b508 19 19 20 20 PassVisitorStats pass_visitor_stats; 21 // TODO: There was a counter for every syntax node created.22 // This has not been translated to the new ast.23 21 // Stats::Counters::SimpleCounter * BaseSyntaxNode::new_nodes = nullptr; 24 22 -
src/AST/Pass.hpp
rfc12f05 r0030b508 172 172 const ast::Stmt * visit( const ast::MutexStmt * ) override final; 173 173 const ast::Stmt * visit( const ast::CorunStmt * ) override final; 174 const ast::Stmt * visit( const ast::CoforStmt * ) override final;175 174 const ast::Expr * visit( const ast::ApplicationExpr * ) override final; 176 175 const ast::Expr * visit( const ast::UntypedExpr * ) override final; -
src/AST/Pass.impl.hpp
rfc12f05 r0030b508 1134 1134 1135 1135 //-------------------------------------------------------------------------- 1136 // CoforStmt1137 template< typename core_t >1138 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CoforStmt * node ) {1139 VISIT_START( node );1140 1141 if ( __visit_children() ) {1142 // for statements introduce a level of scope (for the initialization)1143 guard_symtab guard { *this };1144 maybe_accept( node, &CoforStmt::inits );1145 maybe_accept_top( node, &CoforStmt::cond );1146 maybe_accept_top( node, &CoforStmt::inc );1147 maybe_accept_as_compound( node, &CoforStmt::body );1148 }1149 1150 VISIT_END( Stmt, node );1151 }1152 1153 //--------------------------------------------------------------------------1154 1136 // ApplicationExpr 1155 1137 template< typename core_t > -
src/AST/Print.cpp
rfc12f05 r0030b508 934 934 } 935 935 936 virtual const ast::Stmt * visit( const ast::CoforStmt * node ) override final {937 os << "Cofor Statement" << endl;938 939 if ( ! node->inits.empty() ) {940 os << indent << "... initialization:" << endl;941 ++indent;942 for ( const ast::Stmt * stmt : node->inits ) {943 os << indent+1;944 safe_print( stmt );945 }946 --indent;947 }948 949 if ( node->cond ) {950 os << indent << "... condition:" << endl;951 ++indent;952 os << indent;953 node->cond->accept( *this );954 --indent;955 }956 957 if ( node->inc ) {958 os << indent << "... increment:" << endl;959 ++indent;960 os << indent;961 node->inc->accept( *this );962 --indent;963 }964 965 if ( node->body ) {966 os << indent << "... with body:" << endl;967 ++indent;968 os << indent;969 node->body->accept( *this );970 --indent;971 }972 os << endl;973 print( node->labels );974 975 return node;976 }977 978 936 virtual const ast::Expr * visit( const ast::ApplicationExpr * node ) override final { 979 937 ++indent; -
src/AST/Stmt.hpp
rfc12f05 r0030b508 28 28 // Must be included in *all* AST classes; should be #undef'd at the end of the file 29 29 #define MUTATE_FRIEND \ 30 template<typename node_t> friend node_t * mutate(const node_t * node); \30 template<typename node_t> friend node_t * mutate(const node_t * node); \ 31 31 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 32 32 … … 340 340 341 341 CatchClause( const CodeLocation & loc, ExceptionKind kind, const Decl * decl, const Expr * cond, 342 const Stmt * body )342 const Stmt * body ) 343 343 : StmtClause(loc), decl(decl), cond(cond), body(body), kind(kind) {} 344 344 … … 380 380 // Base class of WaitFor/WaitUntil statements 381 381 // form: KEYWORD(...) ... timeout(...) ... else ... 382 class WaitStmt : public Stmt { 383 public: 384 ptr<Expr> timeout_time;382 class WaitStmt : public Stmt { 383 public: 384 ptr<Expr> timeout_time; 385 385 ptr<Stmt> timeout_stmt; 386 386 ptr<Expr> timeout_cond; … … 388 388 ptr<Expr> else_cond; 389 389 390 WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )390 WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} ) 391 391 : Stmt(loc, std::move(labels)) {} 392 392 393 393 private: 394 WaitStmt * clone() const override = 0;394 WaitStmt * clone() const override = 0; 395 395 MUTATE_FRIEND 396 396 }; … … 444 444 class WaitUntilStmt final : public WaitStmt { 445 445 public: 446 // Non-ast node used during compilation to store data needed to generate predicates447 // and set initial status values for clauses448 // Used to create a tree corresponding to the structure of the clauses in a WaitUntil449 struct ClauseNode { 450 enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag451 // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing452 453 ClauseNode * left;454 ClauseNode * right;455 WhenClause * leaf; // only set if this node is a leaf (points into vector of clauses)456 457 bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses458 bool whenState; // used to track if when_cond is toggled on or off for generating init values459 bool childOfAnd; // true on leaf nodes that are children of AND, false otherwise460 461 ClauseNode( Op op, ClauseNode * left, ClauseNode * right )462 : op(op), left(left), right(right), leaf(nullptr), 463 ambiguousWhen(false), whenState(true), childOfAnd(false) {}464 ClauseNode( Op op, WhenClause * leaf )465 : op(op), left(nullptr), right(nullptr), leaf(leaf),466 ambiguousWhen(false), whenState(true), childOfAnd(false) {}467 ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {}468 469 ~ClauseNode() {470 if ( left ) delete left;471 if ( right ) delete right;472 }473 };446 // Non-ast node used during compilation to store data needed to generate predicates 447 // and set initial status values for clauses 448 // Used to create a tree corresponding to the structure of the clauses in a WaitUntil 449 struct ClauseNode { 450 enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag 451 // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing 452 453 ClauseNode * left; 454 ClauseNode * right; 455 WhenClause * leaf; // only set if this node is a leaf (points into vector of clauses) 456 457 bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses 458 bool whenState; // used to track if when_cond is toggled on or off for generating init values 459 bool childOfAnd; // true on leaf nodes that are children of AND, false otherwise 460 461 ClauseNode( Op op, ClauseNode * left, ClauseNode * right ) 462 : op(op), left(left), right(right), leaf(nullptr), 463 ambiguousWhen(false), whenState(true), childOfAnd(false) {} 464 ClauseNode( Op op, WhenClause * leaf ) 465 : op(op), left(nullptr), right(nullptr), leaf(leaf), 466 ambiguousWhen(false), whenState(true), childOfAnd(false) {} 467 ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {} 468 469 ~ClauseNode() { 470 if ( left ) delete left; 471 if ( right ) delete right; 472 } 473 }; 474 474 475 475 std::vector<ptr<WhenClause>> clauses; 476 ClauseNode * predicateTree;476 ClauseNode * predicateTree; 477 477 478 478 WaitUntilStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} ) 479 479 : WaitStmt(loc, std::move(labels)) {} 480 480 481 ~WaitUntilStmt() { delete predicateTree; }481 ~WaitUntilStmt() { delete predicateTree; } 482 482 483 483 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } … … 522 522 std::vector<ptr<Expr>> mutexObjs; 523 523 524 MutexStmt( const CodeLocation & loc, const Stmt * stmt, 524 MutexStmt( const CodeLocation & loc, const Stmt * stmt, 525 525 const std::vector<ptr<Expr>> && mutexes, const std::vector<Label> && labels = {} ) 526 526 : Stmt(loc, std::move(labels)), stmt(stmt), mutexObjs(std::move(mutexes)) {} … … 543 543 private: 544 544 CorunStmt * clone() const override { return new CorunStmt{ *this }; } 545 MUTATE_FRIEND546 };547 548 // Corun Statement549 class CoforStmt final : public Stmt {550 public:551 std::vector<ptr<Stmt>> inits;552 ptr<Expr> cond;553 ptr<Expr> inc;554 ptr<Stmt> body;555 556 CoforStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits, const Expr * cond,557 const Expr * inc, const Stmt * body, const std::vector<Label> && label = {} )558 : Stmt(loc, std::move(label)), inits(std::move(inits)), cond(cond), inc(inc), body(body) {}559 560 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }561 private:562 CoforStmt * clone() const override { return new CoforStmt{ *this }; }563 545 MUTATE_FRIEND 564 546 }; -
src/AST/Type.hpp
rfc12f05 r0030b508 34 34 35 35 namespace ast { 36 37 template< typename T > class Pass; 36 38 37 39 class Type : public Node { -
src/AST/Visitor.hpp
rfc12f05 r0030b508 60 60 virtual const ast::Stmt * visit( const ast::MutexStmt * ) = 0; 61 61 virtual const ast::Stmt * visit( const ast::CorunStmt * ) = 0; 62 virtual const ast::Stmt * visit( const ast::CoforStmt * ) = 0;63 62 virtual const ast::Expr * visit( const ast::ApplicationExpr * ) = 0; 64 63 virtual const ast::Expr * visit( const ast::UntypedExpr * ) = 0; -
src/AST/module.mk
rfc12f05 r0030b508 20 20 AST/Bitfield.hpp \ 21 21 AST/Chain.hpp \ 22 AST/Convert.cpp \ 23 AST/Convert.hpp \ 22 24 AST/Copy.cpp \ 23 25 AST/Copy.hpp \ -
src/BasicTypes-gen.cc
rfc12f05 r0030b508 117 117 // { LongDoubleImaginary, "LongDoubleImaginary", "LDI", "long double _Imaginary", "Ie", false, LongDoubleComplex, -1, -1, 17 }, 118 118 119 { uFloat128x, "uFloat128x", "_FBX", "_Float128x", "DF128x_", Floating, uFloat128xComplex, -1, -1, 18 }, 119 { uFloat128x, "uFloat128x", "_FBX", "_Float128x", "DF128x_", Floating, uFloat128xComplex, -1, -1, 18 }, 120 120 { uFloat128xComplex, "uFloat128xComplex", "_FLDXC", "_Float128x _Complex", "CDF128x_", Floating, -1, -1, -1, 18 } 121 121 }; // graph … … 127 127 void generateCosts( int row ) { 128 128 bool seen[NUMBER_OF_BASIC_TYPES] = { false /*, ... */ }; 129 129 130 130 struct el_cost { 131 131 int i; 132 132 int path; 133 133 int sign; 134 134 135 135 el_cost( int i = 0, int p = 0, int s = 0 ) : i(i), path(p), sign(s) {} 136 136 137 137 // reverse the sense for use in largest-on-top priority queue 138 138 bool operator< (const el_cost& o) const { … … 195 195 return; 196 196 } // if 197 197 198 198 i = graph[col].middle; 199 199 if ( i == -1 ) assert("invalid ancestor assumption"); … … 272 272 size_t start, end; 273 273 274 #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp" 275 resetInput( file, TypeH_AST, buffer, code, str ); 276 277 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH_AST ); 274 275 #define TypeH TOP_SRCDIR "src/SynTree/Type.h" 276 resetInput( file, TypeH, buffer, code, str ); 277 278 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH ); 278 279 start += sizeof( STARTMK ); // includes newline 279 280 code << str.substr( 0, start ); … … 283 284 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 284 285 code << "\t\t" << graph[r].name << "," << endl; 285 } // for 286 } // for 286 287 code << "\t\tNUMBER_OF_BASIC_TYPES" << endl; 287 288 code << "\t} kind;" << endl; 288 289 code << "\t"; // indentation for end marker 289 290 290 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH _AST);291 code << str.substr( start ); 292 293 output( file, TypeH _AST, code );294 // cout << code.str(); 295 296 297 #define TypeC _AST TOP_SRCDIR "src/AST/Type.cpp"298 resetInput( file, TypeC _AST, buffer, code, str );299 300 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC _AST);291 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH ); 292 code << str.substr( start ); 293 294 output( file, TypeH, code ); 295 // cout << code.str(); 296 297 298 #define TypeC TOP_SRCDIR "src/SynTree/Type.cc" 299 resetInput( file, TypeC, buffer, code, str ); 300 301 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC ); 301 302 start += sizeof( STARTMK ); // includes newline 302 303 code << str.substr( 0, start ); … … 306 307 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 307 308 code << "\t\"" << graph[r].type << "\"," << endl; 308 } // for 309 } // for 310 code << "};" << endl; 311 312 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeC ); 313 code << str.substr( start ); 314 315 output( file, TypeC, code ); 316 // cout << code.str(); 317 318 319 // TEMPORARY DURING CHANGE OVER 320 #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp" 321 resetInput( file, TypeH_AST, buffer, code, str ); 322 323 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH_AST ); 324 start += sizeof( STARTMK ); // includes newline 325 code << str.substr( 0, start ); 326 327 code << "\t" << BYMK << endl; 328 code << "\tenum Kind {" << endl; 329 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 330 code << "\t\t" << graph[r].name << "," << endl; 331 } // for 332 code << "\t\tNUMBER_OF_BASIC_TYPES" << endl; 333 code << "\t} kind;" << endl; 334 code << "\t"; // indentation for end marker 335 336 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST ); 337 code << str.substr( start ); 338 339 output( file, TypeH_AST, code ); 340 // cout << code.str(); 341 342 343 #define TypeC_AST TOP_SRCDIR "src/AST/Type.cpp" 344 resetInput( file, TypeC_AST, buffer, code, str ); 345 346 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC_AST ); 347 start += sizeof( STARTMK ); // includes newline 348 code << str.substr( 0, start ); 349 350 code << BYMK << endl; 351 code << "const char * BasicType::typeNames[] = {" << endl; 352 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 353 code << "\t\"" << graph[r].type << "\"," << endl; 354 } // for 309 355 code << "};" << endl; 310 356 … … 345 391 end += sizeof( STARTMK ); 346 392 code << str.substr( start, end - start ); 347 393 348 394 code << "\t" << BYMK << endl; 349 code << "\tstatic const int costMatrix[ ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node" << endl395 code << "\tstatic const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node" << endl 350 396 << "\t\t/* "; 351 397 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles … … 365 411 code << "\tstatic const int maxIntCost = " << *max_element(costMatrix[SignedInt], costMatrix[SignedInt] + NUMBER_OF_BASIC_TYPES) << ";" << endl; 366 412 code << "\t"; // indentation for end marker 367 413 368 414 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", ConversionCost ); 369 415 if ( (end = str.find( STARTMK, start + 1 )) == string::npos ) Abort( "start", ConversionCost ); … … 372 418 373 419 code << "\t" << BYMK << endl; 374 code << "\tstatic const int signMatrix[ ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion" << endl420 code << "\tstatic const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion" << endl 375 421 << "\t\t/* "; 376 422 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles … … 404 450 enum { PER_ROW = 6 }; 405 451 code << "\t" << BYMK << endl; 406 code << "\t#define BT ast::BasicType::" << endl;407 code << "\tstatic const B T Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BTNUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl452 code << "\t#define BT BasicType::" << endl; 453 code << "\tstatic const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl 408 454 << "\t\t/*\t\t "; 409 455 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles … … 459 505 "\t\t\t// - \"Di\" char32_t\n" 460 506 "\t\t\t// - \"Ds\" char16_t\n"; 461 462 code << "\t\t\tconst std::string basicTypes[ ast::BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;507 508 code << "\t\t\tconst std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl; 463 509 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 464 510 code << "\t\t\t\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl; 465 } // for 511 } // for 466 512 code << "\t\t\t}; // basicTypes" << endl; 467 513 code << "\t\t\t"; // indentation for end marker -
src/CodeGen/FixMain.cc
rfc12f05 r0030b508 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // FixMain.cc -- Tools to change a Cforall main into a C main.7 // FixMain.cc -- 8 8 // 9 9 // Author : Thierry Delisle … … 13 13 // Update Count : 0 14 14 // 15 15 16 16 17 #include "FixMain.h" … … 22 23 23 24 #include "AST/Decl.hpp" 24 #include "AST/Pass.hpp"25 25 #include "AST/Type.hpp" 26 #include " AST/Vector.hpp"26 #include "Common/PassVisitor.h" 27 27 #include "Common/SemanticError.h" // for SemanticError 28 28 #include "CodeGen/GenType.h" // for GenType 29 #include "SynTree/Declaration.h" // for FunctionDecl, operator<< 30 #include "SynTree/Type.h" // for FunctionType 29 31 #include "SymTab/Mangler.h" 30 32 … … 33 35 namespace { 34 36 35 struct FindMainCore final{36 ast::FunctionDecl const * main_declaration= nullptr;37 struct FindMainCore { 38 FunctionDecl * main_signature = nullptr; 37 39 38 void previsit( ast::FunctionDecl const* decl ) {39 if ( isMain( decl ) ) {40 if ( main_ declaration) {40 void previsit( FunctionDecl * decl ) { 41 if ( FixMain::isMain( decl ) ) { 42 if ( main_signature ) { 41 43 SemanticError( decl, "Multiple definition of main routine\n" ); 42 44 } 43 main_ declaration= decl;45 main_signature = decl; 44 46 } 45 47 } 46 48 }; 47 49 48 std::string genTypeAt( const ast::vector<ast::Type> & types, size_t at ) {49 return genType( types[at], "", Options( false, false, false, false ) );50 50 } 51 51 52 ast::ObjectDecl * makeIntObj(){ 53 return new ast::ObjectDecl( CodeLocation(), "", 54 new ast::BasicType( ast::BasicType::SignedInt ) ); 52 template<typename container> 53 std::string genTypeAt(const container& p, size_t idx) { 54 return genType((*std::next(p.begin(), idx))->get_type(), ""); 55 } 56 57 void FixMain::fix( std::list< Declaration * > & translationUnit, 58 std::ostream &os, const char* bootloader_filename ) { 59 PassVisitor< FindMainCore > main_finder; 60 acceptAll( translationUnit, main_finder ); 61 FunctionDecl * main_signature = main_finder.pass.main_signature; 62 63 if( main_signature ) { 64 os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return "; 65 main_signature->mangleName = SymTab::Mangler::mangle(main_signature); 66 67 os << main_signature->get_scopedMangleName() << "("; 68 const auto& params = main_signature->get_functionType()->get_parameters(); 69 switch(params.size()) { 70 case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break; 71 case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break; 72 case 0: break; 73 default : assert(false); 74 } 75 os << "); }\n"; 76 77 std::ifstream bootloader(bootloader_filename, std::ios::in); 78 assertf( bootloader.is_open(), "cannot open bootloader.c\n" ); 79 os << bootloader.rdbuf(); 80 } 81 } 82 83 namespace { 84 85 ObjectDecl * signedIntObj() { 86 return new ObjectDecl( 87 "", Type::StorageClasses(), LinkageSpec::Cforall, 0, 88 new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ); 55 89 } 56 90 57 ast::ObjectDecl * makeCharStarStarObj() { 58 return new ast::ObjectDecl( CodeLocation(), "", 59 new ast::PointerType( 60 new ast::PointerType( 61 new ast::BasicType( ast::BasicType::Char ) ) ) ); 91 ObjectDecl * makeArgvObj() { 92 return new ObjectDecl( 93 "", Type::StorageClasses(), LinkageSpec::Cforall, 0, 94 new PointerType( Type::Qualifiers(), 95 new PointerType( Type::Qualifiers(), 96 new BasicType( Type::Qualifiers(), BasicType::Char ) ) ), 97 nullptr ); 62 98 } 63 99 64 std::string getMangledNameOfMain( 65 ast::vector<ast::DeclWithType> && params, ast::ArgumentFlag isVarArgs ) { 66 ast::ptr<ast::FunctionDecl> decl = new ast::FunctionDecl( 67 CodeLocation(), 68 "main", 69 ast::vector<ast::TypeDecl>(), 70 ast::vector<ast::DeclWithType>(), 71 std::move( params ), 72 { makeIntObj() }, 73 nullptr, 74 ast::Storage::Classes(), 75 ast::Linkage::Spec(), 76 ast::vector<ast::Attribute>(), 77 ast::Function::Specs(), 78 isVarArgs 79 ); 80 return Mangle::mangle( decl.get() ); 100 std::string create_mangled_main_function_name( FunctionType * function_type ) { 101 std::unique_ptr<FunctionDecl> decl( new FunctionDecl( 102 "main", Type::StorageClasses(), LinkageSpec::Cforall, 103 function_type, nullptr ) ); 104 return SymTab::Mangler::mangle( decl.get() ); 81 105 } 82 106 83 std::string getMangledNameOf0ParameterMain() { 84 return getMangledNameOfMain( {}, ast::VariableArgs ); 107 std::string mangled_0_argument_main() { 108 FunctionType* main_type = new FunctionType( Type::Qualifiers(), true ); 109 main_type->get_returnVals().push_back( signedIntObj() ); 110 return create_mangled_main_function_name( main_type ); 85 111 } 86 112 87 std::string getMangledNameOf2ParameterMain() { 88 return getMangledNameOfMain( { 89 makeIntObj(), 90 makeCharStarStarObj(), 91 }, ast::FixedArgs ); 113 std::string mangled_2_argument_main() { 114 FunctionType* main_type = new FunctionType( Type::Qualifiers(), false ); 115 main_type->get_returnVals().push_back( signedIntObj() ); 116 main_type->get_parameters().push_back( signedIntObj() ); 117 main_type->get_parameters().push_back( makeArgvObj() ); 118 return create_mangled_main_function_name( main_type ); 92 119 } 93 120 … … 95 122 // This breaks if you move it out of the function. 96 123 static const std::string mangled_mains[] = { 97 getMangledNameOf0ParameterMain(),98 getMangledNameOf2ParameterMain(),99 // getMangledNameOf3ParameterMain(),124 mangled_0_argument_main(), 125 mangled_2_argument_main(), 126 //mangled_3_argument_main(), 100 127 }; 101 128 … … 106 133 } 107 134 108 struct FixLinkageCore final {109 ast::Linkage::Spec const spec;110 FixLinkageCore( ast::Linkage::Spec spec ) : spec( spec ) {}111 112 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl ) {113 if ( decl->name != "main" ) return decl;114 return ast::mutate_field( decl, &ast::FunctionDecl::linkage, spec );115 }116 };117 118 135 } // namespace 119 136 120 bool isMain( const ast::FunctionDecl * decl ) { 137 bool FixMain::isMain( FunctionDecl * decl ) { 138 if ( std::string("main") != decl->name ) { 139 return false; 140 } 141 return is_main( SymTab::Mangler::mangle( decl, true, true ) ); 142 } 143 144 bool FixMain::isMain( const ast::FunctionDecl * decl ) { 121 145 if ( std::string("main") != decl->name ) { 122 146 return false; … … 125 149 } 126 150 127 void fixMainLinkage( ast::TranslationUnit & translationUnit, 128 bool replace_main ) { 129 ast::Linkage::Spec const spec = 130 ( replace_main ) ? ast::Linkage::Cforall : ast::Linkage::C; 131 ast::Pass<FixLinkageCore>::run( translationUnit, spec ); 132 } 133 134 void fixMainInvoke( ast::TranslationUnit & translationUnit, 135 std::ostream &os, const char * bootloader_filename ) { 136 137 ast::Pass<FindMainCore> main_finder; 138 ast::accept_all( translationUnit, main_finder ); 139 if ( nullptr == main_finder.core.main_declaration ) return; 140 141 ast::FunctionDecl * main_declaration = 142 ast::mutate( main_finder.core.main_declaration ); 143 144 main_declaration->mangleName = Mangle::mangle( main_declaration ); 145 146 os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return "; 147 os << main_declaration->scopedMangleName() << "("; 148 const auto& params = main_declaration->type->params; 149 switch ( params.size() ) { 150 case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break; 151 case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break; 152 case 0: break; 153 default : assert(false); 154 } 155 os << "); }\n"; 156 157 std::ifstream bootloader( bootloader_filename, std::ios::in ); 158 assertf( bootloader.is_open(), "cannot open bootloader.c\n" ); 159 os << bootloader.rdbuf(); 160 } 161 162 } // namespace CodeGen 151 }; -
src/CodeGen/FixMain.h
rfc12f05 r0030b508 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // FixMain.h -- Tools to change a Cforall main into a C main.7 // FixMain.h -- 8 8 // 9 9 // Author : Thierry Delisle … … 17 17 18 18 #include <iosfwd> 19 #include <memory> 20 #include <list> 19 21 22 #include "SynTree/LinkageSpec.h" 23 24 class Declaration; 25 class FunctionDecl; 20 26 namespace ast { 21 27 class FunctionDecl; 22 class TranslationUnit;23 28 } 24 29 25 30 namespace CodeGen { 26 31 27 /// Is this function a program main function? 28 bool isMain( const ast::FunctionDecl * decl ); 32 class FixMain { 33 public : 34 static inline LinkageSpec::Spec mainLinkage() { 35 return replace_main ? LinkageSpec::Cforall : LinkageSpec::C; 36 } 29 37 30 /// Adjust the linkage of main functions. 31 void fixMainLinkage( ast::TranslationUnit & transUnit, bool replaceMain ); 38 static inline void setReplaceMain(bool val) { 39 replace_main = val; 40 } 32 41 33 /// Add a wrapper around to run the Cforall main. 34 void fixMainInvoke( ast::TranslationUnit & transUnit, 35 std::ostream & os, const char * bootloaderFilename ); 42 static bool isMain(FunctionDecl* decl); 43 static bool isMain(const ast::FunctionDecl * decl); 44 45 static void fix( std::list< Declaration * > & decls, 46 std::ostream &os, const char* bootloader_filename ); 47 48 private: 49 static bool replace_main; 50 }; 36 51 37 52 } // namespace CodeGen -
src/CodeGen/FixNames.cc
rfc12f05 r0030b508 22 22 #include "AST/Expr.hpp" 23 23 #include "AST/Pass.hpp" 24 #include "Common/PassVisitor.h" 24 25 #include "Common/SemanticError.h" // for SemanticError 25 26 #include "FixMain.h" // for FixMain 26 27 #include "SymTab/Mangler.h" // for Mangler 28 #include "SynTree/LinkageSpec.h" // for Cforall, isMangled 29 #include "SynTree/Constant.h" // for Constant 30 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarat... 31 #include "SynTree/Expression.h" // for ConstantExpr 32 #include "SynTree/Label.h" // for Label, noLabels 33 #include "SynTree/Statement.h" // for ReturnStmt, CompoundStmt 34 #include "SynTree/Type.h" // for Type, BasicType, Type::Qualifiers 35 #include "SynTree/Visitor.h" // for Visitor, acceptAll 27 36 #include "CompilationState.h" 28 37 29 38 namespace CodeGen { 39 class FixNames : public WithGuards { 40 public: 41 void postvisit( ObjectDecl *objectDecl ); 42 void postvisit( FunctionDecl *functionDecl ); 30 43 31 namespace { 44 void previsit( CompoundStmt *compoundStmt ); 45 private: 46 int scopeLevel = 1; 47 48 void fixDWT( DeclarationWithType *dwt ); 49 }; 50 51 void fixNames( std::list< Declaration* > & translationUnit ) { 52 PassVisitor<FixNames> fixer; 53 acceptAll( translationUnit, fixer ); 54 } 55 56 void FixNames::fixDWT( DeclarationWithType * dwt ) { 57 if ( dwt->get_name() != "" ) { 58 if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) { 59 if (!useNewAST) { 60 dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) ); 61 } 62 dwt->set_scopeLevel( scopeLevel ); 63 } // if 64 } // if 65 } 66 67 void FixNames::postvisit( ObjectDecl * objectDecl ) { 68 fixDWT( objectDecl ); 69 } 70 71 void FixNames::postvisit( FunctionDecl * functionDecl ) { 72 fixDWT( functionDecl ); 73 74 if ( FixMain::isMain( functionDecl ) ) { 75 int nargs = functionDecl->get_functionType()->get_parameters().size(); 76 if( !(nargs == 0 || nargs == 2 || nargs == 3) ) { 77 SemanticError(functionDecl, "Main expected to have 0, 2 or 3 arguments\n"); 78 } 79 functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( new ConstantExpr( Constant::from_int( 0 ) ) ) ); 80 } 81 } 82 83 void FixNames::previsit( CompoundStmt * ) { 84 scopeLevel++; 85 GuardAction( [this](){ scopeLevel--; } ); 86 } 32 87 33 88 /// Does work with the main function and scopeLevels. 34 class FixNames final {89 class FixNames_new final { 35 90 int scopeLevel = 1; 36 91 … … 48 103 49 104 const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) { 50 if ( isMain( functionDecl ) ) {105 if ( FixMain::isMain( functionDecl ) ) { 51 106 auto mutDecl = ast::mutate( functionDecl ); 52 107 … … 83 138 }; 84 139 85 } // namespace86 87 140 void fixNames( ast::TranslationUnit & translationUnit ) { 88 ast::Pass<FixNames >::run( translationUnit );141 ast::Pass<FixNames_new>::run( translationUnit ); 89 142 } 90 143 -
src/CodeGen/FixNames.h
rfc12f05 r0030b508 16 16 #pragma once 17 17 18 #include <list> // for list 19 20 class Declaration; 18 21 namespace ast { 19 22 class TranslationUnit; … … 21 24 22 25 namespace CodeGen { 23 26 /// mangles object and function names 27 void fixNames( std::list< Declaration* > & translationUnit ); 24 28 /// Sets scope levels and fills in main's default return. 25 29 void fixNames( ast::TranslationUnit & translationUnit ); 26 27 30 } // namespace CodeGen 28 31 -
src/CodeGen/GenType.cc
rfc12f05 r0030b508 19 19 #include <sstream> // for operator<<, ostringstream, basic_os... 20 20 21 #include "AST/Print.hpp" // for print 22 #include "AST/Vector.hpp" // for vector 23 #include "CodeGeneratorNew.hpp" // for CodeGenerator_new 24 #include "Common/UniqueName.h" // for UniqueName 21 #include "CodeGenerator.h" // for CodeGenerator 22 #include "SynTree/Declaration.h" // for DeclarationWithType 23 #include "SynTree/Expression.h" // for Expression 24 #include "SynTree/Type.h" // for PointerType, Type, FunctionType 25 #include "SynTree/Visitor.h" // for Visitor 25 26 26 27 namespace CodeGen { 27 28 namespace { 29 30 #warning Remove the _new when old version is removed. 31 struct GenType_new : 32 public ast::WithShortCircuiting, 33 public ast::WithVisitorRef<GenType_new> { 34 std::string result; 35 GenType_new( const std::string &typeString, const Options &options ); 36 37 void previsit( ast::Node const * ); 38 void postvisit( ast::Node const * ); 39 40 void postvisit( ast::FunctionType const * type ); 41 void postvisit( ast::VoidType const * type ); 42 void postvisit( ast::BasicType const * type ); 43 void postvisit( ast::PointerType const * type ); 44 void postvisit( ast::ArrayType const * type ); 45 void postvisit( ast::ReferenceType const * type ); 46 void postvisit( ast::StructInstType const * type ); 47 void postvisit( ast::UnionInstType const * type ); 48 void postvisit( ast::EnumInstType const * type ); 49 void postvisit( ast::TypeInstType const * type ); 50 void postvisit( ast::TupleType const * type ); 51 void postvisit( ast::VarArgsType const * type ); 52 void postvisit( ast::ZeroType const * type ); 53 void postvisit( ast::OneType const * type ); 54 void postvisit( ast::GlobalScopeType const * type ); 55 void postvisit( ast::TraitInstType const * type ); 56 void postvisit( ast::TypeofType const * type ); 57 void postvisit( ast::VTableType const * type ); 58 void postvisit( ast::QualifiedType const * type ); 59 60 private: 61 void handleQualifiers( ast::Type const *type ); 62 std::string handleGeneric( ast::BaseInstType const * type ); 63 void genArray( const ast::CV::Qualifiers &qualifiers, ast::Type const *base, ast::Expr const *dimension, bool isVarLen, bool isStatic ); 64 std::string genParamList( const ast::vector<ast::Type> & ); 65 66 Options options; 67 }; 68 69 GenType_new::GenType_new( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {} 70 71 void GenType_new::previsit( ast::Node const * ) { 72 // Turn off automatic recursion for all nodes, to allow each visitor to 73 // precisely control the order in which its children are visited. 74 visit_children = false; 75 } 76 77 void GenType_new::postvisit( ast::Node const * node ) { 78 std::stringstream ss; 79 ast::print( ss, node ); 80 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() ); 81 } 82 83 void GenType_new::postvisit( ast::VoidType const * type ) { 84 result = "void " + result; 85 handleQualifiers( type ); 86 } 87 88 void GenType_new::postvisit( ast::BasicType const * type ) { 89 ast::BasicType::Kind kind = type->kind; 90 assert( 0 <= kind && kind < ast::BasicType::NUMBER_OF_BASIC_TYPES ); 91 result = std::string( ast::BasicType::typeNames[kind] ) + " " + result; 92 handleQualifiers( type ); 93 } 94 95 void GenType_new::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) { 96 std::ostringstream os; 97 if ( result != "" ) { 98 if ( result[ 0 ] == '*' ) { 99 os << "(" << result << ")"; 28 struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting { 29 std::string typeString; 30 GenType( const std::string &typeString, const Options &options ); 31 32 void previsit( BaseSyntaxNode * ); 33 void postvisit( BaseSyntaxNode * ); 34 35 void postvisit( FunctionType * funcType ); 36 void postvisit( VoidType * voidType ); 37 void postvisit( BasicType * basicType ); 38 void postvisit( PointerType * pointerType ); 39 void postvisit( ArrayType * arrayType ); 40 void postvisit( ReferenceType * refType ); 41 void postvisit( StructInstType * structInst ); 42 void postvisit( UnionInstType * unionInst ); 43 void postvisit( EnumInstType * enumInst ); 44 void postvisit( TypeInstType * typeInst ); 45 void postvisit( TupleType * tupleType ); 46 void postvisit( VarArgsType * varArgsType ); 47 void postvisit( ZeroType * zeroType ); 48 void postvisit( OneType * oneType ); 49 void postvisit( GlobalScopeType * globalType ); 50 void postvisit( TraitInstType * inst ); 51 void postvisit( TypeofType * typeof ); 52 void postvisit( VTableType * vtable ); 53 void postvisit( QualifiedType * qualType ); 54 55 private: 56 void handleQualifiers( Type *type ); 57 std::string handleGeneric( ReferenceToType * refType ); 58 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic ); 59 60 Options options; 61 }; 62 63 std::string genType( Type *type, const std::string &baseString, const Options &options ) { 64 PassVisitor<GenType> gt( baseString, options ); 65 std::ostringstream os; 66 67 if ( ! type->get_attributes().empty() ) { 68 PassVisitor<CodeGenerator> cg( os, options ); 69 cg.pass.genAttributes( type->get_attributes() ); 70 } // if 71 72 type->accept( gt ); 73 return os.str() + gt.pass.typeString; 74 } 75 76 std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) { 77 return genType( type, baseString, Options(pretty, genC, lineMarks, false ) ); 78 } 79 80 std::string genPrettyType( Type * type, const std::string & baseString ) { 81 return genType( type, baseString, true, false ); 82 } 83 84 GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {} 85 86 // *** BaseSyntaxNode 87 void GenType::previsit( BaseSyntaxNode * ) { 88 // turn off automatic recursion for all nodes, to allow each visitor to 89 // precisely control the order in which its children are visited. 90 visit_children = false; 91 } 92 93 void GenType::postvisit( BaseSyntaxNode * node ) { 94 std::stringstream ss; 95 node->print( ss ); 96 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() ); 97 } 98 99 void GenType::postvisit( VoidType * voidType ) { 100 typeString = "void " + typeString; 101 handleQualifiers( voidType ); 102 } 103 104 void GenType::postvisit( BasicType * basicType ) { 105 BasicType::Kind kind = basicType->kind; 106 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES ); 107 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString; 108 handleQualifiers( basicType ); 109 } 110 111 void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) { 112 std::ostringstream os; 113 if ( typeString != "" ) { 114 if ( typeString[ 0 ] == '*' ) { 115 os << "(" << typeString << ")"; 116 } else { 117 os << typeString; 118 } // if 119 } // if 120 os << "["; 121 122 if ( isStatic ) { 123 os << "static "; 124 } // if 125 if ( qualifiers.is_const ) { 126 os << "const "; 127 } // if 128 if ( qualifiers.is_volatile ) { 129 os << "volatile "; 130 } // if 131 if ( qualifiers.is_restrict ) { 132 os << "__restrict "; 133 } // if 134 if ( qualifiers.is_atomic ) { 135 os << "_Atomic "; 136 } // if 137 if ( dimension != 0 ) { 138 PassVisitor<CodeGenerator> cg( os, options ); 139 dimension->accept( cg ); 140 } else if ( isVarLen ) { 141 // no dimension expression on a VLA means it came in with the * token 142 os << "*"; 143 } // if 144 os << "]"; 145 146 typeString = os.str(); 147 148 base->accept( *visitor ); 149 } 150 151 void GenType::postvisit( PointerType * pointerType ) { 152 assert( pointerType->base != 0); 153 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) { 154 genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() ); 100 155 } else { 101 os << result; 156 handleQualifiers( pointerType ); 157 if ( typeString[ 0 ] == '?' ) { 158 typeString = "* " + typeString; 159 } else { 160 typeString = "*" + typeString; 161 } // if 162 pointerType->base->accept( *visitor ); 163 } // if 164 } 165 166 void GenType::postvisit( ArrayType * arrayType ) { 167 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() ); 168 } 169 170 void GenType::postvisit( ReferenceType * refType ) { 171 assert( 0 != refType->base ); 172 assertf( ! options.genC, "Reference types should not reach code generation." ); 173 handleQualifiers( refType ); 174 typeString = "&" + typeString; 175 refType->base->accept( *visitor ); 176 } 177 178 void GenType::postvisit( FunctionType * funcType ) { 179 std::ostringstream os; 180 181 if ( typeString != "" ) { 182 if ( typeString[ 0 ] == '*' ) { 183 os << "(" << typeString << ")"; 184 } else { 185 os << typeString; 186 } // if 187 } // if 188 189 /************* parameters ***************/ 190 191 const std::list<DeclarationWithType *> &pars = funcType->parameters; 192 193 if ( pars.empty() ) { 194 if ( funcType->get_isVarArgs() ) { 195 os << "()"; 196 } else { 197 os << "(void)"; 198 } // if 199 } else { 200 PassVisitor<CodeGenerator> cg( os, options ); 201 os << "(" ; 202 203 cg.pass.genCommaList( pars.begin(), pars.end() ); 204 205 if ( funcType->get_isVarArgs() ) { 206 os << ", ..."; 207 } // if 208 os << ")"; 209 } // if 210 211 typeString = os.str(); 212 213 if ( funcType->returnVals.size() == 0 ) { 214 typeString = "void " + typeString; 215 } else { 216 funcType->returnVals.front()->get_type()->accept( *visitor ); 217 } // if 218 219 // add forall 220 if( ! funcType->forall.empty() && ! options.genC ) { 221 // assertf( ! genC, "Aggregate type parameters should not reach code generation." ); 222 std::ostringstream os; 223 PassVisitor<CodeGenerator> cg( os, options ); 224 os << "forall("; 225 cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() ); 226 os << ")" << std::endl; 227 typeString = os.str() + typeString; 102 228 } 103 229 } 104 os << "["; 105 if ( isStatic ) { 106 os << "static "; 107 } 108 if ( qualifiers.is_const ) { 109 os << "const "; 110 } 111 if ( qualifiers.is_volatile ) { 112 os << "volatile "; 113 } 114 if ( qualifiers.is_restrict ) { 115 os << "__restrict "; 116 } 117 if ( qualifiers.is_atomic ) { 118 os << "_Atomic "; 119 } 120 if ( dimension != 0 ) { 121 ast::Pass<CodeGenerator_new>::read( dimension, os, options ); 122 } else if ( isVarLen ) { 123 // no dimension expression on a VLA means it came in with the * token 124 os << "*"; 125 } 126 os << "]"; 127 128 result = os.str(); 129 130 base->accept( *visitor ); 131 } 132 133 void GenType_new::postvisit( ast::PointerType const * type ) { 134 if ( type->isStatic || type->isVarLen || type->dimension ) { 135 genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic ); 136 } else { 137 handleQualifiers( type ); 138 if ( result[ 0 ] == '?' ) { 139 result = "* " + result; 230 231 std::string GenType::handleGeneric( ReferenceToType * refType ) { 232 if ( ! refType->parameters.empty() ) { 233 std::ostringstream os; 234 PassVisitor<CodeGenerator> cg( os, options ); 235 os << "("; 236 cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() ); 237 os << ") "; 238 return os.str(); 239 } 240 return ""; 241 } 242 243 void GenType::postvisit( StructInstType * structInst ) { 244 typeString = structInst->name + handleGeneric( structInst ) + " " + typeString; 245 if ( options.genC ) typeString = "struct " + typeString; 246 handleQualifiers( structInst ); 247 } 248 249 void GenType::postvisit( UnionInstType * unionInst ) { 250 typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString; 251 if ( options.genC ) typeString = "union " + typeString; 252 handleQualifiers( unionInst ); 253 } 254 255 void GenType::postvisit( EnumInstType * enumInst ) { 256 if ( enumInst->baseEnum && enumInst->baseEnum->base ) { 257 typeString = genType(enumInst->baseEnum->base, typeString, options); 140 258 } else { 141 result = "*" + result; 259 typeString = enumInst->name + " " + typeString; 260 if ( options.genC ) { 261 typeString = "enum " + typeString; 262 } 142 263 } 143 type->base->accept( *visitor ); 144 } 145 } 146 147 void GenType_new::postvisit( ast::ArrayType const * type ) { 148 genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic ); 149 } 150 151 void GenType_new::postvisit( ast::ReferenceType const * type ) { 152 assertf( !options.genC, "Reference types should not reach code generation." ); 153 handleQualifiers( type ); 154 result = "&" + result; 155 type->base->accept( *visitor ); 156 } 157 158 void GenType_new::postvisit( ast::FunctionType const * type ) { 159 std::ostringstream os; 160 161 if ( result != "" ) { 162 if ( result[ 0 ] == '*' ) { 163 os << "(" << result << ")"; 164 } else { 165 os << result; 264 handleQualifiers( enumInst ); 265 } 266 267 void GenType::postvisit( TypeInstType * typeInst ) { 268 assertf( ! options.genC, "Type instance types should not reach code generation." ); 269 typeString = typeInst->name + " " + typeString; 270 handleQualifiers( typeInst ); 271 } 272 273 void GenType::postvisit( TupleType * tupleType ) { 274 assertf( ! options.genC, "Tuple types should not reach code generation." ); 275 unsigned int i = 0; 276 std::ostringstream os; 277 os << "["; 278 for ( Type * t : *tupleType ) { 279 i++; 280 os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", "); 166 281 } 167 } 168 169 if ( type->params.empty() ) { 170 if ( type->isVarArgs ) { 171 os << "()"; 172 } else { 173 os << "(void)"; 174 } 175 } else { 176 os << "(" ; 177 178 os << genParamList( type->params ); 179 180 if ( type->isVarArgs ) { 181 os << ", ..."; 182 } 183 os << ")"; 184 } 185 186 result = os.str(); 187 188 if ( type->returns.size() == 0 ) { 189 result = "void " + result; 190 } else { 191 type->returns.front()->accept( *visitor ); 192 } 193 194 // Add forall clause. 195 if( !type->forall.empty() && !options.genC ) { 196 //assertf( !options.genC, "FunctionDecl type parameters should not reach code generation." ); 197 std::ostringstream os; 198 ast::Pass<CodeGenerator_new> cg( os, options ); 199 os << "forall("; 200 cg.core.genCommaList( type->forall ); 201 os << ")" << std::endl; 202 result = os.str() + result; 203 } 204 } 205 206 std::string GenType_new::handleGeneric( ast::BaseInstType const * type ) { 207 if ( !type->params.empty() ) { 208 std::ostringstream os; 209 ast::Pass<CodeGenerator_new> cg( os, options ); 210 os << "("; 211 cg.core.genCommaList( type->params ); 212 os << ") "; 213 return os.str(); 214 } 215 return ""; 216 } 217 218 void GenType_new::postvisit( ast::StructInstType const * type ) { 219 result = type->name + handleGeneric( type ) + " " + result; 220 if ( options.genC ) result = "struct " + result; 221 handleQualifiers( type ); 222 } 223 224 void GenType_new::postvisit( ast::UnionInstType const * type ) { 225 result = type->name + handleGeneric( type ) + " " + result; 226 if ( options.genC ) result = "union " + result; 227 handleQualifiers( type ); 228 } 229 230 void GenType_new::postvisit( ast::EnumInstType const * type ) { 231 if ( type->base && type->base->base ) { 232 result = genType( type->base->base, result, options ); 233 } else { 234 result = type->name + " " + result; 235 if ( options.genC ) { 236 result = "enum " + result; 237 } 238 } 239 handleQualifiers( type ); 240 } 241 242 void GenType_new::postvisit( ast::TypeInstType const * type ) { 243 assertf( !options.genC, "TypeInstType should not reach code generation." ); 244 result = type->name + " " + result; 245 handleQualifiers( type ); 246 } 247 248 void GenType_new::postvisit( ast::TupleType const * type ) { 249 assertf( !options.genC, "TupleType should not reach code generation." ); 250 unsigned int i = 0; 251 std::ostringstream os; 252 os << "["; 253 for ( ast::ptr<ast::Type> const & t : type->types ) { 254 i++; 255 os << genType( t, "", options ) << (i == type->size() ? "" : ", "); 256 } 257 os << "] "; 258 result = os.str() + result; 259 } 260 261 void GenType_new::postvisit( ast::VarArgsType const * type ) { 262 result = "__builtin_va_list " + result; 263 handleQualifiers( type ); 264 } 265 266 void GenType_new::postvisit( ast::ZeroType const * type ) { 267 // Ideally these wouldn't hit codegen at all, but should be safe to make them ints. 268 result = (options.pretty ? "zero_t " : "long int ") + result; 269 handleQualifiers( type ); 270 } 271 272 void GenType_new::postvisit( ast::OneType const * type ) { 273 // Ideally these wouldn't hit codegen at all, but should be safe to make them ints. 274 result = (options.pretty ? "one_t " : "long int ") + result; 275 handleQualifiers( type ); 276 } 277 278 void GenType_new::postvisit( ast::GlobalScopeType const * type ) { 279 assertf( !options.genC, "GlobalScopeType should not reach code generation." ); 280 handleQualifiers( type ); 281 } 282 283 void GenType_new::postvisit( ast::TraitInstType const * type ) { 284 assertf( !options.genC, "TraitInstType should not reach code generation." ); 285 result = type->name + " " + result; 286 handleQualifiers( type ); 287 } 288 289 void GenType_new::postvisit( ast::TypeofType const * type ) { 290 std::ostringstream os; 291 os << "typeof("; 292 ast::Pass<CodeGenerator_new>::read( type, os, options ); 293 os << ") " << result; 294 result = os.str(); 295 handleQualifiers( type ); 296 } 297 298 void GenType_new::postvisit( ast::VTableType const * type ) { 299 assertf( !options.genC, "Virtual table types should not reach code generation." ); 300 std::ostringstream os; 301 os << "vtable(" << genType( type->base, "", options ) << ") " << result; 302 result = os.str(); 303 handleQualifiers( type ); 304 } 305 306 void GenType_new::postvisit( ast::QualifiedType const * type ) { 307 assertf( !options.genC, "QualifiedType should not reach code generation." ); 308 std::ostringstream os; 309 os << genType( type->parent, "", options ) << "." << genType( type->child, "", options ) << result; 310 result = os.str(); 311 handleQualifiers( type ); 312 } 313 314 void GenType_new::handleQualifiers( ast::Type const * type ) { 315 if ( type->is_const() ) { 316 result = "const " + result; 317 } 318 if ( type->is_volatile() ) { 319 result = "volatile " + result; 320 } 321 if ( type->is_restrict() ) { 322 result = "__restrict " + result; 323 } 324 if ( type->is_atomic() ) { 325 result = "_Atomic " + result; 326 } 327 } 328 329 std::string GenType_new::genParamList( const ast::vector<ast::Type> & range ) { 330 auto cur = range.begin(); 331 auto end = range.end(); 332 if ( cur == end ) return ""; 333 std::ostringstream oss; 334 UniqueName param( "__param_" ); 335 while ( true ) { 336 oss << genType( *cur++, options.genC ? param.newName() : "", options ); 337 if ( cur == end ) break; 338 oss << ", "; 339 } 340 return oss.str(); 341 } 342 343 } // namespace 344 345 std::string genType( ast::Type const * type, const std::string & base, const Options & options ) { 346 std::ostringstream os; 347 if ( !type->attributes.empty() ) { 348 ast::Pass<CodeGenerator_new> cg( os, options ); 349 cg.core.genAttributes( type->attributes ); 350 } 351 352 return os.str() + ast::Pass<GenType_new>::read( type, base, options ); 353 } 354 355 std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options ) { 356 return ast::Pass<GenType_new>::read( type, base, options ); 357 } 358 282 os << "] "; 283 typeString = os.str() + typeString; 284 } 285 286 void GenType::postvisit( VarArgsType * varArgsType ) { 287 typeString = "__builtin_va_list " + typeString; 288 handleQualifiers( varArgsType ); 289 } 290 291 void GenType::postvisit( ZeroType * zeroType ) { 292 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 293 typeString = (options.pretty ? "zero_t " : "long int ") + typeString; 294 handleQualifiers( zeroType ); 295 } 296 297 void GenType::postvisit( OneType * oneType ) { 298 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 299 typeString = (options.pretty ? "one_t " : "long int ") + typeString; 300 handleQualifiers( oneType ); 301 } 302 303 void GenType::postvisit( GlobalScopeType * globalType ) { 304 assertf( ! options.genC, "Global scope type should not reach code generation." ); 305 handleQualifiers( globalType ); 306 } 307 308 void GenType::postvisit( TraitInstType * inst ) { 309 assertf( ! options.genC, "Trait types should not reach code generation." ); 310 typeString = inst->name + " " + typeString; 311 handleQualifiers( inst ); 312 } 313 314 void GenType::postvisit( TypeofType * typeof ) { 315 std::ostringstream os; 316 PassVisitor<CodeGenerator> cg( os, options ); 317 os << "typeof("; 318 typeof->expr->accept( cg ); 319 os << ") " << typeString; 320 typeString = os.str(); 321 handleQualifiers( typeof ); 322 } 323 324 void GenType::postvisit( VTableType * vtable ) { 325 assertf( ! options.genC, "Virtual table types should not reach code generation." ); 326 std::ostringstream os; 327 os << "vtable(" << genType( vtable->base, "", options ) << ") " << typeString; 328 typeString = os.str(); 329 handleQualifiers( vtable ); 330 } 331 332 void GenType::postvisit( QualifiedType * qualType ) { 333 assertf( ! options.genC, "Qualified types should not reach code generation." ); 334 std::ostringstream os; 335 os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString; 336 typeString = os.str(); 337 handleQualifiers( qualType ); 338 } 339 340 void GenType::handleQualifiers( Type * type ) { 341 if ( type->get_const() ) { 342 typeString = "const " + typeString; 343 } // if 344 if ( type->get_volatile() ) { 345 typeString = "volatile " + typeString; 346 } // if 347 if ( type->get_restrict() ) { 348 typeString = "__restrict " + typeString; 349 } // if 350 if ( type->get_atomic() ) { 351 typeString = "_Atomic " + typeString; 352 } // if 353 } 359 354 } // namespace CodeGen 360 355 -
src/CodeGen/GenType.h
rfc12f05 r0030b508 21 21 22 22 class Type; 23 namespace ast {24 class Type;25 }26 23 27 24 namespace CodeGen { … … 29 26 std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false ); 30 27 std::string genPrettyType( Type * type, const std::string & baseString ); 31 32 std::string genType( ast::Type const * type, const std::string & base, const Options & options );33 std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options );34 35 28 } // namespace CodeGen 36 29 -
src/CodeGen/Generate.cc
rfc12f05 r0030b508 19 19 #include <string> // for operator<< 20 20 21 #include "CodeGenerator New.hpp" // for CodeGenerator_new, doSemicolon,...21 #include "CodeGenerator.h" // for CodeGenerator, doSemicolon, oper... 22 22 #include "GenType.h" // for genPrettyType 23 #include "Common/PassVisitor.h" // for PassVisitor 24 #include "SynTree/LinkageSpec.h" // for isBuiltin, isGeneratable 25 #include "SynTree/BaseSyntaxNode.h" // for BaseSyntaxNode 26 #include "SynTree/Declaration.h" // for Declaration 27 #include "SynTree/Type.h" // for Type 23 28 24 29 using namespace std; 25 30 26 31 namespace CodeGen { 32 namespace { 33 /// Removes misc. nodes that should not exist in CodeGen 34 struct TreeCleaner { 35 void premutate( CompoundStmt * stmt ); 36 Statement * postmutate( ImplicitCtorDtorStmt * stmt ); 27 37 28 namespace { 29 bool shouldClean( ast::Decl const * decl ) { 30 return dynamic_cast<ast::TraitDecl const *>( decl ); 38 static bool shouldClean( Declaration * ); 39 }; 40 41 void cleanTree( std::list< Declaration * > & translationUnit ) { 42 PassVisitor<TreeCleaner> cleaner; 43 filter( translationUnit, [](Declaration * decl) { return TreeCleaner::shouldClean(decl); }, false ); 44 mutateAll( translationUnit, cleaner ); 45 } // cleanTree 46 } // namespace 47 48 void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) { 49 cleanTree( translationUnit ); 50 51 PassVisitor<CodeGenerator> cgv( os, pretty, generateC, lineMarks, printExprTypes ); 52 for ( auto & dcl : translationUnit ) { 53 if ( LinkageSpec::isGeneratable( dcl->get_linkage() ) && (doIntrinsics || ! LinkageSpec::isBuiltin( dcl->get_linkage() ) ) ) { 54 cgv.pass.updateLocation( dcl ); 55 dcl->accept(cgv); 56 if ( doSemicolon( dcl ) ) { 57 os << ";"; 58 } // if 59 os << cgv.pass.endl; 60 } // if 61 } // for 31 62 } 32 63 33 /// Removes various nodes that should not exist in CodeGen. 34 struct TreeCleaner_new { 35 ast::CompoundStmt const * previsit( ast::CompoundStmt const * stmt ) { 36 auto mutStmt = ast::mutate( stmt ); 37 erase_if( mutStmt->kids, []( ast::Stmt const * stmt ){ 38 auto declStmt = dynamic_cast<ast::DeclStmt const *>( stmt ); 39 return ( declStmt ) ? shouldClean( declStmt->decl ) : false; 40 } ); 41 return mutStmt; 64 void generate( BaseSyntaxNode * node, std::ostream & os ) { 65 if ( Type * type = dynamic_cast< Type * >( node ) ) { 66 os << genPrettyType( type, "" ); 67 } else { 68 PassVisitor<CodeGenerator> cgv( os, true, false, false, false ); 69 node->accept( cgv ); 70 } 71 os << std::endl; 72 } 73 74 namespace { 75 void TreeCleaner::premutate( CompoundStmt * cstmt ) { 76 filter( cstmt->kids, [](Statement * stmt) { 77 if ( DeclStmt * declStmt = dynamic_cast< DeclStmt * >( stmt ) ) { 78 return shouldClean( declStmt->decl ); 79 } 80 return false; 81 }, false ); 42 82 } 43 83 44 ast::Stmt const * postvisit( ast::ImplicitCtorDtorStmt const * stmt ) { 45 return stmt->callStmt; 84 Statement * TreeCleaner::postmutate( ImplicitCtorDtorStmt * stmt ) { 85 Statement * callStmt = nullptr; 86 std::swap( stmt->callStmt, callStmt ); 87 delete stmt; 88 return callStmt; 46 89 } 47 };48 } // namespace49 90 50 void generate( ast::TranslationUnit & translationUnit, std::ostream & os, bool doIntrinsics, 51 bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) { 52 erase_if( translationUnit.decls, shouldClean ); 53 ast::Pass<TreeCleaner_new>::run( translationUnit ); 54 55 ast::Pass<CodeGenerator_new> cgv( os, 56 Options( pretty, generateC, lineMarks, printExprTypes ) ); 57 for ( auto & decl : translationUnit.decls ) { 58 if ( decl->linkage.is_generatable && (doIntrinsics || !decl->linkage.is_builtin ) ) { 59 cgv.core.updateLocation( decl ); 60 decl->accept( cgv ); 61 if ( doSemicolon( decl ) ) { 62 os << ";"; 63 } 64 os << cgv.core.endl; 91 bool TreeCleaner::shouldClean( Declaration * decl ) { 92 return dynamic_cast< TraitDecl * >( decl ); 65 93 } 66 } 67 } 68 94 } // namespace 69 95 } // namespace CodeGen 70 96 -
src/CodeGen/Generate.h
rfc12f05 r0030b508 22 22 class Declaration; 23 23 24 namespace ast{25 class TranslationUnit;26 } 24 namespace CodeGen { 25 /// Generates code. doIntrinsics determines if intrinsic functions are printed, pretty formats output nicely (e.g., uses unmangled names, etc.), generateC is true when the output must consist only of C code (allows some assertions, etc.) 26 void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC = false , bool lineMarks = false, bool printTypeExpr = false ); 27 27 28 namespace CodeGen { 29 30 /// Generates all code in transUnit and writing it to the os. 31 /// doIntrinsics: Should intrinsic functions be printed? 32 /// pretty: Format output nicely (e.g., uses unmangled names, etc.). 33 /// generateC: Make sure the output only consists of C code (allows some assertions, etc.) 34 /// lineMarks: Output line marks (processed line directives) in the output. 35 /// printExprTypes: Print the types of expressions in comments. 36 void generate( ast::TranslationUnit & transUnit, std::ostream &os, bool doIntrinsics, 37 bool pretty, bool generateC, bool lineMarks, bool printExprTypes ); 38 28 /// Generate code for a single node -- helpful for debugging in gdb 29 void generate( BaseSyntaxNode * node, std::ostream & os ); 39 30 } // namespace CodeGen 40 31 -
src/CodeGen/LinkOnce.cc
rfc12f05 r0030b508 22 22 #include "AST/Expr.hpp" 23 23 #include "AST/Pass.hpp" 24 #include "Common/PassVisitor.h" // for PassVisitor, WithShortCircuiting 24 25 25 26 namespace CodeGen { 26 27 27 28 namespace { 29 30 bool is_cfa_linkonce_old( Attribute const * attr ) { 31 return std::string("cfa_linkonce") == attr->name; 32 } 33 34 bool is_section_attribute_old( Attribute const * attr ) { 35 return std::string("section") == attr->name; 36 } 37 38 class LinkOnceVisitorCore : public WithShortCircuiting { 39 public: 40 void previsit( Declaration * ) { 41 visit_children = false; 42 } 43 44 void previsit( DeclarationWithType * decl ) { 45 std::list< Attribute * > & attributes = decl->attributes; 46 // See if we can find the element: 47 auto found = std::find_if(attributes.begin(), attributes.end(), is_cfa_linkonce_old ); 48 if ( attributes.end() != found ) { 49 // Remove any other sections: 50 attributes.remove_if( is_section_attribute_old ); 51 // Iterator to the cfa_linkonce attribute should still be valid. 52 Attribute * attribute = *found; 53 assert( attribute->parameters.empty() ); 54 assert( !decl->mangleName.empty() ); 55 // Overwrite the attribute in place. 56 const std::string section_name = ".gnu.linkonce." + decl->mangleName; 57 attribute->name = "section"; 58 attribute->parameters.push_back( 59 new ConstantExpr( Constant::from_string( section_name ) ) 60 ); 61 62 // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce 63 // visibility is a mess otherwise 64 attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )})); 65 66 } 67 visit_children = false; 68 } 69 }; 28 70 29 71 bool is_cfa_linkonce( ast::Attribute const * attr ) { … … 80 122 } // namespace 81 123 124 void translateLinkOnce( std::list< Declaration *> & translationUnit ) { 125 PassVisitor<LinkOnceVisitorCore> translator; 126 acceptAll( translationUnit, translator ); 127 } 128 82 129 void translateLinkOnce( ast::TranslationUnit & translationUnit ) { 83 130 ast::Pass<LinkOnceCore>::run( translationUnit ); -
src/CodeGen/LinkOnce.h
rfc12f05 r0030b508 20 20 // for now its almost the only attribute we handle. 21 21 22 #include <list> // for list 22 23 24 class Declaration; 23 25 namespace ast { 24 26 class TranslationUnit; … … 27 29 namespace CodeGen { 28 30 31 void translateLinkOnce( std::list< Declaration *> & translationUnit ); 29 32 void translateLinkOnce( ast::TranslationUnit & translationUnit ); 30 33 /* Convert the cfa_linkonce attribute on top level declaration into -
src/CodeGen/OperatorTable.cc
rfc12f05 r0030b508 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Nov 3 16:00:00 202313 // Update Count : 5 611 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Feb 18 15:55:01 2020 13 // Update Count : 55 14 14 // 15 15 16 #include <algorithm> // for any_of 17 #include <map> // for map, _Rb_tree_const_iterator, map<>::const_iterator 18 #include <utility> // for pair 19 using namespace std; 20 16 21 #include "OperatorTable.h" 17 18 #include <cassert> // for assert 19 #include <unordered_map> // for unordered_map 22 #include "Common/utility.h" 20 23 21 24 namespace CodeGen { 25 const OperatorInfo CodeGen::tableValues[] = { 26 // inputName symbol outputName friendlyName type 27 { "?[?]", "", "_operator_index", "Index", OT_INDEX }, 28 { "?{}", "=", "_constructor", "Constructor", OT_CTOR }, 29 { "^?{}", "", "_destructor", "Destructor", OT_DTOR }, 30 { "?()", "", "_operator_call", "Call Operator", OT_CALL }, 31 { "?++", "++", "_operator_postincr", "Postfix Increment", OT_POSTFIXASSIGN }, 32 { "?--", "--", "_operator_postdecr", "Postfix Decrement", OT_POSTFIXASSIGN }, 33 { "*?", "*", "_operator_deref", "Dereference", OT_PREFIX }, 34 { "+?", "+", "_operator_unaryplus", "Plus", OT_PREFIX }, 35 { "-?", "-", "_operator_unaryminus", "Minus", OT_PREFIX }, 36 { "~?", "~", "_operator_bitnot", "Bitwise Not", OT_PREFIX }, 37 { "!?", "!", "_operator_lognot", "Logical Not", OT_PREFIX }, 38 { "++?", "++", "_operator_preincr", "Prefix Increment", OT_PREFIXASSIGN }, 39 { "--?", "--", "_operator_predecr", "Prefix Decrement", OT_PREFIXASSIGN }, 40 { "?\\?", "\\", "_operator_exponential", "Exponentiation", OT_INFIX }, 41 { "?*?", "*", "_operator_multiply", "Multiplication", OT_INFIX }, 42 { "?/?", "/", "_operator_divide", "Division", OT_INFIX }, 43 { "?%?", "%", "_operator_modulus", "Modulo", OT_INFIX }, 44 { "?+?", "+", "_operator_add", "Addition", OT_INFIX }, 45 { "?-?", "-", "_operator_subtract", "Substraction", OT_INFIX }, 46 { "?<<?", "<<", "_operator_shiftleft", "Shift Left", OT_INFIX }, 47 { "?>>?", ">>", "_operator_shiftright", "Shift Right", OT_INFIX }, 48 { "?<?", "<", "_operator_less", "Less-than", OT_INFIX }, 49 { "?>?", ">", "_operator_greater", "Greater-than", OT_INFIX }, 50 { "?<=?", "<=", "_operator_lessequal", "Less-than-or-Equal", OT_INFIX }, 51 { "?>=?", ">=", "_operator_greaterequal", "Greater-than-or-Equal", OT_INFIX }, 52 { "?==?", "==", "_operator_equal", "Equality", OT_INFIX }, 53 { "?!=?", "!=", "_operator_notequal", "Not-Equal", OT_INFIX }, 54 { "?&?", "&", "_operator_bitand", "Bitwise And", OT_INFIX }, 55 { "?^?", "^", "_operator_bitxor", "Bitwise Xor", OT_INFIX }, 56 { "?|?", "|", "_operator_bitor", "Bitwise Or", OT_INFIX }, 57 { "?=?", "=", "_operator_assign", "Assignment", OT_INFIXASSIGN }, 58 { "?\\=?", "\\=", "_operator_expassign", "Exponentiation Assignment", OT_INFIXASSIGN }, 59 { "?*=?", "*=", "_operator_multassign", "Multiplication Assignment", OT_INFIXASSIGN }, 60 { "?/=?", "/=", "_operator_divassign", "Division Assignment", OT_INFIXASSIGN }, 61 { "?%=?", "%=", "_operator_modassign", "Modulo Assignment", OT_INFIXASSIGN }, 62 { "?+=?", "+=", "_operator_addassign", "Addition Assignment", OT_INFIXASSIGN }, 63 { "?-=?", "-=", "_operator_subassign", "Substrction Assignment", OT_INFIXASSIGN }, 64 { "?<<=?", "<<=", "_operator_shiftleftassign", "Shift Left Assignment", OT_INFIXASSIGN }, 65 { "?>>=?", ">>=", "_operator_shiftrightassign", "Shift Right Assignment", OT_INFIXASSIGN }, 66 { "?&=?", "&=", "_operator_bitandassign", "Bitwise And Assignment", OT_INFIXASSIGN }, 67 { "?^=?", "^=", "_operator_bitxorassign", "Bitwise Xor Assignment", OT_INFIXASSIGN }, 68 { "?|=?", "|=", "_operator_bitorassign", "Bitwise Or Assignment", OT_INFIXASSIGN }, 69 }; // tableValues 22 70 23 static const OperatorInfo tableValues[] = { 24 // inputName symbol outputName friendlyName type 25 { "?[?]", "", "_operator_index", "Index", OT_INDEX }, 26 { "?{}", "=", "_constructor", "Constructor", OT_CTOR }, 27 { "^?{}", "", "_destructor", "Destructor", OT_DTOR }, 28 { "?()", "", "_operator_call", "Call Operator", OT_CALL }, 29 { "?++", "++", "_operator_postincr", "Postfix Increment", OT_POSTFIXASSIGN }, 30 { "?--", "--", "_operator_postdecr", "Postfix Decrement", OT_POSTFIXASSIGN }, 31 { "*?", "*", "_operator_deref", "Dereference", OT_PREFIX }, 32 { "+?", "+", "_operator_unaryplus", "Plus", OT_PREFIX }, 33 { "-?", "-", "_operator_unaryminus", "Minus", OT_PREFIX }, 34 { "~?", "~", "_operator_bitnot", "Bitwise Not", OT_PREFIX }, 35 { "!?", "!", "_operator_lognot", "Logical Not", OT_PREFIX }, 36 { "++?", "++", "_operator_preincr", "Prefix Increment", OT_PREFIXASSIGN }, 37 { "--?", "--", "_operator_predecr", "Prefix Decrement", OT_PREFIXASSIGN }, 38 { "?\\?", "\\", "_operator_exponential", "Exponentiation", OT_INFIX }, 39 { "?*?", "*", "_operator_multiply", "Multiplication", OT_INFIX }, 40 { "?/?", "/", "_operator_divide", "Division", OT_INFIX }, 41 { "?%?", "%", "_operator_modulus", "Modulo", OT_INFIX }, 42 { "?+?", "+", "_operator_add", "Addition", OT_INFIX }, 43 { "?-?", "-", "_operator_subtract", "Substraction", OT_INFIX }, 44 { "?<<?", "<<", "_operator_shiftleft", "Shift Left", OT_INFIX }, 45 { "?>>?", ">>", "_operator_shiftright", "Shift Right", OT_INFIX }, 46 { "?<?", "<", "_operator_less", "Less-than", OT_INFIX }, 47 { "?>?", ">", "_operator_greater", "Greater-than", OT_INFIX }, 48 { "?<=?", "<=", "_operator_lessequal", "Less-than-or-Equal", OT_INFIX }, 49 { "?>=?", ">=", "_operator_greaterequal", "Greater-than-or-Equal", OT_INFIX }, 50 { "?==?", "==", "_operator_equal", "Equality", OT_INFIX }, 51 { "?!=?", "!=", "_operator_notequal", "Not-Equal", OT_INFIX }, 52 { "?&?", "&", "_operator_bitand", "Bitwise And", OT_INFIX }, 53 { "?^?", "^", "_operator_bitxor", "Bitwise Xor", OT_INFIX }, 54 { "?|?", "|", "_operator_bitor", "Bitwise Or", OT_INFIX }, 55 { "?=?", "=", "_operator_assign", "Assignment", OT_INFIXASSIGN }, 56 { "?\\=?", "\\=", "_operator_expassign", "Exponentiation Assignment", OT_INFIXASSIGN }, 57 { "?*=?", "*=", "_operator_multassign", "Multiplication Assignment", OT_INFIXASSIGN }, 58 { "?/=?", "/=", "_operator_divassign", "Division Assignment", OT_INFIXASSIGN }, 59 { "?%=?", "%=", "_operator_modassign", "Modulo Assignment", OT_INFIXASSIGN }, 60 { "?+=?", "+=", "_operator_addassign", "Addition Assignment", OT_INFIXASSIGN }, 61 { "?-=?", "-=", "_operator_subassign", "Substrction Assignment", OT_INFIXASSIGN }, 62 { "?<<=?", "<<=", "_operator_shiftleftassign", "Shift Left Assignment", OT_INFIXASSIGN }, 63 { "?>>=?", ">>=", "_operator_shiftrightassign", "Shift Right Assignment", OT_INFIXASSIGN }, 64 { "?&=?", "&=", "_operator_bitandassign", "Bitwise And Assignment", OT_INFIXASSIGN }, 65 { "?^=?", "^=", "_operator_bitxorassign", "Bitwise Xor Assignment", OT_INFIXASSIGN }, 66 { "?|=?", "|=", "_operator_bitorassign", "Bitwise Or Assignment", OT_INFIXASSIGN }, 67 }; // tableValues 71 std::map< std::string, OperatorInfo > CodeGen::table; 68 72 69 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) }; 70 71 const OperatorInfo * operatorLookup( const std::string & inputName ) { 72 // Static information set up: 73 static std::unordered_map<std::string, const OperatorInfo *> inputTable; 74 if ( inputTable.empty() ) for ( const OperatorInfo & op : tableValues ) { 75 inputTable[ op.inputName ] = &op; 73 CodeGen::CodeGen() { 74 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) }; 75 for ( int i = 0; i < numOps; i += 1 ) { 76 table[ tableValues[i].inputName ] = tableValues[i]; 77 } // for 76 78 } 77 79 78 if ( inputName.find_first_of( "?^*+-!", 0, 1 ) == std::string::npos ) return nullptr; // prefilter79 const OperatorInfo * ret = inputTable.find( inputName )->second;80 // This can only happen if an invalid identifier name has been used.81 assert( ret );82 return ret;83 }80 const OperatorInfo * operatorLookup( const string & funcName ) { 81 if ( funcName.find_first_of( "?^*+-!", 0, 1 ) == string::npos ) return nullptr; // prefilter 82 const OperatorInfo * ret = &CodeGen::table.find( funcName )->second; // must be in the table 83 assert( ret ); 84 return ret; 85 } 84 86 85 bool isOperator( const std::string & inputName ) {86 return operatorLookup( inputName ) != nullptr;87 }87 bool isOperator( const string & funcName ) { 88 return operatorLookup( funcName ) != nullptr; 89 } 88 90 89 std::string operatorFriendlyName( const std::string & inputName ) {90 const OperatorInfo * info = operatorLookup( inputName );91 if ( info ) return info->friendlyName;92 return "";93 }91 string operatorFriendlyName( const string & funcName ) { 92 const OperatorInfo * info = operatorLookup( funcName ); 93 if ( info ) return info->friendlyName; 94 return ""; 95 } 94 96 95 // This is only used in the demangler, so it is smaller (and only maybe slow). 96 const OperatorInfo * operatorLookupByOutput( const std::string & outputName ) { 97 if ( '_' != outputName[0] ) return nullptr; 98 for ( const OperatorInfo & op : tableValues ) { 99 if ( outputName == op.outputName ) { 100 return &op; 101 } 97 bool isConstructor( const string & funcName ) { 98 const OperatorInfo * info = operatorLookup( funcName ); 99 if ( info ) return info->type == OT_CTOR; 100 return false; 102 101 } 103 return nullptr;104 }105 102 106 bool isConstructor( const std::string & inputName ) {107 const OperatorInfo * info = operatorLookup( inputName );108 if ( info ) return info->type == OT_CTOR;109 return false;110 }103 bool isDestructor( const string & funcName ) { 104 const OperatorInfo * info = operatorLookup( funcName ); 105 if ( info ) return info->type == OT_DTOR; 106 return false; 107 } 111 108 112 bool isDestructor( const std::string & inputName ) {113 const OperatorInfo * info = operatorLookup( inputName );114 if ( info ) return info->type == OT_DTOR;115 return false;116 }109 bool isCtorDtor( const string & funcName ) { 110 const OperatorInfo * info = operatorLookup( funcName ); 111 if ( info ) return info->type <= OT_CONSTRUCTOR; 112 return false; 113 } 117 114 118 bool isCtorDtor( const std::string & inputName ) {119 const OperatorInfo * info = operatorLookup( inputName );120 if ( info ) return info->type <= OT_CONSTRUCTOR;121 return false;122 }115 bool isAssignment( const string & funcName ) { 116 const OperatorInfo * info = operatorLookup( funcName ); 117 if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT; 118 return false; 119 } 123 120 124 bool isAssignment( const std::string & inputName ) {125 const OperatorInfo * info = operatorLookup( inputName );126 if ( info ) return info->type > OT_CONSTRUCTOR &&info->type <= OT_ASSIGNMENT;127 return false;128 }121 bool isCtorDtorAssign( const string & funcName ) { 122 const OperatorInfo * info = operatorLookup( funcName ); 123 if ( info ) return info->type <= OT_ASSIGNMENT; 124 return false; 125 } 129 126 130 bool isCtorDtorAssign( const std::string & inputName ) { 131 const OperatorInfo * info = operatorLookup( inputName ); 132 if ( info ) return info->type <= OT_ASSIGNMENT; 133 return false; 134 } 135 127 CodeGen codegen; // initialize singleton package 136 128 } // namespace CodeGen 137 129 -
src/CodeGen/OperatorTable.h
rfc12f05 r0030b508 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Nov 3 14:53:00 202313 // Update Count : 2 711 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 16 08:13:34 2020 13 // Update Count : 26 14 14 // 15 15 … … 17 17 18 18 #include <string> 19 #include <map> 19 20 20 21 namespace CodeGen { 22 enum OperatorType { 23 OT_CTOR, 24 OT_DTOR, 25 OT_CONSTRUCTOR = OT_DTOR, 26 OT_PREFIXASSIGN, 27 OT_POSTFIXASSIGN, 28 OT_INFIXASSIGN, 29 OT_ASSIGNMENT = OT_INFIXASSIGN, 30 OT_CALL, 31 OT_PREFIX, 32 OT_INFIX, 33 OT_POSTFIX, 34 OT_INDEX, 35 OT_LABELADDRESS, 36 OT_CONSTANT 37 }; 21 38 22 enum OperatorType { 23 OT_CTOR, 24 OT_DTOR, 25 OT_CONSTRUCTOR = OT_DTOR, 26 OT_PREFIXASSIGN, 27 OT_POSTFIXASSIGN, 28 OT_INFIXASSIGN, 29 OT_ASSIGNMENT = OT_INFIXASSIGN, 30 OT_CALL, 31 OT_PREFIX, 32 OT_INFIX, 33 OT_POSTFIX, 34 OT_INDEX, 35 OT_LABELADDRESS, 36 OT_CONSTANT 37 }; 39 struct OperatorInfo { 40 std::string inputName; 41 std::string symbol; 42 std::string outputName; 43 std::string friendlyName; 44 OperatorType type; 45 }; 38 46 39 struct OperatorInfo { 40 // The Cforall special function name. 41 std::string inputName; 42 // The string used when the operator is used as an operator. 43 std::string symbol; 44 // The base name used in the mangled name. 45 std::string outputName; 46 // Human-readable name of the operator. 47 std::string friendlyName; 48 // The type of operator shows how it is used as an operator. 49 OperatorType type; 50 }; 47 class CodeGen { 48 friend const OperatorInfo * operatorLookup( const std::string & funcName ); 51 49 52 // Look up the operator (by inputName), return nullptr if no such operator. 53 const OperatorInfo * operatorLookup( const std::string & inputName ); 54 // Is there an operator with this name? 55 bool isOperator( const std::string & inputName ); 56 // Get the friendlyName of the operator with the inputName 57 std::string operatorFriendlyName( const std::string & inputName ); 58 // Get the OperatorInfo with the given outputName, if one exists. 59 const OperatorInfo * operatorLookupByOutput( const std::string & outputName ); 50 static const OperatorInfo tableValues[]; 51 static std::map< std::string, OperatorInfo > table; 52 public: 53 CodeGen(); 54 }; // CodeGen 60 55 61 // Is the operator a constructor, destructor or any form of assignment. 62 // (Last two are "or" combinations of the first three.) 63 bool isConstructor( const std::string & ); 64 bool isDestructor( const std::string & ); 65 bool isAssignment( const std::string & ); 66 bool isCtorDtor( const std::string & ); 67 bool isCtorDtorAssign( const std::string & ); 56 bool isOperator( const std::string & funcName ); 57 const OperatorInfo * operatorLookup( const std::string & funcName ); 58 std::string operatorFriendlyName( const std::string & funcName ); 68 59 60 bool isConstructor( const std::string & ); 61 bool isDestructor( const std::string & ); 62 bool isAssignment( const std::string & ); 63 bool isCtorDtor( const std::string & ); 64 bool isCtorDtorAssign( const std::string & ); 69 65 } // namespace CodeGen 70 66 -
src/CodeGen/module.mk
rfc12f05 r0030b508 16 16 17 17 SRC_CODEGEN = \ 18 CodeGen/CodeGeneratorNew.cpp \ 19 CodeGen/CodeGeneratorNew.hpp \ 20 CodeGen/GenType.cc \ 21 CodeGen/GenType.h \ 18 CodeGen/FixMain2.cc \ 19 CodeGen/FixMain.h \ 22 20 CodeGen/OperatorTable.cc \ 23 21 CodeGen/OperatorTable.h 24 22 25 23 SRC += $(SRC_CODEGEN) \ 24 CodeGen/CodeGenerator.cc \ 25 CodeGen/CodeGenerator.h \ 26 26 CodeGen/Generate.cc \ 27 27 CodeGen/Generate.h \ 28 28 CodeGen/FixMain.cc \ 29 CodeGen/FixMain.h \30 29 CodeGen/FixNames.cc \ 31 30 CodeGen/FixNames.h \ 31 CodeGen/GenType.cc \ 32 CodeGen/GenType.h \ 32 33 CodeGen/LinkOnce.cc \ 33 34 CodeGen/LinkOnce.h \ -
src/Common/CodeLocationTools.cpp
rfc12f05 r0030b508 138 138 macro(MutexStmt, Stmt) \ 139 139 macro(CorunStmt, Stmt) \ 140 macro(CoforStmt, Stmt) \141 140 macro(ApplicationExpr, Expr) \ 142 141 macro(UntypedExpr, Expr) \ -
src/Common/Eval.cc
rfc12f05 r0030b508 19 19 20 20 #include "AST/Inspect.hpp" 21 #include "Common/PassVisitor.h" 21 22 #include "CodeGen/OperatorTable.h" // access: OperatorInfo 22 23 #include "AST/Pass.hpp" 23 24 #include "InitTweak/InitTweak.h" 24 25 #include "SynTree/Expression.h" 26 27 //------------------------------------------------------------- 28 // Old AST 29 struct EvalOld : public WithShortCircuiting { 30 long long int value = 0; // compose the result of the constant expression 31 bool valid = true; // true => constant expression and value is the result 32 // false => not constant expression, e.g., ++i 33 bool cfavalid = true; // true => constant expression and value computable 34 // false => constant expression but value not computable, e.g., sizeof(int) 35 36 void previsit( const BaseSyntaxNode * ) { visit_children = false; } 37 void postvisit( const BaseSyntaxNode * ) { valid = false; } 38 39 void postvisit( const SizeofExpr * ) { 40 } 41 42 void postvisit( const ConstantExpr * expr ) { 43 value = expr->intValue(); 44 } 45 46 void postvisit( const CastExpr * expr ) { 47 auto arg = eval(expr->arg); 48 valid = arg.second; 49 value = arg.first; 50 // TODO: perform type conversion on value if valid 51 } 52 53 void postvisit( const VariableExpr * const expr ) { 54 if ( EnumInstType * inst = dynamic_cast<EnumInstType *>(expr->result) ) { 55 if ( EnumDecl * decl = inst->baseEnum ) { 56 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf 57 return; 58 } 59 } 60 } 61 valid = false; 62 } 63 64 void postvisit( const ApplicationExpr * expr ) { 65 DeclarationWithType * function = InitTweak::getFunction(const_cast<ApplicationExpr *>(expr)); 66 if ( ! function || function->linkage != LinkageSpec::Intrinsic ) { valid = false; return; } 67 const std::string & fname = function->name; 68 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() ); 69 std::pair<long long int, bool> arg1, arg2; 70 arg1 = eval(expr->args.front()); 71 valid = valid && arg1.second; 72 if ( ! valid ) return; 73 if ( expr->args.size() == 2 ) { 74 arg2 = eval(expr->args.back()); 75 valid = valid && arg2.second; 76 if ( ! valid ) return; 77 } 78 if (fname == "?+?") { 79 value = arg1.first + arg2.first; 80 } else if (fname == "?-?") { 81 value = arg1.first - arg2.first; 82 } else if (fname == "?*?") { 83 value = arg1.first * arg2.first; 84 } else if (fname == "?/?") { 85 value = arg1.first / arg2.first; 86 } else if (fname == "?%?") { 87 value = arg1.first % arg2.first; 88 } else { 89 valid = false; 90 } 91 // TODO: implement other intrinsic functions 92 } 93 }; 94 95 //------------------------------------------------------------- 96 // New AST 25 97 struct EvalNew : public ast::WithShortCircuiting { 26 98 Evaluation result = { 0, true, true }; … … 198 270 }; 199 271 272 std::pair<long long int, bool> eval( const Expression * expr ) { 273 PassVisitor<EvalOld> ev; 274 if ( expr ) { 275 expr->accept( ev ); 276 return std::make_pair( ev.pass.value, ev.pass.valid ); 277 } else { 278 return std::make_pair( 0, false ); 279 } 280 } 281 200 282 Evaluation eval( const ast::Expr * expr ) { 201 283 if ( expr ) { -
src/Common/Eval.h
rfc12f05 r0030b508 30 30 31 31 /// Evaluates expr as a long long int. 32 /// If second is false, expr could not be evaluated. 33 std::pair<long long int, bool> eval(const Expression * expr); 32 34 Evaluation eval(const ast::Expr * expr); 33 35 -
src/Common/Examine.cc
rfc12f05 r0030b508 19 19 #include "CodeGen/OperatorTable.h" 20 20 #include "InitTweak/InitTweak.h" 21 22 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ) { 23 if (func->name != "main") return nullptr; 24 if (func->type->parameters.size() != 1) return nullptr; 25 26 auto param = func->type->parameters.front(); 27 28 auto type = dynamic_cast<ReferenceType * >(param->get_type()); 29 if (!type) return nullptr; 30 31 auto obj = dynamic_cast<StructInstType *>(type->base); 32 if (!obj) return nullptr; 33 34 if (kind != obj->baseStruct->kind) return nullptr; 35 36 return param; 37 } 21 38 22 39 namespace { … … 52 69 53 70 namespace { 71 Type * getDestructorParam( FunctionDecl * func ) { 72 if ( !CodeGen::isDestructor( func->name ) ) return nullptr; 73 74 auto params = func->type->parameters; 75 if ( 1 != params.size() ) return nullptr; 76 77 auto ref = dynamic_cast<ReferenceType *>( params.front()->get_type() ); 78 if ( ref ) { 79 return ref->base; 80 } 81 return nullptr; 82 } 54 83 55 84 const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) { … … 59 88 } 60 89 90 } 91 92 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl ) { 93 if ( Type * type = getDestructorParam( func ) ) { 94 auto stype = dynamic_cast<StructInstType *>( type ); 95 return stype && stype->baseStruct == type_decl; 96 } 97 return false; 61 98 } 62 99 -
src/Common/Examine.h
rfc12f05 r0030b508 15 15 16 16 #include "AST/Decl.hpp" 17 #include "SynTree/Declaration.h" 17 18 18 19 /// Check if this is a main function for a type of an aggregate kind. 20 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ); 19 21 const ast::DeclWithType * isMainFor( 20 22 const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind ); … … 22 24 23 25 /// Check if this function is a destructor for the given structure. 26 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl ); 24 27 bool isDestructorFor( 25 28 const ast::FunctionDecl * func, const ast::StructDecl * type ); -
src/Common/UniqueName.cc
rfc12f05 r0030b508 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // UniqueName.cc -- Create a unique variants of a base name with a counter.7 // UniqueName.cc -- 8 8 // 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 Nov 7 15:04:00 202313 // Update Count : 411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jun 8 14:47:49 2015 13 // Update Count : 3 14 14 // 15 15 16 #include <string> 17 #include <sstream> 18 16 19 #include "UniqueName.h" 17 18 #include "Common/ToString.hpp"19 20 20 21 UniqueName::UniqueName( const std::string &base ) : base( base ), count( 0 ) { … … 22 23 23 24 std::string UniqueName::newName( const std::string &additional ) { 24 return toString( base, additional, count++ ); 25 std::ostringstream os; 26 os << base << additional << count++; 27 return os.str(); 25 28 } 26 29 -
src/Common/UniqueName.h
rfc12f05 r0030b508 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // UniqueName.h -- Create a unique variants of a base name with a counter.7 // UniqueName.h -- 8 8 // 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 Nov 7 15:00:00 202313 // Update Count : 311 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 21 22:18:45 2017 13 // Update Count : 2 14 14 // 15 15 … … 19 19 20 20 class UniqueName { 21 public:22 UniqueName( const std::string &base );21 public: 22 UniqueName( const std::string &base = "" ); 23 23 std::string newName( const std::string &additional = "" ); 24 private:24 private: 25 25 std::string base; 26 26 int count; -
src/Common/module.mk
rfc12f05 r0030b508 31 31 Common/Indenter.cc \ 32 32 Common/Iterate.hpp \ 33 Common/PassVisitor.cc \ 34 Common/PassVisitor.h \ 35 Common/PassVisitor.impl.h \ 36 Common/PassVisitor.proto.h \ 33 37 Common/PersistentMap.h \ 34 38 Common/ResolvProtoDump.hpp \ -
src/Concurrency/Corun.cpp
rfc12f05 r0030b508 27 27 struct CorunKeyword : public WithDeclsToAdd<>, public WithStmtsToAdd<> { 28 28 UniqueName CorunFnNamer = "__CFA_corun_lambda_"s; 29 UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;30 // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;31 29 UniqueName RunnerBlockNamer = "__CFA_corun_block_"s; 32 33 string coforArgName = "__CFA_cofor_lambda_arg";34 string numProcsName = "__CFA_cofor_num_procs";35 string currProcsName = "__CFA_cofor_curr_procs";36 string thdArrName = "__CFA_cofor_thread_array";37 string loopTempName = "__CFA_cofor_loop_temp";38 39 30 40 31 const StructDecl * runnerBlockDecl = nullptr; 41 const StructDecl * coforRunnerDecl = nullptr;42 32 43 // Finds runner_block (corun task) and cofor_runner (cofor task) decls33 // Finds select_node decl 44 34 void previsit( const StructDecl * decl ) { 45 35 if ( !decl->body ) { … … 48 38 assert( !runnerBlockDecl ); 49 39 runnerBlockDecl = decl; 50 } else if ( "cofor_runner" == decl->name ) {51 assert( !coforRunnerDecl );52 coforRunnerDecl = decl;53 40 } 54 41 } 55 42 56 // codegen for cofor statements57 Stmt * postvisit( const CoforStmt * stmt ) {58 if ( !runnerBlockDecl || !coforRunnerDecl )59 SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>\n" );60 61 if ( stmt->inits.size() != 1 )62 SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control\n" );63 64 if ( !stmt->body )65 return nullptr;66 67 const CodeLocation & loc = stmt->location;68 const string fnName = CoforFnNamer.newName();69 70 CompoundStmt * body = new CompoundStmt( loc );71 72 // push back cofor initializer to generated body73 body->push_back( deepCopy( stmt->inits.at(0) ) );74 75 CompoundStmt * fnBody = new CompoundStmt( loc );76 77 const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());78 if ( ! declStmtPtr )79 SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?\n" );80 81 const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());82 if ( ! declPtr )83 SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?\n" );84 85 Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );86 87 // Generates:88 // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);89 fnBody->push_back( new DeclStmt( loc,90 new ObjectDecl( loc,91 declPtr->name,92 initType,93 new SingleInit( loc,94 UntypedExpr::createDeref( loc,95 new CastExpr( loc,96 new NameExpr( loc, coforArgName ),97 new PointerType( initType ), ExplicitCast98 )99 )100 )101 )102 ));103 104 // push rest of cofor body into loop lambda105 fnBody->push_back( deepCopy( stmt->body ) );106 107 // Generates:108 // void __CFA_cofor_lambda_() {109 // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);110 // stmt->body;111 // }112 Stmt * coforLambda = new DeclStmt( loc,113 new FunctionDecl( loc,114 fnName, // name115 {}, // forall116 {117 new ObjectDecl( loc,118 coforArgName,119 new ast::PointerType( new ast::VoidType() )120 )121 }, // params122 {}, // return123 fnBody // body124 )125 );126 body->push_back( coforLambda );127 128 // Generates:129 // unsigned __CFA_cofor_num_procs = get_proc_count();130 body->push_back( new DeclStmt( loc,131 new ObjectDecl( loc,132 numProcsName,133 new BasicType( BasicType::Kind::UnsignedInt ),134 new SingleInit( loc,135 new UntypedExpr( loc,136 new NameExpr( loc, "get_proc_count" ),137 {}138 )139 )140 )141 )142 );143 144 // Generates:145 // unsigned __CFA_cofor_curr_procs = 0;146 body->push_back( new DeclStmt( loc,147 new ObjectDecl( loc,148 currProcsName,149 new BasicType( BasicType::Kind::UnsignedInt ),150 new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )151 )152 )153 );154 155 // Generates:156 // unsigned cofor_runner __CFA_cofor_thread_array[nprocs];157 body->push_back( new DeclStmt( loc,158 new ObjectDecl( loc,159 thdArrName,160 new ast::ArrayType(161 new StructInstType( coforRunnerDecl ),162 new NameExpr( loc, numProcsName ),163 ast::FixedLen,164 ast::DynamicDim165 )166 )167 )168 );169 170 // Generates:171 // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );172 body->push_back( new ExprStmt( loc,173 new UntypedExpr( loc,174 new NameExpr( loc, "start_runners" ),175 {176 new NameExpr( loc, thdArrName ),177 new NameExpr( loc, numProcsName ),178 new NameExpr( loc, fnName )179 }180 )181 ));182 183 // Generates:184 // typeof(initializer) * __CFA_cofor_loop_temp = malloc();185 CompoundStmt * forLoopBody = new CompoundStmt( loc );186 forLoopBody->push_back( new DeclStmt( loc,187 new ObjectDecl( loc,188 loopTempName,189 new PointerType( initType ),190 new SingleInit( loc,191 new UntypedExpr( loc,192 new NameExpr( loc, "malloc" ),193 {}194 )195 )196 )197 )198 );199 200 // Generates:201 // *__CFA_cofor_loop_temp = initializer;202 forLoopBody->push_back( new ExprStmt( loc,203 UntypedExpr::createAssign( loc,204 UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),205 new NameExpr( loc, declPtr->name )206 )207 ));208 209 // Generates:210 // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,211 // __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );212 forLoopBody->push_back( new ExprStmt( loc,213 new UntypedExpr( loc,214 new NameExpr( loc, "send_work" ),215 {216 new NameExpr( loc, thdArrName ),217 new NameExpr( loc, numProcsName ),218 new NameExpr( loc, currProcsName ),219 new NameExpr( loc, loopTempName )220 }221 )222 ));223 224 body->push_back( new ForStmt( loc,225 {},226 deepCopy( stmt->cond ),227 deepCopy( stmt->inc ),228 forLoopBody229 ));230 231 // Generates:232 // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );233 body->push_back( new ExprStmt( loc,234 new UntypedExpr( loc,235 new NameExpr( loc, "end_runners" ),236 {237 new NameExpr( loc, thdArrName ),238 new NameExpr( loc, numProcsName )239 }240 )241 ));242 243 return body;244 }245 246 // codegen for corun statements247 43 Stmt * postvisit( const CorunStmt * stmt ) { 248 if ( !runnerBlockDecl || !coforRunnerDecl)44 if ( !runnerBlockDecl ) 249 45 SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>\n" ); 250 46 -
src/Concurrency/module.mk
rfc12f05 r0030b508 21 21 Concurrency/Corun.hpp \ 22 22 Concurrency/KeywordsNew.cpp \ 23 Concurrency/Keywords.cc \ 23 24 Concurrency/Keywords.h \ 24 25 Concurrency/WaitforNew.cpp \ 26 Concurrency/Waitfor.cc \ 25 27 Concurrency/Waitfor.h \ 26 28 Concurrency/Waituntil.cpp \ -
src/ControlStruct/module.mk
rfc12f05 r0030b508 16 16 17 17 SRC += \ 18 ControlStruct/ExceptDecl.cc \ 18 19 ControlStruct/ExceptDeclNew.cpp \ 19 20 ControlStruct/ExceptDecl.h \ 20 21 ControlStruct/ExceptTranslateNew.cpp \ 22 ControlStruct/ExceptTranslate.cc \ 21 23 ControlStruct/ExceptTranslate.h \ 22 24 ControlStruct/FixLabels.cpp \ 23 25 ControlStruct/FixLabels.hpp \ 26 ControlStruct/ForExprMutator.cc \ 27 ControlStruct/ForExprMutator.h \ 24 28 ControlStruct/HoistControlDecls.cpp \ 25 29 ControlStruct/HoistControlDecls.hpp \ 30 ControlStruct/LabelFixer.cc \ 31 ControlStruct/LabelFixer.h \ 32 ControlStruct/LabelGenerator.cc \ 33 ControlStruct/LabelGenerator.h \ 26 34 ControlStruct/LabelGeneratorNew.cpp \ 27 35 ControlStruct/LabelGeneratorNew.hpp \ 36 ControlStruct/MLEMutator.cc \ 37 ControlStruct/MLEMutator.h \ 28 38 ControlStruct/MultiLevelExit.cpp \ 29 ControlStruct/MultiLevelExit.hpp 39 ControlStruct/MultiLevelExit.hpp \ 40 ControlStruct/Mutate.cc \ 41 ControlStruct/Mutate.h 30 42 -
src/GenPoly/BoxNew.cpp
rfc12f05 r0030b508 39 39 40 40 namespace { 41 42 /// Common field of several sub-passes of box. 43 struct BoxPass { 44 TypeVarMap scopeTypeVars; 45 BoxPass() : scopeTypeVars( ast::TypeData() ) {} 46 }; 47 48 // TODO: Could this be a common helper somewhere? 49 ast::FunctionType * makeFunctionType( ast::FunctionDecl const * decl ) { 50 ast::FunctionType * type = new ast::FunctionType( 51 decl->type->isVarArgs, decl->type->qualifiers 52 ); 53 for ( auto type_param : decl->type_params ) { 54 type->forall.emplace_back( new ast::TypeInstType( type_param ) ); 55 } 56 for ( auto assertion : decl->assertions ) { 57 type->assertions.emplace_back( new ast::VariableExpr( 58 assertion->location, assertion ) ); 59 } 60 for ( auto param : decl->params ) { 61 type->params.emplace_back( param->get_type() ); 62 } 63 for ( auto retval : decl->returns ) { 64 type->returns.emplace_back( retval->get_type() ); 65 } 66 return type; 67 } 41 68 42 69 // -------------------------------------------------------------------------- … … 332 359 /// * Adds appropriate type variables to the function calls. 333 360 struct CallAdapter final : 361 public BoxPass, 334 362 public ast::WithConstTypeSubstitution, 335 363 public ast::WithGuards, … … 348 376 ast::Expr const * postvisit( ast::AddressExpr const * expr ); 349 377 ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt ); 378 void previsit( ast::PointerType const * type ); 379 void previsit( ast::FunctionType const * type ); 350 380 351 381 void beginScope(); … … 410 440 CodeLocation const & location, ast::Type const * type ); 411 441 412 TypeVarMap scopeTypeVars;442 /// Set of adapter functions in the current scope. 413 443 ScopedMap< std::string, ast::DeclWithType const * > adapters; 414 444 std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals; … … 523 553 524 554 ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) { 525 // Prevent type declaration information from leaking out. 555 if ( nullptr == decl->stmts ) { 556 // This may keep TypeDecls we don't ever want from sneaking in. 557 // Not visiting child nodes might just be faster. 558 GuardScope( scopeTypeVars ); 559 return decl; 560 } 561 526 562 GuardScope( scopeTypeVars ); 527 528 if ( nullptr == decl->stmts ) {529 return decl;530 }531 532 563 GuardValue( retval ); 533 564 … … 631 662 ptrdiff_t initArgCount = mutExpr->args.size(); 632 663 633 TypeVarMap exprTypeVars ;664 TypeVarMap exprTypeVars = { ast::TypeData() }; 634 665 // TODO: Should this take into account the variables already bound in 635 666 // scopeTypeVars ([ex] remove them from exprTypeVars)? … … 656 687 657 688 assert( typeSubs ); 689 ast::Type const * concRetType = replaceWithConcrete( dynRetType, *typeSubs ); 690 // Used to use dynRetType instead of concRetType; this changed so that 691 // the correct type parameters are passed for return types (it should be 692 // the concrete type's parameters, not the formal type's). 658 693 ast::vector<ast::Expr>::iterator argIt = 659 694 passTypeVars( mutExpr, function ); … … 733 768 } 734 769 return stmt; 770 } 771 772 void CallAdapter::previsit( ast::PointerType const * type ) { 773 GuardScope( scopeTypeVars ); 774 makeTypeVarMap( type, scopeTypeVars ); 775 } 776 777 void CallAdapter::previsit( ast::FunctionType const * type ) { 778 GuardScope( scopeTypeVars ); 779 makeTypeVarMap( type, scopeTypeVars ); 735 780 } 736 781 … … 1382 1427 1383 1428 ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) { 1384 TypeVarMap localTypeVars ;1429 TypeVarMap localTypeVars = { ast::TypeData() }; 1385 1430 makeTypeVarMap( decl, localTypeVars ); 1386 1431 … … 1413 1458 layoutParams.emplace_back( alignParam ); 1414 1459 } 1415 // Assertions should be stored in the main list. 1416 assert( mutParam->assertions.empty() ); 1460 // TODO: These should possibly all be gone. 1461 // More all assertions into parameter list. 1462 for ( ast::ptr<ast::DeclWithType> & assert : mutParam->assertions ) { 1463 // Assertion parameters may not be used in body, 1464 // pass along with unused attribute. 1465 assert.get_and_mutate()->attributes.push_back( 1466 new ast::Attribute( "unused" ) ); 1467 inferredParams.push_back( assert ); 1468 } 1469 mutParam->assertions.clear(); 1417 1470 typeParam = mutParam; 1418 1471 } 1472 // TODO: New version of inner loop. 1419 1473 for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) { 1420 1474 // Assertion parameters may not be used in body, … … 1431 1485 spliceBegin( mutDecl->params, layoutParams ); 1432 1486 addAdapters( mutDecl, localTypeVars ); 1433 1434 // Now have to update the type to match the declaration.1435 ast::FunctionType * type = new ast::FunctionType(1436 mutDecl->type->isVarArgs, mutDecl->type->qualifiers );1437 for ( auto type_param : mutDecl->type_params ) {1438 type->forall.emplace_back( new ast::TypeInstType( type_param ) );1439 }1440 for ( auto param : mutDecl->params ) {1441 type->params.emplace_back( param->get_type() );1442 }1443 for ( auto retval : mutDecl->returns ) {1444 type->returns.emplace_back( retval->get_type() );1445 }1446 mutDecl->type = type;1447 1487 1448 1488 return mutDecl; … … 1478 1518 } 1479 1519 } 1520 // TODO: Can this be updated as we go along? 1521 mutDecl->type = makeFunctionType( mutDecl ); 1480 1522 return mutDecl; 1481 1523 } … … 1533 1575 assertf( it != adapters.end(), "Could not correct floating node." ); 1534 1576 return ast::mutate_field( expr, &ast::VariableExpr::var, it->second ); 1577 1535 1578 } 1536 1579 … … 1544 1587 /// * Inserts dynamic calculation of polymorphic type layouts where needed. 1545 1588 struct PolyGenericCalculator final : 1589 public BoxPass, 1546 1590 public ast::WithConstTypeSubstitution, 1547 1591 public ast::WithDeclsToAdd<>, … … 1551 1595 PolyGenericCalculator(); 1552 1596 1597 void previsit( ast::ObjectDecl const * decl ); 1553 1598 void previsit( ast::FunctionDecl const * decl ); 1554 1599 void previsit( ast::TypedefDecl const * decl ); … … 1557 1602 ast::StructDecl const * previsit( ast::StructDecl const * decl ); 1558 1603 ast::UnionDecl const * previsit( ast::UnionDecl const * decl ); 1604 void previsit( ast::PointerType const * type ); 1605 void previsit( ast::FunctionType const * type ); 1559 1606 ast::DeclStmt const * previsit( ast::DeclStmt const * stmt ); 1560 1607 ast::Expr const * postvisit( ast::MemberExpr const * expr ); … … 1588 1635 /// C sizeof(). 1589 1636 ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * ); 1637 1590 1638 /// Enters a new scope for type-variables, 1591 1639 /// adding the type variables from the provided type. 1592 1640 void beginTypeScope( ast::Type const * ); 1593 1594 /// The type variables and polymorphic parameters currently in scope.1595 TypeVarMap scopeTypeVars; 1641 /// Enters a new scope for known layouts and offsets, and queues exit calls. 1642 void beginGenericScope(); 1643 1596 1644 /// Set of generic type layouts known in the current scope, 1597 1645 /// indexed by sizeofName. … … 1604 1652 /// If the argument of an AddressExpr is MemberExpr, it is stored here. 1605 1653 ast::MemberExpr const * addrMember = nullptr; 1654 /// Used to avoid recursing too deep in type declarations. 1655 bool expect_func_type = false; 1606 1656 }; 1607 1657 … … 1625 1675 } 1626 1676 1677 void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) { 1678 beginTypeScope( decl->type ); 1679 } 1680 1627 1681 void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) { 1628 GuardScope( *this);1682 beginGenericScope(); 1629 1683 beginTypeScope( decl->type ); 1630 1684 } … … 1642 1696 ast::TypeDecl const * decl ) { 1643 1697 ast::Type const * base = decl->base; 1644 if ( nullptr == base ) return decl;1698 if ( nullptr == base) return decl; 1645 1699 1646 1700 // Add size/align variables for opaque type declarations. … … 1667 1721 alignDecl->accept( *visitor ); 1668 1722 1669 // A little trick to replace this with two declarations.1670 // Adding after makes sure that there is no conflict with adding stmts.1723 // Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls 1724 // can occur at global scope. 1671 1725 declsToAddAfter.push_back( alignDecl ); 1726 // replace with sizeDecl. 1672 1727 return sizeDecl; 1673 1728 } … … 1687 1742 } 1688 1743 1744 void PolyGenericCalculator::previsit( ast::PointerType const * type ) { 1745 beginTypeScope( type ); 1746 } 1747 1748 void PolyGenericCalculator::previsit( ast::FunctionType const * type ) { 1749 beginTypeScope( type ); 1750 1751 GuardValue( expect_func_type ); 1752 GuardScope( *this ); 1753 1754 // The other functions type we will see in this scope are probably 1755 // function parameters they don't help us with the layout and offsets so 1756 // don't mark them as known in this scope. 1757 expect_func_type = false; 1758 } 1759 1760 //void PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) { 1689 1761 ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) { 1690 1762 ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>(); … … 1694 1766 1695 1767 // Change initialization of a polymorphic value object to allocate via a 1696 // variable-length-array (alloca cannot be safely used in loops). 1768 // variable-length-array (alloca was previouly used, but it cannot be 1769 // safely used in loops). 1697 1770 ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location, 1698 1771 bufNamer.newName(), … … 2175 2248 } 2176 2249 2250 void PolyGenericCalculator::beginGenericScope() { 2251 GuardScope( *this ); 2252 // We expect the first function type see to be the type relating to this 2253 // scope but any further type is probably some unrelated function pointer 2254 // keep track of whrich is the first. 2255 GuardValue( expect_func_type ) = true; 2256 } 2257 2177 2258 // -------------------------------------------------------------------------- 2178 /// Removes unneeded or incorrect type information.2259 /// No common theme found. 2179 2260 /// * Replaces initialization of polymorphic values with alloca. 2180 2261 /// * Replaces declaration of dtype/ftype with appropriate void expression. … … 2182 2263 /// * Strips fields from generic structure declarations. 2183 2264 struct Eraser final : 2265 public BoxPass, 2184 2266 public ast::WithGuards { 2185 2267 void guardTypeVarMap( ast::Type const * type ) { … … 2196 2278 void previsit( ast::PointerType const * type ); 2197 2279 void previsit( ast::FunctionType const * type ); 2198 public:2199 TypeVarMap scopeTypeVars;2200 2280 }; 2201 2281 -
src/GenPoly/FindFunction.cc
rfc12f05 r0030b508 20 20 #include "AST/Pass.hpp" // for Pass 21 21 #include "AST/Type.hpp" 22 #include "Common/PassVisitor.h" // for PassVisitor 22 23 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::iterator 23 24 #include "GenPoly/GenPoly.h" // for TyVarMap 24 25 #include "ScrubTyVars.h" // for ScrubTyVars 26 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl 27 #include "SynTree/Mutator.h" // for Mutator, mutateAll 28 #include "SynTree/Type.h" // for FunctionType, Type, Type::For... 25 29 26 30 namespace GenPoly { 31 class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting { 32 public: 33 FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate ); 34 35 void premutate( FunctionType * functionType ); 36 Type * postmutate( FunctionType * functionType ); 37 void premutate( PointerType * pointerType ); 38 private: 39 void handleForall( const Type::ForallList &forall ); 40 41 std::list< FunctionType const * > & functions; 42 TyVarMap tyVars; 43 bool replaceMode; 44 FindFunctionPredicate predicate; 45 }; 46 47 void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) { 48 PassVisitor<FindFunction> finder( functions, tyVars, false, predicate ); 49 type->acceptMutator( finder ); 50 } 51 52 void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) { 53 PassVisitor<FindFunction> finder( functions, tyVars, true, predicate ); 54 type = type->acceptMutator( finder ); 55 } 56 57 FindFunction::FindFunction( std::list< FunctionType const * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate ) 58 : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) { 59 } 60 61 void FindFunction::handleForall( const Type::ForallList &forall ) { 62 for ( const Declaration * td : forall ) { 63 TyVarMap::iterator var = tyVars.find( td->name ); 64 if ( var != tyVars.end() ) { 65 tyVars.erase( var->first ); 66 } // if 67 } // for 68 } 69 70 void FindFunction::premutate( FunctionType * functionType ) { 71 visit_children = false; 72 GuardScope( tyVars ); 73 handleForall( functionType->get_forall() ); 74 mutateAll( functionType->get_returnVals(), *visitor ); 75 } 76 77 Type * FindFunction::postmutate( FunctionType * functionType ) { 78 Type *ret = functionType; 79 if ( predicate( functionType, tyVars ) ) { 80 functions.push_back( functionType ); 81 if ( replaceMode ) { 82 // replace type parameters in function type with void* 83 ret = ScrubTyVars::scrub( functionType->clone(), tyVars ); 84 } // if 85 } // if 86 return ret; 87 } 88 89 void FindFunction::premutate( PointerType * pointerType ) { 90 GuardScope( tyVars ); 91 handleForall( pointerType->get_forall() ); 92 } 27 93 28 94 namespace { … … 88 154 void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) { 89 155 GuardScope( typeVars ); 156 //handleForall( type->forall ); 90 157 } 91 158 … … 97 164 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false ); 98 165 type->accept( pass ); 166 //(void)type; 167 //(void)functions; 168 //(void)typeVars; 169 //(void)predicate; 99 170 } 100 171 … … 104 175 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true ); 105 176 return type->accept( pass ); 177 //(void)functions; 178 //(void)typeVars; 179 //(void)predicate; 180 //return type; 106 181 } 107 182 -
src/GenPoly/FindFunction.h
rfc12f05 r0030b508 16 16 #pragma once 17 17 18 #include <list> // for list 19 18 20 #include "GenPoly.h" // for TyVarMap 19 21 22 class FunctionType; 23 class Type; 24 20 25 namespace GenPoly { 26 typedef bool (*FindFunctionPredicate)( FunctionType*, const TyVarMap& ); 27 28 /// recursively walk `type`, placing all functions that match `predicate` under `tyVars` into `functions` 29 void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ); 30 /// like `findFunction`, but also replaces the function type with void ()(void) 31 void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ); 21 32 22 33 typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & ); -
src/GenPoly/GenPoly.cc
rfc12f05 r0030b508 29 29 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::const_it... 30 30 #include "ResolvExpr/typeops.h" // for flatten 31 #include "SynTree/Constant.h" // for Constant 32 #include "SynTree/Expression.h" // for Expression, TypeExpr, Constan... 33 #include "SynTree/Type.h" // for Type, StructInstType, UnionIn... 34 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 31 35 32 36 using namespace std; … … 35 39 namespace { 36 40 /// Checks a parameter list for polymorphic parameters; will substitute according to env if present 41 bool hasPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) { 42 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { 43 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); 44 assertf(paramType, "Aggregate parameters should be type expressions"); 45 if ( isPolyType( paramType->get_type(), env ) ) return true; 46 } 47 return false; 48 } 49 37 50 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) { 38 51 for ( auto ¶m : params ) { … … 45 58 46 59 /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present 60 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { 61 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { 62 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); 63 assertf(paramType, "Aggregate parameters should be type expressions"); 64 if ( isPolyType( paramType->get_type(), tyVars, env ) ) return true; 65 } 66 return false; 67 } 68 47 69 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) { 48 70 for ( auto & param : params ) { … … 55 77 56 78 /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present 79 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { 80 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { 81 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); 82 assertf(paramType, "Aggregate parameters should be type expressions"); 83 if ( isDynType( paramType->get_type(), tyVars, env ) ) return true; 84 } 85 return false; 86 } 87 57 88 bool hasDynParams( 58 89 const std::vector<ast::ptr<ast::Expr>> & params, … … 68 99 return false; 69 100 } 101 102 /// Checks a parameter list for inclusion of polymorphic parameters; will substitute according to env if present 103 bool includesPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) { 104 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { 105 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); 106 assertf(paramType, "Aggregate parameters should be type expressions"); 107 if ( includesPolyType( paramType->get_type(), env ) ) return true; 108 } 109 return false; 110 } 111 112 /// Checks a parameter list for inclusion of polymorphic parameters from tyVars; will substitute according to env if present 113 bool includesPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { 114 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { 115 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); 116 assertf(paramType, "Aggregate parameters should be type expressions"); 117 if ( includesPolyType( paramType->get_type(), tyVars, env ) ) return true; 118 } 119 return false; 120 } 121 } 122 123 Type* replaceTypeInst( Type* type, const TypeSubstitution* env ) { 124 if ( ! env ) return type; 125 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) { 126 Type *newType = env->lookup( typeInst->get_name() ); 127 if ( newType ) return newType; 128 } 129 return type; 130 } 131 132 const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) { 133 if ( ! env ) return type; 134 if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) { 135 Type *newType = env->lookup( typeInst->get_name() ); 136 if ( newType ) return newType; 137 } 138 return type; 70 139 } 71 140 … … 77 146 } 78 147 return type; 148 } 149 150 Type *isPolyType( Type *type, const TypeSubstitution *env ) { 151 type = replaceTypeInst( type, env ); 152 153 if ( dynamic_cast< TypeInstType * >( type ) ) { 154 return type; 155 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { 156 return isPolyType( arrayType->base, env ); 157 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { 158 if ( hasPolyParams( structType->get_parameters(), env ) ) return type; 159 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { 160 if ( hasPolyParams( unionType->get_parameters(), env ) ) return type; 161 } 162 return 0; 79 163 } 80 164 … … 94 178 } 95 179 180 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { 181 type = replaceTypeInst( type, env ); 182 183 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) { 184 if ( tyVars.contains( typeInst->get_name() ) ) { 185 return type; 186 } 187 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { 188 return isPolyType( arrayType->base, tyVars, env ); 189 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { 190 if ( hasPolyParams( structType->get_parameters(), tyVars, env ) ) return type; 191 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { 192 if ( hasPolyParams( unionType->get_parameters(), tyVars, env ) ) return type; 193 } 194 return 0; 195 } 196 96 197 const ast::Type * isPolyType( const ast::Type * type, 97 198 const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { … … 110 211 } 111 212 213 ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { 214 type = replaceTypeInst( type, env ); 215 216 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) { 217 auto var = tyVars.find( typeInst->get_name() ); 218 if ( var != tyVars.end() && var->second.isComplete ) { 219 return typeInst; 220 } 221 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { 222 if ( hasDynParams( structType->get_parameters(), tyVars, env ) ) return structType; 223 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { 224 if ( hasDynParams( unionType->get_parameters(), tyVars, env ) ) return unionType; 225 } 226 return 0; 227 } 228 112 229 const ast::BaseInstType * isDynType( 113 230 const ast::Type * type, const TypeVarMap & typeVars, … … 132 249 } 133 250 251 ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) { 252 if ( function->get_returnVals().empty() ) return 0; 253 254 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes ); 255 } 256 134 257 const ast::BaseInstType *isDynRet( 135 258 const ast::FunctionType * type, const TypeVarMap & typeVars ) { … … 139 262 } 140 263 264 ReferenceToType *isDynRet( FunctionType *function ) { 265 if ( function->get_returnVals().empty() ) return 0; 266 267 TyVarMap forallTypes( TypeDecl::Data{} ); 268 makeTyVarMap( function, forallTypes ); 269 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes ); 270 } 271 141 272 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) { 142 273 if ( func->returns.empty() ) return nullptr; 143 274 144 TypeVarMap forallTypes ;275 TypeVarMap forallTypes = { ast::TypeData() }; 145 276 makeTypeVarMap( func, forallTypes ); 146 277 return isDynType( func->returns.front(), forallTypes ); 147 278 } 279 280 bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) { 281 // if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) { 282 // return true; 283 // } // if 284 if ( isDynRet( adaptee, tyVars ) ) return true; 285 286 for ( std::list< DeclarationWithType* >::const_iterator innerArg = adaptee->get_parameters().begin(); innerArg != adaptee->get_parameters().end(); ++innerArg ) { 287 // if ( isPolyType( (*innerArg)->get_type(), tyVars ) ) { 288 if ( isDynType( (*innerArg)->get_type(), tyVars ) ) { 289 return true; 290 } // if 291 } // for 292 return false; 293 } 148 294 149 295 bool needsAdapter( … … 158 304 return false; 159 305 } 306 307 Type *isPolyPtr( Type *type, const TypeSubstitution *env ) { 308 type = replaceTypeInst( type, env ); 309 310 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) { 311 return isPolyType( ptr->get_base(), env ); 312 } 313 return 0; 314 } 315 316 Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { 317 type = replaceTypeInst( type, env ); 318 319 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) { 320 return isPolyType( ptr->get_base(), tyVars, env ); 321 } 322 return 0; 323 } 160 324 161 325 const ast::Type * isPolyPtr( … … 169 333 return nullptr; 170 334 } 335 336 Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) { 337 int dummy; 338 if ( ! levels ) { levels = &dummy; } 339 *levels = 0; 340 341 while ( true ) { 342 type = replaceTypeInst( type, env ); 343 344 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) { 345 type = ptr->get_base(); 346 ++(*levels); 347 } else break; 348 } 349 350 return isPolyType( type, env ); 351 } 352 353 Type * hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels, const TypeSubstitution *env ) { 354 int dummy; 355 if ( ! levels ) { levels = &dummy; } 356 *levels = 0; 357 358 while ( true ) { 359 type = replaceTypeInst( type, env ); 360 361 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) { 362 type = ptr->get_base(); 363 ++(*levels); 364 } else break; 365 } 366 367 return isPolyType( type, tyVars, env ); 368 } 171 369 172 370 ast::Type const * hasPolyBase( … … 190 388 } 191 389 390 bool includesPolyType( Type *type, const TypeSubstitution *env ) { 391 type = replaceTypeInst( type, env ); 392 393 if ( dynamic_cast< TypeInstType * >( type ) ) { 394 return true; 395 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) { 396 if ( includesPolyType( pointerType->get_base(), env ) ) return true; 397 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { 398 if ( includesPolyParams( structType->get_parameters(), env ) ) return true; 399 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { 400 if ( includesPolyParams( unionType->get_parameters(), env ) ) return true; 401 } 402 return false; 403 } 404 405 bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { 406 type = replaceTypeInst( type, env ); 407 408 if ( TypeInstType *typeInstType = dynamic_cast< TypeInstType * >( type ) ) { 409 if ( tyVars.contains( typeInstType->get_name() ) ) { 410 return true; 411 } 412 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) { 413 if ( includesPolyType( pointerType->get_base(), tyVars, env ) ) return true; 414 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) { 415 if ( includesPolyParams( structType->get_parameters(), tyVars, env ) ) return true; 416 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { 417 if ( includesPolyParams( unionType->get_parameters(), tyVars, env ) ) return true; 418 } 419 return false; 420 } 421 422 FunctionType * getFunctionType( Type *ty ) { 423 PointerType *ptrType; 424 if ( ( ptrType = dynamic_cast< PointerType* >( ty ) ) ) { 425 return dynamic_cast< FunctionType* >( ptrType->get_base() ); // pointer if FunctionType, NULL otherwise 426 } else { 427 return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise 428 } 429 } 430 192 431 const ast::FunctionType * getFunctionType( const ast::Type * ty ) { 193 432 if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) { … … 198 437 } 199 438 439 VariableExpr * getBaseVar( Expression *expr, int *levels ) { 440 int dummy; 441 if ( ! levels ) { levels = &dummy; } 442 *levels = 0; 443 444 while ( true ) { 445 if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( expr ) ) { 446 return varExpr; 447 } else if ( MemberExpr *memberExpr = dynamic_cast< MemberExpr* >( expr ) ) { 448 expr = memberExpr->get_aggregate(); 449 } else if ( AddressExpr *addressExpr = dynamic_cast< AddressExpr* >( expr ) ) { 450 expr = addressExpr->get_arg(); 451 } else if ( UntypedExpr *untypedExpr = dynamic_cast< UntypedExpr* >( expr ) ) { 452 // look for compiler-inserted dereference operator 453 NameExpr *fn = dynamic_cast< NameExpr* >( untypedExpr->get_function() ); 454 if ( ! fn || fn->get_name() != std::string("*?") ) return 0; 455 expr = *untypedExpr->begin_args(); 456 } else if ( CommaExpr *commaExpr = dynamic_cast< CommaExpr* >( expr ) ) { 457 // copy constructors insert comma exprs, look at second argument which contains the variable 458 expr = commaExpr->get_arg2(); 459 continue; 460 } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( expr ) ) { 461 int lvl1; 462 int lvl2; 463 VariableExpr * var1 = getBaseVar( condExpr->get_arg2(), &lvl1 ); 464 VariableExpr * var2 = getBaseVar( condExpr->get_arg3(), &lvl2 ); 465 if ( lvl1 == lvl2 && var1 && var2 && var1->get_var() == var2->get_var() ) { 466 *levels = lvl1; 467 return var1; 468 } 469 break; 470 } else break; 471 472 ++(*levels); 473 } 474 475 return 0; 476 } 477 200 478 namespace { 201 479 /// Checks if is a pointer to D … … 210 488 inline D const * as( B const * p ) { 211 489 return reinterpret_cast<D const *>( p ); 490 } 491 492 /// Flattens a declaration list 493 template<typename Output> 494 void flattenList( list< DeclarationWithType* > src, Output out ) { 495 for ( DeclarationWithType* decl : src ) { 496 ResolvExpr::flatten( decl->get_type(), out ); 497 } 498 } 499 500 /// Flattens a list of types 501 template<typename Output> 502 void flattenList( list< Type* > src, Output out ) { 503 for ( Type* ty : src ) { 504 ResolvExpr::flatten( ty, out ); 505 } 212 506 } 213 507 … … 221 515 } 222 516 517 /// Checks if two lists of parameters are equal up to polymorphic substitution. 518 bool paramListsPolyCompatible( const list< Expression* >& aparams, const list< Expression* >& bparams ) { 519 if ( aparams.size() != bparams.size() ) return false; 520 521 for ( list< Expression* >::const_iterator at = aparams.begin(), bt = bparams.begin(); 522 at != aparams.end(); ++at, ++bt ) { 523 TypeExpr *aparam = dynamic_cast< TypeExpr* >(*at); 524 assertf(aparam, "Aggregate parameters should be type expressions"); 525 TypeExpr *bparam = dynamic_cast< TypeExpr* >(*bt); 526 assertf(bparam, "Aggregate parameters should be type expressions"); 527 528 // xxx - might need to let VoidType be a wildcard here too; could have some voids 529 // stuffed in for dtype-statics. 530 // if ( is<VoidType>( aparam->get_type() ) || is<VoidType>( bparam->get_type() ) ) continue; 531 if ( ! typesPolyCompatible( aparam->get_type(), bparam->get_type() ) ) return false; 532 } 533 534 return true; 535 } 536 223 537 bool paramListsPolyCompatible( 224 538 std::vector<ast::ptr<ast::Expr>> const & lparams, … … 245 559 return true; 246 560 } 561 } 562 563 bool typesPolyCompatible( Type *a, Type *b ) { 564 type_index aid{ typeid(*a) }; 565 // polymorphic types always match 566 if ( aid == type_index{typeid(TypeInstType)} ) return true; 567 568 type_index bid{ typeid(*b) }; 569 // polymorphic types always match 570 if ( bid == type_index{typeid(TypeInstType)} ) return true; 571 572 // can't match otherwise if different types 573 if ( aid != bid ) return false; 574 575 // recurse through type structure (conditions borrowed from Unify.cc) 576 if ( aid == type_index{typeid(BasicType)} ) { 577 return as<BasicType>(a)->get_kind() == as<BasicType>(b)->get_kind(); 578 } else if ( aid == type_index{typeid(PointerType)} ) { 579 PointerType *ap = as<PointerType>(a), *bp = as<PointerType>(b); 580 581 // void pointers should match any other pointer type 582 return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() ) 583 || typesPolyCompatible( ap->get_base(), bp->get_base() ); 584 } else if ( aid == type_index{typeid(ReferenceType)} ) { 585 ReferenceType *ap = as<ReferenceType>(a), *bp = as<ReferenceType>(b); 586 return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() ) 587 || typesPolyCompatible( ap->get_base(), bp->get_base() ); 588 } else if ( aid == type_index{typeid(ArrayType)} ) { 589 ArrayType *aa = as<ArrayType>(a), *ba = as<ArrayType>(b); 590 591 if ( aa->get_isVarLen() ) { 592 if ( ! ba->get_isVarLen() ) return false; 593 } else { 594 if ( ba->get_isVarLen() ) return false; 595 596 ConstantExpr *ad = dynamic_cast<ConstantExpr*>( aa->get_dimension() ); 597 ConstantExpr *bd = dynamic_cast<ConstantExpr*>( ba->get_dimension() ); 598 if ( ad && bd 599 && ad->get_constant()->get_value() != bd->get_constant()->get_value() ) 600 return false; 601 } 602 603 return typesPolyCompatible( aa->get_base(), ba->get_base() ); 604 } else if ( aid == type_index{typeid(FunctionType)} ) { 605 FunctionType *af = as<FunctionType>(a), *bf = as<FunctionType>(b); 606 607 vector<Type*> aparams, bparams; 608 flattenList( af->get_parameters(), back_inserter( aparams ) ); 609 flattenList( bf->get_parameters(), back_inserter( bparams ) ); 610 if ( aparams.size() != bparams.size() ) return false; 611 612 vector<Type*> areturns, breturns; 613 flattenList( af->get_returnVals(), back_inserter( areturns ) ); 614 flattenList( bf->get_returnVals(), back_inserter( breturns ) ); 615 if ( areturns.size() != breturns.size() ) return false; 616 617 for ( unsigned i = 0; i < aparams.size(); ++i ) { 618 if ( ! typesPolyCompatible( aparams[i], bparams[i] ) ) return false; 619 } 620 for ( unsigned i = 0; i < areturns.size(); ++i ) { 621 if ( ! typesPolyCompatible( areturns[i], breturns[i] ) ) return false; 622 } 623 return true; 624 } else if ( aid == type_index{typeid(StructInstType)} ) { 625 StructInstType *aa = as<StructInstType>(a), *ba = as<StructInstType>(b); 626 627 if ( aa->get_name() != ba->get_name() ) return false; 628 return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() ); 629 } else if ( aid == type_index{typeid(UnionInstType)} ) { 630 UnionInstType *aa = as<UnionInstType>(a), *ba = as<UnionInstType>(b); 631 632 if ( aa->get_name() != ba->get_name() ) return false; 633 return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() ); 634 } else if ( aid == type_index{typeid(EnumInstType)} ) { 635 return as<EnumInstType>(a)->get_name() == as<EnumInstType>(b)->get_name(); 636 } else if ( aid == type_index{typeid(TraitInstType)} ) { 637 return as<TraitInstType>(a)->get_name() == as<TraitInstType>(b)->get_name(); 638 } else if ( aid == type_index{typeid(TupleType)} ) { 639 TupleType *at = as<TupleType>(a), *bt = as<TupleType>(b); 640 641 vector<Type*> atypes, btypes; 642 flattenList( at->get_types(), back_inserter( atypes ) ); 643 flattenList( bt->get_types(), back_inserter( btypes ) ); 644 if ( atypes.size() != btypes.size() ) return false; 645 646 for ( unsigned i = 0; i < atypes.size(); ++i ) { 647 if ( ! typesPolyCompatible( atypes[i], btypes[i] ) ) return false; 648 } 649 return true; 650 } else return true; // VoidType, VarArgsType, ZeroType & OneType just need the same type 247 651 } 248 652 … … 359 763 } 360 764 765 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) { 766 // is parameter is not polymorphic, don't need to box 767 if ( ! isPolyType( param, exprTyVars ) ) return false; 768 Type * newType = arg->clone(); 769 if ( env ) env->apply( newType ); 770 std::unique_ptr<Type> manager( newType ); 771 // if the argument's type is polymorphic, we don't need to box again! 772 return ! isPolyType( newType ); 773 } 774 361 775 bool needsBoxing( const ast::Type * param, const ast::Type * arg, 362 776 const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { … … 372 786 return !isPolyType( newType ); 373 787 } 788 789 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) { 790 FunctionType * function = getFunctionType( appExpr->function->result ); 791 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() ); 792 TyVarMap exprTyVars( TypeDecl::Data{} ); 793 makeTyVarMap( function, exprTyVars ); 794 return needsBoxing( param, arg, exprTyVars, env ); 795 } 374 796 375 797 bool needsBoxing( … … 379 801 const ast::FunctionType * function = getFunctionType( expr->func->result ); 380 802 assertf( function, "ApplicationExpr has non-function type: %s", toString( expr->func->result ).c_str() ); 381 TypeVarMap exprTyVars ;803 TypeVarMap exprTyVars = { ast::TypeData() }; 382 804 makeTypeVarMap( function, exprTyVars ); 383 805 return needsBoxing( param, arg, exprTyVars, subst ); 384 806 } 385 807 808 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) { 809 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } ); 810 } 811 386 812 void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) { 387 813 typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) ); … … 391 817 typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) ); 392 818 } 819 820 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) { 821 for ( Type::ForallList::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) { 822 assert( *tyVar ); 823 addToTyVarMap( *tyVar, tyVarMap ); 824 } 825 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) { 826 makeTyVarMap( pointer->get_base(), tyVarMap ); 827 } 828 } 393 829 394 830 void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) { … … 410 846 } 411 847 848 void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) { 849 for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) { 850 os << i->first << " (" << i->second << ") "; 851 } // for 852 os << std::endl; 853 } 854 412 855 } // namespace GenPoly 413 856 -
src/GenPoly/GenPoly.h
rfc12f05 r0030b508 23 23 #include "AST/Fwd.hpp" // for ApplicationExpr, BaseInstType, Func... 24 24 #include "SymTab/Mangler.h" // for Mangler 25 #include "SynTree/Declaration.h" // for TypeDecl::Data, AggregateDecl, Type... 26 #include "SynTree/SynTree.h" // for Visitor Nodes 25 27 26 28 namespace ast { … … 30 32 namespace GenPoly { 31 33 32 struct TypeVarMap : public ErasableScopedMap<ast::TypeEnvKey, ast::TypeData> { 33 TypeVarMap() : ErasableScopedMap( ast::TypeData() ) {} 34 }; 34 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap; 35 using TypeVarMap = ErasableScopedMap< ast::TypeEnvKey, ast::TypeData >; 35 36 36 37 /// Replaces a TypeInstType by its referrent in the environment, if applicable 38 Type* replaceTypeInst( Type* type, const TypeSubstitution* env ); 39 const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ); 37 40 const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * ); 38 41 39 42 /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided 43 Type *isPolyType( Type *type, const TypeSubstitution *env = 0 ); 40 44 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr); 41 45 42 46 /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 47 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 ); 43 48 const ast::Type * isPolyType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = nullptr ); 44 49 45 50 /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided 51 ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 ); 46 52 const ast::BaseInstType *isDynType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = 0 ); 47 53 48 54 /// true iff function has dynamic-layout return type under the given type variable map 55 ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &tyVars ); 49 56 const ast::BaseInstType *isDynRet( const ast::FunctionType * type, const TypeVarMap & typeVars ); 50 57 51 58 /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters 59 ReferenceToType *isDynRet( FunctionType *function ); 52 60 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ); 53 61 54 62 /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type 63 bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVarr ); 55 64 bool needsAdapter( ast::FunctionType const * adaptee, const TypeVarMap & typeVars ); 56 65 66 /// returns polymorphic type if is pointer to polymorphic type, NULL otherwise; will look up substitution in env if provided 67 Type *isPolyPtr( Type *type, const TypeSubstitution *env = 0 ); 68 57 69 /// returns polymorphic type if is pointer to polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 70 Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 ); 58 71 const ast::Type * isPolyPtr( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * env = 0 ); 72 73 /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type, returns the base type, NULL otherwise; 74 /// N will be stored in levels, if provided, will look up substitution in env if provided 75 Type *hasPolyBase( Type *type, int *levels = 0, const TypeSubstitution *env = 0 ); 59 76 60 77 /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type in tyVars, returns the base type, NULL otherwise; 61 78 /// N will be stored in levels, if provided, will look up substitution in env if provided 79 Type *hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels = 0, const TypeSubstitution *env = 0 ); 62 80 const ast::Type * hasPolyBase( const ast::Type * type, const TypeVarMap & typeVars, int * levels = 0, const ast::TypeSubstitution * env = 0 ); 63 81 82 /// true iff this type or some base of this type after dereferencing pointers is either polymorphic or a generic type with at least one 83 /// polymorphic parameter; will look up substitution in env if provided. 84 bool includesPolyType( Type *type, const TypeSubstitution *env = 0 ); 85 86 /// true iff this type or some base of this type after dereferencing pointers is either polymorphic in tyVars, or a generic type with 87 /// at least one polymorphic parameter in tyVars; will look up substitution in env if provided. 88 bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 ); 89 64 90 /// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise 91 FunctionType *getFunctionType( Type *ty ); 65 92 const ast::FunctionType * getFunctionType( const ast::Type * ty ); 66 93 94 /// If expr (after dereferencing N >= 0 pointers) is a variable expression, returns the variable expression, NULL otherwise; 95 /// N will be stored in levels, if provided 96 VariableExpr *getBaseVar( Expression *expr, int *levels = 0 ); 97 67 98 /// true iff types are structurally identical, where TypeInstType's match any type. 99 bool typesPolyCompatible( Type *aty, Type *bty ); 68 100 bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ); 69 101 70 102 /// true if arg requires boxing given exprTyVars 103 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ); 71 104 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ); 72 105 73 106 /// true if arg requires boxing in the call to appExpr 107 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ); 74 108 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * expr, const ast::TypeSubstitution * subst ); 75 109 76 110 /// Adds the type variable `tyVar` to `tyVarMap` 111 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ); 77 112 void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars ); 78 113 void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ); 79 114 80 115 /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap` 116 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ); 81 117 void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ); 82 118 void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ); 119 120 /// Prints type variable map 121 void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ); 122 123 /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType(). 124 inline std::string mangleType( const Type *ty ) { return SymTab::Mangler::mangleType( ty ); } 83 125 84 126 /// Gets the name of the sizeof parameter for the type, given its mangled name … … 92 134 93 135 /// Gets the name of the layout function for a given aggregate type, given its declaration 136 inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); } 94 137 inline std::string layoutofName( ast::AggregateDecl const * decl ) { 95 138 return std::string( "_layoutof_" ) + decl->name; -
src/GenPoly/ScrubTyVars.cc
rfc12f05 r0030b508 21 21 #include "ScrubTyVars.h" 22 22 #include "SymTab/Mangler.h" // for mangleType 23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data, Typ... 24 #include "SynTree/Expression.h" // for Expression (ptr only), NameExpr 25 #include "SynTree/Mutator.h" // for Mutator 26 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type 23 27 24 28 namespace GenPoly { 29 Type * ScrubTyVars::postmutate( TypeInstType * typeInst ) { 30 if ( ! tyVars ) { 31 if ( typeInst->get_isFtype() ) { 32 delete typeInst; 33 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) ); 34 } else { 35 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) ); 36 delete typeInst; 37 return ret; 38 } 39 } 40 41 TyVarMap::const_iterator tyVar = tyVars->find( typeInst->name ); 42 if ( tyVar != tyVars->end() ) { 43 switch ( tyVar->second.kind ) { 44 case TypeDecl::Dtype: 45 case TypeDecl::Ttype: 46 { 47 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) ); 48 delete typeInst; 49 return ret; 50 } 51 case TypeDecl::Ftype: 52 delete typeInst; 53 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) ); 54 default: 55 assertf(false, "Unhandled tyvar kind: %d", tyVar->second.kind); 56 } // switch 57 } // if 58 return typeInst; 59 } 60 61 Type * ScrubTyVars::mutateAggregateType( Type * ty ) { 62 if ( shouldScrub( ty ) ) { 63 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) ); 64 delete ty; 65 return ret; 66 } 67 return ty; 68 } 69 70 Type * ScrubTyVars::postmutate( StructInstType * structInst ) { 71 return mutateAggregateType( structInst ); 72 } 73 74 Type * ScrubTyVars::postmutate( UnionInstType * unionInst ) { 75 return mutateAggregateType( unionInst ); 76 } 77 78 void ScrubTyVars::primeBaseScrub( Type * type ) { 79 // need to determine whether type needs to be scrubbed to determine whether 80 // automatic recursion is necessary 81 if ( Type * t = shouldScrub( type ) ) { 82 visit_children = false; 83 GuardValue( dynType ); 84 dynType = t; 85 } 86 } 87 88 Expression * ScrubTyVars::postmutate( SizeofExpr * szeof ) { 89 // sizeof( T ) => _sizeof_T parameter, which is the size of T 90 if ( dynType ) { 91 Expression *expr = new NameExpr( sizeofName( mangleType( dynType ) ) ); 92 return expr; 93 } // if 94 return szeof; 95 } 96 97 Expression * ScrubTyVars::postmutate( AlignofExpr * algnof ) { 98 // alignof( T ) => _alignof_T parameter, which is the alignment of T 99 if ( dynType ) { 100 Expression *expr = new NameExpr( alignofName( mangleType( dynType ) ) ); 101 return expr; 102 } // if 103 return algnof; 104 } 105 106 Type * ScrubTyVars::postmutate( PointerType * pointer ) { 107 if ( dynType ) { 108 Type * ret = dynType->acceptMutator( *visitor ); 109 ret->get_qualifiers() |= pointer->get_qualifiers(); 110 pointer->base = nullptr; 111 delete pointer; 112 return ret; 113 } 114 return pointer; 115 } 25 116 26 117 namespace { -
src/GenPoly/ScrubTyVars.h
rfc12f05 r0030b508 19 19 20 20 #include "AST/Fwd.hpp" // for Node 21 #include "Common/PassVisitor.h" 21 22 #include "GenPoly.h" // for TyVarMap, isPolyType, isDynType 23 #include "SynTree/Mutator.h" // for Mutator 24 #include "SynTree/Type.h" // for Type (ptr only), PointerType (ptr only) 25 26 class AlignofExpr; 27 class Expression; 28 class SizeofExpr; 22 29 23 30 namespace GenPoly { 31 struct ScrubTyVars : public WithVisitorRef<ScrubTyVars>, public WithShortCircuiting, public WithGuards { 32 /// Whether to scrub all type variables from the provided map, dynamic type variables from the provided map, or all type variables 33 enum ScrubMode { FromMap, DynamicFromMap, All }; 34 35 ScrubTyVars() : tyVars(nullptr), mode( All ) {} 36 37 ScrubTyVars( const TyVarMap &tyVars, ScrubMode mode = FromMap ): tyVars( &tyVars ), mode( mode ) {} 38 39 public: 40 /// For all polymorphic types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type, 41 /// and sizeof/alignof expressions with the proper variable 42 template< typename SynTreeClass > 43 static SynTreeClass *scrub( SynTreeClass *target, const TyVarMap &tyVars ); 44 45 /// For all dynamic-layout types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type, 46 /// and sizeof/alignof expressions with the proper variable 47 template< typename SynTreeClass > 48 static SynTreeClass *scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars ); 49 50 /// For all polymorphic types, replaces generic types, dtypes, and ftypes with the appropriate void type, 51 /// and sizeof/alignof expressions with the proper variable 52 template< typename SynTreeClass > 53 static SynTreeClass *scrubAll( SynTreeClass *target ); 54 55 /// determine if children should be visited based on whether base type should be scrubbed. 56 void primeBaseScrub( Type * ); 57 58 void premutate( TypeInstType * ) { visit_children = false; } 59 void premutate( StructInstType * ) { visit_children = false; } 60 void premutate( UnionInstType * ) { visit_children = false; } 61 void premutate( SizeofExpr * szeof ) { primeBaseScrub( szeof->type ); } 62 void premutate( AlignofExpr * algnof ) { primeBaseScrub( algnof->type ); } 63 void premutate( PointerType * pointer ) { primeBaseScrub( pointer->base ); } 64 65 Type * postmutate( TypeInstType * typeInst ); 66 Type * postmutate( StructInstType * structInst ); 67 Type * postmutate( UnionInstType * unionInst ); 68 Expression * postmutate( SizeofExpr * szeof ); 69 Expression * postmutate( AlignofExpr * algnof ); 70 Type * postmutate( PointerType * pointer ); 71 72 private: 73 /// Returns the type if it should be scrubbed, NULL otherwise. 74 Type* shouldScrub( Type *ty ) { 75 switch ( mode ) { 76 case FromMap: return isPolyType( ty, *tyVars ); 77 case DynamicFromMap: return isDynType( ty, *tyVars ); 78 case All: return isPolyType( ty ); 79 } 80 assert(false); return nullptr; // unreachable 81 // return dynamicOnly ? isDynType( ty, tyVars ) : isPolyType( ty, tyVars ); 82 } 83 84 /// Mutates (possibly generic) aggregate types appropriately 85 Type* mutateAggregateType( Type *ty ); 86 87 const TyVarMap *tyVars; ///< Type variables to scrub 88 ScrubMode mode; ///< which type variables to scrub? [FromMap] 89 90 Type * dynType = nullptr; ///< result of shouldScrub 91 }; 92 93 template< typename SynTreeClass > 94 SynTreeClass * ScrubTyVars::scrub( SynTreeClass *target, const TyVarMap &tyVars ) { 95 PassVisitor<ScrubTyVars> scrubber( tyVars ); 96 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) ); 97 } 98 99 template< typename SynTreeClass > 100 SynTreeClass * ScrubTyVars::scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars ) { 101 PassVisitor<ScrubTyVars> scrubber( tyVars, ScrubTyVars::DynamicFromMap ); 102 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) ); 103 } 104 105 template< typename SynTreeClass > 106 SynTreeClass * ScrubTyVars::scrubAll( SynTreeClass *target ) { 107 PassVisitor<ScrubTyVars> scrubber; 108 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) ); 109 } 24 110 25 111 // ScrubMode and scrubTypeVarsBase are internal. -
src/GenPoly/SpecializeNew.cpp
rfc12f05 r0030b508 23 23 #include "GenPoly/GenPoly.h" // for getFunctionType 24 24 #include "ResolvExpr/FindOpenVars.h" // for findOpenVars 25 #include "ResolvExpr/TypeEnvironment.h" // for FirstOpen, FirstClosed 25 26 26 27 namespace GenPoly { … … 80 81 } 81 82 82 // The number of elements in a list, if all tuples had been flattened.83 size_t flatT ypeListSize( const std::vector<ast::ptr<ast::Type>> & types) {84 size_t sum = 0;85 for ( const ast::ptr<ast::Type> & type : types ) {86 if ( const ast::TupleType * tuple = type.as<ast::TupleType>()) {87 sum += flatT ypeListSize( tuple->types);88 } else {89 sum += 1;90 }91 }92 return sum;83 // The number of elements in a type if it is a flattened tuple. 84 size_t flatTupleSize( const ast::Type * type ) { 85 if ( auto tuple = dynamic_cast<const ast::TupleType *>( type ) ) { 86 size_t sum = 0; 87 for ( auto t : *tuple ) { 88 sum += flatTupleSize( t ); 89 } 90 return sum; 91 } else { 92 return 1; 93 } 93 94 } 94 95 95 96 // Find the total number of components in a parameter list. 96 97 size_t functionParameterSize( const ast::FunctionType * type ) { 97 return flatTypeListSize( type->params ); 98 size_t sum = 0; 99 for ( auto param : type->params ) { 100 sum += flatTupleSize( param ); 101 } 102 return sum; 98 103 } 99 104 -
src/GenPoly/module.mk
rfc12f05 r0030b508 23 23 SRC += $(SRC_GENPOLY) \ 24 24 GenPoly/BoxNew.cpp \ 25 GenPoly/Box.cc \ 25 26 GenPoly/Box.h \ 26 27 GenPoly/ErasableScopedMap.h \ … … 28 29 GenPoly/FindFunction.h \ 29 30 GenPoly/InstantiateGenericNew.cpp \ 31 GenPoly/InstantiateGeneric.cc \ 30 32 GenPoly/InstantiateGeneric.h \ 31 33 GenPoly/LvalueNew.cpp \ 34 GenPoly/Lvalue.cc \ 32 35 GenPoly/ScopedSet.h \ 33 36 GenPoly/ScrubTyVars.cc \ 34 37 GenPoly/ScrubTyVars.h \ 38 GenPoly/Specialize.cc \ 35 39 GenPoly/SpecializeNew.cpp \ 36 40 GenPoly/Specialize.h -
src/InitTweak/FixGlobalInit.cc
rfc12f05 r0030b508 20 20 #include <algorithm> // for replace_if 21 21 22 #include "Common/PassVisitor.h" 23 #include "Common/UniqueName.h" // for UniqueName 24 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt 25 #include "SynTree/LinkageSpec.h" // for C 26 #include "SynTree/Attribute.h" // for Attribute 27 #include "SynTree/Constant.h" // for Constant 28 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declaration 29 #include "SynTree/Expression.h" // for ConstantExpr, Expression (ptr only) 30 #include "SynTree/Initializer.h" // for ConstructorInit, Initializer 31 #include "SynTree/Label.h" // for Label 32 #include "SynTree/Statement.h" // for CompoundStmt, Statement (ptr only) 33 #include "SynTree/Type.h" // for Type, Type::StorageClasses, Functi... 34 #include "SynTree/Visitor.h" // for acceptAll, Visitor 35 22 36 #include "AST/Expr.hpp" 23 37 #include "AST/Node.hpp" 24 38 #include "AST/Pass.hpp" 25 #include "Common/UniqueName.h" // for UniqueName26 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt27 39 28 40 namespace InitTweak { 41 class GlobalFixer : public WithShortCircuiting { 42 public: 43 GlobalFixer( bool inLibrary ); 44 45 void previsit( ObjectDecl *objDecl ); 46 void previsit( FunctionDecl *functionDecl ); 47 void previsit( StructDecl *aggregateDecl ); 48 void previsit( UnionDecl *aggregateDecl ); 49 void previsit( EnumDecl *aggregateDecl ); 50 void previsit( TraitDecl *aggregateDecl ); 51 void previsit( TypeDecl *typeDecl ); 52 53 UniqueName tempNamer; 54 FunctionDecl * initFunction; 55 FunctionDecl * destroyFunction; 56 }; 57 29 58 class GlobalFixer_new : public ast::WithShortCircuiting { 30 59 public: … … 41 70 }; 42 71 72 void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ) { 73 PassVisitor<GlobalFixer> visitor( inLibrary ); 74 acceptAll( translationUnit, visitor ); 75 GlobalFixer & fixer = visitor.pass; 76 // don't need to include function if it's empty 77 if ( fixer.initFunction->get_statements()->get_kids().empty() ) { 78 delete fixer.initFunction; 79 } else { 80 translationUnit.push_back( fixer.initFunction ); 81 } // if 82 83 if ( fixer.destroyFunction->get_statements()->get_kids().empty() ) { 84 delete fixer.destroyFunction; 85 } else { 86 translationUnit.push_back( fixer.destroyFunction ); 87 } // if 88 } 89 90 GlobalFixer::GlobalFixer( bool inLibrary ) : tempNamer( "_global_init" ) { 91 std::list< Expression * > ctorParameters; 92 std::list< Expression * > dtorParameters; 93 if ( inLibrary ) { 94 // Constructor/destructor attributes take a single parameter which 95 // is the priority, with lower numbers meaning higher priority. 96 // Functions specified with priority are guaranteed to run before 97 // functions without a priority. To ensure that constructors and destructors 98 // for library code are run before constructors and destructors for user code, 99 // specify a priority when building the library. Priorities 0-100 are reserved by gcc. 100 // Priorities 101-200 are reserved by cfa, so use priority 200 for CFA library globals, 101 // allowing room for overriding with a higher priority. 102 ctorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) ); 103 dtorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) ); 104 } 105 initFunction = new FunctionDecl( "__global_init__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() ); 106 initFunction->get_attributes().push_back( new Attribute( "constructor", ctorParameters ) ); 107 destroyFunction = new FunctionDecl( "__global_destroy__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() ); 108 destroyFunction->get_attributes().push_back( new Attribute( "destructor", dtorParameters ) ); 109 } 110 43 111 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { 44 112 ast::Pass<GlobalFixer_new> fixer; … … 70 138 71 139 translationUnit.decls.emplace_back(destroyFunction); 140 } // if 141 } 142 143 void GlobalFixer::previsit( ObjectDecl *objDecl ) { 144 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids(); 145 std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids(); 146 147 // C allows you to initialize objects with constant expressions 148 // xxx - this is an optimization. Need to first resolve constructors before we decide 149 // to keep C-style initializer. 150 // if ( isConstExpr( objDecl->get_init() ) ) return; 151 152 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) { 153 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 154 assert( ! ctorInit->ctor || ! ctorInit->init ); 155 156 Statement * dtor = ctorInit->dtor; 157 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 158 // don't need to call intrinsic dtor, because it does nothing, but 159 // non-intrinsic dtors must be called 160 destroyStatements.push_front( dtor ); 161 ctorInit->dtor = nullptr; 162 } // if 163 if ( Statement * ctor = ctorInit->ctor ) { 164 addDataSectionAttribute( objDecl ); 165 initStatements.push_back( ctor ); 166 objDecl->init = nullptr; 167 ctorInit->ctor = nullptr; 168 } else if ( Initializer * init = ctorInit->init ) { 169 objDecl->init = init; 170 ctorInit->init = nullptr; 171 } else { 172 // no constructor and no initializer, which is okay 173 objDecl->init = nullptr; 174 } // if 175 delete ctorInit; 72 176 } // if 73 177 } … … 103 207 } 104 208 209 // only modify global variables 210 void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; } 211 void GlobalFixer::previsit( StructDecl * ) { visit_children = false; } 212 void GlobalFixer::previsit( UnionDecl * ) { visit_children = false; } 213 void GlobalFixer::previsit( EnumDecl * ) { visit_children = false; } 214 void GlobalFixer::previsit( TraitDecl * ) { visit_children = false; } 215 void GlobalFixer::previsit( TypeDecl * ) { visit_children = false; } 216 105 217 } // namespace InitTweak 106 218 -
src/InitTweak/FixInitNew.cpp
rfc12f05 r0030b508 33 33 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 34 34 35 bool ctordtorp = false; // print all debug36 bool ctorp = false; // print ctor debug37 bool cpctorp = false; // print copy ctor debug38 bool dtorp = false; // print dtor debug35 extern bool ctordtorp; // print all debug 36 extern bool ctorp; // print ctor debug 37 extern bool cpctorp; // print copy ctor debug 38 extern bool dtorp; // print dtor debug 39 39 #define PRINT( text ) if ( ctordtorp ) { text } 40 40 #define CP_CTOR_PRINT( text ) if ( ctordtorp || cpctorp ) { text } … … 178 178 /// (currently by FixInit) 179 179 struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> { 180 typedef std::list< ObjectDecl * > OrderedDecls; 181 typedef std::list< OrderedDecls > OrderedDeclsStack; 182 180 183 InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {} 181 184 … … 191 194 ast::Pass<LabelFinder> & finder; 192 195 LabelFinder::LabelMap & labelVars; 196 OrderedDeclsStack reverseDeclOrder; 193 197 }; 194 198 -
src/InitTweak/GenInit.cc
rfc12f05 r0030b508 29 29 #include "CompilationState.h" 30 30 #include "CodeGen/OperatorTable.h" 31 #include "Common/PassVisitor.h" // for PassVisitor, WithGuards, WithShort... 31 32 #include "Common/SemanticError.h" // for SemanticError 32 33 #include "Common/ToString.hpp" // for toCString … … 37 38 #include "InitTweak.h" // for isConstExpr, InitExpander, checkIn... 38 39 #include "ResolvExpr/Resolver.h" 40 #include "SymTab/Autogen.h" // for genImplicitCall 39 41 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 40 42 #include "SymTab/Mangler.h" // for Mangler 43 #include "SynTree/LinkageSpec.h" // for isOverridable, C 44 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType 45 #include "SynTree/Expression.h" // for VariableExpr, UntypedExpr, Address... 46 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit, Initi... 47 #include "SynTree/Label.h" // for Label 48 #include "SynTree/Mutator.h" // for mutateAll 49 #include "SynTree/Statement.h" // for CompoundStmt, ImplicitCtorDtorStmt 50 #include "SynTree/Type.h" // for Type, ArrayType, Type::Qualifiers 51 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 41 52 #include "Tuples/Tuples.h" // for maybeImpure 42 53 #include "Validate/FindSpecialDecls.h" // for SizeType 43 54 44 55 namespace InitTweak { 56 namespace { 57 const std::list<Label> noLabels; 58 const std::list<Expression *> noDesignators; 59 } 60 61 struct ReturnFixer : public WithStmtsToAdd, public WithGuards { 62 /// consistently allocates a temporary variable for the return value 63 /// of a function so that anything which the resolver decides can be constructed 64 /// into the return type of a function can be returned. 65 static void makeReturnTemp( std::list< Declaration * > &translationUnit ); 66 67 void premutate( FunctionDecl *functionDecl ); 68 void premutate( ReturnStmt * returnStmt ); 69 70 protected: 71 FunctionType * ftype = nullptr; 72 std::string funcName; 73 }; 74 75 struct CtorDtor : public WithGuards, public WithShortCircuiting, public WithVisitorRef<CtorDtor> { 76 /// create constructor and destructor statements for object declarations. 77 /// the actual call statements will be added in after the resolver has run 78 /// so that the initializer expression is only removed if a constructor is found 79 /// and the same destructor call is inserted in all of the appropriate locations. 80 static void generateCtorDtor( std::list< Declaration * > &translationUnit ); 81 82 void previsit( ObjectDecl * ); 83 void previsit( FunctionDecl *functionDecl ); 84 85 // should not traverse into any of these declarations to find objects 86 // that need to be constructed or destructed 87 void previsit( StructDecl *aggregateDecl ); 88 void previsit( AggregateDecl * ) { visit_children = false; } 89 void previsit( NamedTypeDecl * ) { visit_children = false; } 90 void previsit( FunctionType * ) { visit_children = false; } 91 92 void previsit( CompoundStmt * compoundStmt ); 93 94 private: 95 // set of mangled type names for which a constructor or destructor exists in the current scope. 96 // these types require a ConstructorInit node to be generated, anything else is a POD type and thus 97 // should not have a ConstructorInit generated. 98 99 ManagedTypes managedTypes; 100 bool inFunction = false; 101 }; 102 103 struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards, public WithIndexer { 104 /// hoist dimension from array types in object declaration so that it uses a single 105 /// const variable of type size_t, so that side effecting array dimensions are only 106 /// computed once. 107 static void hoistArrayDimension( std::list< Declaration * > & translationUnit ); 108 109 void premutate( ObjectDecl * objectDecl ); 110 DeclarationWithType * postmutate( ObjectDecl * objectDecl ); 111 void premutate( FunctionDecl *functionDecl ); 112 // should not traverse into any of these declarations to find objects 113 // that need to be constructed or destructed 114 void premutate( AggregateDecl * ) { visit_children = false; } 115 void premutate( NamedTypeDecl * ) { visit_children = false; } 116 void premutate( FunctionType * ) { visit_children = false; } 117 118 // need this so that enumerators are added to the indexer, due to premutate(AggregateDecl *) 119 void premutate( EnumDecl * ) {} 120 121 void hoist( Type * type ); 122 123 Type::StorageClasses storageClasses; 124 bool inFunction = false; 125 }; 126 127 struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards { 128 /// hoist dimension from array types in object declaration so that it uses a single 129 /// const variable of type size_t, so that side effecting array dimensions are only 130 /// computed once. 131 static void hoistArrayDimension( std::list< Declaration * > & translationUnit ); 132 133 void premutate( ObjectDecl * objectDecl ); 134 DeclarationWithType * postmutate( ObjectDecl * objectDecl ); 135 void premutate( FunctionDecl *functionDecl ); 136 // should not traverse into any of these declarations to find objects 137 // that need to be constructed or destructed 138 void premutate( AggregateDecl * ) { visit_children = false; } 139 void premutate( NamedTypeDecl * ) { visit_children = false; } 140 void premutate( FunctionType * ) { visit_children = false; } 141 142 void hoist( Type * type ); 143 144 Type::StorageClasses storageClasses; 145 bool inFunction = false; 146 }; 147 148 void genInit( std::list< Declaration * > & translationUnit ) { 149 if (!useNewAST) { 150 HoistArrayDimension::hoistArrayDimension( translationUnit ); 151 } 152 else { 153 HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit ); 154 } 155 fixReturnStatements( translationUnit ); 156 157 if (!useNewAST) { 158 CtorDtor::generateCtorDtor( translationUnit ); 159 } 160 } 161 162 void fixReturnStatements( std::list< Declaration * > & translationUnit ) { 163 PassVisitor<ReturnFixer> fixer; 164 mutateAll( translationUnit, fixer ); 165 } 166 167 void ReturnFixer::premutate( ReturnStmt *returnStmt ) { 168 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals(); 169 assert( returnVals.size() == 0 || returnVals.size() == 1 ); 170 // hands off if the function returns a reference - we don't want to allocate a temporary if a variable's address 171 // is being returned 172 if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) { 173 // explicitly construct the return value using the return expression and the retVal object 174 assertf( returnVals.front()->name != "", "Function %s has unnamed return value\n", funcName.c_str() ); 175 176 ObjectDecl * retVal = strict_dynamic_cast< ObjectDecl * >( returnVals.front() ); 177 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( returnStmt->expr ) ) { 178 // return statement has already been mutated - don't need to do it again 179 if ( varExpr->var == retVal ) return; 180 } 181 Statement * stmt = genCtorDtor( "?{}", retVal, returnStmt->expr ); 182 assertf( stmt, "ReturnFixer: genCtorDtor returned nullptr: %s / %s", toString( retVal ).c_str(), toString( returnStmt->expr ).c_str() ); 183 stmtsToAddBefore.push_back( stmt ); 184 185 // return the retVal object 186 returnStmt->expr = new VariableExpr( returnVals.front() ); 187 } // if 188 } 189 190 void ReturnFixer::premutate( FunctionDecl *functionDecl ) { 191 GuardValue( ftype ); 192 GuardValue( funcName ); 193 194 ftype = functionDecl->type; 195 funcName = functionDecl->name; 196 } 197 198 // precompute array dimension expression, because constructor generation may duplicate it, 199 // which would be incorrect if it is a side-effecting computation. 200 void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) { 201 PassVisitor<HoistArrayDimension> hoister; 202 mutateAll( translationUnit, hoister ); 203 } 204 205 void HoistArrayDimension::premutate( ObjectDecl * objectDecl ) { 206 GuardValue( storageClasses ); 207 storageClasses = objectDecl->get_storageClasses(); 208 } 209 210 DeclarationWithType * HoistArrayDimension::postmutate( ObjectDecl * objectDecl ) { 211 hoist( objectDecl->get_type() ); 212 return objectDecl; 213 } 214 215 void HoistArrayDimension::hoist( Type * type ) { 216 // if in function, generate const size_t var 217 static UniqueName dimensionName( "_array_dim" ); 218 219 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension. 220 if ( ! inFunction ) return; 221 if ( storageClasses.is_static ) return; 222 223 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { 224 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist? 225 226 // need to resolve array dimensions in order to accurately determine if constexpr 227 ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer ); 228 // array is variable-length when the dimension is not constexpr 229 arrayType->isVarLen = ! isConstExpr( arrayType->dimension ); 230 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects. 231 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve 232 // still try to detect constant expressions 233 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return; 234 235 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) ); 236 arrayDimension->get_type()->set_const( true ); 237 238 arrayType->set_dimension( new VariableExpr( arrayDimension ) ); 239 declsToAddBefore.push_back( arrayDimension ); 240 241 hoist( arrayType->get_base() ); 242 return; 243 } 244 } 245 246 void HoistArrayDimension::premutate( FunctionDecl * ) { 247 GuardValue( inFunction ); 248 inFunction = true; 249 } 250 251 // precompute array dimension expression, because constructor generation may duplicate it, 252 // which would be incorrect if it is a side-effecting computation. 253 void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) { 254 PassVisitor<HoistArrayDimension_NoResolve> hoister; 255 mutateAll( translationUnit, hoister ); 256 } 257 258 void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) { 259 GuardValue( storageClasses ); 260 storageClasses = objectDecl->get_storageClasses(); 261 } 262 263 DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) { 264 hoist( objectDecl->get_type() ); 265 return objectDecl; 266 } 267 268 void HoistArrayDimension_NoResolve::hoist( Type * type ) { 269 // if in function, generate const size_t var 270 static UniqueName dimensionName( "_array_dim" ); 271 272 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension. 273 if ( ! inFunction ) return; 274 if ( storageClasses.is_static ) return; 275 276 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { 277 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist? 278 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects. 279 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve 280 // still try to detect constant expressions 281 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return; 282 283 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) ); 284 arrayDimension->get_type()->set_const( true ); 285 286 arrayType->set_dimension( new VariableExpr( arrayDimension ) ); 287 declsToAddBefore.push_back( arrayDimension ); 288 289 hoist( arrayType->get_base() ); 290 return; 291 } 292 } 293 294 void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) { 295 GuardValue( inFunction ); 296 inFunction = true; 297 } 45 298 46 299 namespace { … … 273 526 } 274 527 528 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) { 529 PassVisitor<CtorDtor> ctordtor; 530 acceptAll( translationUnit, ctordtor ); 531 } 532 533 bool ManagedTypes::isManaged( Type * type ) const { 534 // references are never constructed 535 if ( dynamic_cast< ReferenceType * >( type ) ) return false; 536 // need to clear and reset qualifiers when determining if a type is managed 537 ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() ); 538 type->get_qualifiers() = Type::Qualifiers(); 539 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) { 540 // tuple is also managed if any of its components are managed 541 if ( std::any_of( tupleType->types.begin(), tupleType->types.end(), [&](Type * type) { return isManaged( type ); }) ) { 542 return true; 543 } 544 } 545 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable) 546 return managedTypes.find( SymTab::Mangler::mangleConcrete( type ) ) != managedTypes.end() || GenPoly::isPolyType( type ); 547 } 548 549 bool ManagedTypes::isManaged( ObjectDecl * objDecl ) const { 550 Type * type = objDecl->get_type(); 551 while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) { 552 // must always construct VLAs with an initializer, since this is an error in C 553 if ( at->isVarLen && objDecl->init ) return true; 554 type = at->get_base(); 555 } 556 return isManaged( type ); 557 } 558 559 // why is this not just on FunctionDecl? 560 void ManagedTypes::handleDWT( DeclarationWithType * dwt ) { 561 // if this function is a user-defined constructor or destructor, mark down the type as "managed" 562 if ( ! LinkageSpec::isOverridable( dwt->get_linkage() ) && CodeGen::isCtorDtor( dwt->get_name() ) ) { 563 std::list< DeclarationWithType * > & params = GenPoly::getFunctionType( dwt->get_type() )->get_parameters(); 564 assert( ! params.empty() ); 565 Type * type = InitTweak::getPointerBase( params.front()->get_type() ); 566 assert( type ); 567 managedTypes.insert( SymTab::Mangler::mangleConcrete( type ) ); 568 } 569 } 570 571 void ManagedTypes::handleStruct( StructDecl * aggregateDecl ) { 572 // don't construct members, but need to take note if there is a managed member, 573 // because that means that this type is also managed 574 for ( Declaration * member : aggregateDecl->get_members() ) { 575 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) { 576 if ( isManaged( field ) ) { 577 // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that 578 // polymorphic constructors make generic types managed types 579 StructInstType inst( Type::Qualifiers(), aggregateDecl ); 580 managedTypes.insert( SymTab::Mangler::mangleConcrete( &inst ) ); 581 break; 582 } 583 } 584 } 585 } 586 587 void ManagedTypes::beginScope() { managedTypes.beginScope(); } 588 void ManagedTypes::endScope() { managedTypes.endScope(); } 589 275 590 bool ManagedTypes_new::isManaged( const ast::Type * type ) const { 276 591 // references are never constructed … … 332 647 void ManagedTypes_new::endScope() { managedTypes.endScope(); } 333 648 649 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) { 650 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor 651 assertf( objDecl, "genCtorDtor passed null objDecl" ); 652 std::list< Statement * > stmts; 653 InitExpander_old srcParam( maybeClone( arg ) ); 654 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl ); 655 assert( stmts.size() <= 1 ); 656 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr; 657 658 } 659 334 660 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 335 661 assertf(objDecl, "genCtorDtor passed null objDecl"); 336 662 InitExpander_new srcParam(arg); 337 663 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl); 664 } 665 666 ConstructorInit * genCtorInit( ObjectDecl * objDecl ) { 667 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor 668 // for each constructable object 669 std::list< Statement * > ctor; 670 std::list< Statement * > dtor; 671 672 InitExpander_old srcParam( objDecl->get_init() ); 673 InitExpander_old nullParam( (Initializer *)NULL ); 674 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl ); 675 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false ); 676 677 // Currently genImplicitCall produces a single Statement - a CompoundStmt 678 // which wraps everything that needs to happen. As such, it's technically 679 // possible to use a Statement ** in the above calls, but this is inherently 680 // unsafe, so instead we take the slightly less efficient route, but will be 681 // immediately informed if somehow the above assumption is broken. In this case, 682 // we could always wrap the list of statements at this point with a CompoundStmt, 683 // but it seems reasonable at the moment for this to be done by genImplicitCall 684 // itself. It is possible that genImplicitCall produces no statements (e.g. if 685 // an array type does not have a dimension). In this case, it's fine to ignore 686 // the object for the purposes of construction. 687 assert( ctor.size() == dtor.size() && ctor.size() <= 1 ); 688 if ( ctor.size() == 1 ) { 689 // need to remember init expression, in case no ctors exist 690 // if ctor does exist, want to use ctor expression instead of init 691 // push this decision to the resolver 692 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) ); 693 return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ); 694 } 695 return nullptr; 696 } 697 698 void CtorDtor::previsit( ObjectDecl * objDecl ) { 699 managedTypes.handleDWT( objDecl ); 700 // hands off if @=, extern, builtin, etc. 701 // even if unmanaged, try to construct global or static if initializer is not constexpr, since this is not legal C 702 if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) { 703 // constructed objects cannot be designated 704 if ( isDesignated( objDecl->get_init() ) ) SemanticError( objDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" ); 705 // constructed objects should not have initializers nested too deeply 706 if ( ! checkInitDepth( objDecl ) ) SemanticError( objDecl, "Managed object's initializer is too deep " ); 707 708 objDecl->set_init( genCtorInit( objDecl ) ); 709 } 710 } 711 712 void CtorDtor::previsit( FunctionDecl *functionDecl ) { 713 visit_children = false; // do not try and construct parameters or forall parameters 714 GuardValue( inFunction ); 715 inFunction = true; 716 717 managedTypes.handleDWT( functionDecl ); 718 719 GuardScope( managedTypes ); 720 // go through assertions and recursively add seen ctor/dtors 721 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) { 722 for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) { 723 managedTypes.handleDWT( assertion ); 724 } 725 } 726 727 maybeAccept( functionDecl->get_statements(), *visitor ); 728 } 729 730 void CtorDtor::previsit( StructDecl *aggregateDecl ) { 731 visit_children = false; // do not try to construct and destruct aggregate members 732 733 managedTypes.handleStruct( aggregateDecl ); 734 } 735 736 void CtorDtor::previsit( CompoundStmt * ) { 737 GuardScope( managedTypes ); 338 738 } 339 739 -
src/InitTweak/GenInit.h
rfc12f05 r0030b508 22 22 #include "Common/CodeLocation.h" 23 23 #include "GenPoly/ScopedSet.h" // for ScopedSet 24 #include "SynTree/SynTree.h" // for Visitor Nodes 24 25 25 26 namespace InitTweak { 26 27 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 void genInit( std::list< Declaration * > & translationUnit ); 27 29 void genInit( ast::TranslationUnit & translationUnit ); 28 30 29 31 /// Converts return statements into copy constructor calls on the hidden return variable. 30 32 /// This pass must happen before auto-gen. 33 void fixReturnStatements( std::list< Declaration * > & translationUnit ); 31 34 void fixReturnStatements( ast::TranslationUnit & translationUnit ); 32 35 33 36 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 37 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr ); 34 38 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 35 39 36 40 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 41 ConstructorInit * genCtorInit( ObjectDecl * objDecl ); 37 42 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ); 43 44 class ManagedTypes { 45 public: 46 bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed 47 bool isManaged( Type * type ) const; // determine if type is managed 48 49 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor 50 void handleStruct( StructDecl * aggregateDecl ); // add type to managed if child is managed 51 52 void beginScope(); 53 void endScope(); 54 private: 55 GenPoly::ScopedSet< std::string > managedTypes; 56 }; 38 57 39 58 class ManagedTypes_new { -
src/InitTweak/InitTweak.cc
rfc12f05 r0030b508 29 29 #include "AST/Type.hpp" 30 30 #include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto... 31 #include "Common/PassVisitor.h" 31 32 #include "Common/SemanticError.h" // for SemanticError 32 33 #include "Common/UniqueName.h" // for UniqueName … … 35 36 #include "InitTweak.h" 36 37 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 38 #include "SymTab/Autogen.h" 39 #include "SymTab/Indexer.h" // for Indexer 40 #include "SynTree/LinkageSpec.h" // for Spec, isBuiltin, Intrinsic 41 #include "SynTree/Attribute.h" // for Attribute 42 #include "SynTree/Constant.h" // for Constant 43 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType 44 #include "SynTree/Expression.h" // for Expression, UntypedExpr, Applicati... 45 #include "SynTree/Initializer.h" // for Initializer, ListInit, Designation 46 #include "SynTree/Label.h" // for Label 47 #include "SynTree/Statement.h" // for CompoundStmt, ExprStmt, BranchStmt 48 #include "SynTree/Type.h" // for FunctionType, ArrayType, PointerType 49 #include "SynTree/Visitor.h" // for Visitor, maybeAccept 37 50 #include "Tuples/Tuples.h" // for Tuples::isTtype 38 51 39 52 namespace InitTweak { 40 53 namespace { 54 struct HasDesignations : public WithShortCircuiting { 55 bool hasDesignations = false; 56 57 void previsit( BaseSyntaxNode * ) { 58 // short circuit if we already know there are designations 59 if ( hasDesignations ) visit_children = false; 60 } 61 62 void previsit( Designation * des ) { 63 // short circuit if we already know there are designations 64 if ( hasDesignations ) visit_children = false; 65 else if ( ! des->get_designators().empty() ) { 66 hasDesignations = true; 67 visit_children = false; 68 } 69 } 70 }; 71 72 struct InitDepthChecker : public WithGuards { 73 bool depthOkay = true; 74 Type * type; 75 int curDepth = 0, maxDepth = 0; 76 InitDepthChecker( Type * type ) : type( type ) { 77 Type * t = type; 78 while ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) { 79 maxDepth++; 80 t = at->get_base(); 81 } 82 maxDepth++; 83 } 84 void previsit( ListInit * ) { 85 curDepth++; 86 GuardAction( [this]() { curDepth--; } ); 87 if ( curDepth > maxDepth ) depthOkay = false; 88 } 89 }; 90 41 91 struct HasDesignations_new : public ast::WithShortCircuiting { 42 92 bool result = false; … … 57 107 }; 58 108 59 struct InitDepthChecker_new {109 struct InitDepthChecker_new : public ast::WithGuards { 60 110 bool result = true; 61 111 const ast::Type * type; … … 69 119 maxDepth++; 70 120 } 71 void previsit( ast::ListInit const * ) {121 void previsit( ListInit * ) { 72 122 curDepth++; 123 GuardAction( [this]() { curDepth--; } ); 73 124 if ( curDepth > maxDepth ) result = false; 74 125 } 75 void postvisit( ast::ListInit const * ) { 76 curDepth--; 77 } 126 }; 127 128 struct InitFlattener_old : public WithShortCircuiting { 129 void previsit( SingleInit * singleInit ) { 130 visit_children = false; 131 argList.push_back( singleInit->value->clone() ); 132 } 133 std::list< Expression * > argList; 78 134 }; 79 135 … … 88 144 89 145 } // anonymous namespace 146 147 std::list< Expression * > makeInitList( Initializer * init ) { 148 PassVisitor<InitFlattener_old> flattener; 149 maybeAccept( init, flattener ); 150 return flattener.pass.argList; 151 } 152 153 bool isDesignated( Initializer * init ) { 154 PassVisitor<HasDesignations> finder; 155 maybeAccept( init, finder ); 156 return finder.pass.hasDesignations; 157 } 158 159 bool checkInitDepth( ObjectDecl * objDecl ) { 160 PassVisitor<InitDepthChecker> checker( objDecl->type ); 161 maybeAccept( objDecl->init, checker ); 162 return checker.pass.depthOkay; 163 } 90 164 91 165 bool isDesignated( const ast::Init * init ) { … … 106 180 return std::move( flattener.core.argList ); 107 181 } 182 183 class InitExpander_old::ExpanderImpl { 184 public: 185 virtual ~ExpanderImpl() = default; 186 virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0; 187 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0; 188 }; 189 190 class InitImpl_old : public InitExpander_old::ExpanderImpl { 191 public: 192 InitImpl_old( Initializer * init ) : init( init ) {} 193 virtual ~InitImpl_old() = default; 194 195 virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) { 196 // this is wrong, but just a placeholder for now 197 // if ( ! flattened ) flatten( indices ); 198 // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >(); 199 return makeInitList( init ); 200 } 201 202 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ); 203 private: 204 Initializer * init; 205 }; 206 207 class ExprImpl_old : public InitExpander_old::ExpanderImpl { 208 public: 209 ExprImpl_old( Expression * expr ) : arg( expr ) {} 210 virtual ~ExprImpl_old() { delete arg; } 211 212 virtual std::list< Expression * > next( std::list< Expression * > & indices ) { 213 std::list< Expression * > ret; 214 Expression * expr = maybeClone( arg ); 215 if ( expr ) { 216 for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) { 217 // go through indices and layer on subscript exprs ?[?] 218 ++it; 219 UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") ); 220 subscriptExpr->get_args().push_back( expr ); 221 subscriptExpr->get_args().push_back( (*it)->clone() ); 222 expr = subscriptExpr; 223 } 224 ret.push_back( expr ); 225 } 226 return ret; 227 } 228 229 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ); 230 private: 231 Expression * arg; 232 }; 233 234 InitExpander_old::InitExpander_old( Initializer * init ) : expander( new InitImpl_old( init ) ) {} 235 236 InitExpander_old::InitExpander_old( Expression * expr ) : expander( new ExprImpl_old( expr ) ) {} 237 238 std::list< Expression * > InitExpander_old::operator*() { 239 return cur; 240 } 241 242 InitExpander_old & InitExpander_old::operator++() { 243 cur = expander->next( indices ); 244 return *this; 245 } 246 247 // use array indices list to build switch statement 248 void InitExpander_old::addArrayIndex( Expression * index, Expression * dimension ) { 249 indices.push_back( index ); 250 indices.push_back( dimension ); 251 } 252 253 void InitExpander_old::clearArrayIndices() { 254 deleteAll( indices ); 255 indices.clear(); 256 } 257 258 bool InitExpander_old::addReference() { 259 bool added = false; 260 for ( Expression *& expr : cur ) { 261 expr = new AddressExpr( expr ); 262 added = true; 263 } 264 return added; 265 } 266 267 namespace { 268 /// given index i, dimension d, initializer init, and callExpr f, generates 269 /// if (i < d) f(..., init) 270 /// ++i; 271 /// so that only elements within the range of the array are constructed 272 template< typename OutIterator > 273 void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) { 274 UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") ); 275 cond->get_args().push_back( index->clone() ); 276 cond->get_args().push_back( dimension->clone() ); 277 278 std::list< Expression * > args = makeInitList( init ); 279 callExpr->get_args().splice( callExpr->get_args().end(), args ); 280 281 *out++ = new IfStmt( cond, new ExprStmt( callExpr ), nullptr ); 282 283 UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) ); 284 increment->get_args().push_back( index->clone() ); 285 *out++ = new ExprStmt( increment ); 286 } 287 288 template< typename OutIterator > 289 void build( UntypedExpr * callExpr, InitExpander_old::IndexList::iterator idx, InitExpander_old::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) { 290 if ( idx == idxEnd ) return; 291 Expression * index = *idx++; 292 assert( idx != idxEnd ); 293 Expression * dimension = *idx++; 294 295 // xxx - may want to eventually issue a warning here if we can detect 296 // that the number of elements exceeds to dimension of the array 297 if ( idx == idxEnd ) { 298 if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) { 299 for ( Initializer * init : *listInit ) { 300 buildCallExpr( callExpr->clone(), index, dimension, init, out ); 301 } 302 } else { 303 buildCallExpr( callExpr->clone(), index, dimension, init, out ); 304 } 305 } else { 306 std::list< Statement * > branches; 307 308 unsigned long cond = 0; 309 ListInit * listInit = dynamic_cast< ListInit * >( init ); 310 if ( ! listInit ) { 311 // xxx - this shouldn't be an error, but need a way to 312 // terminate without creating output, so should catch this error 313 SemanticError( init->location, "unbalanced list initializers" ); 314 } 315 316 static UniqueName targetLabel( "L__autogen__" ); 317 Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } ); 318 for ( Initializer * init : *listInit ) { 319 Expression * condition; 320 // check for designations 321 // if ( init-> ) { 322 condition = new ConstantExpr( Constant::from_ulong( cond ) ); 323 ++cond; 324 // } else { 325 // condition = // ... take designation 326 // cond = // ... take designation+1 327 // } 328 std::list< Statement * > stmts; 329 build( callExpr, idx, idxEnd, init, back_inserter( stmts ) ); 330 stmts.push_back( new BranchStmt( switchLabel, BranchStmt::Break ) ); 331 CaseStmt * caseStmt = new CaseStmt( condition, stmts ); 332 branches.push_back( caseStmt ); 333 } 334 *out++ = new SwitchStmt( index->clone(), branches ); 335 *out++ = new NullStmt( { switchLabel } ); 336 } 337 } 338 } 339 340 // if array came with an initializer list: initialize each element 341 // may have more initializers than elements in the array - need to check at each index that 342 // we haven't exceeded size. 343 // may have fewer initializers than elements in the array - need to default construct 344 // remaining elements. 345 // To accomplish this, generate switch statement, consuming all of expander's elements 346 Statement * InitImpl_old::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) { 347 if ( ! init ) return nullptr; 348 CompoundStmt * block = new CompoundStmt(); 349 build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) ); 350 if ( block->get_kids().empty() ) { 351 delete block; 352 return nullptr; 353 } else { 354 init = nullptr; // init was consumed in creating the list init 355 return block; 356 } 357 } 358 359 Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) { 360 return nullptr; 361 } 362 363 Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) { 364 return expander->buildListInit( dst, indices ); 365 } 108 366 109 367 class InitExpander_new::ExpanderImpl { … … 277 535 } 278 536 537 Type * getTypeofThis( FunctionType * ftype ) { 538 assertf( ftype, "getTypeofThis: nullptr ftype" ); 539 ObjectDecl * thisParam = getParamThis( ftype ); 540 ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( thisParam->type ); 541 return refType->base; 542 } 543 279 544 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { 280 545 assertf( ftype, "getTypeofThis: nullptr ftype" ); … … 287 552 } 288 553 554 ObjectDecl * getParamThis( FunctionType * ftype ) { 555 assertf( ftype, "getParamThis: nullptr ftype" ); 556 auto & params = ftype->parameters; 557 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( ftype ).c_str() ); 558 return strict_dynamic_cast< ObjectDecl * >( params.front() ); 559 } 560 289 561 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 290 562 assertf( func, "getParamThis: nullptr ftype" ); … … 292 564 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str()); 293 565 return params.front().strict_as<ast::ObjectDecl>(); 566 } 567 568 bool tryConstruct( DeclarationWithType * dwt ) { 569 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt ); 570 if ( ! objDecl ) return false; 571 return (objDecl->get_init() == nullptr || 572 ( objDecl->get_init() != nullptr && objDecl->get_init()->get_maybeConstructed() )) 573 && ! objDecl->get_storageClasses().is_extern 574 && isConstructable( objDecl->type ); 575 } 576 577 bool isConstructable( Type * type ) { 578 return ! dynamic_cast< VarArgsType * >( type ) && ! dynamic_cast< ReferenceType * >( type ) && ! dynamic_cast< FunctionType * >( type ) && ! Tuples::isTtype( type ); 294 579 } 295 580 … … 308 593 } 309 594 595 struct CallFinder_old { 596 CallFinder_old( const std::list< std::string > & names ) : names( names ) {} 597 598 void postvisit( ApplicationExpr * appExpr ) { 599 handleCallExpr( appExpr ); 600 } 601 602 void postvisit( UntypedExpr * untypedExpr ) { 603 handleCallExpr( untypedExpr ); 604 } 605 606 std::list< Expression * > * matches; 607 private: 608 const std::list< std::string > names; 609 610 template< typename CallExpr > 611 void handleCallExpr( CallExpr * expr ) { 612 std::string fname = getFunctionName( expr ); 613 if ( std::find( names.begin(), names.end(), fname ) != names.end() ) { 614 matches->push_back( expr ); 615 } 616 } 617 }; 618 310 619 struct CallFinder_new final { 311 620 std::vector< const ast::Expr * > matches; … … 325 634 }; 326 635 636 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) { 637 static PassVisitor<CallFinder_old> finder( std::list< std::string >{ "?{}", "^?{}" } ); 638 finder.pass.matches = &matches; 639 maybeAccept( stmt, finder ); 640 } 641 327 642 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 328 643 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; … … 331 646 } 332 647 648 Expression * getCtorDtorCall( Statement * stmt ) { 649 std::list< Expression * > matches; 650 collectCtorDtorCalls( stmt, matches ); 651 assertf( matches.size() <= 1, "%zd constructor/destructors found in %s", matches.size(), toString( stmt ).c_str() ); 652 return matches.size() == 1 ? matches.front() : nullptr; 653 } 654 333 655 namespace { 656 DeclarationWithType * getCalledFunction( Expression * expr ); 657 658 template<typename CallExpr> 659 DeclarationWithType * handleDerefCalledFunction( CallExpr * expr ) { 660 // (*f)(x) => should get "f" 661 std::string name = getFunctionName( expr ); 662 assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() ); 663 assertf( ! expr->get_args().empty(), "Cannot get called function from dereference with no arguments" ); 664 return getCalledFunction( expr->get_args().front() ); 665 } 666 667 DeclarationWithType * getCalledFunction( Expression * expr ) { 668 assert( expr ); 669 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) { 670 return varExpr->var; 671 } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( expr ) ) { 672 return memberExpr->member; 673 } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) { 674 return getCalledFunction( castExpr->arg ); 675 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( expr ) ) { 676 return handleDerefCalledFunction( untypedExpr ); 677 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) { 678 return handleDerefCalledFunction( appExpr ); 679 } else if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) { 680 return getCalledFunction( addrExpr->arg ); 681 } else if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( expr ) ) { 682 return getCalledFunction( commaExpr->arg2 ); 683 } 684 return nullptr; 685 } 686 687 DeclarationWithType * getFunctionCore( const Expression * expr ) { 688 if ( const auto * appExpr = dynamic_cast< const ApplicationExpr * >( expr ) ) { 689 return getCalledFunction( appExpr->function ); 690 } else if ( const auto * untyped = dynamic_cast< const UntypedExpr * >( expr ) ) { 691 return getCalledFunction( untyped->function ); 692 } 693 assertf( false, "getFunction with unknown expression: %s", toString( expr ).c_str() ); 694 } 695 } 696 697 DeclarationWithType * getFunction( Expression * expr ) { 698 return getFunctionCore( expr ); 699 } 700 701 const DeclarationWithType * getFunction( const Expression * expr ) { 702 return getFunctionCore( expr ); 703 } 704 705 ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) { 706 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ); 707 if ( ! appExpr ) return nullptr; 708 DeclarationWithType * function = getCalledFunction( appExpr->get_function() ); 709 assertf( function, "getCalledFunction returned nullptr: %s", toString( appExpr->get_function() ).c_str() ); 710 // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor 711 // will call all member dtors, and some members may have a user defined dtor. 712 return function->get_linkage() == LinkageSpec::Intrinsic ? appExpr : nullptr; 713 } 714 715 namespace { 716 template <typename Predicate> 717 bool allofCtorDtor( Statement * stmt, const Predicate & pred ) { 718 std::list< Expression * > callExprs; 719 collectCtorDtorCalls( stmt, callExprs ); 720 return std::all_of( callExprs.begin(), callExprs.end(), pred); 721 } 722 334 723 template <typename Predicate> 335 724 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { … … 337 726 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 338 727 } 728 } 729 730 bool isIntrinsicSingleArgCallStmt( Statement * stmt ) { 731 return allofCtorDtor( stmt, []( Expression * callExpr ){ 732 if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) { 733 FunctionType *funcType = GenPoly::getFunctionType( appExpr->function->result ); 734 assert( funcType ); 735 return funcType->get_parameters().size() == 1; 736 } 737 return false; 738 }); 339 739 } 340 740 … … 349 749 return false; 350 750 }); 751 } 752 753 bool isIntrinsicCallStmt( Statement * stmt ) { 754 return allofCtorDtor( stmt, []( Expression * callExpr ) { 755 return isIntrinsicCallExpr( callExpr ); 756 }); 757 } 758 759 namespace { 760 template<typename CallExpr> 761 Expression *& callArg( CallExpr * callExpr, unsigned int pos ) { 762 if ( pos >= callExpr->get_args().size() ) assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", pos, toString( callExpr ).c_str() ); 763 for ( Expression *& arg : callExpr->get_args() ) { 764 if ( pos == 0 ) return arg; 765 pos--; 766 } 767 assert( false ); 768 } 769 } 770 771 Expression *& getCallArg( Expression * callExpr, unsigned int pos ) { 772 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr ) ) { 773 return callArg( appExpr, pos ); 774 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( callExpr ) ) { 775 return callArg( untypedExpr, pos ); 776 } else if ( TupleAssignExpr * tupleExpr = dynamic_cast< TupleAssignExpr * > ( callExpr ) ) { 777 std::list< Statement * > & stmts = tupleExpr->get_stmtExpr()->get_statements()->get_kids(); 778 assertf( ! stmts.empty(), "TupleAssignExpr somehow has no statements." ); 779 ExprStmt * stmt = strict_dynamic_cast< ExprStmt * >( stmts.back() ); 780 TupleExpr * tuple = strict_dynamic_cast< TupleExpr * >( stmt->get_expr() ); 781 assertf( ! tuple->get_exprs().empty(), "TupleAssignExpr somehow has empty tuple expr." ); 782 return getCallArg( tuple->get_exprs().front(), pos ); 783 } else if ( ImplicitCopyCtorExpr * copyCtor = dynamic_cast< ImplicitCopyCtorExpr * >( callExpr ) ) { 784 return getCallArg( copyCtor->callExpr, pos ); 785 } else { 786 assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() ); 787 } 788 } 789 790 namespace { 791 std::string funcName( Expression * func ); 792 793 template<typename CallExpr> 794 std::string handleDerefName( CallExpr * expr ) { 795 // (*f)(x) => should get name "f" 796 std::string name = getFunctionName( expr ); 797 assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() ); 798 assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" ); 799 return funcName( expr->get_args().front() ); 800 } 801 802 std::string funcName( Expression * func ) { 803 if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( func ) ) { 804 return nameExpr->get_name(); 805 } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) { 806 return varExpr->get_var()->get_name(); 807 } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) { 808 return funcName( castExpr->get_arg() ); 809 } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( func ) ) { 810 return memberExpr->get_member()->get_name(); 811 } else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) { 812 return funcName( memberExpr->get_member() ); 813 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( func ) ) { 814 return handleDerefName( untypedExpr ); 815 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( func ) ) { 816 return handleDerefName( appExpr ); 817 } else if ( ConstructorExpr * ctorExpr = dynamic_cast< ConstructorExpr * >( func ) ) { 818 return funcName( getCallArg( ctorExpr->get_callExpr(), 0 ) ); 819 } else { 820 assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() ); 821 } 822 } 823 } 824 825 std::string getFunctionName( Expression * expr ) { 826 // there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and 827 // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction 828 // can't possibly do anything reasonable. 829 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) { 830 return funcName( appExpr->get_function() ); 831 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) { 832 return funcName( untypedExpr->get_function() ); 833 } else { 834 std::cerr << expr << std::endl; 835 assertf( false, "Unexpected expression type passed to getFunctionName" ); 836 } 837 } 838 839 Type * getPointerBase( Type * type ) { 840 if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) { 841 return ptrType->get_base(); 842 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { 843 return arrayType->get_base(); 844 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( type ) ) { 845 return refType->get_base(); 846 } else { 847 return nullptr; 848 } 849 } 850 851 Type * isPointerType( Type * type ) { 852 return getPointerBase( type ) ? type : nullptr; 853 } 854 855 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ) { 856 static FunctionDecl * assign = nullptr; 857 if ( ! assign ) { 858 // temporary? Generate a fake assignment operator to represent bitwise assignments. 859 // This operator could easily exist as a real function, but it's tricky because nothing should resolve to this function. 860 TypeDecl * td = new TypeDecl( "T", noStorageClasses, nullptr, TypeDecl::Dtype, true ); 861 assign = new FunctionDecl( "?=?", noStorageClasses, LinkageSpec::Intrinsic, SymTab::genAssignType( new TypeInstType( noQualifiers, td->name, td ) ), nullptr ); 862 } 863 if ( dynamic_cast< ReferenceType * >( dst->result ) ) { 864 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) { 865 dst = new AddressExpr( dst ); 866 } 867 } else { 868 dst = new CastExpr( dst, new ReferenceType( noQualifiers, dst->result->clone() ) ); 869 } 870 if ( dynamic_cast< ReferenceType * >( src->result ) ) { 871 for (int depth = src->result->referenceDepth(); depth > 0; depth--) { 872 src = new AddressExpr( src ); 873 } 874 } 875 return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } ); 351 876 } 352 877 … … 380 905 return app; 381 906 } 907 908 struct ConstExprChecker : public WithShortCircuiting { 909 // most expressions are not const expr 910 void previsit( Expression * ) { isConstExpr = false; visit_children = false; } 911 912 void previsit( AddressExpr *addressExpr ) { 913 visit_children = false; 914 915 // address of a variable or member expression is constexpr 916 Expression * arg = addressExpr->get_arg(); 917 if ( ! dynamic_cast< NameExpr * >( arg) && ! dynamic_cast< VariableExpr * >( arg ) && ! dynamic_cast< MemberExpr * >( arg ) && ! dynamic_cast< UntypedMemberExpr * >( arg ) ) isConstExpr = false; 918 } 919 920 // these expressions may be const expr, depending on their children 921 void previsit( SizeofExpr * ) {} 922 void previsit( AlignofExpr * ) {} 923 void previsit( UntypedOffsetofExpr * ) {} 924 void previsit( OffsetofExpr * ) {} 925 void previsit( OffsetPackExpr * ) {} 926 void previsit( CommaExpr * ) {} 927 void previsit( LogicalExpr * ) {} 928 void previsit( ConditionalExpr * ) {} 929 void previsit( CastExpr * ) {} 930 void previsit( ConstantExpr * ) {} 931 932 void previsit( VariableExpr * varExpr ) { 933 visit_children = false; 934 935 if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( varExpr->result ) ) { 936 long long int value; 937 if ( inst->baseEnum->valueOf( varExpr->var, value ) ) { 938 // enumerators are const expr 939 return; 940 } 941 } 942 isConstExpr = false; 943 } 944 945 bool isConstExpr = true; 946 }; 382 947 383 948 struct ConstExprChecker_new : public ast::WithShortCircuiting { … … 424 989 }; 425 990 991 bool isConstExpr( Expression * expr ) { 992 if ( expr ) { 993 PassVisitor<ConstExprChecker> checker; 994 expr->accept( checker ); 995 return checker.pass.isConstExpr; 996 } 997 return true; 998 } 999 1000 bool isConstExpr( Initializer * init ) { 1001 if ( init ) { 1002 PassVisitor<ConstExprChecker> checker; 1003 init->accept( checker ); 1004 return checker.pass.isConstExpr; 1005 } // if 1006 // for all intents and purposes, no initializer means const expr 1007 return true; 1008 } 1009 426 1010 bool isConstExpr( const ast::Expr * expr ) { 427 1011 if ( expr ) { … … 443 1027 } 444 1028 1029 const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname ) { 1030 const FunctionDecl * function = dynamic_cast< const FunctionDecl * >( decl ); 1031 if ( ! function ) return nullptr; 1032 if ( function->name != fname ) return nullptr; 1033 FunctionType * ftype = function->type; 1034 if ( ftype->parameters.size() != 2 ) return nullptr; 1035 1036 Type * t1 = getPointerBase( ftype->get_parameters().front()->get_type() ); 1037 Type * t2 = ftype->parameters.back()->get_type(); 1038 assert( t1 ); 1039 1040 if ( ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, SymTab::Indexer() ) ) { 1041 return function; 1042 } else { 1043 return nullptr; 1044 } 1045 } 1046 445 1047 bool isAssignment( const ast::FunctionDecl * decl ) { 446 1048 return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl ); … … 469 1071 return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 ); 470 1072 } 1073 1074 1075 const FunctionDecl * isAssignment( const Declaration * decl ) { 1076 return isCopyFunction( decl, "?=?" ); 1077 } 1078 const FunctionDecl * isDestructor( const Declaration * decl ) { 1079 if ( CodeGen::isDestructor( decl->name ) ) { 1080 return dynamic_cast< const FunctionDecl * >( decl ); 1081 } 1082 return nullptr; 1083 } 1084 const FunctionDecl * isDefaultConstructor( const Declaration * decl ) { 1085 if ( CodeGen::isConstructor( decl->name ) ) { 1086 if ( const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl ) ) { 1087 if ( func->type->parameters.size() == 1 ) { 1088 return func; 1089 } 1090 } 1091 } 1092 return nullptr; 1093 } 1094 const FunctionDecl * isCopyConstructor( const Declaration * decl ) { 1095 return isCopyFunction( decl, "?{}" ); 1096 } 471 1097 472 1098 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message … … 477 1103 static const char * const data_section = ".data" ASM_COMMENT; 478 1104 static const char * const tlsd_section = ".tdata" ASM_COMMENT; 1105 void addDataSectionAttribute( ObjectDecl * objDecl ) { 1106 const bool is_tls = objDecl->get_storageClasses().is_threadlocal_any(); 1107 const char * section = is_tls ? tlsd_section : data_section; 1108 objDecl->attributes.push_back(new Attribute("section", { 1109 new ConstantExpr( Constant::from_string( section ) ) 1110 })); 1111 } 479 1112 480 1113 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { -
src/InitTweak/InitTweak.h
rfc12f05 r0030b508 22 22 23 23 #include "AST/Fwd.hpp" // for AST nodes 24 #include "SynTree/SynTree.h" // for Visitor Nodes 24 25 25 26 // helper functions for initialization 26 27 namespace InitTweak { 28 const FunctionDecl * isAssignment( const Declaration * decl ); 29 const FunctionDecl * isDestructor( const Declaration * decl ); 30 const FunctionDecl * isDefaultConstructor( const Declaration * decl ); 31 const FunctionDecl * isCopyConstructor( const Declaration * decl ); 32 const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname ); 27 33 bool isAssignment( const ast::FunctionDecl * decl ); 28 34 bool isDestructor( const ast::FunctionDecl * decl ); … … 32 38 33 39 /// returns the base type of the first parameter to a constructor/destructor/assignment function 40 Type * getTypeofThis( FunctionType * ftype ); 34 41 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 35 42 36 43 /// returns the first parameter of a constructor/destructor/assignment function 44 ObjectDecl * getParamThis( FunctionType * ftype ); 37 45 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 38 46 39 47 /// generate a bitwise assignment operation. 48 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ); 49 40 50 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 41 51 42 52 /// transform Initializer into an argument list that can be passed to a call expression 53 std::list< Expression * > makeInitList( Initializer * init ); 43 54 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ); 44 55 45 56 /// True if the resolver should try to construct dwt 57 bool tryConstruct( DeclarationWithType * dwt ); 46 58 bool tryConstruct( const ast::DeclWithType * dwt ); 47 59 48 60 /// True if the type can have a user-defined constructor 61 bool isConstructable( Type * t ); 49 62 bool isConstructable( const ast::Type * t ); 50 63 51 64 /// True if the Initializer contains designations 65 bool isDesignated( Initializer * init ); 52 66 bool isDesignated( const ast::Init * init ); 53 67 54 68 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 55 69 /// type, where the depth of its type is the number of nested ArrayTypes + 1 70 bool checkInitDepth( ObjectDecl * objDecl ); 56 71 bool checkInitDepth( const ast::ObjectDecl * objDecl ); 72 73 /// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr) 74 DeclarationWithType * getFunction( Expression * expr ); 75 const DeclarationWithType * getFunction( const Expression * expr ); 76 77 /// Non-Null if expr is a call expression whose target function is intrinsic 78 ApplicationExpr * isIntrinsicCallExpr( Expression * expr ); 57 79 58 80 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 59 81 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 60 82 /// Currently has assertions that make it less than fully general. 83 bool isIntrinsicSingleArgCallStmt( Statement * stmt ); 61 84 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ); 62 85 86 /// True if stmt is a call statement where the function called is intrinsic. 87 bool isIntrinsicCallStmt( Statement * stmt ); 88 63 89 /// get all Ctor/Dtor call expressions from a Statement 90 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ); 64 91 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 65 92 93 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call 94 Expression * getCtorDtorCall( Statement * stmt ); 95 96 /// returns the name of the function being called 97 std::string getFunctionName( Expression * expr ); 98 99 /// returns the argument to a call expression in position N indexed from 0 100 Expression *& getCallArg( Expression * callExpr, unsigned int pos ); 101 102 /// returns the base type of a PointerType or ArrayType, else returns NULL 103 Type * getPointerBase( Type * ); 104 105 /// returns the argument if it is a PointerType or ArrayType, else returns NULL 106 Type * isPointerType( Type * ); 107 66 108 /// returns true if expr is trivially a compile-time constant 109 bool isConstExpr( Expression * expr ); 110 bool isConstExpr( Initializer * init ); 111 67 112 bool isConstExpr( const ast::Expr * expr ); 68 113 bool isConstExpr( const ast::Init * init ); … … 77 122 /// .section .data#,"a" 78 123 /// to avoid assembler warning "ignoring changed section attributes for .data" 124 void addDataSectionAttribute( ObjectDecl * objDecl ); 125 79 126 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 127 128 class InitExpander_old { 129 public: 130 // expand by stepping through init to get each list of arguments 131 InitExpander_old( Initializer * init ); 132 133 // always expand to expr 134 InitExpander_old( Expression * expr ); 135 136 // iterator-like interface 137 std::list< Expression * > operator*(); 138 InitExpander_old & operator++(); 139 140 // builds statement which has the same semantics as a C-style list initializer 141 // (for array initializers) using callExpr as the base expression to perform initialization 142 Statement * buildListInit( UntypedExpr * callExpr ); 143 void addArrayIndex( Expression * index, Expression * dimension ); 144 void clearArrayIndices(); 145 bool addReference(); 146 147 class ExpanderImpl; 148 149 typedef std::list< Expression * > IndexList; 150 private: 151 std::shared_ptr< ExpanderImpl > expander; 152 std::list< Expression * > cur; 153 154 // invariant: list of size 2N (elements come in pairs [index, dimension]) 155 IndexList indices; 156 }; 80 157 81 158 class InitExpander_new { -
src/InitTweak/module.mk
rfc12f05 r0030b508 24 24 InitTweak/FixGlobalInit.cc \ 25 25 InitTweak/FixGlobalInit.h \ 26 InitTweak/FixInit.cc \ 26 27 InitTweak/FixInit.h \ 27 28 InitTweak/FixInitNew.cpp -
src/MakeLibCfa.h
rfc12f05 r0030b508 24 24 25 25 namespace LibCfa { 26 void makeLibCfa( std::list< Declaration* > &prelude ); 26 27 void makeLibCfa( ast::TranslationUnit & translationUnit ); 27 28 } // namespace LibCfa -
src/Makefile.am
rfc12f05 r0030b508 22 22 CompilationState.cc \ 23 23 CompilationState.h \ 24 MakeLibCfa.cc \ 24 25 MakeLibCfaNew.cpp \ 25 26 MakeLibCfa.h … … 41 42 include AST/module.mk 42 43 include CodeGen/module.mk 44 include CodeTools/module.mk 43 45 include Concurrency/module.mk 44 46 include Common/module.mk … … 49 51 include ResolvExpr/module.mk 50 52 include SymTab/module.mk 53 include SynTree/module.mk 51 54 include Tuples/module.mk 52 55 include Validate/module.mk 53 56 include Virtual/module.mk 54 57 55 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/ AST/Type.hpp58 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h 56 59 57 60 $(srcdir)/AST/Type.hpp : BasicTypes-gen.cc -
src/Parser/RunParser.cpp
rfc12f05 r0030b508 16 16 #include "RunParser.hpp" 17 17 18 #include "AST/Convert.hpp" // for convert 18 19 #include "AST/TranslationUnit.hpp" // for TranslationUnit 20 #include "CodeTools/TrackLoc.h" // for fillLocations 19 21 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 20 22 #include "Parser/DeclarationNode.h" // for DeclarationNode, buildList -
src/Parser/StatementNode.cc
rfc12f05 r0030b508 503 503 } // build_corun 504 504 505 ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ) {506 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty507 buildMoveList( forctl->init, astinit );508 509 ast::Expr * astcond = nullptr; // maybe empty510 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );511 512 ast::Expr * astincr = nullptr; // maybe empty513 astincr = maybeMoveBuild( forctl->change );514 delete forctl;515 516 return new ast::CoforStmt( location,517 std::move( astinit ),518 astcond,519 astincr,520 buildMoveSingle( stmt )521 );522 } // build_cofor523 524 505 // Local Variables: // 525 506 // tab-width: 4 // -
src/Parser/StatementNode.h
rfc12f05 r0030b508 106 106 ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt ); 107 107 ast::Stmt * build_corun( const CodeLocation &, StatementNode * stmt ); 108 ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ); -
src/Parser/parser.yy
rfc12f05 r0030b508 48 48 using namespace std; 49 49 50 #include "SynTree/Type.h" // for Type 50 51 #include "DeclarationNode.h" // for DeclarationNode, ... 51 52 #include "ExpressionNode.h" // for ExpressionNode, ... … … 57 58 #include "Common/SemanticError.h" // error_str 58 59 #include "Common/utility.h" // for maybeMoveBuild, maybeBuild, CodeLo... 60 61 #include "SynTree/Attribute.h" // for Attribute 59 62 60 63 // lex uses __null in a boolean context, it's fine. … … 1723 1726 cofor_statement: 1724 1727 COFOR '(' for_control_expression_list ')' statement 1725 { $$ = new StatementNode( build_cofor( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }1728 { SemanticError( yylloc, "cofor statement is currently unimplemented." ); $$ = nullptr; } 1726 1729 ; 1727 1730 … … 2166 2169 type_qualifier_name: 2167 2170 CONST 2168 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Const ); }2171 { $$ = DeclarationNode::newTypeQualifier( Type::Const ); } 2169 2172 | RESTRICT 2170 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Restrict ); }2173 { $$ = DeclarationNode::newTypeQualifier( Type::Restrict ); } 2171 2174 | VOLATILE 2172 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Volatile ); }2175 { $$ = DeclarationNode::newTypeQualifier( Type::Volatile ); } 2173 2176 | ATOMIC 2174 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Atomic ); }2177 { $$ = DeclarationNode::newTypeQualifier( Type::Atomic ); } 2175 2178 | forall 2176 2179 { $$ = DeclarationNode::newForall( $1 ); } … … 2203 2206 storage_class: 2204 2207 EXTERN 2205 { $$ = DeclarationNode::newStorageClass( ast::Storage::Extern ); }2208 { $$ = DeclarationNode::newStorageClass( Type::Extern ); } 2206 2209 | STATIC 2207 { $$ = DeclarationNode::newStorageClass( ast::Storage::Static ); }2210 { $$ = DeclarationNode::newStorageClass( Type::Static ); } 2208 2211 | AUTO 2209 { $$ = DeclarationNode::newStorageClass( ast::Storage::Auto ); }2212 { $$ = DeclarationNode::newStorageClass( Type::Auto ); } 2210 2213 | REGISTER 2211 { $$ = DeclarationNode::newStorageClass( ast::Storage::Register ); }2214 { $$ = DeclarationNode::newStorageClass( Type::Register ); } 2212 2215 | THREADLOCALGCC // GCC 2213 { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalGcc ); }2216 { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalGcc ); } 2214 2217 | THREADLOCALC11 // C11 2215 { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalC11 ); }2218 { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalC11 ); } 2216 2219 // Put function specifiers here to simplify parsing rules, but separate them semantically. 2217 2220 | INLINE // C99 2218 { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Inline ); }2221 { $$ = DeclarationNode::newFuncSpecifier( Type::Inline ); } 2219 2222 | FORTRAN // C99 2220 { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Fortran ); }2223 { $$ = DeclarationNode::newFuncSpecifier( Type::Fortran ); } 2221 2224 | NORETURN // C11 2222 { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Noreturn ); }2225 { $$ = DeclarationNode::newFuncSpecifier( Type::Noreturn ); } 2223 2226 ; 2224 2227 … … 3714 3717 { $$ = $1->addQualifiers( $2 ); } 3715 3718 | '&' MUTEX paren_identifier attribute_list_opt 3716 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }3719 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); } 3717 3720 | identifier_parameter_ptr 3718 3721 | identifier_parameter_array attribute_list_opt … … 3764 3767 { $$ = $1->addQualifiers( $2 ); } 3765 3768 | '&' MUTEX typedef_name attribute_list_opt 3766 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }3769 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); } 3767 3770 | type_parameter_ptr 3768 3771 | type_parameter_array attribute_list_opt … … 3938 3941 abstract_parameter_ptr 3939 3942 | '&' MUTEX attribute_list_opt 3940 { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); }3943 { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); } 3941 3944 | abstract_parameter_array attribute_list_opt 3942 3945 { $$ = $1->addQualifiers( $2 ); } -
src/ResolvExpr/AdjustExprType.cc
rfc12f05 r0030b508 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h" 22 #include "SymTab/Indexer.h" // for Indexer 23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype 24 #include "SynTree/Mutator.h" // for Mutator 25 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type 26 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment 21 27 22 28 namespace ResolvExpr { 29 30 namespace { 31 class AdjustExprType_old final : public WithShortCircuiting { 32 public: 33 AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer ); 34 void premutate( VoidType * ) { visit_children = false; } 35 void premutate( BasicType * ) { visit_children = false; } 36 void premutate( PointerType * ) { visit_children = false; } 37 void premutate( ArrayType * ) { visit_children = false; } 38 void premutate( FunctionType * ) { visit_children = false; } 39 void premutate( StructInstType * ) { visit_children = false; } 40 void premutate( UnionInstType * ) { visit_children = false; } 41 void premutate( EnumInstType * ) { visit_children = false; } 42 void premutate( TraitInstType * ) { visit_children = false; } 43 void premutate( TypeInstType * ) { visit_children = false; } 44 void premutate( TupleType * ) { visit_children = false; } 45 void premutate( VarArgsType * ) { visit_children = false; } 46 void premutate( ZeroType * ) { visit_children = false; } 47 void premutate( OneType * ) { visit_children = false; } 48 49 Type * postmutate( ArrayType * arrayType ); 50 Type * postmutate( FunctionType * functionType ); 51 Type * postmutate( TypeInstType * aggregateUseType ); 52 53 private: 54 const TypeEnvironment & env; 55 const SymTab::Indexer & indexer; 56 }; 57 58 AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer ) 59 : env( env ), indexer( indexer ) { 60 } 61 62 Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) { 63 PointerType * pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base }; 64 arrayType->base = nullptr; 65 delete arrayType; 66 return pointerType; 67 } 68 69 Type * AdjustExprType_old::postmutate( FunctionType * functionType ) { 70 return new PointerType{ Type::Qualifiers(), functionType }; 71 } 72 73 Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) { 74 if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) { 75 if ( eqvClass->data.kind == TypeDecl::Ftype ) { 76 return new PointerType{ Type::Qualifiers(), typeInst }; 77 } 78 } else if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->get_name() ) ) { 79 if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl * >( ntDecl ) ) { 80 if ( tyDecl->get_kind() == TypeDecl::Ftype ) { 81 return new PointerType{ Type::Qualifiers(), typeInst }; 82 } // if 83 } // if 84 } // if 85 return typeInst; 86 } 87 } // anonymous namespace 88 89 void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) { 90 PassVisitor<AdjustExprType_old> adjuster( env, indexer ); 91 Type * newType = type->acceptMutator( adjuster ); 92 type = newType; 93 } 94 95 void adjustExprType( Type *& type ) { 96 TypeEnvironment env; 97 SymTab::Indexer indexer; 98 adjustExprType( type, env, indexer ); 99 } 23 100 24 101 namespace { -
src/ResolvExpr/CandidateFinder.cpp
rfc12f05 r0030b508 57 57 58 58 /// Unique identifier for matching expression resolutions to their requesting expression 59 ast::UniqueId globalResnSlot = 0;59 UniqueId globalResnSlot = 0; 60 60 61 61 namespace { … … 686 686 void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) { 687 687 // Set need bindings for any unbound assertions 688 ast::UniqueId crntResnSlot = 0; // matching ID for this expression's assertions688 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions 689 689 for ( auto & assn : newCand->need ) { 690 690 // skip already-matched assertions -
src/ResolvExpr/CastCost.cc
rfc12f05 r0030b508 26 26 #include "ResolvExpr/ConversionCost.h" // for conversionCost 27 27 #include "ResolvExpr/PtrsCastable.hpp" // for ptrsCastable 28 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment, EqvClass 28 29 #include "ResolvExpr/typeops.h" // for ptrsCastable 29 30 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 31 #include "SymTab/Indexer.h" // for Indexer 32 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl 33 #include "SynTree/Type.h" // for PointerType, Type, TypeInstType 30 34 31 35 #if 0 … … 36 40 37 41 namespace ResolvExpr { 42 struct CastCost_old : public ConversionCost { 43 public: 44 CastCost_old( const Type * dest, bool srcIsLvalue, 45 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc ); 46 47 using ConversionCost::previsit; 48 using ConversionCost::postvisit; 49 void postvisit( const BasicType * basicType ); 50 void postvisit( const PointerType * pointerType ); 51 }; 52 53 Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue, 54 const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 55 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) { 56 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) { 57 if ( eqvClass->type ) { 58 return castCost( src, eqvClass->type, srcIsLvalue, indexer, env ); 59 } else { 60 return Cost::infinity; 61 } 62 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) { 63 // all typedefs should be gone by this point 64 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( namedType ); 65 if ( type->base ) { 66 return castCost( src, type->base, srcIsLvalue, indexer, env ) + Cost::safe; 67 } // if 68 } // if 69 } // if 70 71 PRINT( 72 std::cerr << "castCost ::: src is "; 73 src->print( std::cerr ); 74 std::cerr << std::endl << "dest is "; 75 dest->print( std::cerr ); 76 std::cerr << std::endl << "env is" << std::endl; 77 env.print( std::cerr, 8 ); 78 ) 79 80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) { 81 PRINT( std::cerr << "compatible!" << std::endl; ) 82 return Cost::zero; 83 } else if ( dynamic_cast< const VoidType * >( dest ) ) { 84 return Cost::safe; 85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) { 86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; ) 87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * t1, const Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) { 88 return ptrsCastable( t1, t2, env, indexer ); 89 }); 90 } else { 91 PassVisitor<CastCost_old> converter( 92 dest, srcIsLvalue, indexer, env, 93 (Cost (*)( const Type *, const Type *, bool, const SymTab::Indexer &, const TypeEnvironment & )) 94 castCost ); 95 src->accept( converter ); 96 if ( converter.pass.get_cost() == Cost::infinity ) { 97 return Cost::infinity; 98 } else { 99 // xxx - why are we adding cost 0 here? 100 return converter.pass.get_cost() + Cost::zero; 101 } // if 102 } // if 103 } 104 105 CastCost_old::CastCost_old( const Type * dest, bool srcIsLvalue, 106 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc ) 107 : ConversionCost( dest, srcIsLvalue, indexer, env, costFunc ) { 108 } 109 110 void CastCost_old::postvisit( const BasicType * basicType ) { 111 const PointerType * destAsPointer = dynamic_cast< const PointerType * >( dest ); 112 if ( destAsPointer && basicType->isInteger() ) { 113 // necessary for, e.g. unsigned long => void * 114 cost = Cost::unsafe; 115 } else { 116 cost = conversionCost( basicType, dest, srcIsLvalue, indexer, env ); 117 } // if 118 } 119 120 void CastCost_old::postvisit( const PointerType * pointerType ) { 121 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) { 122 if ( pointerType->tq <= destAsPtr->tq && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) { 123 cost = Cost::safe; 124 } else { 125 TypeEnvironment newEnv( env ); 126 newEnv.add( pointerType->forall ); 127 newEnv.add( pointerType->base->forall ); 128 int castResult = ptrsCastable( pointerType->base, destAsPtr->base, newEnv, indexer ); 129 if ( castResult > 0 ) { 130 cost = Cost::safe; 131 } else if ( castResult < 0 ) { 132 cost = Cost::infinity; 133 } // if 134 } // if 135 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) { 136 if ( destAsBasic->isInteger() ) { 137 // necessary for, e.g. void * => unsigned long 138 cost = Cost::unsafe; 139 } // if 140 } 141 } 38 142 39 143 namespace { … … 96 200 } // anonymous namespace 97 201 202 203 98 204 Cost castCost( 99 205 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, -
src/ResolvExpr/CommonType.cc
rfc12f05 r0030b508 23 23 #include "AST/Pass.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h" 26 #include "ResolvExpr/TypeEnvironment.h" // for OpenVarSet, AssertionSet 27 #include "SymTab/Indexer.h" // for Indexer 28 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl (ptr... 29 #include "SynTree/Type.h" // for BasicType, BasicType::Kind::... 30 #include "SynTree/Visitor.h" // for Visitor 25 31 #include "Unify.h" // for unifyExact, WidenMode 26 32 #include "typeops.h" // for isFtype … … 35 41 36 42 namespace ResolvExpr { 43 struct CommonType_old : public WithShortCircuiting { 44 CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ); 45 Type * get_result() const { return result; } 46 47 void previsit( BaseSyntaxNode * ) { visit_children = false; } 48 49 void postvisit( VoidType * voidType ); 50 void postvisit( BasicType * basicType ); 51 void postvisit( PointerType * pointerType ); 52 void postvisit( ArrayType * arrayType ); 53 void postvisit( ReferenceType * refType ); 54 void postvisit( FunctionType * functionType ); 55 void postvisit( StructInstType * aggregateUseType ); 56 void postvisit( UnionInstType * aggregateUseType ); 57 void postvisit( EnumInstType * aggregateUseType ); 58 void postvisit( TraitInstType * aggregateUseType ); 59 void postvisit( TypeInstType * aggregateUseType ); 60 void postvisit( TupleType * tupleType ); 61 void postvisit( VarArgsType * varArgsType ); 62 void postvisit( ZeroType * zeroType ); 63 void postvisit( OneType * oneType ); 64 65 private: 66 template< typename Pointer > void getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ); 67 template< typename RefType > void handleRefType( RefType * inst, Type * other ); 68 69 Type * result; 70 Type * type2; // inherited 71 bool widenFirst, widenSecond; 72 const SymTab::Indexer &indexer; 73 TypeEnvironment &env; 74 const OpenVarSet &openVars; 75 }; 76 77 Type * handleReference( Type * t1, Type * t2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) { 78 Type * common = nullptr; 79 AssertionSet have, need; 80 OpenVarSet newOpen( openVars ); 81 // need unify to bind type variables 82 if ( unify( t1, t2, env, have, need, newOpen, indexer, common ) ) { 83 PRINT( 84 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl; 85 ) 86 if ( (widenFirst || t2->tq <= t1->tq) && (widenSecond || t1->tq <= t2->tq) ) { 87 PRINT( 88 std::cerr << "widen okay" << std::endl; 89 ) 90 common->tq |= t1->tq; 91 common->tq |= t2->tq; 92 return common; 93 } 94 } 95 PRINT( 96 std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl; 97 ) 98 return nullptr; 99 } 100 101 Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) { 102 PassVisitor<CommonType_old> visitor( type2, widenFirst, widenSecond, indexer, env, openVars ); 103 104 int depth1 = type1->referenceDepth(); 105 int depth2 = type2->referenceDepth(); 106 if ( depth1 > 0 || depth2 > 0 ) { 107 int diff = depth1-depth2; 108 // TODO: should it be possible for commonType to generate complicated conversions? I would argue no, only conversions that involve types of the same reference level or a difference of 1 should be allowed. 109 // if ( diff > 1 || diff < -1 ) return nullptr; 110 111 // special case where one type has a reference depth of 1 larger than the other 112 if ( diff > 0 || diff < 0 ) { 113 PRINT( 114 std::cerr << "reference depth diff: " << diff << std::endl; 115 ) 116 Type * result = nullptr; 117 ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 ); 118 ReferenceType * ref2 = dynamic_cast< ReferenceType * >( type2 ); 119 if ( diff > 0 ) { 120 // deeper on the left 121 assert( ref1 ); 122 result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars ); 123 } else { 124 // deeper on the right 125 assert( ref2 ); 126 result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars ); 127 } 128 if ( result && ref1 ) { 129 // formal is reference, so result should be reference 130 PRINT( 131 std::cerr << "formal is reference; result should be reference" << std::endl; 132 ) 133 result = new ReferenceType( ref1->tq, result ); 134 } 135 PRINT( 136 std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is [" << result << "]" << std::endl; 137 ) 138 return result; 139 } 140 // otherwise, both are reference types of the same depth and this is handled by the CommonType visitor. 141 } 142 143 type1->accept( visitor ); 144 Type * result = visitor.pass.get_result(); 145 if ( ! result ) { 146 // this appears to be handling for opaque type declarations 147 if ( widenSecond ) { 148 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type2 ) ) { 149 if ( const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ) ) { 150 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt ); 151 if ( type->get_base() ) { 152 Type::Qualifiers tq1 = type1->tq, tq2 = type2->tq; 153 AssertionSet have, need; 154 OpenVarSet newOpen( openVars ); 155 type1->tq = Type::Qualifiers(); 156 type->get_base()->tq = tq1; 157 if ( unifyExact( type1, type->get_base(), env, have, need, newOpen, indexer ) ) { 158 result = type1->clone(); 159 result->tq = tq1 | tq2; 160 } // if 161 type1->tq = tq1; 162 type->get_base()->tq = Type::Qualifiers(); 163 } // if 164 } // if 165 } // if 166 } // if 167 } // if 168 #ifdef DEBUG 169 std::cerr << "============= commonType" << std::endl << "type1 is "; 170 type1->print( std::cerr ); 171 std::cerr << " type2 is "; 172 type2->print( std::cerr ); 173 if ( result ) { 174 std::cerr << " common type is "; 175 result->print( std::cerr ); 176 } else { 177 std::cerr << " no common type"; 178 } // if 179 std::cerr << std::endl; 180 #endif 181 return result; 182 } 37 183 38 184 // GENERATED START, DO NOT EDIT 39 185 // GENERATED BY BasicTypes-gen.cc 40 #define BT ast::BasicType::41 static const B T Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BTNUMBER_OF_BASIC_TYPES] = { // nearest common ancestor186 #define BT BasicType:: 187 static const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor 42 188 /* B C SC UC SI SUI 43 189 I UI LI LUI LLI LLUI … … 339 485 // GENERATED END 340 486 static_assert( 341 sizeof(commonTypes)/sizeof(commonTypes[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,487 sizeof(commonTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES, 342 488 "Each basic type kind should have a corresponding row in the combined type matrix" 343 489 ); 490 491 CommonType_old::CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) 492 : result( 0 ), type2( type2 ), widenFirst( widenFirst ), widenSecond( widenSecond ), indexer( indexer ), env( env ), openVars( openVars ) { 493 } 494 495 void CommonType_old::postvisit( VoidType * ) {} 496 497 void CommonType_old::postvisit( BasicType * basicType ) { 498 if ( BasicType * otherBasic = dynamic_cast< BasicType * >( type2 ) ) { 499 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ otherBasic->get_kind() ]; 500 if ( ( ( newType == basicType->get_kind() && basicType->tq >= otherBasic->tq ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->tq <= otherBasic->tq ) || widenSecond ) ) { 501 result = new BasicType( basicType->tq | otherBasic->tq, newType ); 502 } // if 503 } else if ( dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) { 504 // use signed int in lieu of the enum/zero/one type 505 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ]; 506 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) { 507 result = new BasicType( basicType->tq | type2->tq, newType ); 508 } // if 509 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * > ( type2 ) ) { 510 const EnumDecl* enumDecl = enumInst->baseEnum; 511 if ( const Type* baseType = enumDecl->base ) { 512 result = baseType->clone(); 513 } else { 514 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ]; 515 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) { 516 result = new BasicType( basicType->tq | type2->tq, newType ); 517 } // if 518 } 519 } 520 } 521 522 template< typename Pointer > 523 void CommonType_old::getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ) { 524 if ( TypeInstType * var = dynamic_cast< TypeInstType * >( otherPointer->get_base() ) ) { 525 OpenVarSet::const_iterator entry = openVars.find( var->get_name() ); 526 if ( entry != openVars.end() ) { 527 AssertionSet need, have; 528 WidenMode widen( widenFirst, widenSecond ); 529 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return; 530 } 531 } 532 result = voidPointer->clone(); 533 result->tq |= otherPointer->tq; 534 } 535 536 void CommonType_old::postvisit( PointerType * pointerType ) { 537 if ( PointerType * otherPointer = dynamic_cast< PointerType * >( type2 ) ) { 538 // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl; 539 if ( widenFirst && dynamic_cast< VoidType * >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) { 540 getCommonWithVoidPointer( otherPointer, pointerType ); 541 } else if ( widenSecond && dynamic_cast< VoidType * >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) { 542 getCommonWithVoidPointer( pointerType, otherPointer ); 543 } else if ( ( pointerType->get_base()->tq >= otherPointer->get_base()->tq || widenFirst ) 544 && ( pointerType->get_base()->tq <= otherPointer->get_base()->tq || widenSecond ) ) { 545 // std::cerr << "middle case" << std::endl; 546 Type::Qualifiers tq1 = pointerType->get_base()->tq, tq2 = otherPointer->get_base()->tq; 547 pointerType->get_base()->tq = Type::Qualifiers(); 548 otherPointer->get_base()->tq = Type::Qualifiers(); 549 AssertionSet have, need; 550 OpenVarSet newOpen( openVars ); 551 if ( unifyExact( pointerType->get_base(), otherPointer->get_base(), env, have, need, newOpen, indexer ) ) { 552 // std::cerr << "unifyExact success" << std::endl; 553 if ( tq1 < tq2 ) { 554 result = pointerType->clone(); 555 } else { 556 result = otherPointer->clone(); 557 } // if 558 strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2; 559 } else { 560 /// std::cerr << "place for ptr-to-type" << std::endl; 561 } // if 562 pointerType->get_base()->tq = tq1; 563 otherPointer->get_base()->tq = tq2; 564 } // if 565 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) { 566 result = pointerType->clone(); 567 result->tq |= type2->tq; 568 } // if 569 } 570 571 void CommonType_old::postvisit( ArrayType * ) {} 572 573 void CommonType_old::postvisit( ReferenceType * refType ) { 574 if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( type2 ) ) { 575 // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl; 576 // std::cerr << ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) << (refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond) << std::endl; 577 if ( widenFirst && dynamic_cast< VoidType * >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) { 578 getCommonWithVoidPointer( otherRef, refType ); 579 } else if ( widenSecond && dynamic_cast< VoidType * >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) { 580 getCommonWithVoidPointer( refType, otherRef ); 581 } else if ( ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) 582 && ( refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond ) ) { 583 // std::cerr << "middle case" << std::endl; 584 Type::Qualifiers tq1 = refType->get_base()->tq, tq2 = otherRef->get_base()->tq; 585 refType->get_base()->tq = Type::Qualifiers(); 586 otherRef->get_base()->tq = Type::Qualifiers(); 587 AssertionSet have, need; 588 OpenVarSet newOpen( openVars ); 589 if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) { 590 if ( tq1 < tq2 ) { 591 result = refType->clone(); 592 } else { 593 result = otherRef->clone(); 594 } // if 595 strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2; 596 } else { 597 /// std::cerr << "place for ptr-to-type" << std::endl; 598 } // if 599 refType->get_base()->tq = tq1; 600 otherRef->get_base()->tq = tq2; 601 } // if 602 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) { 603 result = refType->clone(); 604 result->tq |= type2->tq; 605 } // if 606 } 607 608 void CommonType_old::postvisit( FunctionType * ) {} 609 void CommonType_old::postvisit( StructInstType * ) {} 610 void CommonType_old::postvisit( UnionInstType * ) {} 611 612 void CommonType_old::postvisit( EnumInstType * enumInstType ) { 613 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) { 614 // reuse BasicType, EnumInstType code by swapping type2 with enumInstType 615 result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars ); 616 } // if 617 } 618 619 void CommonType_old::postvisit( TraitInstType * ) { 620 } 621 622 void CommonType_old::postvisit( TypeInstType * inst ) { 623 if ( widenFirst ) { 624 const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ); 625 if ( nt ) { 626 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt ); 627 if ( type->get_base() ) { 628 Type::Qualifiers tq1 = inst->tq, tq2 = type2->tq; 629 AssertionSet have, need; 630 OpenVarSet newOpen( openVars ); 631 type2->tq = Type::Qualifiers(); 632 type->get_base()->tq = tq1; 633 if ( unifyExact( type->get_base(), type2, env, have, need, newOpen, indexer ) ) { 634 result = type2->clone(); 635 result->tq = tq1 | tq2; 636 } // if 637 type2->tq = tq2; 638 type->get_base()->tq = Type::Qualifiers(); 639 } // if 640 } // if 641 } // if 642 } 643 644 void CommonType_old::postvisit( TupleType * ) {} 645 void CommonType_old::postvisit( VarArgsType * ) {} 646 647 void CommonType_old::postvisit( ZeroType * zeroType ) { 648 if ( widenFirst ) { 649 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< PointerType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) { 650 if ( widenSecond || zeroType->tq <= type2->tq ) { 651 result = type2->clone(); 652 result->tq |= zeroType->tq; 653 } 654 } else if ( widenSecond && dynamic_cast< OneType * >( type2 ) ) { 655 result = new BasicType( zeroType->tq, BasicType::SignedInt ); 656 result->tq |= type2->tq; 657 } 658 } 659 } 660 661 void CommonType_old::postvisit( OneType * oneType ) { 662 if ( widenFirst ) { 663 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) { 664 if ( widenSecond || oneType->tq <= type2->tq ) { 665 result = type2->clone(); 666 result->tq |= oneType->tq; 667 } 668 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) { 669 result = new BasicType( oneType->tq, BasicType::SignedInt ); 670 result->tq |= type2->tq; 671 } 672 } 673 } 344 674 345 675 class CommonType_new final : public ast::WithShortCircuiting { … … 370 700 else if (!widen.first) kind = basic->kind; // widen.second 371 701 else if (!widen.second) kind = basic2->kind; 372 else kind = commonTypes[ basic->kind ][basic2->kind ];702 else kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ]; 373 703 // xxx - what does qualifiers even do here?? 374 704 if ( (basic->qualifiers >= basic2->qualifiers || widen.first) … … 389 719 } else { 390 720 #warning remove casts when `commonTypes` moved to new AST 391 ast::BasicType::Kind kind = commonTypes[ basic->kind ][ast::BasicType::SignedInt ];721 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ]; 392 722 if ( 393 723 ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers ) -
src/ResolvExpr/CommonType.hpp
rfc12f05 r0030b508 18 18 #include "AST/Fwd.hpp" 19 19 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 20 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet 20 21 #include "WidenMode.h" // for WidenMode 22 23 class Type; 24 namespace SymTab { 25 class Indexer; 26 } 21 27 22 28 namespace ResolvExpr { 23 29 30 Type * commonType( 31 Type * type1, Type * type2, bool widenFirst, bool widenSecond, 32 const SymTab::Indexer & indexer, TypeEnvironment & env, 33 const OpenVarSet & openVars ); 24 34 ast::ptr< ast::Type > commonType( 25 35 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, -
src/ResolvExpr/ConversionCost.cc
rfc12f05 r0030b508 21 21 22 22 #include "ResolvExpr/Cost.h" // for Cost 23 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment 23 24 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 24 25 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 26 #include "SymTab/Indexer.h" // for Indexer 27 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl 28 #include "SynTree/Type.h" // for Type, BasicType, TypeInstType 29 25 30 26 31 namespace ResolvExpr { 32 #if 0 33 const Cost Cost::zero = Cost{ 0, 0, 0, 0, 0, 0, 0 }; 34 const Cost Cost::infinity = Cost{ -1, -1, -1, -1, -1, 1, -1 }; 35 const Cost Cost::unsafe = Cost{ 1, 0, 0, 0, 0, 0, 0 }; 36 const Cost Cost::poly = Cost{ 0, 1, 0, 0, 0, 0, 0 }; 37 const Cost Cost::safe = Cost{ 0, 0, 1, 0, 0, 0, 0 }; 38 const Cost Cost::sign = Cost{ 0, 0, 0, 1, 0, 0, 0 }; 39 const Cost Cost::var = Cost{ 0, 0, 0, 0, 1, 0, 0 }; 40 const Cost Cost::spec = Cost{ 0, 0, 0, 0, 0, -1, 0 }; 41 const Cost Cost::reference = Cost{ 0, 0, 0, 0, 0, 0, 1 }; 42 #endif 27 43 28 44 #if 0 … … 31 47 #define PRINT(x) 32 48 #endif 49 50 Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue, 51 const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 52 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) { 53 PRINT( std::cerr << "type inst " << destAsTypeInst->name; ) 54 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) { 55 if ( eqvClass->type ) { 56 return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env ); 57 } else { 58 return Cost::infinity; 59 } 60 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) { 61 PRINT( std::cerr << " found" << std::endl; ) 62 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType ); 63 // all typedefs should be gone by this point 64 assert( type ); 65 if ( type->base ) { 66 return conversionCost( src, type->base, srcIsLvalue, indexer, env ) 67 + Cost::safe; 68 } // if 69 } // if 70 PRINT( std::cerr << " not found" << std::endl; ) 71 } // if 72 PRINT( 73 std::cerr << "src is "; 74 src->print( std::cerr ); 75 std::cerr << std::endl << "dest is "; 76 dest->print( std::cerr ); 77 std::cerr << std::endl << "env is" << std::endl; 78 env.print( std::cerr, 8 ); 79 ) 80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) { 81 PRINT( std::cerr << "compatible!" << std::endl; ) 82 return Cost::zero; 83 } else if ( dynamic_cast< const VoidType * >( dest ) ) { 84 return Cost::safe; 85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) { 86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; ) 87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){ 88 return ptrsAssignable( t1, t2, env ); 89 }); 90 } else { 91 PassVisitor<ConversionCost> converter( 92 dest, srcIsLvalue, indexer, env, 93 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&)) 94 conversionCost ); 95 src->accept( converter ); 96 if ( converter.pass.get_cost() == Cost::infinity ) { 97 return Cost::infinity; 98 } else { 99 return converter.pass.get_cost() + Cost::zero; 100 } // if 101 } // if 102 } 103 104 static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue, 105 int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) { 106 PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; ) 107 if ( diff > 0 ) { 108 // TODO: document this 109 Cost cost = convertToReferenceCost( 110 strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue, 111 diff-1, indexer, env, func ); 112 cost.incReference(); 113 return cost; 114 } else if ( diff < -1 ) { 115 // TODO: document this 116 Cost cost = convertToReferenceCost( 117 src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue, 118 diff+1, indexer, env, func ); 119 cost.incReference(); 120 return cost; 121 } else if ( diff == 0 ) { 122 const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src ); 123 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest ); 124 if ( srcAsRef && destAsRef ) { // pointer-like conversions between references 125 PRINT( std::cerr << "converting between references" << std::endl; ) 126 Type::Qualifiers tq1 = srcAsRef->base->tq; 127 Type::Qualifiers tq2 = destAsRef->base->tq; 128 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) { 129 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; ) 130 if ( tq1 == tq2 ) { 131 // types are the same 132 return Cost::zero; 133 } else { 134 // types are the same, except otherPointer has more qualifiers 135 return Cost::safe; 136 } 137 } else { // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right? 138 int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env ); 139 PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; ) 140 if ( assignResult > 0 ) { 141 return Cost::safe; 142 } else if ( assignResult < 0 ) { 143 return Cost::unsafe; 144 } // if 145 } // if 146 } else { 147 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; ) 148 PassVisitor<ConversionCost> converter( 149 dest, srcIsLvalue, indexer, env, 150 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&)) 151 conversionCost ); 152 src->accept( converter ); 153 return converter.pass.get_cost(); 154 } // if 155 } else { 156 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest ); 157 assert( diff == -1 && destAsRef ); 158 PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; ) 159 if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) { 160 PRINT( std::cerr << "converting compatible base type" << std::endl; ) 161 if ( srcIsLvalue ) { 162 PRINT( 163 std::cerr << "lvalue to reference conversion" << std::endl; 164 std::cerr << src << " => " << destAsRef << std::endl; 165 ) 166 // lvalue-to-reference conversion: cv lvalue T => cv T & 167 if ( src->tq == destAsRef->base->tq ) { 168 return Cost::reference; // cost needs to be non-zero to add cast 169 } if ( src->tq < destAsRef->base->tq ) { 170 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same 171 } else { 172 return Cost::unsafe; 173 } // if 174 } else if ( destAsRef->base->get_const() ) { 175 PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; ) 176 // rvalue-to-const-reference conversion: T => const T & 177 return Cost::safe; 178 } else { 179 PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; ) 180 // rvalue-to-reference conversion: T => T & 181 return Cost::unsafe; 182 } // if 183 } // if 184 PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; ) 185 } 186 return Cost::infinity; 187 } 188 189 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue, 190 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) { 191 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth(); 192 Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func ); 193 PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; ) 194 return cost; 195 } 196 197 ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc ) 198 : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) { 199 } 33 200 34 201 // GENERATED START, DO NOT EDIT … … 59 226 // GENERATED START, DO NOT EDIT 60 227 // GENERATED BY BasicTypes-gen.cc 61 static const int costMatrix[ ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node228 static const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node 62 229 /* 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 */ 63 230 /* 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, }, … … 101 268 // GENERATED END 102 269 static_assert( 103 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,270 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES, 104 271 "Missing row in the cost matrix" 105 272 ); … … 107 274 // GENERATED START, DO NOT EDIT 108 275 // GENERATED BY BasicTypes-gen.cc 109 static const int signMatrix[ ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion276 static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion 110 277 /* 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 */ 111 278 /* 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, }, … … 148 315 // GENERATED END 149 316 static_assert( 150 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,317 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES, 151 318 "Missing row in the sign matrix" 152 319 ); 320 321 void ConversionCost::postvisit( const VoidType * ) { 322 cost = Cost::infinity; 323 } 324 325 // refactor for code resue 326 void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) { 327 int tableResult = costMatrix[ src->kind ][ dest->kind ]; 328 if ( tableResult == -1 ) { 329 cost = Cost::unsafe; 330 } else { 331 cost = Cost::zero; 332 cost.incSafe( tableResult ); 333 cost.incSign( signMatrix[ src->kind ][ dest->kind ] ); 334 } // if 335 } // ConversionCost::conversionCostFromBasicToBasic 336 337 void ConversionCost::postvisit(const BasicType * basicType) { 338 if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) { 339 conversionCostFromBasicToBasic(basicType, destAsBasic); 340 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) { 341 const EnumDecl * base_enum = enumInst->baseEnum; 342 if ( const Type * base = base_enum->base ) { 343 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) { 344 conversionCostFromBasicToBasic(basicType, enumBaseAstBasic); 345 } else { 346 cost = Cost::infinity; 347 } // if 348 } else { 349 cost = Cost::unsafe; 350 } // if 351 } // if 352 // no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t. 353 } 354 355 void ConversionCost::postvisit( const PointerType * pointerType ) { 356 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) { 357 PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; ) 358 Type::Qualifiers tq1 = pointerType->base->tq; 359 Type::Qualifiers tq2 = destAsPtr->base->tq; 360 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) { 361 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; ) 362 if ( tq1 == tq2 ) { 363 // types are the same 364 cost = Cost::zero; 365 } else { 366 // types are the same, except otherPointer has more qualifiers 367 cost = Cost::safe; 368 } // if 369 } else { 370 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env ); 371 PRINT( std::cerr << " :: " << assignResult << std::endl; ) 372 if ( assignResult > 0 && tq1 <= tq2 ) { 373 // xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct? 374 if ( tq1 == tq2 ) { 375 cost = Cost::safe; 376 } else if ( tq1 < tq2 ) { 377 cost = Cost::safe+Cost::safe; 378 } 379 } else if ( assignResult < 0 ) { 380 cost = Cost::unsafe; 381 } // if 382 // assignResult == 0 means Cost::Infinity 383 } // if 384 // case case for zero_t because it should not be possible to convert pointers to zero_t. 385 } // if 386 } 387 388 void ConversionCost::postvisit( const ArrayType * ) {} 389 390 void ConversionCost::postvisit( const ReferenceType * refType ) { 391 // Note: dest can never be a reference, since it would have been caught in an earlier check 392 assert( ! dynamic_cast< const ReferenceType * >( dest ) ); 393 // convert reference to rvalue: cv T1 & => T2 394 // recursively compute conversion cost from T1 to T2. 395 // cv can be safely dropped because of 'implicit dereference' behavior. 396 cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env ); 397 if ( refType->base->tq == dest->tq ) { 398 cost.incReference(); // prefer exact qualifiers 399 } else if ( refType->base->tq < dest->tq ) { 400 cost.incSafe(); // then gaining qualifiers 401 } else { 402 cost.incUnsafe(); // lose qualifiers as last resort 403 } 404 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; ) 405 } 406 407 void ConversionCost::postvisit( const FunctionType * ) {} 408 409 void ConversionCost::postvisit( const EnumInstType * enumInst) { 410 const EnumDecl * enumDecl = enumInst -> baseEnum; 411 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum 412 cost = costFunc( enumType, dest, srcIsLvalue, indexer, env ); 413 } else { 414 static Type::Qualifiers q; 415 static BasicType integer( q, BasicType::SignedInt ); 416 cost = costFunc( &integer, dest, srcIsLvalue, indexer, env ); // safe if dest >= int 417 } // if 418 if ( cost < Cost::unsafe ) { 419 cost.incSafe(); 420 } // if 421 } 422 423 void ConversionCost::postvisit( const TraitInstType * ) {} 424 425 void ConversionCost::postvisit( const TypeInstType * inst ) { 426 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) { 427 cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env ); 428 } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) { 429 if ( inst->name == destAsInst->name ) { 430 cost = Cost::zero; 431 } 432 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) { 433 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType ); 434 // all typedefs should be gone by this point 435 assert( type ); 436 if ( type->base ) { 437 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe; 438 } // if 439 } // if 440 } 441 442 void ConversionCost::postvisit( const TupleType * tupleType ) { 443 Cost c = Cost::zero; 444 if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) { 445 std::list< Type * >::const_iterator srcIt = tupleType->types.begin(); 446 std::list< Type * >::const_iterator destIt = destAsTuple->types.begin(); 447 while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) { 448 Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env ); 449 if ( newCost == Cost::infinity ) { 450 return; 451 } // if 452 c += newCost; 453 } // while 454 if ( destIt != destAsTuple->types.end() ) { 455 cost = Cost::infinity; 456 } else { 457 cost = c; 458 } // if 459 } // if 460 } 461 462 void ConversionCost::postvisit( const VarArgsType * ) { 463 if ( dynamic_cast< const VarArgsType * >( dest ) ) { 464 cost = Cost::zero; 465 } 466 } 467 468 void ConversionCost::postvisit( const ZeroType * ) { 469 if ( dynamic_cast< const ZeroType * >( dest ) ) { 470 cost = Cost::zero; 471 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) { 472 // copied from visit(BasicType *) for signed int, but +1 for safe conversions 473 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ]; 474 if ( tableResult == -1 ) { 475 cost = Cost::unsafe; 476 } else { 477 cost = Cost::zero; 478 cost.incSafe( tableResult + 1 ); 479 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] ); 480 } // if 481 } else if ( dynamic_cast< const PointerType * >( dest ) ) { 482 cost = Cost::zero; 483 cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation 484 } // if 485 } 486 487 void ConversionCost::postvisit( const OneType * ) { 488 if ( dynamic_cast< const OneType * >( dest ) ) { 489 cost = Cost::zero; 490 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) { 491 // copied from visit(BasicType *) for signed int, but +1 for safe conversions 492 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ]; 493 if ( tableResult == -1 ) { 494 cost = Cost::unsafe; 495 } else { 496 cost = Cost::zero; 497 cost.incSafe( tableResult + 1 ); 498 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] ); 499 } // if 500 } // if 501 } 153 502 154 503 namespace { -
src/ResolvExpr/ConversionCost.h
rfc12f05 r0030b508 22 22 #include "AST/Fwd.hpp" 23 23 #include "AST/Pass.hpp" // for WithShortCircuiting 24 #include "Common/PassVisitor.h" 25 #include "SynTree/Visitor.h" // for Visitor 26 #include "SynTree/SynTree.h" // for Visitor Nodes 24 27 25 28 namespace SymTab { … … 29 32 namespace ResolvExpr { 30 33 class TypeEnvironment; 34 35 Cost conversionCost( 36 const Type * src, const Type * dest, bool srcIsLvalue, 37 const SymTab::Indexer & indexer, const TypeEnvironment & env ); 38 39 typedef std::function<Cost(const Type *, const Type *, bool, 40 const SymTab::Indexer &, const TypeEnvironment &)> CostFunction; 41 42 struct ConversionCost : public WithShortCircuiting { 43 public: 44 ConversionCost( const Type * dest, bool srcIsLvalue, 45 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction ); 46 47 Cost get_cost() const { return cost; } 48 49 void previsit( const BaseSyntaxNode * ) { visit_children = false; } 50 51 void postvisit( const VoidType * voidType ); 52 void postvisit( const BasicType * basicType ); 53 void postvisit( const PointerType * pointerType ); 54 void postvisit( const ArrayType * arrayType ); 55 void postvisit( const ReferenceType * refType ); 56 void postvisit( const FunctionType * functionType ); 57 void postvisit( const EnumInstType * aggregateUseType ); 58 void postvisit( const TraitInstType * aggregateUseType ); 59 void postvisit( const TypeInstType * aggregateUseType ); 60 void postvisit( const TupleType * tupleType ); 61 void postvisit( const VarArgsType * varArgsType ); 62 void postvisit( const ZeroType * zeroType ); 63 void postvisit( const OneType * oneType ); 64 protected: 65 const Type * dest; 66 bool srcIsLvalue; 67 const SymTab::Indexer &indexer; 68 Cost cost; 69 const TypeEnvironment &env; 70 CostFunction costFunc; 71 private: 72 // refactor for code resue 73 void conversionCostFromBasicToBasic( const BasicType * src, const BasicType* dest ); 74 }; 75 76 typedef std::function<int(const Type *, const Type *, const SymTab::Indexer &, const TypeEnvironment &)> PtrsFunction; 77 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue, 78 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ); 31 79 32 80 // Some function pointer types, differ in return type. -
src/ResolvExpr/CurrentObject.cc
rfc12f05 r0030b508 33 33 #include "Common/utility.h" // for toString 34 34 #include "CurrentObject.h" 35 #include "SynTree/Constant.h" // for Constant 36 #include "SynTree/Declaration.h" // for ObjectDecl, Declaration, Struc... 37 #include "SynTree/Expression.h" // for InitAlternative, VariableExpr 38 #include "SynTree/Initializer.h" // for Designation, operator<< 39 #include "SynTree/Type.h" // for Type, StructInstType, UnionIns... 40 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 35 41 36 42 #if 0 … … 39 45 #define PRINT(x) 40 46 #endif 47 48 namespace ResolvExpr { 49 template< typename AggrInst > 50 TypeSubstitution makeGenericSubstitution( AggrInst * inst ) { 51 assert( inst ); 52 assert( inst->get_baseParameters() ); 53 std::list< TypeDecl * > baseParams = *inst->get_baseParameters(); 54 std::list< Expression * > typeSubs = inst->get_parameters(); 55 TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() ); 56 return subs; 57 } 58 59 TypeSubstitution makeGenericSubstitution( Type * type ) { 60 if ( StructInstType * inst = dynamic_cast< StructInstType * >( type ) ) { 61 return makeGenericSubstitution( inst ); 62 } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( type ) ) { 63 return makeGenericSubstitution( inst ); 64 } else { 65 return TypeSubstitution(); 66 } 67 } 68 69 class MemberIterator { 70 public: 71 virtual ~MemberIterator() {} 72 73 /// walks the current object using the given designators as a guide 74 virtual void setPosition( std::list< Expression * > & designators ) = 0; 75 76 /// retrieve the list of possible Type/Designation pairs for the current position in the currect object 77 virtual std::list<InitAlternative> operator*() const = 0; 78 79 /// true if the iterator is not currently at the end 80 virtual operator bool() const = 0; 81 82 /// moves the iterator by one member in the current object 83 virtual MemberIterator & bigStep() = 0; 84 85 /// moves the iterator by one member in the current subobject 86 virtual MemberIterator & smallStep() = 0; 87 88 /// the type of the current object 89 virtual Type * getType() = 0; 90 91 /// the type of the current subobject 92 virtual Type * getNext() = 0; 93 94 /// printing for debug 95 virtual void print( std::ostream & out, Indenter indent ) const = 0; 96 97 /// helper for operator*; aggregates must add designator to each init alternative, but 98 /// adding designators in operator* creates duplicates. 99 virtual std::list<InitAlternative> first() const = 0; // should be protected 100 }; 101 102 std::ostream & operator<<(std::ostream & out, const MemberIterator & it) { 103 Indenter indenter; 104 it.print( out, indenter ); 105 return out; 106 } 107 108 /// create a new MemberIterator that traverses a type correctly 109 MemberIterator * createMemberIterator( Type * type ); 110 111 /// iterates "other" types, e.g. basic types, pointer types, etc. which do not change at list initializer entry 112 class SimpleIterator : public MemberIterator { 113 public: 114 SimpleIterator( Type * type ) : type( type ) {} 115 116 virtual void setPosition( std::list< Expression * > & designators ) { 117 assertf( designators.empty(), "simple iterator given non-empty designator..." ); // xxx - might be semantic error 118 } 119 120 virtual std::list<InitAlternative> operator*() const { return first(); } 121 virtual operator bool() const { return type; } 122 123 // big step is the same as small step 124 virtual MemberIterator & bigStep() { return smallStep(); } 125 virtual MemberIterator & smallStep() { 126 type = nullptr; // type is nullified on increment since SimpleIterators do not have members 127 return *this; 128 } 129 130 virtual void print( std::ostream & out, __attribute__((unused)) Indenter indent ) const { 131 out << "SimpleIterator(" << type << ")"; 132 } 133 134 virtual Type * getType() { return type; } 135 virtual Type * getNext() { return type; } 136 137 protected: 138 virtual std::list<InitAlternative> first() const { 139 if ( type ) return std::list<InitAlternative>{ { type->clone(), new Designation( {} ) } }; 140 else return std::list<InitAlternative>{}; 141 } 142 private: 143 Type * type = nullptr; 144 }; 145 146 class ArrayIterator : public MemberIterator { 147 public: 148 ArrayIterator( ArrayType * at ) : array( at ) { 149 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) 150 base = at->base; 151 memberIter = createMemberIterator( base ); 152 if ( at->isVarLen ) SemanticError( at, "VLA initialization does not support @=: " ); 153 setSize( at->dimension ); 154 } 155 156 ~ArrayIterator() { 157 delete memberIter; 158 } 159 160 private: 161 void setSize( Expression * expr ) { 162 auto res = eval( expr ); 163 if (res.second) { 164 size = res.first; 165 } else { 166 SemanticError( expr->location, toString("Array designator must be a constant expression: ", expr) ); 167 } 168 } 169 170 public: 171 void setPosition( Expression * expr ) { 172 // need to permit integer-constant-expressions, including: integer constants, enumeration constants, character constants, sizeof expressions, _Alignof expressions, cast expressions 173 auto arg = eval( expr ); 174 index = arg.first; 175 return; 176 177 // if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) { 178 // try { 179 // index = constExpr->intValue(); 180 // } catch( SemanticErrorException & ) { 181 // SemanticError( expr, "Constant expression of non-integral type in array designator: " ); 182 // } 183 // } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) { 184 // setPosition( castExpr->get_arg() ); 185 // } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) { 186 // EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() ); 187 // assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() ); 188 // long long int value; 189 // if ( inst->baseEnum->valueOf( varExpr->var, value ) ) { 190 // index = value; 191 // } 192 // } else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) { 193 // index = 0; // xxx - get actual sizeof/alignof value? 194 // } else { 195 // assertf( false, "4 bad designator given to ArrayIterator: %s", toString( expr ).c_str() ); 196 // } 197 } 198 199 virtual void setPosition( std::list< Expression * > & designators ) { 200 if ( ! designators.empty() ) { 201 setPosition( designators.front() ); 202 designators.pop_front(); 203 memberIter->setPosition( designators ); 204 } 205 } 206 207 virtual std::list<InitAlternative> operator*() const { 208 return first(); 209 } 210 211 virtual operator bool() const { return index < size; } 212 213 virtual MemberIterator & bigStep() { 214 PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; ) 215 ++index; 216 delete memberIter; 217 if ( index < size ) memberIter = createMemberIterator( base ); 218 else memberIter = nullptr; 219 return *this; 220 } 221 222 virtual MemberIterator & smallStep() { 223 PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; ) 224 if ( memberIter ) { 225 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; ) 226 memberIter->smallStep(); 227 if ( *memberIter ) { 228 PRINT( std::cerr << "has valid member iter" << std::endl; ) 229 return *this; 230 } 231 } 232 return bigStep(); 233 } 234 235 virtual Type * getType() { return array; } 236 virtual Type * getNext() { return base; } 237 238 virtual std::list<InitAlternative> first() const { 239 PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; ) 240 if ( memberIter && *memberIter ) { 241 std::list<InitAlternative> ret = memberIter->first(); 242 for ( InitAlternative & alt : ret ) { 243 alt.designation->get_designators().push_front( new ConstantExpr( Constant::from_ulong( index ) ) ); 244 } 245 return ret; 246 } 247 return std::list<InitAlternative>(); 248 } 249 250 virtual void print( std::ostream & out, Indenter indent ) const { 251 out << "ArrayIterator(Array of " << base << ")"; 252 if ( memberIter ) { 253 Indenter childIndent = indent+1; 254 out << std::endl << childIndent; 255 memberIter->print( out, childIndent ); 256 } 257 } 258 259 private: 260 ArrayType * array = nullptr; 261 Type * base = nullptr; 262 size_t index = 0; 263 size_t size = 0; 264 MemberIterator * memberIter = nullptr; 265 }; 266 267 class AggregateIterator : public MemberIterator { 268 public: 269 typedef std::list<Declaration *> MemberList; 270 typedef MemberList::const_iterator iterator; 271 std::string kind = ""; // for debug 272 std::string name; 273 Type * inst = nullptr; 274 const MemberList & members; 275 iterator curMember; 276 bool atbegin = true; // false at first {small,big}Step -- this aggr type is only added to the possibilities at the beginning 277 Type * curType = nullptr; 278 MemberIterator * memberIter = nullptr; 279 mutable TypeSubstitution sub; 280 281 AggregateIterator( const std::string & kind, const std::string & name, Type * inst, const MemberList & members ) : kind( kind ), name( name ), inst( inst ), members( members ), curMember( members.begin() ), sub( makeGenericSubstitution( inst ) ) { 282 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; ) 283 init(); 284 } 285 286 virtual ~AggregateIterator() { 287 delete memberIter; 288 } 289 290 bool init() { 291 PRINT( std::cerr << "--init()--" << members.size() << std::endl; ) 292 if ( curMember != members.end() ) { 293 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( *curMember ) ) { 294 PRINT( std::cerr << "incremented to field: " << field << std::endl; ) 295 curType = field->get_type(); 296 memberIter = createMemberIterator( curType ); 297 return true; 298 } 299 } 300 return false; 301 } 302 303 virtual std::list<InitAlternative> operator*() const { 304 if (memberIter && *memberIter) { 305 std::list<InitAlternative> ret = memberIter->first(); 306 PRINT( std::cerr << "sub: " << sub << std::endl; ) 307 for ( InitAlternative & alt : ret ) { 308 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 309 alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) ); 310 // need to substitute for generic types, so that casts are to concrete types 311 PRINT( std::cerr << " type is: " << alt.type; ) 312 sub.apply( alt.type ); // also apply to designation?? 313 PRINT( std::cerr << " ==> " << alt.type << std::endl; ) 314 } 315 return ret; 316 } 317 return std::list<InitAlternative>(); 318 } 319 320 virtual void setPosition( std::list< Expression * > & designators ) { 321 if ( ! designators.empty() ) { 322 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( designators.front() ) ) { 323 for ( curMember = members.begin(); curMember != members.end(); ++curMember ) { 324 if ( *curMember == varExpr->get_var() ) { 325 designators.pop_front(); 326 delete memberIter; 327 memberIter = createMemberIterator( varExpr->get_result() ); 328 curType = varExpr->get_result(); 329 atbegin = curMember == members.begin() && designators.empty(); // xxx - is this the right condition for atbegin?? 330 memberIter->setPosition( designators ); 331 return; 332 } // if 333 } // for 334 assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() ); 335 } else { 336 assertf( false, "3 bad designator given to %s: %s", kind.c_str(), toString( designators.front() ).c_str() ); 337 } // if 338 } // if 339 } 340 341 virtual MemberIterator & smallStep() { 342 PRINT( std::cerr << "smallStep in " << kind << std::endl; ) 343 atbegin = false; 344 if ( memberIter ) { 345 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; ) 346 memberIter->smallStep(); 347 if ( *memberIter ) { 348 PRINT( std::cerr << "success!" << std::endl; ) 349 return *this; 350 } 351 } 352 return bigStep(); 353 } 354 355 virtual Type * getType() { return inst; } 356 virtual Type * getNext() { 357 if ( memberIter && *memberIter ) return memberIter->getType(); // xxx - ??? recursive call??? 358 return nullptr; 359 } 360 361 virtual std::list<InitAlternative> first() const { 362 std::list<InitAlternative> ret; 363 PRINT( std::cerr << "first " << kind << std::endl; ) 364 if ( memberIter && *memberIter ) { // might not need *memberIter?? 365 PRINT( std::cerr << "adding children" << std::endl; ) 366 ret = memberIter->first(); 367 for ( InitAlternative & alt : ret ) { 368 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 369 alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) ); 370 } 371 } 372 if ( atbegin ) { 373 // xxx - what about case of empty struct?? 374 // only add self if at the very beginning of the structure 375 PRINT( std::cerr << "adding self" << std::endl; ) 376 ret.push_front( { inst->clone(), new Designation( {} ) } ); 377 } 378 return ret; 379 } 380 381 virtual void print( std::ostream & out, Indenter indent ) const { 382 out << kind << "(" << name << ")"; 383 if ( memberIter ) { 384 Indenter childIndent = indent+1; 385 out << std::endl << childIndent; 386 memberIter->print( out, childIndent ); 387 } 388 } 389 }; 390 391 class UnionIterator : public AggregateIterator { 392 public: 393 UnionIterator( UnionInstType * inst ) : AggregateIterator( "UnionIterator", inst->get_name(), inst, inst->get_baseUnion()->get_members() ) {} 394 395 virtual operator bool() const { return (memberIter && *memberIter); } 396 virtual MemberIterator & bigStep() { 397 // unions only initialize one member 398 PRINT( std::cerr << "bigStep in " << kind << std::endl; ) 399 atbegin = false; 400 delete memberIter; 401 memberIter = nullptr; 402 curType = nullptr; 403 curMember = members.end(); 404 return *this; 405 } 406 }; 407 408 class StructIterator : public AggregateIterator { 409 public: 410 StructIterator( StructInstType * inst ) : AggregateIterator( "StructIterator", inst->get_name(), inst, inst->get_baseStruct()->get_members() ) {} 411 412 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); } 413 414 virtual MemberIterator & bigStep() { 415 PRINT( std::cerr << "bigStep in " << kind << std::endl; ) 416 atbegin = false; 417 delete memberIter; 418 memberIter = nullptr; 419 curType = nullptr; 420 for ( ; curMember != members.end(); ) { 421 ++curMember; 422 if ( init() ) { 423 return *this; 424 } 425 } 426 return *this; 427 } 428 }; 429 430 class TupleIterator : public AggregateIterator { 431 public: 432 TupleIterator( TupleType * inst ) : AggregateIterator( "TupleIterator", toString("Tuple", inst->size()), inst, inst->get_members() ) {} 433 434 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); } 435 436 virtual MemberIterator & bigStep() { 437 PRINT( std::cerr << "bigStep in " << kind << std::endl; ) 438 atbegin = false; 439 delete memberIter; 440 memberIter = nullptr; 441 curType = nullptr; 442 for ( ; curMember != members.end(); ) { 443 ++curMember; 444 if ( init() ) { 445 return *this; 446 } 447 } 448 return *this; 449 } 450 }; 451 452 MemberIterator * createMemberIterator( Type * type ) { 453 if ( ReferenceToType * aggr = dynamic_cast< ReferenceToType * >( type ) ) { 454 if ( StructInstType * sit = dynamic_cast< StructInstType * >( aggr ) ) { 455 return new StructIterator( sit ); 456 } else if ( UnionInstType * uit = dynamic_cast< UnionInstType * >( aggr ) ) { 457 return new UnionIterator( uit ); 458 } else { 459 assertf( dynamic_cast< EnumInstType * >( type ) || dynamic_cast< TypeInstType * >( type ), "Encountered unhandled ReferenceToType in createMemberIterator: %s", toString( type ).c_str() ); 460 return new SimpleIterator( type ); 461 } 462 } else if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) { 463 return new ArrayIterator( at ); 464 } else if ( TupleType * tt = dynamic_cast< TupleType * >( type ) ) { 465 return new TupleIterator( tt ); 466 } else { 467 return new SimpleIterator( type ); 468 } 469 } 470 471 CurrentObject::CurrentObject() {} 472 CurrentObject::CurrentObject( Type * type ) { 473 objStack.push( new SimpleIterator( type ) ); 474 } 475 476 477 void CurrentObject::setNext( Designation * designation ) { 478 assertf( ! objStack.empty(), "obj stack empty in setNext" ); 479 PRINT( std::cerr << "____setNext" << designation << std::endl; ) 480 objStack.top()->setPosition( designation->get_designators() ); 481 } 482 483 Designation * CurrentObject::findNext( Designation * designation ) { 484 typedef std::list< Expression * > DesignatorChain; 485 PRINT( std::cerr << "___findNext" << std::endl; ) 486 // find all the d's 487 std::list<DesignatorChain> desigAlts{ { } }, newDesigAlts; 488 std::list<Type *> curTypes { (objStack.top())->getType() }, newTypes; 489 for ( Expression * expr : designation->get_designators() ) { 490 PRINT( std::cerr << "____untyped: " << expr << std::endl; ) 491 std::list<DesignatorChain>::iterator dit = desigAlts.begin(); 492 if ( NameExpr * nexpr = dynamic_cast<NameExpr *>(expr) ) { 493 for ( Type * t : curTypes ) { 494 assert( dit != desigAlts.end() ); 495 DesignatorChain & d = *dit; 496 PRINT( std::cerr << "____actual: " << t << std::endl; ) 497 ReferenceToType * refType = dynamic_cast<ReferenceToType *>(t); 498 std::list<Declaration *> members; 499 if ( refType ) { 500 refType->lookup( nexpr->get_name(), members ); // concatenate identical field name 501 // xxx - need to also include anonymous members in this somehow... 502 for ( Declaration * mem: members ) { 503 if ( ObjectDecl * field = dynamic_cast<ObjectDecl *>(mem) ) { 504 PRINT( std::cerr << "____alt: " << field->get_type() << std::endl; ) 505 DesignatorChain newD = d; 506 newD.push_back( new VariableExpr( field ) ); 507 newDesigAlts.push_back( newD ); 508 newTypes.push_back( field->get_type() ); 509 } // if 510 } // for 511 } // if 512 ++dit; 513 } // for 514 } else { 515 for ( Type * t : curTypes ) { 516 assert( dit != desigAlts.end() ); 517 DesignatorChain & d = *dit; 518 if ( ArrayType * at = dynamic_cast< ArrayType * > ( t ) ) { 519 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; ) 520 d.push_back( expr ); 521 newDesigAlts.push_back( d ); 522 newTypes.push_back( at->get_base() ); 523 } 524 ++dit; 525 } // for 526 } // if 527 desigAlts = newDesigAlts; 528 newDesigAlts.clear(); 529 curTypes = newTypes; 530 newTypes.clear(); 531 assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() ); 532 } // for 533 if ( desigAlts.size() > 1 ) { 534 SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") ); 535 } else if ( desigAlts.size() == 0 ) { 536 SemanticError( designation, "No reasonable alternatives for designation: " ); 537 } 538 DesignatorChain & d = desigAlts.back(); 539 PRINT( for ( Expression * expr : d ) { 540 std::cerr << "____desig: " << expr << std::endl; 541 } ) // for 542 assertf( ! curTypes.empty(), "empty designator chosen"); 543 544 // set new designators 545 assertf( ! objStack.empty(), "empty object stack when setting designation" ); 546 Designation * actualDesignation = new Designation( d ); 547 objStack.top()->setPosition( d ); // destroys d 548 return actualDesignation; 549 } 550 551 void CurrentObject::increment() { 552 PRINT( std::cerr << "____increment" << std::endl; ) 553 if ( ! objStack.empty() ) { 554 PRINT( std::cerr << *objStack.top() << std::endl; ) 555 objStack.top()->smallStep(); 556 } 557 } 558 559 void CurrentObject::enterListInit() { 560 PRINT( std::cerr << "____entering list init" << std::endl; ) 561 assertf( ! objStack.empty(), "empty obj stack entering list init" ); 562 Type * type = objStack.top()->getNext(); 563 if ( type ) { 564 objStack.push( createMemberIterator( type ) ); 565 } else { 566 assertf( false, "not sure about this case..." ); 567 } 568 } 569 570 void CurrentObject::exitListInit() { 571 PRINT( std::cerr << "____exiting list init" << std::endl; ) 572 assertf( ! objStack.empty(), "objstack empty" ); 573 delete objStack.top(); 574 objStack.pop(); 575 if ( ! objStack.empty() ) { 576 PRINT( std::cerr << *objStack.top() << std::endl; ) 577 objStack.top()->bigStep(); 578 } 579 } 580 581 std::list< InitAlternative > CurrentObject::getOptions() { 582 PRINT( std::cerr << "____getting current options" << std::endl; ) 583 assertf( ! objStack.empty(), "objstack empty in getOptions" ); 584 return **objStack.top(); 585 } 586 587 Type * CurrentObject::getCurrentType() { 588 PRINT( std::cerr << "____getting current type" << std::endl; ) 589 assertf( ! objStack.empty(), "objstack empty in getCurrentType" ); 590 return objStack.top()->getNext(); 591 } 592 } // namespace ResolvExpr 41 593 42 594 namespace ast { … … 512 1064 } else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) { 513 1065 auto nexpr = dynamic_cast< const NameExpr *>( expr ); 1066 auto res = eval( nexpr ); 514 1067 for ( const Decl * mem : refType->lookup( nexpr->name ) ) { 515 1068 if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) { … … 517 1070 d2.emplace_back( new VariableExpr{ expr->location, field } ); 518 1071 newDesigAlts.emplace_back( std::move( d2 ) ); 1072 // newTypes.emplace_back( field->type ); 519 1073 newTypes.emplace_back( at->base ); 520 1074 } 521 1075 } 1076 1077 // d.emplace_back( expr ); 1078 // newDesigAlts.emplace_back( d ); 1079 // newTypes.emplace_back( at->base ); 522 1080 } 523 1081 -
src/ResolvExpr/FindOpenVars.cc
rfc12f05 r0030b508 16 16 #include "FindOpenVars.h" 17 17 18 #include <list> // for _List_const_iterator, list<>::const... 19 #include <map> // for map<>::mapped_type 20 18 21 #include "AST/Pass.hpp" 19 22 #include "AST/Type.hpp" 20 23 #include "AST/TypeEnvironment.hpp" 24 #include "Common/PassVisitor.h" 25 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType (ptr ... 26 #include "SynTree/Type.h" // for Type, Type::ForallList, ArrayType 21 27 22 28 #include <iostream> 23 29 24 30 namespace ResolvExpr { 31 struct FindOpenVars_old : public WithGuards { 32 FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ); 33 34 void previsit( const PointerType * pointerType ); 35 void previsit( const ArrayType * arrayType ); 36 void previsit( const FunctionType * functionType ); 37 void previsit( const TupleType * tupleType ); 38 39 void common_action( const Type *type ); 40 41 OpenVarSet &openVars, &closedVars; 42 AssertionSet &needAssertions, &haveAssertions; 43 bool nextIsOpen; 44 }; 45 46 void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) { 47 PassVisitor<FindOpenVars_old> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen ); 48 type->accept( finder ); 49 } 50 51 FindOpenVars_old::FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) 52 : openVars( openVars ), closedVars( closedVars ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), nextIsOpen( firstIsOpen ) { 53 } 54 55 void FindOpenVars_old::common_action( const Type * type ) { 56 if ( nextIsOpen ) { 57 for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) { 58 openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) }; 59 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) { 60 needAssertions[ *assert ].isUsed = false; 61 } 62 /// cloneAll( (*i)->get_assertions(), needAssertions ); 63 /// needAssertions.insert( needAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() ); 64 } 65 } else { 66 for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) { 67 closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) }; 68 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) { 69 haveAssertions[ *assert ].isUsed = false; 70 } 71 /// cloneAll( (*i)->get_assertions(), haveAssertions ); 72 /// haveAssertions.insert( haveAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() ); 73 } // for 74 } // if 75 /// std::cerr << "type is "; 76 /// type->print( std::cerr ); 77 /// std::cerr << std::endl << "need is" << std::endl; 78 /// printAssertionSet( needAssertions, std::cerr ); 79 /// std::cerr << std::endl << "have is" << std::endl; 80 /// printAssertionSet( haveAssertions, std::cerr ); 81 } 82 83 void FindOpenVars_old::previsit(const PointerType * pointerType) { 84 common_action( pointerType ); 85 } 86 87 void FindOpenVars_old::previsit(const ArrayType * arrayType) { 88 common_action( arrayType ); 89 } 90 91 void FindOpenVars_old::previsit(const FunctionType * functionType) { 92 common_action( functionType ); 93 nextIsOpen = ! nextIsOpen; 94 GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } ); 95 } 96 97 void FindOpenVars_old::previsit(const TupleType * tupleType) { 98 common_action( tupleType ); 99 } 25 100 26 101 namespace { -
src/ResolvExpr/FindOpenVars.h
rfc12f05 r0030b508 17 17 18 18 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 19 #include "ResolvExpr/TypeEnvironment.h" // for AssertionSet, OpenVarSet 19 20 21 class Type; 20 22 namespace ast { 21 23 class Type; … … 23 25 24 26 namespace ResolvExpr { 27 // Updates open and closed variables and their associated assertions 28 void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ); 29 25 30 enum FirstMode { FirstClosed, FirstOpen }; 26 31 -
src/ResolvExpr/PolyCost.cc
rfc12f05 r0030b508 18 18 #include "AST/Type.hpp" 19 19 #include "AST/TypeEnvironment.hpp" 20 #include "Common/PassVisitor.h" 21 #include "SymTab/Indexer.h" // for Indexer 22 #include "SynTree/Type.h" // for TypeInstType, Type 23 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment 20 24 21 25 namespace ResolvExpr { 26 struct PolyCost { 27 PolyCost( const TypeEnvironment &env, const SymTab::Indexer &indexer ); 28 29 void previsit( TypeInstType * aggregateUseType ); 30 int result; 31 const TypeEnvironment &tenv; 32 const SymTab::Indexer &indexer; 33 }; 34 35 int polyCost( Type *type, const TypeEnvironment & env, const SymTab::Indexer &indexer ) { 36 PassVisitor<PolyCost> coster( env, indexer ); 37 type->accept( coster ); 38 return (coster.pass.result > 0) ? 1 : 0; 39 } 40 41 PolyCost::PolyCost( const TypeEnvironment & env, const SymTab::Indexer & indexer ) : result( 0 ), tenv( env ), indexer( indexer ) { 42 } 43 44 void PolyCost::previsit(TypeInstType * typeInst) { 45 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) { 46 if ( eqvClass->type ) { 47 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type ) ) { 48 if ( indexer.lookupType( otherTypeInst->name ) ) { 49 // bound to opaque type 50 result += 1; 51 } // if 52 } else { 53 // bound to concrete type 54 result += 1; 55 } // if 56 } // if 57 } // if 58 } 22 59 23 60 // TODO: When the old PolyCost is torn out get rid of the _new suffix. -
src/ResolvExpr/PtrsAssignable.cc
rfc12f05 r0030b508 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h" 22 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment 23 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType 24 #include "SynTree/Visitor.h" // for Visitor 25 21 26 22 27 namespace ResolvExpr { 28 struct PtrsAssignable : public WithShortCircuiting { 29 PtrsAssignable( const Type * dest, const TypeEnvironment &env ); 30 31 int get_result() const { return result; } 32 33 void previsit( const Type * ) { visit_children = false; } 34 35 void postvisit( const VoidType * voidType ); 36 void postvisit( const BasicType * basicType ); 37 void postvisit( const PointerType * pointerType ); 38 void postvisit( const ArrayType * arrayType ); 39 void postvisit( const FunctionType * functionType ); 40 void postvisit( const StructInstType * inst ); 41 void postvisit( const UnionInstType * inst ); 42 void postvisit( const EnumInstType * inst ); 43 void postvisit( const TraitInstType * inst ); 44 void postvisit( const TypeInstType * inst ); 45 void postvisit( const TupleType * tupleType ); 46 void postvisit( const VarArgsType * varArgsType ); 47 void postvisit( const ZeroType * zeroType ); 48 void postvisit( const OneType * oneType ); 49 private: 50 const Type * dest; 51 int result; 52 const TypeEnvironment &env; 53 }; 54 55 int ptrsAssignable( const Type *src, const Type * dest, const TypeEnvironment &env ) { 56 // std::cerr << "assignable: " << src << " | " << dest << std::endl; 57 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) { 58 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) { 59 return ptrsAssignable( src, eqvClass->type, env ); 60 } // if 61 } // if 62 if ( dynamic_cast< const VoidType* >( dest ) ) { 63 // void * = T * for any T is unsafe 64 // xxx - this should be safe, but that currently breaks the build 65 return -1; 66 } else { 67 PassVisitor<PtrsAssignable> ptrs( dest, env ); 68 src->accept( ptrs ); 69 return ptrs.pass.get_result(); 70 } // if 71 } 72 73 PtrsAssignable::PtrsAssignable( const Type * dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {} 74 75 void PtrsAssignable::postvisit( const VoidType * ) { 76 // T * = void * is disallowed - this is a change from C, where any 77 // void * can be assigned or passed to a non-void pointer without a cast. 78 } 79 80 void PtrsAssignable::postvisit( const BasicType * ) {} 81 void PtrsAssignable::postvisit( const PointerType * ) {} 82 void PtrsAssignable::postvisit( const ArrayType * ) {} 83 void PtrsAssignable::postvisit( const FunctionType * ) {} 84 85 void PtrsAssignable::postvisit( const StructInstType * ) {} 86 void PtrsAssignable::postvisit( const UnionInstType * ) {} 87 88 void PtrsAssignable::postvisit( const EnumInstType * ) { 89 if ( dynamic_cast< const BasicType* >( dest ) ) { 90 // int * = E *, etc. is safe. This isn't technically correct, as each 91 // enum has one basic type that it is compatible with, an that type can 92 // differ from enum to enum. Without replicating GCC's internal logic, 93 // there is no way to know which type this particular enum is compatible 94 // with, so punt on this for now. 95 result = 1; 96 } 97 } 98 99 void PtrsAssignable::postvisit( const TraitInstType * ) {} 100 void PtrsAssignable::postvisit( const TypeInstType * inst ) { 101 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) { 102 if ( eqvClass->type ) { 103 // T * = S * for any S depends on the type bound to T 104 result = ptrsAssignable( eqvClass->type, dest, env ); 105 } 106 } // if 107 } 108 109 void PtrsAssignable::postvisit( const TupleType * ) {} 110 void PtrsAssignable::postvisit( const VarArgsType * ) {} 111 void PtrsAssignable::postvisit( const ZeroType * ) {} 112 void PtrsAssignable::postvisit( const OneType * ) {} 23 113 24 114 // TODO: Get rid of the `_new` suffix when the old version is removed. -
src/ResolvExpr/PtrsCastable.cc
rfc12f05 r0030b508 20 20 #include "AST/Type.hpp" 21 21 #include "AST/TypeEnvironment.hpp" 22 #include "Common/PassVisitor.h" 22 23 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 24 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment 25 #include "SymTab/Indexer.h" // for Indexer 26 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype 27 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType 28 #include "SynTree/Visitor.h" // for Visitor 23 29 24 30 namespace ResolvExpr { 31 struct PtrsCastable_old : public WithShortCircuiting { 32 public: 33 PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ); 34 35 int get_result() const { return result; } 36 37 void previsit( const Type * ) { visit_children = false; } 38 39 void postvisit( const VoidType * voidType ); 40 void postvisit( const BasicType * basicType ); 41 void postvisit( const PointerType * pointerType ); 42 void postvisit( const ArrayType * arrayType ); 43 void postvisit( const FunctionType * functionType ); 44 void postvisit( const StructInstType * inst ); 45 void postvisit( const UnionInstType * inst ); 46 void postvisit( const EnumInstType * inst ); 47 void postvisit( const TraitInstType * inst ); 48 void postvisit( const TypeInstType * inst ); 49 void postvisit( const TupleType * tupleType ); 50 void postvisit( const VarArgsType * varArgsType ); 51 void postvisit( const ZeroType * zeroType ); 52 void postvisit( const OneType * oneType ); 53 private: 54 const Type * dest; 55 int result; 56 const TypeEnvironment &env; 57 const SymTab::Indexer &indexer; 58 }; 59 60 namespace { 61 int objectCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) { 62 if ( dynamic_cast< const FunctionType* >( src ) ) { 63 return -1; 64 } else if ( const TypeInstType * typeInst = dynamic_cast< const TypeInstType* >( src ) ) { 65 if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->name ) ) { 66 if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl* >( ntDecl ) ) { 67 if ( tyDecl->kind == TypeDecl::Ftype ) { 68 return -1; 69 } // if 70 } //if 71 } else if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) { 72 if ( eqvClass->data.kind == TypeDecl::Ftype ) { 73 return -1; 74 } // if 75 } // if 76 } //if 77 return 1; 78 } 79 int functionCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) { 80 return -1 * objectCast( src, env, indexer ); // reverse the sense of objectCast 81 } 82 } 83 84 int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) { 85 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) { 86 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) { 87 // xxx - should this be ptrsCastable? 88 return ptrsAssignable( src, eqvClass->type, env ); 89 } // if 90 } // if 91 if ( dynamic_cast< const VoidType* >( dest ) ) { 92 return objectCast( src, env, indexer ); 93 } else { 94 PassVisitor<PtrsCastable_old> ptrs( dest, env, indexer ); 95 src->accept( ptrs ); 96 return ptrs.pass.get_result(); 97 } // if 98 } 99 100 PtrsCastable_old::PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) 101 : dest( dest ), result( 0 ), env( env ), indexer( indexer ) { 102 } 103 104 void PtrsCastable_old::postvisit( const VoidType * ) { 105 result = objectCast( dest, env, indexer ); 106 } 107 108 void PtrsCastable_old::postvisit( const BasicType * ) { 109 result = objectCast( dest, env, indexer ); 110 } 111 112 void PtrsCastable_old::postvisit( const PointerType * ) { 113 result = objectCast( dest, env, indexer ); 114 } 115 116 void PtrsCastable_old::postvisit( const ArrayType * ) { 117 result = objectCast( dest, env, indexer ); 118 } 119 120 void PtrsCastable_old::postvisit( const FunctionType * ) { 121 // result = -1; 122 result = functionCast( dest, env, indexer ); 123 } 124 125 void PtrsCastable_old::postvisit( const StructInstType * ) { 126 result = objectCast( dest, env, indexer ); 127 } 128 129 void PtrsCastable_old::postvisit( const UnionInstType * ) { 130 result = objectCast( dest, env, indexer ); 131 } 132 133 void PtrsCastable_old::postvisit( const EnumInstType * ) { 134 if ( dynamic_cast< const EnumInstType * >( dest ) ) { 135 result = 1; 136 } else if ( const BasicType * bt = dynamic_cast< const BasicType * >( dest ) ) { 137 if ( bt->kind == BasicType::SignedInt ) { 138 result = 0; 139 } else { 140 result = 1; 141 } 142 } else { 143 result = objectCast( dest, env, indexer ); 144 } 145 } 146 147 void PtrsCastable_old::postvisit( const TraitInstType * ) {} 148 149 void PtrsCastable_old::postvisit( const TypeInstType *inst ) { 150 //result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1; 151 result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1; 152 } 153 154 void PtrsCastable_old::postvisit( const TupleType * ) { 155 result = objectCast( dest, env, indexer ); 156 } 157 158 void PtrsCastable_old::postvisit( const VarArgsType * ) { 159 result = objectCast( dest, env, indexer ); 160 } 161 162 void PtrsCastable_old::postvisit( const ZeroType * ) { 163 result = objectCast( dest, env, indexer ); 164 } 165 166 void PtrsCastable_old::postvisit( const OneType * ) { 167 result = objectCast( dest, env, indexer ); 168 } 25 169 26 170 namespace { -
src/ResolvExpr/RenameVars.cc
rfc12f05 r0030b508 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h" 23 24 #include "Common/ScopedMap.h" 24 25 #include "Common/SemanticError.h" // for SemanticError 25 26 #include "RenameVars.h" 27 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec... 28 #include "SynTree/Expression.h" // for Expression 29 #include "SynTree/Type.h" // for Type, TypeInstType, TraitInstType 30 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 26 31 27 32 #include "AST/Copy.hpp" … … 44 49 } 45 50 51 void rename( TypeInstType * type ) { 52 auto it = nameMap.find( type->name ); 53 if ( it != nameMap.end() ) { 54 type->name = it->second; 55 } 56 } 57 46 58 void nextUsage() { 47 59 ++next_usage_id; 60 } 61 62 void openLevel( Type * type ) { 63 if ( ! type->forall.empty() ) { 64 nameMap.beginScope(); 65 // renames all "forall" type names to `_${level}_${name}' 66 for ( auto td : type->forall ) { 67 std::ostringstream output; 68 output << "_" << resetCount << "_" << level << "_" << td->name; 69 std::string newname( output.str() ); 70 nameMap[ td->get_name() ] = newname; 71 td->name = newname; 72 // ditto for assertion names, the next level in 73 level++; 74 } 75 } 76 } 77 78 void closeLevel( Type * type ) { 79 if ( !type->forall.empty() ) { 80 nameMap.endScope(); 81 } 48 82 } 49 83 … … 101 135 RenamingData renaming; 102 136 137 struct RenameVars_old { 138 void previsit( TypeInstType * instType ) { 139 renaming.openLevel( (Type*)instType ); 140 renaming.rename( instType ); 141 } 142 void previsit( Type * type ) { 143 renaming.openLevel( type ); 144 } 145 void postvisit( Type * type ) { 146 renaming.closeLevel( type ); 147 } 148 }; 149 103 150 struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ { 104 151 RenameMode mode; … … 130 177 131 178 } // namespace 179 180 void renameTyVars( Type * t ) { 181 PassVisitor<RenameVars_old> renamer; 182 t->accept( renamer ); 183 } 132 184 133 185 const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) { -
src/ResolvExpr/RenameVars.h
rfc12f05 r0030b508 16 16 #pragma once 17 17 18 #include <list> // for list 19 #include <map> // for map 20 #include <string> // for string 21 22 #include "SynTree/SynTree.h" // for Visitor Nodes 23 #include "SynTree/Visitor.h" // for Visitor 24 18 25 namespace ast { 19 26 class Type; … … 21 28 22 29 namespace ResolvExpr { 30 /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID 31 void renameTyVars( Type * ); 32 23 33 enum RenameMode { 24 34 GEN_USAGE, // for type in VariableExpr -
src/ResolvExpr/ResolveTypeof.cc
rfc12f05 r0030b508 24 24 #include "AST/Type.hpp" 25 25 #include "AST/TypeEnvironment.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor 26 27 #include "Common/utility.h" // for copy 27 28 #include "InitTweak/InitTweak.h" // for isConstExpr … … 29 30 #include "Resolver.h" // for resolveInVoidContext 30 31 #include "SymTab/Mangler.h" 32 #include "SynTree/Expression.h" // for Expression 33 #include "SynTree/Mutator.h" // for Mutator 34 #include "SynTree/Type.h" // for TypeofType, Type 35 36 namespace SymTab { 37 class Indexer; 38 } // namespace SymTab 31 39 32 40 namespace ResolvExpr { 41 namespace { 42 #if 0 43 void 44 printAlts( const AltList &list, std::ostream &os, int indent = 0 ) 45 { 46 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) { 47 i->print( os, indent ); 48 os << std::endl; 49 } 50 } 51 #endif 52 } 53 54 class ResolveTypeof_old : public WithShortCircuiting { 55 public: 56 ResolveTypeof_old( const SymTab::Indexer &indexer ) : indexer( indexer ) {} 57 void premutate( TypeofType *typeofType ); 58 Type * postmutate( TypeofType *typeofType ); 59 60 private: 61 const SymTab::Indexer &indexer; 62 }; 63 64 Type * resolveTypeof( Type *type, const SymTab::Indexer &indexer ) { 65 PassVisitor<ResolveTypeof_old> mutator( indexer ); 66 return type->acceptMutator( mutator ); 67 } 68 69 void ResolveTypeof_old::premutate( TypeofType * ) { 70 visit_children = false; 71 } 72 73 Type * ResolveTypeof_old::postmutate( TypeofType *typeofType ) { 74 #if 0 75 std::cerr << "resolving typeof: "; 76 typeofType->print( std::cerr ); 77 std::cerr << std::endl; 78 #endif 79 // pass on null expression 80 if ( ! typeofType->expr ) return typeofType; 81 82 bool isBasetypeof = typeofType->is_basetypeof; 83 auto oldQuals = typeofType->get_qualifiers().val; 84 85 Type* newType; 86 if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(typeofType->expr) ) { 87 // typeof wrapping type 88 newType = tyExpr->type; 89 tyExpr->type = nullptr; 90 delete tyExpr; 91 } else { 92 // typeof wrapping expression 93 Expression * newExpr = resolveInVoidContext( typeofType->expr, indexer ); 94 assert( newExpr->result && ! newExpr->result->isVoid() ); 95 newType = newExpr->result; 96 newExpr->result = nullptr; 97 delete typeofType; 98 delete newExpr; 99 } 100 101 // clear qualifiers for base, combine with typeoftype quals in any case 102 if ( isBasetypeof ) { 103 // replace basetypeof(<enum>) by int 104 if ( dynamic_cast<EnumInstType*>(newType) ) { 105 Type* newerType = 106 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 107 newType->attributes }; 108 delete newType; 109 newType = newerType; 110 } 111 newType->get_qualifiers().val 112 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals; 113 } else { 114 newType->get_qualifiers().val |= oldQuals; 115 } 116 117 return newType; 118 } 33 119 34 120 namespace { -
src/ResolvExpr/Resolver.cc
rfc12f05 r0030b508 19 19 #include <vector> // for vector 20 20 21 #include "Alternative.h" // for Alternative, AltList 22 #include "AlternativeFinder.h" // for AlternativeFinder, resolveIn... 21 23 #include "Candidate.hpp" 22 24 #include "CandidateFinder.hpp" … … 38 40 #include "Common/Eval.h" // for eval 39 41 #include "Common/Iterate.hpp" // for group_iterate 42 #include "Common/PassVisitor.h" // for PassVisitor 40 43 #include "Common/SemanticError.h" // for SemanticError 41 44 #include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop() 42 45 #include "Common/ToString.hpp" // for toCString 43 #include "Common/UniqueName.h" // for UniqueName44 46 #include "InitTweak/GenInit.h" 45 47 #include "InitTweak/InitTweak.h" // for isIntrinsicSingleArgCallStmt 48 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment 49 #include "SymTab/Autogen.h" // for SizeType 50 #include "SymTab/Indexer.h" // for Indexer 46 51 #include "SymTab/Mangler.h" // for Mangler 52 #include "SynTree/Declaration.h" // for ObjectDecl, TypeDecl, Declar... 53 #include "SynTree/Expression.h" // for Expression, CastExpr, InitExpr 54 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit 55 #include "SynTree/Statement.h" // for ForStmt, Statement, BranchStmt 56 #include "SynTree/Type.h" // for Type, BasicType, PointerType 57 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 58 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 47 59 #include "Tuples/Tuples.h" 48 60 #include "Validate/FindSpecialDecls.h" // for SizeType … … 51 63 52 64 namespace ResolvExpr { 65 struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd { 66 Resolver_old() {} 67 Resolver_old( const SymTab::Indexer & other ) { 68 indexer = other; 69 } 70 71 void previsit( FunctionDecl * functionDecl ); 72 void postvisit( FunctionDecl * functionDecl ); 73 void previsit( ObjectDecl * objectDecll ); 74 void previsit( EnumDecl * enumDecl ); 75 void previsit( StaticAssertDecl * assertDecl ); 76 77 void previsit( ArrayType * at ); 78 void previsit( PointerType * at ); 79 80 void previsit( ExprStmt * exprStmt ); 81 void previsit( AsmExpr * asmExpr ); 82 void previsit( AsmStmt * asmStmt ); 83 void previsit( IfStmt * ifStmt ); 84 void previsit( WhileDoStmt * whileDoStmt ); 85 void previsit( ForStmt * forStmt ); 86 void previsit( SwitchStmt * switchStmt ); 87 void previsit( CaseStmt * caseStmt ); 88 void previsit( BranchStmt * branchStmt ); 89 void previsit( ReturnStmt * returnStmt ); 90 void previsit( ThrowStmt * throwStmt ); 91 void previsit( CatchStmt * catchStmt ); 92 void postvisit( CatchStmt * catchStmt ); 93 void previsit( WaitForStmt * stmt ); 94 95 void previsit( SingleInit * singleInit ); 96 void previsit( ListInit * listInit ); 97 void previsit( ConstructorInit * ctorInit ); 98 private: 99 typedef std::list< Initializer * >::iterator InitIterator; 100 101 template< typename PtrType > 102 void handlePtrType( PtrType * type ); 103 104 void fallbackInit( ConstructorInit * ctorInit ); 105 106 Type * functionReturn = nullptr; 107 CurrentObject currentObject = nullptr; 108 bool inEnumDecl = false; 109 }; 110 111 struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd { 112 void previsit( FunctionDecl * ); 113 void previsit( WithStmt * ); 114 115 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ); 116 }; 117 118 void resolve( std::list< Declaration * > translationUnit ) { 119 PassVisitor<Resolver_old> resolver; 120 acceptAll( translationUnit, resolver ); 121 } 122 123 void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) { 124 PassVisitor<Resolver_old> resolver( indexer ); 125 maybeAccept( decl, resolver ); 126 } 127 128 namespace { 129 struct DeleteFinder_old : public WithShortCircuiting { 130 DeletedExpr * delExpr = nullptr; 131 void previsit( DeletedExpr * expr ) { 132 if ( delExpr ) visit_children = false; 133 else delExpr = expr; 134 } 135 136 void previsit( Expression * ) { 137 if ( delExpr ) visit_children = false; 138 } 139 }; 140 } 141 142 DeletedExpr * findDeletedExpr( Expression * expr ) { 143 PassVisitor<DeleteFinder_old> finder; 144 expr->accept( finder ); 145 return finder.pass.delExpr; 146 } 147 148 namespace { 149 struct StripCasts_old { 150 Expression * postmutate( CastExpr * castExpr ) { 151 if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) { 152 // generated cast is to the same type as its argument, so it's unnecessary -- remove it 153 Expression * expr = castExpr->arg; 154 castExpr->arg = nullptr; 155 std::swap( expr->env, castExpr->env ); 156 return expr; 157 } 158 return castExpr; 159 } 160 161 static void strip( Expression *& expr ) { 162 PassVisitor<StripCasts_old> stripper; 163 expr = expr->acceptMutator( stripper ); 164 } 165 }; 166 167 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) { 168 expr->env = oldenv ? oldenv->clone() : new TypeSubstitution; 169 env.makeSubstitution( *expr->env ); 170 StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression 171 } 172 173 void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) { 174 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) { 175 if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) { 176 // cast is to the same type as its argument, so it's unnecessary -- remove it 177 expr = castExpr->arg; 178 castExpr->arg = nullptr; 179 std::swap( expr->env, castExpr->env ); 180 delete castExpr; 181 } 182 } 183 } 184 } // namespace 185 186 namespace { 187 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) { 188 assertf( untyped, "expected a non-null expression." ); 189 190 // xxx - this isn't thread-safe, but should work until we parallelize the resolver 191 static unsigned recursion_level = 0; 192 193 ++recursion_level; 194 TypeEnvironment env; 195 AlternativeFinder finder( indexer, env ); 196 finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode ); 197 --recursion_level; 198 199 #if 0 200 if ( finder.get_alternatives().size() != 1 ) { 201 std::cerr << "untyped expr is "; 202 untyped->print( std::cerr ); 203 std::cerr << std::endl << "alternatives are:"; 204 for ( const Alternative & alt : finder.get_alternatives() ) { 205 alt.print( std::cerr ); 206 } // for 207 } // if 208 #endif 209 210 // produce filtered list of alternatives 211 AltList candidates; 212 for ( Alternative & alt : finder.get_alternatives() ) { 213 if ( pred( alt ) ) { 214 candidates.push_back( std::move( alt ) ); 215 } 216 } 217 218 // produce invalid error if no candidates 219 if ( candidates.empty() ) { 220 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") ); 221 } 222 223 // search for cheapest candidate 224 AltList winners; 225 bool seen_undeleted = false; 226 for ( unsigned i = 0; i < candidates.size(); ++i ) { 227 int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost ); 228 229 if ( c > 0 ) continue; // skip more expensive than winner 230 231 if ( c < 0 ) { 232 // reset on new cheapest 233 seen_undeleted = ! findDeletedExpr( candidates[i].expr ); 234 winners.clear(); 235 } else /* if ( c == 0 ) */ { 236 if ( findDeletedExpr( candidates[i].expr ) ) { 237 // skip deleted expression if already seen one equivalent-cost not 238 if ( seen_undeleted ) continue; 239 } else if ( ! seen_undeleted ) { 240 // replace list of equivalent-cost deleted expressions with one non-deleted 241 winners.clear(); 242 seen_undeleted = true; 243 } 244 } 245 246 winners.emplace_back( std::move( candidates[i] ) ); 247 } 248 249 // promote alternative.cvtCost to .cost 250 // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost 251 for ( Alternative& winner : winners ) { 252 winner.cost = winner.cvtCost; 253 } 254 255 // produce ambiguous errors, if applicable 256 if ( winners.size() != 1 ) { 257 std::ostringstream stream; 258 stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n"; 259 untyped->print( stream ); 260 stream << " Alternatives are:\n"; 261 printAlts( winners, stream, 1 ); 262 SemanticError( untyped->location, stream.str() ); 263 } 264 265 // single selected choice 266 Alternative& choice = winners.front(); 267 268 // fail on only expression deleted 269 if ( ! seen_undeleted ) { 270 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " ); 271 } 272 273 // xxx - check for ambiguous expressions 274 275 // output selected choice 276 alt = std::move( choice ); 277 } 278 279 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages 280 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) { 281 if ( ! untyped ) return; 282 Alternative choice; 283 findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode ); 284 finishExpr( choice.expr, choice.env, untyped->env ); 285 delete untyped; 286 untyped = choice.expr; 287 choice.expr = nullptr; 288 } 289 290 bool standardAlternativeFilter( const Alternative & ) { 291 // currently don't need to filter, under normal circumstances. 292 // in the future, this may be useful for removing deleted expressions 293 return true; 294 } 295 } // namespace 296 297 // used in resolveTypeof 298 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) { 299 TypeEnvironment env; 300 return resolveInVoidContext( expr, indexer, env ); 301 } 302 303 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) { 304 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0 305 // interpretations, an exception has already been thrown. 306 assertf( expr, "expected a non-null expression." ); 307 308 CastExpr * untyped = new CastExpr( expr ); // cast to void 309 untyped->location = expr->location; 310 311 // set up and resolve expression cast to void 312 Alternative choice; 313 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() ); 314 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr ); 315 assert( castExpr ); 316 env = std::move( choice.env ); 317 318 // clean up resolved expression 319 Expression * ret = castExpr->arg; 320 castExpr->arg = nullptr; 321 322 // unlink the arg so that it isn't deleted twice at the end of the program 323 untyped->arg = nullptr; 324 return ret; 325 } 326 327 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) { 328 resetTyVarRenaming(); 329 TypeEnvironment env; 330 Expression * newExpr = resolveInVoidContext( untyped, indexer, env ); 331 finishExpr( newExpr, env, untyped->env ); 332 delete untyped; 333 untyped = newExpr; 334 } 335 336 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) { 337 findKindExpression( untyped, indexer, "", standardAlternativeFilter ); 338 } 339 340 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) { 341 assert( untyped && type ); 342 // transfer location to generated cast for error purposes 343 CodeLocation location = untyped->location; 344 untyped = new CastExpr( untyped, type ); 345 untyped->location = location; 346 findSingleExpression( untyped, indexer ); 347 removeExtraneousCast( untyped, indexer ); 348 } 349 350 namespace { 351 bool isIntegralType( const Alternative & alt ) { 352 Type * type = alt.expr->result; 353 if ( dynamic_cast< EnumInstType * >( type ) ) { 354 return true; 355 } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) { 356 return bt->isInteger(); 357 } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) { 358 return true; 359 } else { 360 return false; 361 } // if 362 } 363 364 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) { 365 findKindExpression( untyped, indexer, "condition", isIntegralType ); 366 } 367 } 368 369 370 bool isStructOrUnion( const Alternative & alt ) { 371 Type * t = alt.expr->result->stripReferences(); 372 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ); 373 } 374 375 void resolveWithExprs( std::list< Declaration * > & translationUnit ) { 376 PassVisitor<ResolveWithExprs> resolver; 377 acceptAll( translationUnit, resolver ); 378 } 379 380 void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) { 381 for ( Expression *& expr : withExprs ) { 382 // only struct- and union-typed expressions are viable candidates 383 findKindExpression( expr, indexer, "with statement", isStructOrUnion ); 384 385 // if with expression might be impure, create a temporary so that it is evaluated once 386 if ( Tuples::maybeImpure( expr ) ) { 387 static UniqueName tmpNamer( "_with_tmp_" ); 388 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) ); 389 expr = new VariableExpr( tmp ); 390 newStmts.push_back( new DeclStmt( tmp ) ); 391 if ( InitTweak::isConstructable( tmp->type ) ) { 392 // generate ctor/dtor and resolve them 393 tmp->init = InitTweak::genCtorInit( tmp ); 394 tmp->accept( *visitor ); 395 } 396 } 397 } 398 } 399 400 void ResolveWithExprs::previsit( WithStmt * withStmt ) { 401 resolveWithExprs( withStmt->exprs, stmtsToAddBefore ); 402 } 403 404 void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) { 405 { 406 // resolve with-exprs with parameters in scope and add any newly generated declarations to the 407 // front of the function body. 408 auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this](){ indexer.leaveScope(); } ); 409 indexer.addFunctionType( functionDecl->type ); 410 std::list< Statement * > newStmts; 411 resolveWithExprs( functionDecl->withExprs, newStmts ); 412 if ( functionDecl->statements ) { 413 functionDecl->statements->kids.splice( functionDecl->statements->kids.begin(), newStmts ); 414 } else { 415 assertf( functionDecl->withExprs.empty() && newStmts.empty(), "Function %s without a body has with-clause and/or generated with declarations.", functionDecl->name.c_str() ); 416 } 417 } 418 } 419 420 void Resolver_old::previsit( ObjectDecl * objectDecl ) { 421 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that 422 // class-variable initContext is changed multiple time because the LHS is analysed twice. 423 // The second analysis changes initContext because of a function type can contain object 424 // declarations in the return and parameter types. So each value of initContext is 425 // retained, so the type on the first analysis is preserved and used for selecting the RHS. 426 GuardValue( currentObject ); 427 currentObject = CurrentObject( objectDecl->get_type() ); 428 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) { 429 // enumerator initializers should not use the enum type to initialize, since 430 // the enum type is still incomplete at this point. Use signed int instead. 431 // TODO: BasicType::SignedInt may not longer be true 432 currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ); 433 } 434 } 435 436 template< typename PtrType > 437 void Resolver_old::handlePtrType( PtrType * type ) { 438 if ( type->get_dimension() ) { 439 findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer ); 440 } 441 } 442 443 void Resolver_old::previsit( ArrayType * at ) { 444 handlePtrType( at ); 445 } 446 447 void Resolver_old::previsit( PointerType * pt ) { 448 handlePtrType( pt ); 449 } 450 451 void Resolver_old::previsit( FunctionDecl * functionDecl ) { 452 #if 0 453 std::cerr << "resolver visiting functiondecl "; 454 functionDecl->print( std::cerr ); 455 std::cerr << std::endl; 456 #endif 457 GuardValue( functionReturn ); 458 functionReturn = ResolvExpr::extractResultType( functionDecl->type ); 459 } 460 461 void Resolver_old::postvisit( FunctionDecl * functionDecl ) { 462 // default value expressions have an environment which shouldn't be there and trips up 463 // later passes. 464 // xxx - it might be necessary to somehow keep the information from this environment, but I 465 // can't currently see how it's useful. 466 for ( Declaration * d : functionDecl->type->parameters ) { 467 if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) { 468 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->init ) ) { 469 delete init->value->env; 470 init->value->env = nullptr; 471 } 472 } 473 } 474 } 475 476 void Resolver_old::previsit( EnumDecl * ) { 477 // in case we decide to allow nested enums 478 GuardValue( inEnumDecl ); 479 inEnumDecl = true; 480 } 481 482 void Resolver_old::previsit( StaticAssertDecl * assertDecl ) { 483 findIntegralExpression( assertDecl->condition, indexer ); 484 } 485 486 void Resolver_old::previsit( ExprStmt * exprStmt ) { 487 visit_children = false; 488 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" ); 489 findVoidExpression( exprStmt->expr, indexer ); 490 } 491 492 void Resolver_old::previsit( AsmExpr * asmExpr ) { 493 visit_children = false; 494 findVoidExpression( asmExpr->operand, indexer ); 495 } 496 497 void Resolver_old::previsit( AsmStmt * asmStmt ) { 498 visit_children = false; 499 acceptAll( asmStmt->get_input(), *visitor ); 500 acceptAll( asmStmt->get_output(), *visitor ); 501 } 502 503 void Resolver_old::previsit( IfStmt * ifStmt ) { 504 findIntegralExpression( ifStmt->condition, indexer ); 505 } 506 507 void Resolver_old::previsit( WhileDoStmt * whileDoStmt ) { 508 findIntegralExpression( whileDoStmt->condition, indexer ); 509 } 510 511 void Resolver_old::previsit( ForStmt * forStmt ) { 512 if ( forStmt->condition ) { 513 findIntegralExpression( forStmt->condition, indexer ); 514 } // if 515 516 if ( forStmt->increment ) { 517 findVoidExpression( forStmt->increment, indexer ); 518 } // if 519 } 520 521 void Resolver_old::previsit( SwitchStmt * switchStmt ) { 522 GuardValue( currentObject ); 523 findIntegralExpression( switchStmt->condition, indexer ); 524 525 currentObject = CurrentObject( switchStmt->condition->result ); 526 } 527 528 void Resolver_old::previsit( CaseStmt * caseStmt ) { 529 if ( caseStmt->condition ) { 530 std::list< InitAlternative > initAlts = currentObject.getOptions(); 531 assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." ); 532 // must remove cast from case statement because RangeExpr cannot be cast. 533 Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() ); 534 findSingleExpression( newExpr, indexer ); 535 // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion. 536 // Ideally we would perform the conversion internally here. 537 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) { 538 newExpr = castExpr->arg; 539 castExpr->arg = nullptr; 540 std::swap( newExpr->env, castExpr->env ); 541 delete castExpr; 542 } 543 caseStmt->condition = newExpr; 544 } 545 } 546 547 void Resolver_old::previsit( BranchStmt * branchStmt ) { 548 visit_children = false; 549 // must resolve the argument for a computed goto 550 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement 551 if ( branchStmt->computedTarget ) { 552 // computed goto argument is void * 553 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer ); 554 } // if 555 } // if 556 } 557 558 void Resolver_old::previsit( ReturnStmt * returnStmt ) { 559 visit_children = false; 560 if ( returnStmt->expr ) { 561 findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer ); 562 } // if 563 } 564 565 void Resolver_old::previsit( ThrowStmt * throwStmt ) { 566 visit_children = false; 567 // TODO: Replace *exception type with &exception type. 568 if ( throwStmt->get_expr() ) { 569 const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" ); 570 assert( exception_decl ); 571 Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) ); 572 findSingleExpression( throwStmt->expr, exceptType, indexer ); 573 } 574 } 575 576 void Resolver_old::previsit( CatchStmt * catchStmt ) { 577 // Until we are very sure this invarent (ifs that move between passes have then) 578 // holds, check it. This allows a check for when to decode the mangling. 579 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) { 580 assert( ifStmt->then ); 581 } 582 // Encode the catchStmt so the condition can see the declaration. 583 if ( catchStmt->cond ) { 584 IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body ); 585 catchStmt->cond = nullptr; 586 catchStmt->body = ifStmt; 587 } 588 } 589 590 void Resolver_old::postvisit( CatchStmt * catchStmt ) { 591 // Decode the catchStmt so everything is stored properly. 592 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ); 593 if ( nullptr != ifStmt && nullptr == ifStmt->then ) { 594 assert( ifStmt->condition ); 595 assert( ifStmt->else_ ); 596 catchStmt->cond = ifStmt->condition; 597 catchStmt->body = ifStmt->else_; 598 ifStmt->condition = nullptr; 599 ifStmt->else_ = nullptr; 600 delete ifStmt; 601 } 602 } 603 53 604 template< typename iterator_t > 54 605 inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) { … … 59 610 return it != end; 60 611 } 612 613 void Resolver_old::previsit( WaitForStmt * stmt ) { 614 visit_children = false; 615 616 // Resolve all clauses first 617 for( auto& clause : stmt->clauses ) { 618 619 TypeEnvironment env; 620 AlternativeFinder funcFinder( indexer, env ); 621 622 // Find all alternatives for a function in canonical form 623 funcFinder.findWithAdjustment( clause.target.function ); 624 625 if ( funcFinder.get_alternatives().empty() ) { 626 stringstream ss; 627 ss << "Use of undeclared indentifier '"; 628 ss << strict_dynamic_cast<NameExpr*>( clause.target.function )->name; 629 ss << "' in call to waitfor"; 630 SemanticError( stmt->location, ss.str() ); 631 } 632 633 if(clause.target.arguments.empty()) { 634 SemanticError( stmt->location, "Waitfor clause must have at least one mutex parameter"); 635 } 636 637 // Find all alternatives for all arguments in canonical form 638 std::vector< AlternativeFinder > argAlternatives; 639 funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) ); 640 641 // List all combinations of arguments 642 std::vector< AltList > possibilities; 643 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) ); 644 645 AltList func_candidates; 646 std::vector< AltList > args_candidates; 647 648 // For every possible function : 649 // try matching the arguments to the parameters 650 // not the other way around because we have more arguments than parameters 651 SemanticErrorException errors; 652 for ( Alternative & func : funcFinder.get_alternatives() ) { 653 try { 654 PointerType * pointer = dynamic_cast< PointerType* >( func.expr->get_result()->stripReferences() ); 655 if( !pointer ) { 656 SemanticError( func.expr->get_result(), "candidate not viable: not a pointer type\n" ); 657 } 658 659 FunctionType * function = dynamic_cast< FunctionType* >( pointer->get_base() ); 660 if( !function ) { 661 SemanticError( pointer->get_base(), "candidate not viable: not a function type\n" ); 662 } 663 664 665 { 666 auto param = function->parameters.begin(); 667 auto param_end = function->parameters.end(); 668 669 if( !advance_to_mutex( param, param_end ) ) { 670 SemanticError(function, "candidate function not viable: no mutex parameters\n"); 671 } 672 } 673 674 Alternative newFunc( func ); 675 // Strip reference from function 676 referenceToRvalueConversion( newFunc.expr, newFunc.cost ); 677 678 // For all the set of arguments we have try to match it with the parameter of the current function alternative 679 for ( auto & argsList : possibilities ) { 680 681 try { 682 // Declare data structures need for resolution 683 OpenVarSet openVars; 684 AssertionSet resultNeed, resultHave; 685 TypeEnvironment resultEnv( func.env ); 686 makeUnifiableVars( function, openVars, resultNeed ); 687 // add all type variables as open variables now so that those not used in the parameter 688 // list are still considered open. 689 resultEnv.add( function->forall ); 690 691 // Load type variables from arguemnts into one shared space 692 simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv ); 693 694 // Make sure we don't widen any existing bindings 695 resultEnv.forbidWidening(); 696 697 // Find any unbound type variables 698 resultEnv.extractOpenVars( openVars ); 699 700 auto param = function->parameters.begin(); 701 auto param_end = function->parameters.end(); 702 703 int n_mutex_param = 0; 704 705 // For every arguments of its set, check if it matches one of the parameter 706 // The order is important 707 for( auto & arg : argsList ) { 708 709 // Ignore non-mutex arguments 710 if( !advance_to_mutex( param, param_end ) ) { 711 // We ran out of parameters but still have arguments 712 // this function doesn't match 713 SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" )); 714 } 715 716 n_mutex_param++; 717 718 // Check if the argument matches the parameter type in the current scope 719 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) { 720 // Type doesn't match 721 stringstream ss; 722 ss << "candidate function not viable: no known convertion from '"; 723 (*param)->get_type()->print( ss ); 724 ss << "' to '"; 725 arg.expr->get_result()->print( ss ); 726 ss << "' with env '"; 727 resultEnv.print(ss); 728 ss << "'\n"; 729 SemanticError( function, ss.str() ); 730 } 731 732 param++; 733 } 734 735 // All arguments match ! 736 737 // Check if parameters are missing 738 if( advance_to_mutex( param, param_end ) ) { 739 do { 740 n_mutex_param++; 741 param++; 742 } while( advance_to_mutex( param, param_end ) ); 743 744 // We ran out of arguments but still have parameters left 745 // this function doesn't match 746 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" )); 747 } 748 749 // All parameters match ! 750 751 // Finish the expressions to tie in the proper environments 752 finishExpr( newFunc.expr, resultEnv ); 753 for( Alternative & alt : argsList ) { 754 finishExpr( alt.expr, resultEnv ); 755 } 756 757 // This is a match store it and save it for later 758 func_candidates.push_back( newFunc ); 759 args_candidates.push_back( argsList ); 760 761 } 762 catch( SemanticErrorException & e ) { 763 errors.append( e ); 764 } 765 } 766 } 767 catch( SemanticErrorException & e ) { 768 errors.append( e ); 769 } 770 } 771 772 // Make sure we got the right number of arguments 773 if( func_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for function in call to waitfor" ); top.append( errors ); throw top; } 774 if( args_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for arguments in call to waitfor" ); top.append( errors ); throw top; } 775 if( func_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous function in call to waitfor" ); top.append( errors ); throw top; } 776 if( args_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous arguments in call to waitfor" ); top.append( errors ); throw top; } 777 // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used. 778 779 // Swap the results from the alternative with the unresolved values. 780 // Alternatives will handle deletion on destruction 781 std::swap( clause.target.function, func_candidates.front().expr ); 782 for( auto arg_pair : group_iterate( clause.target.arguments, args_candidates.front() ) ) { 783 std::swap ( std::get<0>( arg_pair), std::get<1>( arg_pair).expr ); 784 } 785 786 // Resolve the conditions as if it were an IfStmt 787 // Resolve the statments normally 788 findSingleExpression( clause.condition, this->indexer ); 789 clause.statement->accept( *visitor ); 790 } 791 792 793 if( stmt->timeout.statement ) { 794 // Resolve the timeout as an size_t for now 795 // Resolve the conditions as if it were an IfStmt 796 // Resolve the statments normally 797 findSingleExpression( stmt->timeout.time, new BasicType( noQualifiers, BasicType::LongLongUnsignedInt ), this->indexer ); 798 findSingleExpression( stmt->timeout.condition, this->indexer ); 799 stmt->timeout.statement->accept( *visitor ); 800 } 801 802 if( stmt->orelse.statement ) { 803 // Resolve the conditions as if it were an IfStmt 804 // Resolve the statments normally 805 findSingleExpression( stmt->orelse.condition, this->indexer ); 806 stmt->orelse.statement->accept( *visitor ); 807 } 808 } 809 810 bool isCharType( Type * t ) { 811 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) { 812 return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar || 813 bt->get_kind() == BasicType::UnsignedChar; 814 } 815 return false; 816 } 817 818 void Resolver_old::previsit( SingleInit * singleInit ) { 819 visit_children = false; 820 // resolve initialization using the possibilities as determined by the currentObject cursor 821 Expression * newExpr = new UntypedInitExpr( singleInit->value, currentObject.getOptions() ); 822 findSingleExpression( newExpr, indexer ); 823 InitExpr * initExpr = strict_dynamic_cast< InitExpr * >( newExpr ); 824 825 // move cursor to the object that is actually initialized 826 currentObject.setNext( initExpr->get_designation() ); 827 828 // discard InitExpr wrapper and retain relevant pieces 829 newExpr = initExpr->expr; 830 initExpr->expr = nullptr; 831 std::swap( initExpr->env, newExpr->env ); 832 // InitExpr may have inferParams in the case where the expression specializes a function 833 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not 834 // sufficient. 835 newExpr->spliceInferParams( initExpr ); 836 delete initExpr; 837 838 // get the actual object's type (may not exactly match what comes back from the resolver 839 // due to conversions) 840 Type * initContext = currentObject.getCurrentType(); 841 842 removeExtraneousCast( newExpr, indexer ); 843 844 // check if actual object's type is char[] 845 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) { 846 if ( isCharType( at->get_base() ) ) { 847 // check if the resolved type is char * 848 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) { 849 if ( isCharType( pt->get_base() ) ) { 850 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) { 851 // strip cast if we're initializing a char[] with a char *, 852 // e.g. char x[] = "hello"; 853 newExpr = ce->get_arg(); 854 ce->set_arg( nullptr ); 855 std::swap( ce->env, newExpr->env ); 856 delete ce; 857 } 858 } 859 } 860 } 861 } 862 863 // set initializer expr to resolved express 864 singleInit->value = newExpr; 865 866 // move cursor to next object in preparation for next initializer 867 currentObject.increment(); 868 } 869 870 void Resolver_old::previsit( ListInit * listInit ) { 871 visit_children = false; 872 // move cursor into brace-enclosed initializer-list 873 currentObject.enterListInit(); 874 // xxx - fix this so that the list isn't copied, iterator should be used to change current 875 // element 876 std::list<Designation *> newDesignations; 877 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) { 878 // iterate designations and initializers in pairs, moving the cursor to the current 879 // designated object and resolving the initializer against that object. 880 Designation * des = std::get<0>(p); 881 Initializer * init = std::get<1>(p); 882 newDesignations.push_back( currentObject.findNext( des ) ); 883 init->accept( *visitor ); 884 } 885 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list 886 listInit->get_designations() = newDesignations; // xxx - memory management 887 currentObject.exitListInit(); 888 889 // xxx - this part has not be folded into CurrentObject yet 890 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) { 891 // Type * base = tt->get_baseType()->get_base(); 892 // if ( base ) { 893 // // know the implementation type, so try using that as the initContext 894 // ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr ); 895 // currentObject = &tmpObj; 896 // visit( listInit ); 897 // } else { 898 // // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context 899 // Parent::visit( listInit ); 900 // } 901 // } else { 902 } 903 904 // ConstructorInit - fall back on C-style initializer 905 void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) { 906 // could not find valid constructor, or found an intrinsic constructor 907 // fall back on C-style initializer 908 delete ctorInit->get_ctor(); 909 ctorInit->set_ctor( nullptr ); 910 delete ctorInit->get_dtor(); 911 ctorInit->set_dtor( nullptr ); 912 maybeAccept( ctorInit->get_init(), *visitor ); 913 } 914 915 // needs to be callable from outside the resolver, so this is a standalone function 916 void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) { 917 assert( ctorInit ); 918 PassVisitor<Resolver_old> resolver( indexer ); 919 ctorInit->accept( resolver ); 920 } 921 922 void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) { 923 assert( stmtExpr ); 924 PassVisitor<Resolver_old> resolver( indexer ); 925 stmtExpr->accept( resolver ); 926 stmtExpr->computeResult(); 927 // xxx - aggregate the environments from all statements? Possibly in AlternativeFinder instead? 928 } 929 930 void Resolver_old::previsit( ConstructorInit * ctorInit ) { 931 visit_children = false; 932 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit 933 maybeAccept( ctorInit->ctor, *visitor ); 934 maybeAccept( ctorInit->dtor, *visitor ); 935 936 // found a constructor - can get rid of C-style initializer 937 delete ctorInit->init; 938 ctorInit->init = nullptr; 939 940 // intrinsic single parameter constructors and destructors do nothing. Since this was 941 // implicitly generated, there's no way for it to have side effects, so get rid of it 942 // to clean up generated code. 943 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) { 944 delete ctorInit->ctor; 945 ctorInit->ctor = nullptr; 946 } 947 948 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) { 949 delete ctorInit->dtor; 950 ctorInit->dtor = nullptr; 951 } 952 953 // xxx - todo -- what about arrays? 954 // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) { 955 // // can reduce the constructor down to a SingleInit using the 956 // // second argument from the ctor call, since 957 // delete ctorInit->get_ctor(); 958 // ctorInit->set_ctor( nullptr ); 959 960 // Expression * arg = 961 // ctorInit->set_init( new SingleInit( arg ) ); 962 // } 963 } 964 965 /////////////////////////////////////////////////////////////////////////// 966 // 967 // *** NEW RESOLVER *** 968 // 969 /////////////////////////////////////////////////////////////////////////// 61 970 62 971 namespace { -
src/ResolvExpr/SatisfyAssertions.cpp
rfc12f05 r0030b508 46 46 #include "SymTab/Mangler.h" 47 47 48 49 48 50 namespace ResolvExpr { 49 51 50 52 // in CandidateFinder.cpp; unique ID for assertion satisfaction 51 extern ast::UniqueId globalResnSlot;53 extern UniqueId globalResnSlot; 52 54 53 55 namespace { … … 296 298 if ( !expr->inferred.hasSlots() ) return expr; 297 299 // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr; 298 std::vector< ast::UniqueId> missingSlots;300 std::vector<UniqueId> missingSlots; 299 301 // find inferred parameters for resolution slots 300 302 ast::InferredParams * newInferred = new ast::InferredParams(); 301 for ( ast::UniqueId slot : expr->inferred.resnSlots() ) {303 for ( UniqueId slot : expr->inferred.resnSlots() ) { 302 304 // fail if no matching assertions found 303 305 auto it = inferred.find( slot ); -
src/ResolvExpr/SpecCost.cc
rfc12f05 r0030b508 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h" 24 #include "SynTree/Declaration.h" 25 #include "SynTree/Expression.h" 26 #include "SynTree/Type.h" 23 27 24 28 namespace ResolvExpr { 29 30 /// Counts specializations in a type 31 class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> { 32 int count = -1; ///< specialization count (-1 for none) 33 34 public: 35 int get_count() const { return count >= 0 ? count : 0; } 36 37 // mark specialization of base type 38 void postvisit(PointerType*) { if ( count >= 0 ) ++count; } 39 40 // mark specialization of base type 41 void postvisit(ArrayType*) { if ( count >= 0 ) ++count; } 42 43 // mark specialization of base type 44 void postvisit(ReferenceType*) { if ( count >= 0 ) ++count; } 45 46 void postvisit(StructInstType*) { if ( count >= 0 ) ++count; } 47 void postvisit(UnionInstType*) { if ( count >= 0 ) ++count; } 48 49 private: 50 // takes minimum non-negative count over parameter/return list 51 void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) { 52 for ( DeclarationWithType* dwt : dwts ) { 53 count = -1; 54 maybeAccept( dwt->get_type(), *visitor ); 55 if ( count != -1 && count < mincount ) mincount = count; 56 } 57 } 58 59 public: 60 // take minimal specialization value over ->returnVals and ->parameters 61 void previsit(FunctionType* fty) { 62 int mincount = std::numeric_limits<int>::max(); 63 takeminover( mincount, fty->parameters ); 64 takeminover( mincount, fty->returnVals ); 65 // add another level to mincount if set 66 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1; 67 // already visited children 68 visit_children = false; 69 } 70 71 private: 72 // returns minimum non-negative count + 1 over type parameters (-1 if none such) 73 int minover( std::list<Expression*>& parms ) { 74 int mincount = std::numeric_limits<int>::max(); 75 for ( Expression* parm : parms ) { 76 count = -1; 77 maybeAccept( parm->result, *visitor ); 78 if ( count != -1 && count < mincount ) mincount = count; 79 } 80 return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1; 81 } 82 83 public: 84 // look for polymorphic parameters 85 void previsit(StructInstType* sty) { 86 count = minover( sty->parameters ); 87 } 88 89 // look for polymorphic parameters 90 void previsit(UnionInstType* uty) { 91 count = minover( uty->parameters ); 92 } 93 94 // note polymorphic type (which may be specialized) 95 // xxx - maybe account for open/closed type variables 96 void postvisit(TypeInstType*) { count = 0; } 97 98 // take minimal specialization over elements 99 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize 100 void previsit(TupleType* tty) { 101 int mincount = std::numeric_limits<int>::max(); 102 for ( Type* ty : tty->types ) { 103 count = -1; 104 maybeAccept( ty, *visitor ); 105 if ( count != -1 && count < mincount ) mincount = count; 106 } 107 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1; 108 visit_children = false; 109 } 110 }; 111 112 /// Returns the (negated) specialization cost for a given type 113 int specCost( Type* ty ) { 114 PassVisitor<CountSpecs> counter; 115 maybeAccept( ty, *counter.pass.visitor ); 116 return counter.pass.get_count(); 117 } 25 118 26 119 namespace { -
src/ResolvExpr/Unify.cc
rfc12f05 r0030b508 33 33 #include "AST/TypeEnvironment.hpp" 34 34 #include "Common/Eval.h" // for eval 35 #include "Common/PassVisitor.h" // for PassVisitor 35 36 #include "CommonType.hpp" // for commonType 36 37 #include "FindOpenVars.h" // for findOpenVars 37 38 #include "SpecCost.hpp" // for SpecCost 39 #include "SynTree/LinkageSpec.h" // for C 40 #include "SynTree/Constant.h" // for Constant 41 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data, Declarati... 42 #include "SynTree/Expression.h" // for TypeExpr, Expression, ConstantExpr 43 #include "SynTree/Mutator.h" // for Mutator 44 #include "SynTree/Type.h" // for Type, TypeInstType, FunctionType 45 #include "SynTree/Visitor.h" // for Visitor 38 46 #include "Tuples/Tuples.h" // for isTtype 47 #include "TypeEnvironment.h" // for EqvClass, AssertionSet, OpenVarSet 39 48 #include "typeops.h" // for flatten, occurs 40 49 … … 43 52 } 44 53 54 namespace SymTab { 55 class Indexer; 56 } // namespace SymTab 57 45 58 // #define DEBUG 46 59 47 60 namespace ResolvExpr { 61 62 // Template Helpers: 63 template< typename Iterator1, typename Iterator2 > 64 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) { 65 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) { 66 Type *commonType = 0; 67 if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) { 68 return false; 69 } // if 70 commonTypes.push_back( commonType ); 71 } // for 72 return ( list1Begin == list1End && list2Begin == list2End ); 73 } 74 75 template< typename Iterator1, typename Iterator2 > 76 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 77 std::list< Type* > commonTypes; 78 if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions, openVars, indexer, commonTypes ) ) { 79 deleteAll( commonTypes ); 80 return true; 81 } else { 82 return false; 83 } // if 84 } 85 86 struct Unify_old : public WithShortCircuiting { 87 Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ); 88 89 bool get_result() const { return result; } 90 91 void previsit( BaseSyntaxNode * ) { visit_children = false; } 92 93 void postvisit( VoidType * voidType ); 94 void postvisit( BasicType * basicType ); 95 void postvisit( PointerType * pointerType ); 96 void postvisit( ArrayType * arrayType ); 97 void postvisit( ReferenceType * refType ); 98 void postvisit( FunctionType * functionType ); 99 void postvisit( StructInstType * aggregateUseType ); 100 void postvisit( UnionInstType * aggregateUseType ); 101 void postvisit( EnumInstType * aggregateUseType ); 102 void postvisit( TraitInstType * aggregateUseType ); 103 void postvisit( TypeInstType * aggregateUseType ); 104 void postvisit( TupleType * tupleType ); 105 void postvisit( VarArgsType * varArgsType ); 106 void postvisit( ZeroType * zeroType ); 107 void postvisit( OneType * oneType ); 108 109 private: 110 template< typename RefType > void handleRefType( RefType *inst, Type *other ); 111 template< typename RefType > void handleGenericRefType( RefType *inst, Type *other ); 112 113 bool result; 114 Type *type2; // inherited 115 TypeEnvironment &env; 116 AssertionSet &needAssertions; 117 AssertionSet &haveAssertions; 118 const OpenVarSet &openVars; 119 WidenMode widen; 120 const SymTab::Indexer &indexer; 121 }; 122 123 /// Attempts an inexact unification of type1 and type2. 124 /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers) 125 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ); 126 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ); 127 128 bool unifyExact( 129 const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env, 130 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open, 131 WidenMode widen ); 132 133 bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) { 134 TypeEnvironment newEnv; 135 OpenVarSet openVars, closedVars; // added closedVars 136 AssertionSet needAssertions, haveAssertions; 137 Type * newFirst = first->clone(), * newSecond = second->clone(); 138 env.apply( newFirst ); 139 env.apply( newSecond ); 140 141 // do we need to do this? Seems like we do, types should be able to be compatible if they 142 // have free variables that can unify 143 findOpenVars( newFirst, openVars, closedVars, needAssertions, haveAssertions, false ); 144 findOpenVars( newSecond, openVars, closedVars, needAssertions, haveAssertions, true ); 145 146 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 147 delete newFirst; 148 delete newSecond; 149 return result; 150 } 48 151 49 152 bool typesCompatible( … … 62 165 63 166 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() ); 167 } 168 169 bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 170 TypeEnvironment newEnv; 171 OpenVarSet openVars; 172 AssertionSet needAssertions, haveAssertions; 173 Type *newFirst = first->clone(), *newSecond = second->clone(); 174 env.apply( newFirst ); 175 env.apply( newSecond ); 176 newFirst->get_qualifiers() = Type::Qualifiers(); 177 newSecond->get_qualifiers() = Type::Qualifiers(); 178 179 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 180 delete newFirst; 181 delete newSecond; 182 return result; 64 183 } 65 184 … … 99 218 subSecond, 100 219 newEnv, need, have, open, noWiden() ); 220 } 221 222 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 223 OpenVarSet closedVars; 224 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false ); 225 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true ); 226 Type *commonType = 0; 227 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) { 228 if ( commonType ) { 229 delete commonType; 230 } // if 231 return true; 232 } else { 233 return false; 234 } // if 235 } 236 237 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ) { 238 OpenVarSet closedVars; 239 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false ); 240 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true ); 241 return unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ); 242 } 243 244 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) { 245 #ifdef DEBUG 246 TypeEnvironment debugEnv( env ); 247 #endif 248 if ( type1->get_qualifiers() != type2->get_qualifiers() ) { 249 return false; 250 } 251 252 bool result; 253 TypeInstType *var1 = dynamic_cast< TypeInstType* >( type1 ); 254 TypeInstType *var2 = dynamic_cast< TypeInstType* >( type2 ); 255 OpenVarSet::const_iterator entry1, entry2; 256 if ( var1 ) { 257 entry1 = openVars.find( var1->get_name() ); 258 } // if 259 if ( var2 ) { 260 entry2 = openVars.find( var2->get_name() ); 261 } // if 262 bool isopen1 = var1 && ( entry1 != openVars.end() ); 263 bool isopen2 = var2 && ( entry2 != openVars.end() ); 264 265 if ( isopen1 && isopen2 ) { 266 if ( entry1->second.kind != entry2->second.kind ) { 267 result = false; 268 } else { 269 result = env.bindVarToVar( 270 var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions, 271 haveAssertions, openVars, widen, indexer ); 272 } 273 } else if ( isopen1 ) { 274 result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer ); 275 } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped? 276 result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer ); 277 } else { 278 PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer ); 279 type1->accept( comparator ); 280 result = comparator.pass.get_result(); 281 } // if 282 #ifdef DEBUG 283 std::cerr << "============ unifyExact" << std::endl; 284 std::cerr << "type1 is "; 285 type1->print( std::cerr ); 286 std::cerr << std::endl << "type2 is "; 287 type2->print( std::cerr ); 288 std::cerr << std::endl << "openVars are "; 289 printOpenVarSet( openVars, std::cerr, 8 ); 290 std::cerr << std::endl << "input env is " << std::endl; 291 debugEnv.print( std::cerr, 8 ); 292 std::cerr << std::endl << "result env is " << std::endl; 293 env.print( std::cerr, 8 ); 294 std::cerr << "result is " << result << std::endl; 295 #endif 296 return result; 297 } 298 299 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 300 return unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 301 } 302 303 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) { 304 Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers(); 305 type1->get_qualifiers() = Type::Qualifiers(); 306 type2->get_qualifiers() = Type::Qualifiers(); 307 bool result; 308 #ifdef DEBUG 309 std::cerr << "unifyInexact type 1 is "; 310 type1->print( std::cerr ); 311 std::cerr << " type 2 is "; 312 type2->print( std::cerr ); 313 std::cerr << std::endl; 314 #endif 315 if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) { 316 #ifdef DEBUG 317 std::cerr << "unifyInexact: no exact unification found" << std::endl; 318 #endif 319 if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) { 320 common->tq = tq1.unify( tq2 ); 321 #ifdef DEBUG 322 std::cerr << "unifyInexact: common type is "; 323 common->print( std::cerr ); 324 std::cerr << std::endl; 325 #endif 326 result = true; 327 } else { 328 #ifdef DEBUG 329 std::cerr << "unifyInexact: no common type found" << std::endl; 330 #endif 331 result = false; 332 } // if 333 } else { 334 if ( tq1 != tq2 ) { 335 if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) { 336 common = type1->clone(); 337 common->tq = tq1.unify( tq2 ); 338 result = true; 339 } else { 340 result = false; 341 } // if 342 } else { 343 common = type1->clone(); 344 common->tq = tq1.unify( tq2 ); 345 result = true; 346 } // if 347 } // if 348 type1->get_qualifiers() = tq1; 349 type2->get_qualifiers() = tq2; 350 return result; 351 } 352 353 Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) 354 : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) { 355 } 356 357 void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) { 358 result = dynamic_cast< VoidType* >( type2 ); 359 } 360 361 void Unify_old::postvisit(BasicType *basicType) { 362 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) { 363 result = basicType->get_kind() == otherBasic->get_kind(); 364 } // if 365 } 366 367 void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) { 368 AssertionSet::iterator i = assertions.find( assert ); 369 if ( i != assertions.end() ) { 370 i->second.isUsed = true; 371 } // if 372 } 373 374 void markAssertions( AssertionSet &assertion1, AssertionSet &assertion2, Type *type ) { 375 for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) { 376 for ( std::list< DeclarationWithType* >::const_iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) { 377 markAssertionSet( assertion1, *assert ); 378 markAssertionSet( assertion2, *assert ); 379 } // for 380 } // for 381 } 382 383 void Unify_old::postvisit(PointerType *pointerType) { 384 if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) { 385 result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 386 markAssertions( haveAssertions, needAssertions, pointerType ); 387 markAssertions( haveAssertions, needAssertions, otherPointer ); 388 } // if 389 } 390 391 void Unify_old::postvisit(ReferenceType *refType) { 392 if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) { 393 result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 394 markAssertions( haveAssertions, needAssertions, refType ); 395 markAssertions( haveAssertions, needAssertions, otherRef ); 396 } // if 397 } 398 399 void Unify_old::postvisit(ArrayType *arrayType) { 400 ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 ); 401 // to unify, array types must both be VLA or both not VLA 402 // and must both have a dimension expression or not have a dimension 403 if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) { 404 405 if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() && 406 arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) { 407 ConstantExpr * ce1 = dynamic_cast< ConstantExpr * >( arrayType->get_dimension() ); 408 ConstantExpr * ce2 = dynamic_cast< ConstantExpr * >( otherArray->get_dimension() ); 409 // see C11 Reference Manual 6.7.6.2.6 410 // two array types with size specifiers that are integer constant expressions are 411 // compatible if both size specifiers have the same constant value 412 if ( ce1 && ce2 ) { 413 Constant * c1 = ce1->get_constant(); 414 Constant * c2 = ce2->get_constant(); 415 416 if ( c1->get_value() != c2->get_value() ) { 417 // does not unify if the dimension is different 418 return; 419 } 420 } 421 } 422 423 result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 424 } // if 425 } 426 427 template< typename Iterator, typename Func > 428 std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) { 429 std::list< Type * > types; 430 for ( ; begin != end; ++begin ) { 431 // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple 432 flatten( toType( *begin ), back_inserter( types ) ); 433 } 434 return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) ); 435 } 436 437 template< typename Iterator1, typename Iterator2 > 438 bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 439 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); }; 440 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) { 441 Type * t1 = (*list1Begin)->get_type(); 442 Type * t2 = (*list2Begin)->get_type(); 443 bool isTtype1 = Tuples::isTtype( t1 ); 444 bool isTtype2 = Tuples::isTtype( t2 ); 445 // xxx - assumes ttype must be last parameter 446 // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases. 447 if ( isTtype1 && ! isTtype2 ) { 448 // combine all of the things in list2, then unify 449 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 450 } else if ( isTtype2 && ! isTtype1 ) { 451 // combine all of the things in list1, then unify 452 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 453 } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) { 454 return false; 455 } // if 456 } // for 457 // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype 458 if ( list1Begin != list1End ) { 459 // try unifying empty tuple type with ttype 460 Type * t1 = (*list1Begin)->get_type(); 461 if ( Tuples::isTtype( t1 ) ) { 462 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 463 } else return false; 464 } else if ( list2Begin != list2End ) { 465 // try unifying empty tuple type with ttype 466 Type * t2 = (*list2Begin)->get_type(); 467 if ( Tuples::isTtype( t2 ) ) { 468 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 469 } else return false; 470 } else { 471 return true; 472 } // if 473 } 474 475 /// Finds ttypes and replaces them with their expansion, if known. 476 /// This needs to be done so that satisfying ttype assertions is easier. 477 /// If this isn't done then argument lists can have wildly different 478 /// size and structure, when they should be compatible. 479 struct TtypeExpander_old : public WithShortCircuiting { 480 TypeEnvironment & tenv; 481 TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {} 482 void premutate( TypeInstType * ) { visit_children = false; } 483 Type * postmutate( TypeInstType * typeInst ) { 484 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) { 485 // expand ttype parameter into its actual type 486 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) { 487 delete typeInst; 488 return eqvClass->type->clone(); 489 } 490 } 491 return typeInst; 492 } 493 }; 494 495 /// flattens a list of declarations, so that each tuple type has a single declaration. 496 /// makes use of TtypeExpander to ensure ttypes are flat as well. 497 void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) { 498 dst.clear(); 499 for ( DeclarationWithType * dcl : src ) { 500 PassVisitor<TtypeExpander_old> expander( env ); 501 dcl->acceptMutator( expander ); 502 std::list< Type * > types; 503 flatten( dcl->get_type(), back_inserter( types ) ); 504 for ( Type * t : types ) { 505 // outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable. 506 // Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function. 507 t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic); 508 509 dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) ); 510 } 511 delete dcl; 512 } 513 } 514 515 void Unify_old::postvisit(FunctionType *functionType) { 516 FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 ); 517 if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) { 518 // flatten the parameter lists for both functions so that tuple structure 519 // doesn't affect unification. Must be a clone so that the types don't change. 520 std::unique_ptr<FunctionType> flatFunc( functionType->clone() ); 521 std::unique_ptr<FunctionType> flatOther( otherFunction->clone() ); 522 flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env ); 523 flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env ); 524 525 // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors 526 if ( 527 (flatFunc->parameters.size() == flatOther->parameters.size() && 528 flatFunc->returnVals.size() == flatOther->returnVals.size()) 529 || flatFunc->isTtype() 530 || flatOther->isTtype() 531 ) { 532 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 533 if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 534 535 // the original types must be used in mark assertions, since pointer comparisons are used 536 markAssertions( haveAssertions, needAssertions, functionType ); 537 markAssertions( haveAssertions, needAssertions, otherFunction ); 538 539 result = true; 540 } // if 541 } // if 542 } // if 543 } // if 544 } 545 546 template< typename RefType > 547 void Unify_old::handleRefType( RefType *inst, Type *other ) { 548 // check that other type is compatible and named the same 549 RefType *otherStruct = dynamic_cast< RefType* >( other ); 550 result = otherStruct && inst->name == otherStruct->name; 551 } 552 553 template< typename RefType > 554 void Unify_old::handleGenericRefType( RefType *inst, Type *other ) { 555 // Check that other type is compatible and named the same 556 handleRefType( inst, other ); 557 if ( ! result ) return; 558 // Check that parameters of types unify, if any 559 std::list< Expression* > params = inst->parameters; 560 std::list< Expression* > otherParams = ((RefType*)other)->parameters; 561 562 std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin(); 563 for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) { 564 TypeExpr *param = dynamic_cast< TypeExpr* >(*it); 565 assertf(param, "Aggregate parameters should be type expressions"); 566 TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt); 567 assertf(otherParam, "Aggregate parameters should be type expressions"); 568 569 Type* paramTy = param->get_type(); 570 Type* otherParamTy = otherParam->get_type(); 571 572 bool tupleParam = Tuples::isTtype( paramTy ); 573 bool otherTupleParam = Tuples::isTtype( otherParamTy ); 574 575 if ( tupleParam && otherTupleParam ) { 576 ++it; ++jt; // skip ttype parameters for break 577 } else if ( tupleParam ) { 578 // bundle other parameters into tuple to match 579 std::list< Type * > binderTypes; 580 581 do { 582 binderTypes.push_back( otherParam->get_type()->clone() ); 583 ++jt; 584 585 if ( jt == otherParams.end() ) break; 586 587 otherParam = dynamic_cast< TypeExpr* >(*jt); 588 assertf(otherParam, "Aggregate parameters should be type expressions"); 589 } while (true); 590 591 otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes }; 592 ++it; // skip ttype parameter for break 593 } else if ( otherTupleParam ) { 594 // bundle parameters into tuple to match other 595 std::list< Type * > binderTypes; 596 597 do { 598 binderTypes.push_back( param->get_type()->clone() ); 599 ++it; 600 601 if ( it == params.end() ) break; 602 603 param = dynamic_cast< TypeExpr* >(*it); 604 assertf(param, "Aggregate parameters should be type expressions"); 605 } while (true); 606 607 paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes }; 608 ++jt; // skip ttype parameter for break 609 } 610 611 if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) { 612 result = false; 613 return; 614 } 615 616 // ttype parameter should be last 617 if ( tupleParam || otherTupleParam ) break; 618 } 619 result = ( it == params.end() && jt == otherParams.end() ); 620 } 621 622 void Unify_old::postvisit(StructInstType *structInst) { 623 handleGenericRefType( structInst, type2 ); 624 } 625 626 void Unify_old::postvisit(UnionInstType *unionInst) { 627 handleGenericRefType( unionInst, type2 ); 628 } 629 630 void Unify_old::postvisit(EnumInstType *enumInst) { 631 handleRefType( enumInst, type2 ); 632 } 633 634 void Unify_old::postvisit(TraitInstType *contextInst) { 635 handleRefType( contextInst, type2 ); 636 } 637 638 void Unify_old::postvisit(TypeInstType *typeInst) { 639 assert( openVars.find( typeInst->get_name() ) == openVars.end() ); 640 TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 ); 641 if ( otherInst && typeInst->get_name() == otherInst->get_name() ) { 642 result = true; 643 /// } else { 644 /// NamedTypeDecl *nt = indexer.lookupType( typeInst->get_name() ); 645 /// if ( nt ) { 646 /// TypeDecl *type = dynamic_cast< TypeDecl* >( nt ); 647 /// assert( type ); 648 /// if ( type->get_base() ) { 649 /// result = unifyExact( type->get_base(), typeInst, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 650 /// } 651 /// } 652 } // if 653 } 654 655 template< typename Iterator1, typename Iterator2 > 656 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 657 auto get_type = [](Type * t) { return t; }; 658 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) { 659 Type * t1 = *list1Begin; 660 Type * t2 = *list2Begin; 661 bool isTtype1 = Tuples::isTtype( t1 ); 662 bool isTtype2 = Tuples::isTtype( t2 ); 663 // xxx - assumes ttype must be last parameter 664 // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases. 665 if ( isTtype1 && ! isTtype2 ) { 666 // combine all of the things in list2, then unify 667 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 668 } else if ( isTtype2 && ! isTtype1 ) { 669 // combine all of the things in list1, then unify 670 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 671 } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) { 672 return false; 673 } // if 674 675 } // for 676 if ( list1Begin != list1End ) { 677 // try unifying empty tuple type with ttype 678 Type * t1 = *list1Begin; 679 if ( Tuples::isTtype( t1 ) ) { 680 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 681 } else return false; 682 } else if ( list2Begin != list2End ) { 683 // try unifying empty tuple type with ttype 684 Type * t2 = *list2Begin; 685 if ( Tuples::isTtype( t2 ) ) { 686 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 687 } else return false; 688 } else { 689 return true; 690 } // if 691 } 692 693 void Unify_old::postvisit(TupleType *tupleType) { 694 if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) { 695 std::unique_ptr<TupleType> flat1( tupleType->clone() ); 696 std::unique_ptr<TupleType> flat2( otherTuple->clone() ); 697 std::list<Type *> types1, types2; 698 699 PassVisitor<TtypeExpander_old> expander( env ); 700 flat1->acceptMutator( expander ); 701 flat2->acceptMutator( expander ); 702 703 flatten( flat1.get(), back_inserter( types1 ) ); 704 flatten( flat2.get(), back_inserter( types2 ) ); 705 706 result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer ); 707 } // if 708 } 709 710 void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) { 711 result = dynamic_cast< VarArgsType* >( type2 ); 712 } 713 714 void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) { 715 result = dynamic_cast< ZeroType* >( type2 ); 716 } 717 718 void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) { 719 result = dynamic_cast< OneType* >( type2 ); 720 } 721 722 Type * extractResultType( FunctionType * function ) { 723 if ( function->get_returnVals().size() == 0 ) { 724 return new VoidType( Type::Qualifiers() ); 725 } else if ( function->get_returnVals().size() == 1 ) { 726 return function->get_returnVals().front()->get_type()->clone(); 727 } else { 728 std::list< Type * > types; 729 for ( DeclarationWithType * decl : function->get_returnVals() ) { 730 types.push_back( decl->get_type()->clone() ); 731 } // for 732 return new TupleType( Type::Qualifiers(), types ); 733 } 101 734 } 102 735 -
src/ResolvExpr/Unify.h
rfc12f05 r0030b508 20 20 #include "AST/Node.hpp" // for ptr 21 21 #include "AST/TypeEnvironment.hpp" // for TypeEnvironment, AssertionSet, OpenVarSet 22 #include "Common/utility.h" // for deleteAll 23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data 24 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet 22 25 #include "WidenMode.h" // for WidenMode 26 27 class Type; 28 class TypeInstType; 29 namespace SymTab { 30 class Indexer; 31 } 23 32 24 33 namespace ast { … … 28 37 29 38 namespace ResolvExpr { 39 40 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ); 41 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ); 42 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ); 43 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ); 44 45 bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env ); 46 bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env ); 47 48 inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) { 49 TypeEnvironment env; 50 return typesCompatible( t1, t2, indexer, env ); 51 } 52 53 inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) { 54 TypeEnvironment env; 55 return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env ); 56 } 30 57 31 58 bool unify( … … 58 85 const ast::TypeEnvironment & env = {} ); 59 86 87 /// Creates the type represented by the list of returnVals in a FunctionType. 88 /// The caller owns the return value. 89 Type * extractResultType( FunctionType * functionType ); 60 90 /// Creates or extracts the type represented by returns in a `FunctionType`. 61 91 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ); -
src/ResolvExpr/module.mk
rfc12f05 r0030b508 18 18 ResolvExpr/AdjustExprType.cc \ 19 19 ResolvExpr/AdjustExprType.hpp \ 20 ResolvExpr/Alternative.cc \ 21 ResolvExpr/AlternativeFinder.cc \ 22 ResolvExpr/AlternativeFinder.h \ 23 ResolvExpr/Alternative.h \ 20 24 ResolvExpr/Candidate.cpp \ 21 25 ResolvExpr/CandidateFinder.cpp \ … … 31 35 ResolvExpr/CurrentObject.cc \ 32 36 ResolvExpr/CurrentObject.h \ 37 ResolvExpr/ExplodedActual.cc \ 38 ResolvExpr/ExplodedActual.h \ 33 39 ResolvExpr/ExplodedArg.cpp \ 34 40 ResolvExpr/ExplodedArg.hpp \ 35 41 ResolvExpr/FindOpenVars.cc \ 36 42 ResolvExpr/FindOpenVars.h \ 43 ResolvExpr/Occurs.cc \ 37 44 ResolvExpr/PolyCost.cc \ 38 45 ResolvExpr/PolyCost.hpp \ … … 43 50 ResolvExpr/RenameVars.cc \ 44 51 ResolvExpr/RenameVars.h \ 52 ResolvExpr/ResolveAssertions.cc \ 53 ResolvExpr/ResolveAssertions.h \ 45 54 ResolvExpr/Resolver.cc \ 46 55 ResolvExpr/Resolver.h \ … … 52 61 ResolvExpr/SpecCost.cc \ 53 62 ResolvExpr/SpecCost.hpp \ 63 ResolvExpr/TypeEnvironment.cc \ 64 ResolvExpr/TypeEnvironment.h \ 54 65 ResolvExpr/typeops.h \ 55 66 ResolvExpr/Unify.cc \ … … 58 69 59 70 SRC += $(SRC_RESOLVEXPR) \ 71 ResolvExpr/AlternativePrinter.cc \ 72 ResolvExpr/AlternativePrinter.h \ 60 73 ResolvExpr/CandidatePrinter.cpp \ 61 74 ResolvExpr/CandidatePrinter.hpp \ -
src/ResolvExpr/typeops.h
rfc12f05 r0030b508 19 19 20 20 #include "AST/Type.hpp" 21 #include "SynTree/Type.h" 21 22 22 23 namespace SymTab { … … 51 52 std::copy( i.begin(), i.end(), inserter ); 52 53 *out++ = result; 54 } 55 } 56 57 // in Occurs.cc 58 bool occurs( const Type * type, const std::string & varName, const TypeEnvironment & env ); 59 // new AST version in TypeEnvironment.cpp (only place it was used in old AST) 60 61 template<typename Iter> 62 bool occursIn( Type* ty, Iter begin, Iter end, const TypeEnvironment & env ) { 63 while ( begin != end ) { 64 if ( occurs( ty, *begin, env ) ) return true; 65 ++begin; 66 } 67 return false; 68 } 69 70 /// flatten tuple type into list of types 71 template< typename OutputIterator > 72 void flatten( Type * type, OutputIterator out ) { 73 if ( TupleType * tupleType = dynamic_cast< TupleType * >( type ) ) { 74 for ( Type * t : tupleType->get_types() ) { 75 flatten( t, out ); 76 } 77 } else { 78 *out++ = type->clone(); 53 79 } 54 80 } … … 94 120 return tupleFromTypes( tys.begin(), tys.end() ); 95 121 } 122 123 // in TypeEnvironment.cc 124 bool isFtype( const Type * type ); 96 125 } // namespace ResolvExpr 97 126 -
src/SymTab/Demangle.cc
rfc12f05 r0030b508 9 9 // Author : Rob Schluntz 10 10 // Created On : Thu Jul 19 12:52:41 2018 11 // Last Modified By : Andrew Beach12 // Last Modified On : Mon Nov 6 15:59:00 202313 // Update Count : 1 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 11 21:28:27 2021 13 // Update Count : 11 14 14 // 15 15 … … 17 17 #include <sstream> 18 18 19 #include "AST/Pass.hpp"20 #include "AST/Type.hpp"21 19 #include "CodeGen/GenType.h" 22 #include "Co deGen/OperatorTable.h"20 #include "Common/PassVisitor.h" 23 21 #include "Common/utility.h" // isPrefix 24 22 #include "Mangler.h" 23 #include "SynTree/Type.h" 24 #include "SynTree/Declaration.h" 25 25 26 26 #define DEBUG … … 31 31 #endif 32 32 33 namespace Mangle {34 35 33 namespace { 36 37 struct Demangler { 38 private: 39 std::string str; 40 size_t index = 0; 41 using Parser = std::function<ast::Type * ( ast::CV::Qualifiers )>; 42 std::vector<std::pair<std::string, Parser>> parsers; 43 public: 44 Demangler( const std::string & str ); 45 46 bool done() const { return str.size() <= index; } 47 char cur() const { assert( !done() ); return str[index]; } 48 bool expect( char ch ) { return str[index++] == ch; } 49 50 bool isPrefix( const std::string & pref ); 51 bool extractNumber( size_t & out ); 52 bool extractName( std::string & out ); 53 bool stripMangleName( std::string & name ); 54 55 ast::Type * parseFunction( ast::CV::Qualifiers tq ); 56 ast::Type * parseTuple( ast::CV::Qualifiers tq ); 57 ast::Type * parsePointer( ast::CV::Qualifiers tq ); 58 ast::Type * parseArray( ast::CV::Qualifiers tq ); 59 ast::Type * parseStruct( ast::CV::Qualifiers tq ); 60 ast::Type * parseUnion( ast::CV::Qualifiers tq ); 61 ast::Type * parseEnum( ast::CV::Qualifiers tq ); 62 ast::Type * parseType( ast::CV::Qualifiers tq ); 63 ast::Type * parseZero( ast::CV::Qualifiers tq ); 64 ast::Type * parseOne( ast::CV::Qualifiers tq ); 65 66 ast::Type * parseType(); 67 bool parse( std::string & name, ast::Type *& type ); 68 }; 69 70 Demangler::Demangler(const std::string & str) : str(str) { 71 for (size_t k = 0; k < ast::BasicType::NUMBER_OF_BASIC_TYPES; ++k) { 72 parsers.emplace_back(Encoding::basicTypes[k], [k]( ast::CV::Qualifiers tq ) { 73 PRINT( std::cerr << "basic type: " << k << std::endl; ) 74 return new ast::BasicType( (ast::BasicType::Kind)k, tq ); 75 }); 76 } 77 78 for (size_t k = 0; k < ast::TypeDecl::NUMBER_OF_KINDS; ++k) { 79 static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", }; 80 static_assert( 81 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == ast::TypeDecl::NUMBER_OF_KINDS, 82 "Each type variable kind should have a demangle name prefix" 83 ); 84 parsers.emplace_back(Encoding::typeVariables[k], [k, this]( ast::CV::Qualifiers tq ) -> ast::TypeInstType * { 85 PRINT( std::cerr << "type variable type: " << k << std::endl; ) 86 size_t N; 87 if (!extractNumber(N)) return nullptr; 88 return new ast::TypeInstType( 89 toString(typeVariableNames[k], N), 90 (ast::TypeDecl::Kind)k, 91 tq ); 92 }); 93 } 94 95 parsers.emplace_back(Encoding::void_t, [this]( ast::CV::Qualifiers tq ) { return new ast::VoidType(tq); }); 96 parsers.emplace_back(Encoding::function, [this]( ast::CV::Qualifiers tq ) { return parseFunction(tq); }); 97 parsers.emplace_back(Encoding::pointer, [this]( ast::CV::Qualifiers tq ) { return parsePointer(tq); }); 98 parsers.emplace_back(Encoding::array, [this]( ast::CV::Qualifiers tq ) { return parseArray(tq); }); 99 parsers.emplace_back(Encoding::tuple, [this]( ast::CV::Qualifiers tq ) { return parseTuple(tq); }); 100 parsers.emplace_back(Encoding::struct_t, [this]( ast::CV::Qualifiers tq ) { return parseStruct(tq); }); 101 parsers.emplace_back(Encoding::union_t, [this]( ast::CV::Qualifiers tq ) { return parseUnion(tq); }); 102 parsers.emplace_back(Encoding::enum_t, [this]( ast::CV::Qualifiers tq ) { return parseEnum(tq); }); 103 parsers.emplace_back(Encoding::type, [this]( ast::CV::Qualifiers tq ) { return parseType(tq); }); 104 parsers.emplace_back(Encoding::zero, []( ast::CV::Qualifiers tq ) { return new ast::ZeroType(tq); }); 105 parsers.emplace_back(Encoding::one, []( ast::CV::Qualifiers tq ) { return new ast::OneType(tq); }); 34 struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting { 35 std::string typeString; 36 GenType( const std::string &typeString ); 37 38 void previsit( BaseSyntaxNode * ); 39 void postvisit( BaseSyntaxNode * ); 40 41 void postvisit( FunctionType * funcType ); 42 void postvisit( VoidType * voidType ); 43 void postvisit( BasicType * basicType ); 44 void postvisit( PointerType * pointerType ); 45 void postvisit( ArrayType * arrayType ); 46 void postvisit( ReferenceType * refType ); 47 void postvisit( StructInstType * structInst ); 48 void postvisit( UnionInstType * unionInst ); 49 void postvisit( EnumInstType * enumInst ); 50 void postvisit( TypeInstType * typeInst ); 51 void postvisit( TupleType * tupleType ); 52 void postvisit( VarArgsType * varArgsType ); 53 void postvisit( ZeroType * zeroType ); 54 void postvisit( OneType * oneType ); 55 void postvisit( GlobalScopeType * globalType ); 56 void postvisit( QualifiedType * qualType ); 57 58 private: 59 void handleQualifiers( Type *type ); 60 std::string handleGeneric( ReferenceToType * refType ); 61 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic ); 62 }; 63 64 std::string genDemangleType( Type * type, const std::string & baseString ) { 65 PassVisitor<GenType> gt( baseString ); 66 assert( type ); 67 type->accept( gt ); 68 return gt.pass.typeString; 69 } 70 71 GenType::GenType( const std::string &typeString ) : typeString( typeString ) {} 72 73 // *** BaseSyntaxNode 74 void GenType::previsit( BaseSyntaxNode * ) { 75 // turn off automatic recursion for all nodes, to allow each visitor to 76 // precisely control the order in which its children are visited. 77 visit_children = false; 78 } 79 80 void GenType::postvisit( BaseSyntaxNode * node ) { 81 std::stringstream ss; 82 node->print( ss ); 83 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() ); 84 } 85 86 void GenType::postvisit( VoidType * voidType ) { 87 typeString = "void " + typeString; 88 handleQualifiers( voidType ); 89 } 90 91 void GenType::postvisit( BasicType * basicType ) { 92 BasicType::Kind kind = basicType->kind; 93 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES ); 94 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString; 95 handleQualifiers( basicType ); 96 } 97 98 void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool ) { 99 std::ostringstream os; 100 if ( typeString != "" ) { 101 if ( typeString[ 0 ] == '*' ) { 102 os << "(" << typeString << ")"; 103 } else { 104 os << typeString; 105 } // if 106 } // if 107 os << "["; 108 109 if ( qualifiers.is_const ) { 110 os << "const "; 111 } // if 112 if ( qualifiers.is_volatile ) { 113 os << "volatile "; 114 } // if 115 if ( qualifiers.is_restrict ) { 116 os << "__restrict "; 117 } // if 118 if ( qualifiers.is_atomic ) { 119 os << "_Atomic "; 120 } // if 121 if ( dimension != 0 ) { 122 // TODO: ??? 123 // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 124 // dimension->accept( cg ); 125 } else if ( isVarLen ) { 126 // no dimension expression on a VLA means it came in with the * token 127 os << "*"; 128 } // if 129 os << "]"; 130 131 typeString = os.str(); 132 133 base->accept( *visitor ); 134 } 135 136 void GenType::postvisit( PointerType * pointerType ) { 137 assert( pointerType->base != 0); 138 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) { 139 assert(false); 140 genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() ); 141 } else { 142 handleQualifiers( pointerType ); 143 if ( typeString[ 0 ] == '?' ) { 144 typeString = "* " + typeString; 145 } else { 146 typeString = "*" + typeString; 147 } // if 148 pointerType->base->accept( *visitor ); 149 } // if 150 } 151 152 void GenType::postvisit( ArrayType * arrayType ) { 153 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() ); 154 } 155 156 void GenType::postvisit( ReferenceType * refType ) { 157 assert( false ); 158 assert( refType->base != 0); 159 handleQualifiers( refType ); 160 typeString = "&" + typeString; 161 refType->base->accept( *visitor ); 162 } 163 164 void GenType::postvisit( FunctionType * funcType ) { 165 std::ostringstream os; 166 167 if ( typeString != "" ) { 168 if ( typeString[0] == '*' ) { 169 os << "(" << typeString << ")"; 170 } else { 171 os << typeString; 172 } // if 173 } // if 174 175 /************* parameters ***************/ 176 const std::list<DeclarationWithType *> &pars = funcType->parameters; 177 178 if ( pars.empty() ) { 179 if ( funcType->get_isVarArgs() ) { 180 os << "()"; 181 } else { 182 os << "(void)"; 183 } // if 184 } else { 185 os << "(" ; 186 187 unsigned int i = 0; 188 for (DeclarationWithType * p : pars) { 189 os << genDemangleType( p->get_type(), "" ); 190 if (++i != pars.size()) os << ", "; 191 } 192 193 if ( funcType->get_isVarArgs() ) { 194 os << ", ..."; 195 } // if 196 os << ")"; 197 } // if 198 199 typeString = os.str(); 200 201 if ( funcType->returnVals.size() == 0 ) { 202 typeString += ": void"; 203 } else { 204 typeString += ": " + genDemangleType(funcType->returnVals.front()->get_type(), ""); 205 } // if 206 207 // add forall 208 if( ! funcType->forall.empty() ) { 209 std::ostringstream os; 210 os << "forall("; 211 unsigned int i = 0; 212 for ( auto td : funcType->forall ) { 213 os << td->typeString() << " " << td->name; 214 if (! td->assertions.empty()) { 215 os << " | { "; 216 unsigned int j = 0; 217 for (DeclarationWithType * assert : td->assertions) { 218 os << genDemangleType(assert->get_type(), assert->name); 219 if (++j != td->assertions.size()) os << ", "; 220 } 221 os << "}"; 222 } 223 if (++i != funcType->forall.size()) os << ", "; 224 } 225 os << ")"; 226 typeString = typeString + " -> " + os.str(); 227 } 228 } 229 230 std::string GenType::handleGeneric( ReferenceToType * refType ) { 231 if ( ! refType->parameters.empty() ) { 232 std::ostringstream os; 233 // TODO: ??? 234 // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 235 os << "("; 236 // cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() ); 237 os << ") "; 238 return os.str(); 239 } 240 return ""; 241 } 242 243 void GenType::postvisit( StructInstType * structInst ) { 244 typeString = "struct " + structInst->name + handleGeneric( structInst ) + " " + typeString; 245 handleQualifiers( structInst ); 246 } 247 248 void GenType::postvisit( UnionInstType * unionInst ) { 249 typeString = "union " + unionInst->name + handleGeneric( unionInst ) + " " + typeString; 250 handleQualifiers( unionInst ); 251 } 252 253 void GenType::postvisit( EnumInstType * enumInst ) { 254 typeString = "enum " + enumInst->name + " " + typeString; 255 handleQualifiers( enumInst ); 256 } 257 258 void GenType::postvisit( TypeInstType * typeInst ) { 259 typeString = typeInst->name + " " + typeString; 260 handleQualifiers( typeInst ); 261 } 262 263 void GenType::postvisit( TupleType * tupleType ) { 264 unsigned int i = 0; 265 std::ostringstream os; 266 os << "["; 267 for ( Type * t : *tupleType ) { 268 i++; 269 os << genDemangleType( t, "" ) << (i == tupleType->size() ? "" : ", "); 270 } 271 os << "] "; 272 typeString = os.str() + typeString; 273 } 274 275 void GenType::postvisit( VarArgsType * varArgsType ) { 276 typeString = "__builtin_va_list " + typeString; 277 handleQualifiers( varArgsType ); 278 } 279 280 void GenType::postvisit( ZeroType * zeroType ) { 281 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 282 typeString = "zero_t " + typeString; 283 handleQualifiers( zeroType ); 284 } 285 286 void GenType::postvisit( OneType * oneType ) { 287 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 288 typeString = "one_t " + typeString; 289 handleQualifiers( oneType ); 290 } 291 292 void GenType::postvisit( GlobalScopeType * globalType ) { 293 handleQualifiers( globalType ); 294 } 295 296 void GenType::postvisit( QualifiedType * qualType ) { 297 std::ostringstream os; 298 os << genDemangleType( qualType->parent, "" ) << "." << genDemangleType( qualType->child, "" ) << typeString; 299 typeString = os.str(); 300 handleQualifiers( qualType ); 301 } 302 303 void GenType::handleQualifiers( Type * type ) { 304 if ( type->get_const() ) { 305 typeString = "const " + typeString; 306 } // if 307 if ( type->get_volatile() ) { 308 typeString = "volatile " + typeString; 309 } // if 310 if ( type->get_restrict() ) { 311 typeString = "__restrict " + typeString; 312 } // if 313 if ( type->get_atomic() ) { 314 typeString = "_Atomic " + typeString; 315 } // if 316 } 106 317 } 107 318 108 bool Demangler::extractNumber( size_t & out ) { 109 std::stringstream numss; 110 if ( str.size() <= index ) return false; 111 while ( isdigit( str[index] ) ) { 112 numss << str[index]; 113 ++index; 114 if ( str.size() == index ) break; 115 } 116 if ( !(numss >> out) ) return false; 117 PRINT( std::cerr << "extractNumber success: " << out << std::endl; ) 118 return true; 119 } 120 121 bool Demangler::extractName( std::string & out ) { 122 size_t len; 123 if ( !extractNumber(len) ) return false; 124 if ( str.size() < index + len ) return false; 125 out = str.substr( index, len ); 126 index += len; 127 PRINT( std::cerr << "extractName success: " << out << std::endl; ) 128 return true; 129 } 130 131 bool Demangler::isPrefix( const std::string & pref ) { 132 // Wraps the utility isPrefix function. 133 if ( ::isPrefix( str, pref, index ) ) { 134 index += pref.size(); 135 return true; 136 } 137 return false; 138 } 139 140 // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise 141 bool Demangler::stripMangleName( std::string & name ) { 142 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; ) 143 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix 144 if ( !isPrefix(Encoding::manglePrefix) || !isdigit(str.back() ) ) return false; 145 146 if (!extractName(name)) return false; 147 148 // Find bounds for type. 149 PRINT( std::cerr << index << " " << str.size() << std::endl; ) 150 PRINT( std::cerr << "["); 151 while (isdigit(str.back())) { 152 PRINT(std::cerr << "."); 153 str.pop_back(); 154 if (str.size() <= index) return false; 155 } 156 PRINT( std::cerr << "]" << std::endl ); 157 if (str.back() != '_') return false; 158 str.pop_back(); 159 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(index) << std::endl; ) 160 return index < str.size(); 161 } 162 163 ast::Type * Demangler::parseFunction( ast::CV::Qualifiers tq ) { 164 PRINT( std::cerr << "function..." << std::endl; ) 165 if ( done() ) return nullptr; 166 ast::FunctionType * ftype = new ast::FunctionType( ast::FixedArgs, tq ); 167 std::unique_ptr<ast::Type> manager( ftype ); 168 ast::Type * retVal = parseType(); 169 if ( !retVal ) return nullptr; 170 PRINT( std::cerr << "with return type: " << retVal << std::endl; ) 171 ftype->returns.emplace_back( retVal ); 172 if ( done() || !expect('_') ) return nullptr; 173 while ( !done() ) { 174 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 175 if ( cur() == '_' ) return manager.release(); 176 ast::Type * param = parseType(); 177 if ( !param ) return nullptr; 178 PRINT( std::cerr << "with parameter : " << param << std::endl; ) 179 ftype->params.emplace_back( param ); 180 } 181 return nullptr; 182 } 183 184 ast::Type * Demangler::parseTuple( ast::CV::Qualifiers tq ) { 185 PRINT( std::cerr << "tuple..." << std::endl; ) 186 std::vector<ast::ptr<ast::Type>> types; 187 size_t ncomponents; 188 if ( !extractNumber(ncomponents) ) return nullptr; 189 for ( size_t i = 0; i < ncomponents; ++i ) { 190 if ( done() ) return nullptr; 191 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 192 ast::Type * t = parseType(); 193 if ( !t ) return nullptr; 194 PRINT( std::cerr << "with type : " << t << std::endl; ) 195 types.push_back( t ); 196 } 197 return new ast::TupleType( std::move( types ), tq ); 198 } 199 200 ast::Type * Demangler::parsePointer( ast::CV::Qualifiers tq ) { 201 PRINT( std::cerr << "pointer..." << std::endl; ) 202 ast::Type * t = parseType(); 203 if ( !t ) return nullptr; 204 return new ast::PointerType( t, tq ); 205 } 206 207 ast::Type * Demangler::parseArray( ast::CV::Qualifiers tq ) { 208 PRINT( std::cerr << "array..." << std::endl; ) 209 size_t length; 210 if ( !extractNumber(length) ) return nullptr; 211 ast::Type * t = parseType(); 212 if ( !t ) return nullptr; 213 return new ast::ArrayType( 214 t, 215 ast::ConstantExpr::from_ulong( CodeLocation(), length ), 216 ast::FixedLen, 217 ast::DynamicDim, 218 tq ); 219 } 220 221 ast::Type * Demangler::parseStruct( ast::CV::Qualifiers tq ) { 222 PRINT( std::cerr << "struct..." << std::endl; ) 223 std::string name; 224 if ( !extractName(name) ) return nullptr; 225 return new ast::StructInstType( name, tq ); 226 } 227 228 ast::Type * Demangler::parseUnion( ast::CV::Qualifiers tq ) { 229 PRINT( std::cerr << "union..." << std::endl; ) 230 std::string name; 231 if ( !extractName(name) ) return nullptr; 232 return new ast::UnionInstType( name, tq ); 233 } 234 235 ast::Type * Demangler::parseEnum( ast::CV::Qualifiers tq ) { 236 PRINT( std::cerr << "enum..." << std::endl; ) 237 std::string name; 238 if ( !extractName(name) ) return nullptr; 239 return new ast::EnumInstType( name, tq ); 240 } 241 242 ast::Type * Demangler::parseType( ast::CV::Qualifiers tq ) { 243 PRINT( std::cerr << "type..." << std::endl; ) 244 std::string name; 245 if ( !extractName(name) ) return nullptr; 246 PRINT( std::cerr << "typename..." << name << std::endl; ) 247 return new ast::TypeInstType( name, ast::TypeDecl::Dtype, tq ); 248 } 249 250 ast::Type * Demangler::parseType() { 251 if (done()) return nullptr; 252 253 if (isPrefix(Encoding::forall)) { 254 PRINT( std::cerr << "polymorphic with..." << std::endl; ) 255 size_t dcount, fcount, vcount, acount; 256 if ( !extractNumber(dcount) ) return nullptr; 257 PRINT( std::cerr << dcount << " dtypes" << std::endl; ) 258 if ( !expect('_') ) return nullptr; 259 if ( !extractNumber(fcount) ) return nullptr; 260 PRINT( std::cerr << fcount << " ftypes" << std::endl; ) 261 if ( !expect('_')) return nullptr; 262 if ( !extractNumber(vcount)) return nullptr; 263 PRINT( std::cerr << vcount << " ttypes" << std::endl; ) 264 if ( !expect('_') ) return nullptr; 265 if ( !extractNumber(acount) ) return nullptr; 266 PRINT( std::cerr << acount << " assertions" << std::endl; ) 267 if ( !expect('_') ) return nullptr; 268 for ( size_t i = 0 ; i < acount ; ++i ) { 269 // TODO: need to recursively parse assertions, but for now just return nullptr so that 270 // demangler does not crash if there are assertions 271 return nullptr; 272 } 273 if ( !expect('_') ) return nullptr; 274 } 275 276 ast::CV::Qualifiers tq; 277 while (true) { 278 auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) { 279 return isPrefix(val.second); 280 }); 281 if (qual == Encoding::qualifiers.end()) break; 282 tq |= qual->first; 283 } 284 285 // Find the correct type parser and then apply it. 286 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, Parser> & p) { 287 return isPrefix(p.first); 288 }); 289 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), index); 290 ast::Type * ret = iter->second(tq); 291 if ( !ret ) return nullptr; 292 return ret; 293 } 294 295 bool Demangler::parse( std::string & name, ast::Type *& type) { 296 if ( !stripMangleName(name) ) return false; 297 PRINT( std::cerr << "stripped name: " << name << std::endl; ) 298 ast::Type * t = parseType(); 299 if ( !t ) return false; 300 type = t; 301 return true; 302 } 303 304 std::string demangle( const std::string & mangleName ) { 305 using namespace CodeGen; 306 Demangler demangler( mangleName ); 307 std::string name; 308 ast::Type * type = nullptr; 309 if ( !demangler.parse( name, type ) ) return mangleName; 310 ast::readonly<ast::Type> roType = type; 311 if ( auto info = operatorLookupByOutput( name ) ) name = info->inputName; 312 return genType( type, name, Options( false, false, false, false ) ); 313 } 314 315 } // namespace 316 317 } // namespace Mangle 319 320 namespace SymTab { 321 namespace Mangler { 322 namespace { 323 struct StringView { 324 private: 325 std::string str; 326 size_t idx = 0; 327 // typedef Type * (StringView::*parser)(Type::Qualifiers); 328 typedef std::function<Type * (Type::Qualifiers)> parser; 329 std::vector<std::pair<std::string, parser>> parsers; 330 public: 331 StringView(const std::string & str); 332 333 bool done() const { return idx >= str.size(); } 334 char cur() const { assert(! done()); return str[idx]; } 335 336 bool expect(char ch) { return str[idx++] == ch; } 337 void next(size_t inc = 1) { idx += inc; } 338 339 /// determines if `pref` is a prefix of `str` 340 bool isPrefix(const std::string & pref); 341 bool extractNumber(size_t & out); 342 bool extractName(std::string & out); 343 bool stripMangleName(std::string & name); 344 345 Type * parseFunction(Type::Qualifiers tq); 346 Type * parseTuple(Type::Qualifiers tq); 347 Type * parseVoid(Type::Qualifiers tq); 348 Type * parsePointer(Type::Qualifiers tq); 349 Type * parseArray(Type::Qualifiers tq); 350 Type * parseStruct(Type::Qualifiers tq); 351 Type * parseUnion(Type::Qualifiers tq); 352 Type * parseEnum(Type::Qualifiers tq); 353 Type * parseType(Type::Qualifiers tq); 354 355 Type * parseType(); 356 bool parse(std::string & name, Type *& type); 357 }; 358 359 StringView::StringView(const std::string & str) : str(str) { 360 // basic types 361 for (size_t k = 0; k < BasicType::NUMBER_OF_BASIC_TYPES; ++k) { 362 parsers.emplace_back(Encoding::basicTypes[k], [k](Type::Qualifiers tq) { 363 PRINT( std::cerr << "basic type: " << k << std::endl; ) 364 return new BasicType(tq, (BasicType::Kind)k); 365 }); 366 } 367 // type variable types 368 for (size_t k = 0; k < TypeDecl::NUMBER_OF_KINDS; ++k) { 369 static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", }; 370 static_assert( 371 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == TypeDecl::NUMBER_OF_KINDS, 372 "Each type variable kind should have a demangle name prefix" 373 ); 374 parsers.emplace_back(Encoding::typeVariables[k], [k, this](Type::Qualifiers tq) -> TypeInstType * { 375 PRINT( std::cerr << "type variable type: " << k << std::endl; ) 376 size_t N; 377 if (! extractNumber(N)) return nullptr; 378 return new TypeInstType(tq, toString(typeVariableNames[k], N), (TypeDecl::Kind)k != TypeDecl::Ftype); 379 }); 380 } 381 // everything else 382 parsers.emplace_back(Encoding::void_t, [this](Type::Qualifiers tq) { return parseVoid(tq); }); 383 parsers.emplace_back(Encoding::function, [this](Type::Qualifiers tq) { return parseFunction(tq); }); 384 parsers.emplace_back(Encoding::pointer, [this](Type::Qualifiers tq) { return parsePointer(tq); }); 385 parsers.emplace_back(Encoding::array, [this](Type::Qualifiers tq) { return parseArray(tq); }); 386 parsers.emplace_back(Encoding::tuple, [this](Type::Qualifiers tq) { return parseTuple(tq); }); 387 parsers.emplace_back(Encoding::struct_t, [this](Type::Qualifiers tq) { return parseStruct(tq); }); 388 parsers.emplace_back(Encoding::union_t, [this](Type::Qualifiers tq) { return parseUnion(tq); }); 389 parsers.emplace_back(Encoding::enum_t, [this](Type::Qualifiers tq) { return parseEnum(tq); }); 390 parsers.emplace_back(Encoding::type, [this](Type::Qualifiers tq) { return parseType(tq); }); 391 parsers.emplace_back(Encoding::zero, [](Type::Qualifiers tq) { return new ZeroType(tq); }); 392 parsers.emplace_back(Encoding::one, [](Type::Qualifiers tq) { return new OneType(tq); }); 393 } 394 395 bool StringView::extractNumber(size_t & out) { 396 std::stringstream numss; 397 if (idx >= str.size()) return false; 398 while (isdigit(str[idx])) { 399 numss << str[idx]; 400 ++idx; 401 if (idx == str.size()) break; 402 } 403 if (! (numss >> out)) return false; 404 PRINT( std::cerr << "extractNumber success: " << out << std::endl; ) 405 return true; 406 } 407 408 bool StringView::extractName(std::string & out) { 409 size_t len; 410 if (! extractNumber(len)) return false; 411 if (idx+len > str.size()) return false; 412 out = str.substr(idx, len); 413 idx += len; 414 PRINT( std::cerr << "extractName success: " << out << std::endl; ) 415 return true; 416 } 417 418 bool StringView::isPrefix(const std::string & pref) { 419 // if ( pref.size() > str.size()-idx ) return false; 420 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) ); 421 // if (its.first == pref.end()) { 422 // idx += pref.size(); 423 // return true; 424 // } 425 426 // This update is untested because there are no tests for this code. 427 if ( ::isPrefix( str, pref, idx ) ) { 428 idx += pref.size(); 429 return true; 430 } 431 return false; 432 } 433 434 // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise 435 bool StringView::stripMangleName(std::string & name) { 436 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; ) 437 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix 438 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false; 439 440 // get name 441 if (! extractName(name)) return false; 442 443 // find bounds for type 444 PRINT( std::cerr << idx << " " << str.size() << std::endl; ) 445 PRINT( std::cerr << "["); 446 while (isdigit(str.back())) { 447 PRINT(std::cerr << "."); 448 str.pop_back(); 449 if (str.size() <= idx) return false; 450 } 451 PRINT( std::cerr << "]" << std::endl ); 452 if (str.back() != '_') return false; 453 str.pop_back(); 454 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(idx) << std::endl; ) 455 return str.size() > idx; 456 } 457 458 Type * StringView::parseFunction(Type::Qualifiers tq) { 459 PRINT( std::cerr << "function..." << std::endl; ) 460 if (done()) return nullptr; 461 FunctionType * ftype = new FunctionType( tq, false ); 462 std::unique_ptr<Type> manager(ftype); 463 Type * retVal = parseType(); 464 if (! retVal) return nullptr; 465 PRINT( std::cerr << "with return type: " << retVal << std::endl; ) 466 ftype->returnVals.push_back(ObjectDecl::newObject("", retVal, nullptr)); 467 if (done() || ! expect('_')) return nullptr; 468 while (! done()) { 469 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 470 if (cur() == '_') return manager.release(); 471 Type * param = parseType(); 472 if (! param) return nullptr; 473 PRINT( std::cerr << "with parameter : " << param << std::endl; ) 474 ftype->parameters.push_back(ObjectDecl::newObject("", param, nullptr)); 475 } 476 return nullptr; 477 } 478 479 Type * StringView::parseTuple(Type::Qualifiers tq) { 480 PRINT( std::cerr << "tuple..." << std::endl; ) 481 std::list< Type * > types; 482 size_t ncomponents; 483 if (! extractNumber(ncomponents)) return nullptr; 484 for (size_t i = 0; i < ncomponents; ++i) { 485 // TODO: delete all on return 486 if (done()) return nullptr; 487 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 488 Type * t = parseType(); 489 if (! t) return nullptr; 490 PRINT( std::cerr << "with type : " << t << std::endl; ) 491 types.push_back(t); 492 } 493 return new TupleType( tq, types ); 494 } 495 496 Type * StringView::parseVoid(Type::Qualifiers tq) { 497 return new VoidType( tq ); 498 } 499 500 Type * StringView::parsePointer(Type::Qualifiers tq) { 501 PRINT( std::cerr << "pointer..." << std::endl; ) 502 Type * t = parseType(); 503 if (! t) return nullptr; 504 return new PointerType( tq, t ); 505 } 506 507 Type * StringView::parseArray(Type::Qualifiers tq) { 508 PRINT( std::cerr << "array..." << std::endl; ) 509 size_t length; 510 if (! extractNumber(length)) return nullptr; 511 Type * t = parseType(); 512 if (! t) return nullptr; 513 return new ArrayType( tq, t, new ConstantExpr( Constant::from_ulong(length) ), false, false ); 514 } 515 516 Type * StringView::parseStruct(Type::Qualifiers tq) { 517 PRINT( std::cerr << "struct..." << std::endl; ) 518 std::string name; 519 if (! extractName(name)) return nullptr; 520 return new StructInstType(tq, name); 521 } 522 523 Type * StringView::parseUnion(Type::Qualifiers tq) { 524 PRINT( std::cerr << "union..." << std::endl; ) 525 std::string name; 526 if (! extractName(name)) return nullptr; 527 return new UnionInstType(tq, name); 528 } 529 530 Type * StringView::parseEnum(Type::Qualifiers tq) { 531 PRINT( std::cerr << "enum..." << std::endl; ) 532 std::string name; 533 if (! extractName(name)) return nullptr; 534 return new EnumInstType(tq, name); 535 } 536 537 Type * StringView::parseType(Type::Qualifiers tq) { 538 PRINT( std::cerr << "type..." << std::endl; ) 539 std::string name; 540 if (! extractName(name)) return nullptr; 541 PRINT( std::cerr << "typename..." << name << std::endl; ) 542 return new TypeInstType(tq, name, false); 543 } 544 545 Type * StringView::parseType() { 546 if (done()) return nullptr; 547 548 std::list<TypeDecl *> forall; 549 if (isPrefix(Encoding::forall)) { 550 PRINT( std::cerr << "polymorphic with..." << std::endl; ) 551 size_t dcount, fcount, vcount, acount; 552 if (! extractNumber(dcount)) return nullptr; 553 PRINT( std::cerr << dcount << " dtypes" << std::endl; ) 554 if (! expect('_')) return nullptr; 555 if (! extractNumber(fcount)) return nullptr; 556 PRINT( std::cerr << fcount << " ftypes" << std::endl; ) 557 if (! expect('_')) return nullptr; 558 if (! extractNumber(vcount)) return nullptr; 559 PRINT( std::cerr << vcount << " ttypes" << std::endl; ) 560 if (! expect('_')) return nullptr; 561 if (! extractNumber(acount)) return nullptr; 562 PRINT( std::cerr << acount << " assertions" << std::endl; ) 563 if (! expect('_')) return nullptr; 564 for (size_t i = 0; i < acount; ++i) { 565 // TODO: need to recursively parse assertions, but for now just return nullptr so that 566 // demangler does not crash if there are assertions 567 return nullptr; 568 } 569 if (! expect('_')) return nullptr; 570 } 571 572 // qualifiers 573 Type::Qualifiers tq; 574 while (true) { 575 auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) { 576 return isPrefix(val.second); 577 }); 578 if (qual == Encoding::qualifiers.end()) break; 579 tq |= qual->first; 580 } 581 582 // find the correct type parser and use it 583 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, parser> & p) { 584 return isPrefix(p.first); 585 }); 586 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), idx); 587 Type * ret = iter->second(tq); 588 if (! ret) return nullptr; 589 ret->forall = std::move(forall); 590 return ret; 591 } 592 593 bool StringView::parse(std::string & name, Type *& type) { 594 if (! stripMangleName(name)) return false; 595 PRINT( std::cerr << "stripped name: " << name << std::endl; ) 596 Type * t = parseType(); 597 if (! t) return false; 598 type = t; 599 return true; 600 } 601 602 std::string demangle(const std::string & mangleName) { 603 SymTab::Mangler::StringView view(mangleName); 604 std::string name; 605 Type * type = nullptr; 606 if (! view.parse(name, type)) return mangleName; 607 std::unique_ptr<Type> manager(type); 608 return genDemangleType(type, name); 609 } 610 } // namespace 611 } // namespace Mangler 612 } // namespace SymTab 318 613 319 614 extern "C" { 320 615 char * cforall_demangle(const char * mangleName, int option __attribute__((unused))) { 321 const std::string & demangleName = Mangle::demangle(mangleName);616 const std::string & demangleName = SymTab::Mangler::demangle(mangleName); 322 617 return strdup(demangleName.c_str()); 323 618 } -
src/SymTab/Demangle.h
rfc12f05 r0030b508 10 10 // Created On : Fri May 13 10:11:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 6 15:48:00 202313 // Update Count : 112 // Last Modified On : Fri May 13 10:30:00 2022 13 // Update Count : 0 14 14 // 15 15 … … 17 17 18 18 extern "C" { 19 /// Main interface to the demangler as a utility.20 /// Caller must free the returned string.21 19 char * cforall_demangle(const char *, int); 22 20 } -
src/SymTab/FixFunction.cc
rfc12f05 r0030b508 22 22 #include "AST/Type.hpp" 23 23 #include "Common/utility.h" // for copy 24 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarati... 25 #include "SynTree/Expression.h" // for Expression 26 #include "SynTree/Type.h" // for ArrayType, PointerType, Type, Basic... 24 27 25 28 namespace SymTab { 29 class FixFunction_old : public WithShortCircuiting { 30 typedef Mutator Parent; 31 public: 32 FixFunction_old() : isVoid( false ) {} 33 34 void premutate(FunctionDecl *functionDecl); 35 DeclarationWithType* postmutate(FunctionDecl *functionDecl); 36 37 Type * postmutate(ArrayType * arrayType); 38 39 void premutate(ArrayType * arrayType); 40 void premutate(VoidType * voidType); 41 void premutate(BasicType * basicType); 42 void premutate(PointerType * pointerType); 43 void premutate(StructInstType * aggregateUseType); 44 void premutate(UnionInstType * aggregateUseType); 45 void premutate(EnumInstType * aggregateUseType); 46 void premutate(TraitInstType * aggregateUseType); 47 void premutate(TypeInstType * aggregateUseType); 48 void premutate(TupleType * tupleType); 49 void premutate(VarArgsType * varArgsType); 50 void premutate(ZeroType * zeroType); 51 void premutate(OneType * oneType); 52 53 bool isVoid; 54 }; 55 56 DeclarationWithType * FixFunction_old::postmutate(FunctionDecl *functionDecl) { 57 // can't delete function type because it may contain assertions, so transfer ownership to new object 58 ObjectDecl *pointer = new ObjectDecl( functionDecl->name, functionDecl->get_storageClasses(), functionDecl->linkage, nullptr, new PointerType( Type::Qualifiers(), functionDecl->type ), nullptr, functionDecl->attributes ); 59 pointer->location = functionDecl->location; 60 functionDecl->attributes.clear(); 61 functionDecl->type = nullptr; 62 delete functionDecl; 63 return pointer; 64 } 65 66 // xxx - this passes on void[], e.g. 67 // void foo(void [10]); 68 // does not cause an error 69 70 Type * FixFunction_old::postmutate(ArrayType *arrayType) { 71 // need to recursively mutate the base type in order for multi-dimensional arrays to work. 72 PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->isVarLen, arrayType->isStatic ); 73 pointerType->location = arrayType->location; 74 arrayType->base = nullptr; 75 arrayType->dimension = nullptr; 76 delete arrayType; 77 return pointerType; 78 } 79 80 void FixFunction_old::premutate(VoidType *) { 81 isVoid = true; 82 } 83 84 void FixFunction_old::premutate(FunctionDecl *) { visit_children = false; } 85 void FixFunction_old::premutate(ArrayType *) { visit_children = false; } 86 void FixFunction_old::premutate(BasicType *) { visit_children = false; } 87 void FixFunction_old::premutate(PointerType *) { visit_children = false; } 88 void FixFunction_old::premutate(StructInstType *) { visit_children = false; } 89 void FixFunction_old::premutate(UnionInstType *) { visit_children = false; } 90 void FixFunction_old::premutate(EnumInstType *) { visit_children = false; } 91 void FixFunction_old::premutate(TraitInstType *) { visit_children = false; } 92 void FixFunction_old::premutate(TypeInstType *) { visit_children = false; } 93 void FixFunction_old::premutate(TupleType *) { visit_children = false; } 94 void FixFunction_old::premutate(VarArgsType *) { visit_children = false; } 95 void FixFunction_old::premutate(ZeroType *) { visit_children = false; } 96 void FixFunction_old::premutate(OneType *) { visit_children = false; } 97 98 bool fixFunction( DeclarationWithType *& dwt ) { 99 PassVisitor<FixFunction_old> fixer; 100 dwt = dwt->acceptMutator( fixer ); 101 return fixer.pass.isVoid; 102 } 26 103 27 104 namespace { -
src/SymTab/FixFunction.h
rfc12f05 r0030b508 16 16 #pragma once 17 17 18 #include "Common/PassVisitor.h" // for PassVisitor 19 #include "SynTree/SynTree.h" // for Types 20 18 21 namespace ast { 19 22 class DeclWithType; … … 22 25 23 26 namespace SymTab { 27 /// Replaces function and array types by equivalent pointer types. Returns true if type is 28 /// void 29 bool fixFunction( DeclarationWithType *& ); 30 24 31 /// Returns declaration with function and array types replaced by equivalent pointer types. 25 32 /// Sets isVoid to true if type is void -
src/SymTab/Mangler.cc
rfc12f05 r0030b508 22 22 #include <string> // for string, char_traits, operator<< 23 23 24 #include "AST/Pass.hpp"25 24 #include "CodeGen/OperatorTable.h" // for OperatorInfo, operatorLookup 25 #include "Common/PassVisitor.h" 26 26 #include "Common/ToString.hpp" // for toCString 27 27 #include "Common/SemanticError.h" // for SemanticError 28 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment 29 #include "SynTree/LinkageSpec.h" // for Spec, isOverridable, AutoGen, Int... 30 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType 31 #include "SynTree/Expression.h" // for TypeExpr, Expression, operator<< 32 #include "SynTree/Type.h" // for Type, ReferenceToType, Type::Fora... 33 34 #include "AST/Pass.hpp" 35 36 namespace SymTab { 37 namespace Mangler { 38 namespace { 39 /// Mangles names to a unique C identifier 40 struct Mangler_old : public WithShortCircuiting, public WithVisitorRef<Mangler_old>, public WithGuards { 41 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams ); 42 Mangler_old( const Mangler_old & ) = delete; 43 44 void previsit( const BaseSyntaxNode * ) { visit_children = false; } 45 46 void postvisit( const ObjectDecl * declaration ); 47 void postvisit( const FunctionDecl * declaration ); 48 void postvisit( const TypeDecl * declaration ); 49 50 void postvisit( const VoidType * voidType ); 51 void postvisit( const BasicType * basicType ); 52 void postvisit( const PointerType * pointerType ); 53 void postvisit( const ArrayType * arrayType ); 54 void postvisit( const ReferenceType * refType ); 55 void postvisit( const FunctionType * functionType ); 56 void postvisit( const StructInstType * aggregateUseType ); 57 void postvisit( const UnionInstType * aggregateUseType ); 58 void postvisit( const EnumInstType * aggregateUseType ); 59 void postvisit( const TypeInstType * aggregateUseType ); 60 void postvisit( const TraitInstType * inst ); 61 void postvisit( const TupleType * tupleType ); 62 void postvisit( const VarArgsType * varArgsType ); 63 void postvisit( const ZeroType * zeroType ); 64 void postvisit( const OneType * oneType ); 65 void postvisit( const QualifiedType * qualType ); 66 67 std::string get_mangleName() { return mangleName; } 68 private: 69 std::string mangleName; ///< Mangled name being constructed 70 typedef std::map< std::string, std::pair< int, int > > VarMapType; 71 VarMapType varNums; ///< Map of type variables to indices 72 int nextVarNum; ///< Next type variable index 73 bool isTopLevel; ///< Is the Mangler at the top level 74 bool mangleOverridable; ///< Specially mangle overridable built-in methods 75 bool typeMode; ///< Produce a unique mangled name for a type 76 bool mangleGenericParams; ///< Include generic parameters in name mangling if true 77 bool inFunctionType = false; ///< Include type qualifiers if false. 78 bool inQualifiedType = false; ///< Add start/end delimiters around qualified type 79 80 public: 81 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 82 int nextVarNum, const VarMapType& varNums ); 83 84 private: 85 void mangleDecl( const DeclarationWithType * declaration ); 86 void mangleRef( const ReferenceToType * refType, std::string prefix ); 87 88 void printQualifiers( const Type *type ); 89 }; // Mangler_old 90 } // namespace 91 92 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) { 93 PassVisitor<Mangler_old> mangler( mangleOverridable, typeMode, mangleGenericParams ); 94 maybeAccept( decl, mangler ); 95 return mangler.pass.get_mangleName(); 96 } 97 98 std::string mangleType( const Type * ty ) { 99 PassVisitor<Mangler_old> mangler( false, true, true ); 100 maybeAccept( ty, mangler ); 101 return mangler.pass.get_mangleName(); 102 } 103 104 std::string mangleConcrete( const Type * ty ) { 105 PassVisitor<Mangler_old> mangler( false, false, false ); 106 maybeAccept( ty, mangler ); 107 return mangler.pass.get_mangleName(); 108 } 109 110 namespace { 111 Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams ) 112 : nextVarNum( 0 ), isTopLevel( true ), 113 mangleOverridable( mangleOverridable ), typeMode( typeMode ), 114 mangleGenericParams( mangleGenericParams ) {} 115 116 Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 117 int nextVarNum, const VarMapType& varNums ) 118 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ), 119 mangleOverridable( mangleOverridable ), typeMode( typeMode ), 120 mangleGenericParams( mangleGenericParams ) {} 121 122 void Mangler_old::mangleDecl( const DeclarationWithType * declaration ) { 123 bool wasTopLevel = isTopLevel; 124 if ( isTopLevel ) { 125 varNums.clear(); 126 nextVarNum = 0; 127 isTopLevel = false; 128 } // if 129 mangleName += Encoding::manglePrefix; 130 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() ); 131 if ( opInfo ) { 132 mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName; 133 } else { 134 mangleName += std::to_string( declaration->name.size() ) + declaration->name; 135 } // if 136 maybeAccept( declaration->get_type(), *visitor ); 137 if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) { 138 // want to be able to override autogenerated and intrinsic routines, 139 // so they need a different name mangling 140 if ( declaration->get_linkage() == LinkageSpec::AutoGen ) { 141 mangleName += Encoding::autogen; 142 } else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) { 143 mangleName += Encoding::intrinsic; 144 } else { 145 // if we add another kind of overridable function, this has to change 146 assert( false && "unknown overrideable linkage" ); 147 } // if 148 } 149 isTopLevel = wasTopLevel; 150 } 151 152 void Mangler_old::postvisit( const ObjectDecl * declaration ) { 153 mangleDecl( declaration ); 154 } 155 156 void Mangler_old::postvisit( const FunctionDecl * declaration ) { 157 mangleDecl( declaration ); 158 } 159 160 void Mangler_old::postvisit( const VoidType * voidType ) { 161 printQualifiers( voidType ); 162 mangleName += Encoding::void_t; 163 } 164 165 void Mangler_old::postvisit( const BasicType * basicType ) { 166 printQualifiers( basicType ); 167 assertf( basicType->kind < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind ); 168 mangleName += Encoding::basicTypes[ basicType->kind ]; 169 } 170 171 void Mangler_old::postvisit( const PointerType * pointerType ) { 172 printQualifiers( pointerType ); 173 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers 174 if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName += Encoding::pointer; 175 maybeAccept( pointerType->base, *visitor ); 176 } 177 178 void Mangler_old::postvisit( const ArrayType * arrayType ) { 179 // TODO: encode dimension 180 printQualifiers( arrayType ); 181 mangleName += Encoding::array + "0"; 182 maybeAccept( arrayType->base, *visitor ); 183 } 184 185 void Mangler_old::postvisit( const ReferenceType * refType ) { 186 // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload. 187 // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.), 188 // by pretending every reference type is a function parameter. 189 GuardValue( inFunctionType ); 190 inFunctionType = true; 191 printQualifiers( refType ); 192 maybeAccept( refType->base, *visitor ); 193 } 194 195 namespace { 196 inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) { 197 std::list< Type* > ret; 198 std::transform( decls.begin(), decls.end(), std::back_inserter( ret ), 199 std::mem_fun( &DeclarationWithType::get_type ) ); 200 return ret; 201 } 202 } 203 204 void Mangler_old::postvisit( const FunctionType * functionType ) { 205 printQualifiers( functionType ); 206 mangleName += Encoding::function; 207 // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters, 208 // since qualifiers on outermost parameter type do not differentiate function types, e.g., 209 // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different 210 GuardValue( inFunctionType ); 211 inFunctionType = true; 212 std::list< Type* > returnTypes = getTypes( functionType->returnVals ); 213 if (returnTypes.empty()) mangleName += Encoding::void_t; 214 else acceptAll( returnTypes, *visitor ); 215 mangleName += "_"; 216 std::list< Type* > paramTypes = getTypes( functionType->parameters ); 217 acceptAll( paramTypes, *visitor ); 218 mangleName += "_"; 219 } 220 221 void Mangler_old::mangleRef( const ReferenceToType * refType, std::string prefix ) { 222 printQualifiers( refType ); 223 224 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name; 225 226 if ( mangleGenericParams ) { 227 const std::list< Expression* > & params = refType->parameters; 228 if ( ! params.empty() ) { 229 mangleName += "_"; 230 for ( const Expression * param : params ) { 231 const TypeExpr * paramType = dynamic_cast< const TypeExpr * >( param ); 232 assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param)); 233 maybeAccept( paramType->type, *visitor ); 234 } 235 mangleName += "_"; 236 } 237 } 238 } 239 240 void Mangler_old::postvisit( const StructInstType * aggregateUseType ) { 241 mangleRef( aggregateUseType, Encoding::struct_t ); 242 } 243 244 void Mangler_old::postvisit( const UnionInstType * aggregateUseType ) { 245 mangleRef( aggregateUseType, Encoding::union_t ); 246 } 247 248 void Mangler_old::postvisit( const EnumInstType * aggregateUseType ) { 249 mangleRef( aggregateUseType, Encoding::enum_t ); 250 } 251 252 void Mangler_old::postvisit( const TypeInstType * typeInst ) { 253 VarMapType::iterator varNum = varNums.find( typeInst->get_name() ); 254 if ( varNum == varNums.end() ) { 255 mangleRef( typeInst, Encoding::type ); 256 } else { 257 printQualifiers( typeInst ); 258 // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g. 259 // forall(dtype T) void f(T); 260 // forall(dtype S) void f(S); 261 // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they 262 // are first found and prefixing with the appropriate encoding for the type class. 263 assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second ); 264 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first ); 265 } // if 266 } 267 268 void Mangler_old::postvisit( const TraitInstType * inst ) { 269 printQualifiers( inst ); 270 mangleName += std::to_string( inst->name.size() ) + inst->name; 271 } 272 273 void Mangler_old::postvisit( const TupleType * tupleType ) { 274 printQualifiers( tupleType ); 275 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() ); 276 acceptAll( tupleType->types, *visitor ); 277 } 278 279 void Mangler_old::postvisit( const VarArgsType * varArgsType ) { 280 printQualifiers( varArgsType ); 281 static const std::string vargs = "__builtin_va_list"; 282 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs; 283 } 284 285 void Mangler_old::postvisit( const ZeroType * ) { 286 mangleName += Encoding::zero; 287 } 288 289 void Mangler_old::postvisit( const OneType * ) { 290 mangleName += Encoding::one; 291 } 292 293 void Mangler_old::postvisit( const QualifiedType * qualType ) { 294 bool inqual = inQualifiedType; 295 if (! inqual ) { 296 // N marks the start of a qualified type 297 inQualifiedType = true; 298 mangleName += Encoding::qualifiedTypeStart; 299 } 300 maybeAccept( qualType->parent, *visitor ); 301 maybeAccept( qualType->child, *visitor ); 302 if ( ! inqual ) { 303 // E marks the end of a qualified type 304 inQualifiedType = false; 305 mangleName += Encoding::qualifiedTypeEnd; 306 } 307 } 308 309 void Mangler_old::postvisit( const TypeDecl * decl ) { 310 // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be 311 // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa. 312 // Note: The current scheme may already work correctly for this case, I have not thought about this deeply 313 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed 314 // aside from the assert false. 315 assertf( false, "Mangler_old should not visit typedecl: %s", toCString(decl)); 316 assertf( decl->kind < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind ); 317 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name; 318 } 319 320 __attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) { 321 for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) { 322 os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl; 323 } // for 324 } 325 326 void Mangler_old::printQualifiers( const Type * type ) { 327 // skip if not including qualifiers 328 if ( typeMode ) return; 329 if ( ! type->forall.empty() ) { 330 std::list< std::string > assertionNames; 331 int dcount = 0, fcount = 0, vcount = 0, acount = 0; 332 mangleName += Encoding::forall; 333 for ( const TypeDecl * i : type->forall ) { 334 switch ( i->kind ) { 335 case TypeDecl::Dtype: 336 dcount++; 337 break; 338 case TypeDecl::Ftype: 339 fcount++; 340 break; 341 case TypeDecl::Ttype: 342 vcount++; 343 break; 344 default: 345 assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[i->kind].c_str() ); 346 } // switch 347 varNums[ i->name ] = std::make_pair( nextVarNum, (int)i->kind ); 348 for ( const DeclarationWithType * assert : i->assertions ) { 349 PassVisitor<Mangler_old> sub_mangler( 350 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ); 351 assert->accept( sub_mangler ); 352 assertionNames.push_back( sub_mangler.pass.get_mangleName() ); 353 acount++; 354 } // for 355 } // for 356 mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_"; 357 for(const auto & a : assertionNames) mangleName += a; 358 // std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) ); 359 mangleName += "_"; 360 } // if 361 if ( ! inFunctionType ) { 362 // these qualifiers do not distinguish the outermost type of a function parameter 363 if ( type->get_const() ) { 364 mangleName += Encoding::qualifiers.at(Type::Const); 365 } // if 366 if ( type->get_volatile() ) { 367 mangleName += Encoding::qualifiers.at(Type::Volatile); 368 } // if 369 // Removed due to restrict not affecting function compatibility in GCC 370 // if ( type->get_isRestrict() ) { 371 // mangleName += "E"; 372 // } // if 373 if ( type->get_atomic() ) { 374 mangleName += Encoding::qualifiers.at(Type::Atomic); 375 } // if 376 } 377 if ( type->get_mutex() ) { 378 mangleName += Encoding::qualifiers.at(Type::Mutex); 379 } // if 380 if ( inFunctionType ) { 381 // turn off inFunctionType so that types can be differentiated for nested qualifiers 382 GuardValue( inFunctionType ); 383 inFunctionType = false; 384 } 385 } 386 } // namespace 387 } // namespace Mangler 388 } // namespace SymTab 28 389 29 390 namespace Mangle { … … 115 476 mangleName += std::to_string( decl->name.size() ) + decl->name; 116 477 } // if 117 decl->get_type()->accept(*visitor );478 maybeAccept( decl->get_type(), *visitor ); 118 479 if ( mangleOverridable && decl->linkage.is_overrideable ) { 119 480 // want to be able to override autogenerated and intrinsic routines, … … 161 522 printQualifiers( arrayType ); 162 523 mangleName += Encoding::array + "0"; 163 arrayType->base->accept(*visitor );524 maybeAccept( arrayType->base.get(), *visitor ); 164 525 } 165 526 … … 171 532 inFunctionType = true; 172 533 printQualifiers( refType ); 173 refType->base->accept(*visitor );534 maybeAccept( refType->base.get(), *visitor ); 174 535 } 175 536 … … 200 561 auto paramType = dynamic_cast< const ast::TypeExpr * >( param ); 201 562 assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param)); 202 paramType->type->accept(*visitor );563 maybeAccept( paramType->type.get(), *visitor ); 203 564 } 204 565 mangleName += "_"; … … 229 590 // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they 230 591 // are first found and prefixing with the appropriate encoding for the type class. 231 assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );592 assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second ); 232 593 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first ); 233 594 } // if … … 261 622 void Mangler_new::postvisit( const ast::QualifiedType * qualType ) { 262 623 bool inqual = inQualifiedType; 263 if ( !inqual ) {624 if (! inqual ) { 264 625 // N marks the start of a qualified type 265 626 inQualifiedType = true; 266 627 mangleName += Encoding::qualifiedTypeStart; 267 628 } 268 qualType->parent->accept(*visitor );269 qualType->child->accept(*visitor );270 if ( ! inqual ) {629 maybeAccept( qualType->parent.get(), *visitor ); 630 maybeAccept( qualType->child.get(), *visitor ); 631 if ( ! inqual ) { 271 632 // E marks the end of a qualified type 272 633 inQualifiedType = false; … … 330 691 // these qualifiers do not distinguish the outermost type of a function parameter 331 692 if ( type->is_const() ) { 332 mangleName += Encoding::qualifiers.at( ast::CV::Const);693 mangleName += Encoding::qualifiers.at(Type::Const); 333 694 } // if 334 695 if ( type->is_volatile() ) { 335 mangleName += Encoding::qualifiers.at( ast::CV::Volatile);696 mangleName += Encoding::qualifiers.at(Type::Volatile); 336 697 } // if 337 698 // Removed due to restrict not affecting function compatibility in GCC … … 340 701 // } // if 341 702 if ( type->is_atomic() ) { 342 mangleName += Encoding::qualifiers.at( ast::CV::Atomic);703 mangleName += Encoding::qualifiers.at(Type::Atomic); 343 704 } // if 344 705 } 345 706 if ( type->is_mutex() ) { 346 mangleName += Encoding::qualifiers.at( ast::CV::Mutex);707 mangleName += Encoding::qualifiers.at(Type::Mutex); 347 708 } // if 348 709 if ( inFunctionType ) { -
src/SymTab/Mangler.h
rfc12f05 r0030b508 22 22 23 23 #include "AST/Bitfield.hpp" 24 #include "SynTree/SynTree.h" // for Types 25 #include "SynTree/Visitor.h" // for Visitor, maybeAccept 24 26 25 27 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling … … 33 35 class Node; 34 36 } 37 namespace ResolvExpr { 38 class TypeEnvironment; 39 } 35 40 36 41 namespace SymTab { 37 42 namespace Mangler { 43 /// Mangle syntax tree object; primary interface to clients 44 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true ); 45 46 /// Mangle a type name; secondary interface 47 std::string mangleType( const Type * ty ); 48 /// Mangle ignoring generic type parameters 49 std::string mangleConcrete( const Type * ty ); 50 38 51 namespace Encoding { 39 52 extern const std::string manglePrefix; -
src/SymTab/ManglerCommon.cc
rfc12f05 r0030b508 15 15 16 16 #include "Mangler.h" 17 18 #include "AST/Decl.hpp" 19 #include "AST/Type.hpp" 17 #include "SynTree/Type.h" 18 #include "SynTree/Declaration.h" 20 19 21 20 namespace SymTab { … … 40 39 // - "Di" char32_t 41 40 // - "Ds" char16_t 42 const std::string basicTypes[ ast::BasicType::NUMBER_OF_BASIC_TYPES] = {41 const std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = { 43 42 "b", // _Bool 44 43 "c", // char … … 80 79 // GENERATED END 81 80 static_assert( 82 sizeof(basicTypes)/sizeof(basicTypes[0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES,81 sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES, 83 82 "Each basic type kind should have a corresponding mangler letter" 84 83 ); 85 84 86 85 const std::map<int, std::string> qualifiers = { 87 { ast::CV::Const, "K" },88 { ast::CV::Volatile, "V" },89 { ast::CV::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA90 { ast::CV::Mutex, "X" },86 { Type::Const, "K" }, 87 { Type::Volatile, "V" }, 88 { Type::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA 89 { Type::Mutex, "X" }, 91 90 }; 92 91 … … 112 111 }; 113 112 static_assert( 114 sizeof(typeVariables) / sizeof(typeVariables[0]) == ast::TypeDecl::NUMBER_OF_KINDS,113 sizeof(typeVariables) / sizeof(typeVariables[0]) == TypeDecl::NUMBER_OF_KINDS, 115 114 "Each type variable kind should have a corresponding mangler prefix" 116 115 ); -
src/SymTab/demangler.cc
rfc12f05 r0030b508 2 2 #include <iostream> 3 3 #include <fstream> 4 using namespace std; 4 5 5 void demangleAndPrint(const std::string & mangleName) {6 void f(const std::string & mangleName) { 6 7 char * demangleName = cforall_demangle(mangleName.c_str(), 0); 7 std::cout << mangleName << " => " << demangleName << std::endl;8 cout << mangleName << " => " << std::flush << demangleName << endl; 8 9 free(demangleName); 9 10 } 10 11 11 int main(int argc, char * argv[]) { 12 char const * fileName = (1 < argc) ? argv[1] : "in-demangle.txt"; 13 std::ifstream in(fileName); 14 12 int main() { 13 ifstream in("in-demangle.txt"); 15 14 std::string line; 16 while (std::getline(in, line)) { 17 if (line.empty()) { 18 std::cout << "=================================" << std::endl; 19 } else if (line[0] == '#') { 20 continue; 21 } else { 22 demangleAndPrint(line); 23 } 15 while (getline(in, line)) { 16 if (line.empty()) { cout << "=================================" << endl; continue; } 17 else if (line[0] == '#') continue; 18 f(line); 24 19 } 25 20 } -
src/SymTab/module.mk
rfc12f05 r0030b508 16 16 17 17 SRC_SYMTAB = \ 18 SymTab/Autogen.cc \ 19 SymTab/Autogen.h \ 18 20 SymTab/FixFunction.cc \ 19 21 SymTab/FixFunction.h \ 20 22 SymTab/GenImplicitCall.cpp \ 21 23 SymTab/GenImplicitCall.hpp \ 24 SymTab/Indexer.cc \ 25 SymTab/Indexer.h \ 22 26 SymTab/Mangler.cc \ 23 27 SymTab/ManglerCommon.cc \ 24 SymTab/Mangler.h 28 SymTab/Mangler.h \ 29 SymTab/ValidateType.cc \ 30 SymTab/ValidateType.h 25 31 26 SRC += $(SRC_SYMTAB) 32 SRC += $(SRC_SYMTAB) \ 33 SymTab/Validate.cc \ 34 SymTab/Validate.h 27 35 28 36 SRCDEMANGLE += $(SRC_SYMTAB) \ -
src/Tuples/Explode.cc
rfc12f05 r0030b508 15 15 16 16 #include "Explode.h" 17 #include <list> // for list 17 18 18 19 #include "AST/Pass.hpp" // for Pass 20 #include "SynTree/Mutator.h" // for Mutator 21 #include "Common/PassVisitor.h" // for PassVisitor 19 22 20 23 namespace Tuples { 24 namespace { 25 // remove one level of reference from a reference type -- may be useful elsewhere. 26 Type * getReferenceBase( Type * t ) { 27 if ( ReferenceType * refType = dynamic_cast<ReferenceType *>( t ) ) { 28 return refType->get_base(); 29 } else { 30 // for the moment, I want to know immediately if a non-reference type is ever passed in here. 31 assertf( false, "getReferenceBase for non-ref: %s", toString( refType ).c_str() ); 32 return nullptr; 33 } 34 } 35 36 struct CastExploder { 37 bool castAdded = false; 38 bool foundUniqueExpr = false; 39 Expression * applyCast( Expression * expr, bool first = true ) { 40 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ){ 41 foundUniqueExpr = true; 42 std::list< Expression * > exprs; 43 for ( Expression *& expr : tupleExpr->get_exprs() ) { 44 // move cast into tuple exprs 45 exprs.push_back( applyCast( expr, false ) ); 46 } 47 // want the top-level expression to be cast to reference type, but not nested 48 // tuple expressions 49 if ( first ) { 50 castAdded = true; 51 Expression * tupleExpr = new TupleExpr( exprs ); 52 return new CastExpr( tupleExpr, new ReferenceType( Type::Qualifiers(), tupleExpr->result->clone() ) ); 53 } else { 54 return new TupleExpr( exprs ); 55 } 56 } 57 if ( dynamic_cast<ReferenceType*>( expr->result ) ) { 58 // don't need to cast reference type to another reference type 59 return expr->clone(); 60 } else { 61 // anything else should be cast to reference as normal 62 castAdded = true; 63 return new CastExpr( expr->clone(), new ReferenceType( Type::Qualifiers(), expr->result->clone() ) ); 64 } 65 } 66 67 Expression * postmutate( UniqueExpr * uniqueExpr ) { 68 // move cast into unique expr so that the unique expr has type T& rather than 69 // type T. In particular, this transformation helps with generating the 70 // correct code for reference-cast member tuple expressions, since the result 71 // should now be a tuple of references rather than a reference to a tuple. 72 // Still, this code is a bit awkward, and could use some improvement. 73 UniqueExpr * newUniqueExpr = new UniqueExpr( applyCast( uniqueExpr->get_expr() ), uniqueExpr->get_id() ); 74 delete uniqueExpr; 75 if ( castAdded ) { 76 // if a cast was added by applyCast, then unique expr now has one more layer of reference 77 // than it had coming into this function. To ensure types still match correctly, need to cast 78 // to reference base so that outer expressions are still correct. 79 castAdded = false; 80 Type * toType = getReferenceBase( newUniqueExpr->result ); 81 return new CastExpr( newUniqueExpr, toType->clone() ); 82 } 83 return newUniqueExpr; 84 } 85 86 87 Expression * postmutate( TupleIndexExpr * tupleExpr ) { 88 // tuple index expr needs to be rebuilt to ensure that the type of the 89 // field is consistent with the type of the tuple expr, since the field 90 // may have changed from type T to T&. 91 Expression * expr = tupleExpr->get_tuple(); 92 tupleExpr->set_tuple( nullptr ); 93 TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() ); 94 delete tupleExpr; 95 return ret; 96 } 97 }; 98 } // namespace 99 100 Expression * distributeReference( Expression * expr ) { 101 PassVisitor<CastExploder> exploder; 102 expr = expr->acceptMutator( exploder ); 103 if ( ! exploder.pass.foundUniqueExpr ) { 104 // if a UniqueExpr was found, then the cast has already been added inside the UniqueExpr as appropriate 105 expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), expr->result->clone() ) ); 106 } 107 return expr; 108 } 21 109 22 110 namespace { -
src/Tuples/Explode.h
rfc12f05 r0030b508 20 20 21 21 #include "AST/Expr.hpp" 22 #include "ResolvExpr/Alternative.h" // for Alternative, AltList 22 23 #include "ResolvExpr/Candidate.hpp" // for Candidate, CandidateList 24 #include "ResolvExpr/ExplodedActual.h" // for ExplodedActual 23 25 #include "ResolvExpr/ExplodedArg.hpp" // for ExplodedArg 26 #include "SynTree/Expression.h" // for Expression, UniqueExpr, AddressExpr 27 #include "SynTree/Type.h" // for TupleType, Type 24 28 #include "Tuples.h" // for maybeImpure 25 29 … … 28 32 } 29 33 34 namespace SymTab { 35 class Indexer; 36 } // namespace SymTab 37 30 38 namespace Tuples { 39 Expression * distributeReference( Expression * ); 40 41 static inline CastExpr * isReferenceCast( Expression * expr ) { 42 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) { 43 if ( dynamic_cast< ReferenceType * >( castExpr->result ) ) { 44 return castExpr; 45 } 46 } 47 return nullptr; 48 } 49 50 /// Append alternative to an OutputIterator of Alternatives 51 template<typename OutputIterator> 52 void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env, 53 const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need, 54 const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) { 55 *out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost }; 56 } 57 58 /// Append alternative to an ExplodedActual 59 static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr, 60 const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&, 61 const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) { 62 ea.exprs.emplace_back( expr ); 63 /// xxx -- merge environment, openVars, need, cost? 64 } 65 66 /// helper function used by explode 67 template< typename Output > 68 void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt, 69 const SymTab::Indexer & indexer, Output&& out, bool isTupleAssign ) { 70 if ( isTupleAssign ) { 71 // tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components 72 if ( CastExpr * castExpr = isReferenceCast( expr ) ) { 73 ResolvExpr::AltList alts; 74 explodeUnique( 75 castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign ); 76 for ( ResolvExpr::Alternative & alt : alts ) { 77 // distribute reference cast over all components 78 append( std::forward<Output>(out), distributeReference( alt.release_expr() ), 79 alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost ); 80 } 81 // in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives) 82 return; 83 } 84 } 85 Type * res = expr->get_result()->stripReferences(); 86 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) { 87 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) { 88 // can open tuple expr and dump its exploded components 89 for ( Expression * expr : tupleExpr->get_exprs() ) { 90 explodeUnique( expr, alt, indexer, std::forward<Output>(out), isTupleAssign ); 91 } 92 } else { 93 // tuple type, but not tuple expr - recursively index into its components. 94 // if expr type is reference, convert to value type 95 Expression * arg = expr->clone(); 96 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 97 // expressions which may contain side effects require a single unique instance of the expression. 98 arg = new UniqueExpr( arg ); 99 } 100 // cast reference to value type to facilitate further explosion 101 if ( dynamic_cast<ReferenceType *>( arg->get_result() ) ) { 102 arg = new CastExpr( arg, tupleType->clone() ); 103 } 104 for ( unsigned int i = 0; i < tupleType->size(); i++ ) { 105 TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i ); 106 explodeUnique( idx, alt, indexer, std::forward<Output>(out), isTupleAssign ); 107 delete idx; 108 } 109 delete arg; 110 } 111 } else { 112 // atomic (non-tuple) type - output a clone of the expression in a new alternative 113 append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need, 114 alt.cost, alt.cvtCost ); 115 } 116 } 117 118 /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type 119 template< typename Output > 120 void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer, 121 Output&& out, bool isTupleAssign = false ) { 122 explodeUnique( alt.expr, alt, indexer, std::forward<Output>(out), isTupleAssign ); 123 } 124 125 // explode list of alternatives 126 template< typename AltIterator, typename Output > 127 void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer, 128 Output&& out, bool isTupleAssign = false ) { 129 for ( ; altBegin != altEnd; ++altBegin ) { 130 explode( *altBegin, indexer, std::forward<Output>(out), isTupleAssign ); 131 } 132 } 133 134 template< typename Output > 135 void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, Output&& out, 136 bool isTupleAssign = false ) { 137 explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign ); 138 } 31 139 32 140 const ast::Expr * distributeReference( const ast::Expr * ); -
src/Tuples/TupleAssignment.cc
rfc12f05 r0030b508 28 28 #include "AST/TypeEnvironment.hpp" 29 29 #include "CodeGen/OperatorTable.h" 30 #include "Common/PassVisitor.h" 30 31 #include "Common/UniqueName.h" // for UniqueName 31 32 #include "Common/utility.h" // for splice, zipWith … … 33 34 #include "InitTweak/GenInit.h" // for genCtorInit 34 35 #include "InitTweak/InitTweak.h" // for getPointerBase, isAssignment 36 #include "ResolvExpr/Alternative.h" // for AltList, Alternative 37 #include "ResolvExpr/AlternativeFinder.h" // for AlternativeFinder, simpleC... 35 38 #include "ResolvExpr/Cost.h" // for Cost 36 39 #include "ResolvExpr/Resolver.h" // for resolveCtorInit 40 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment 37 41 #include "ResolvExpr/typeops.h" // for combos 42 #include "SynTree/LinkageSpec.h" // for Cforall 43 #include "SynTree/Declaration.h" // for ObjectDecl 44 #include "SynTree/Expression.h" // for Expression, CastExpr, Name... 45 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit 46 #include "SynTree/Statement.h" // for ExprStmt 47 #include "SynTree/Type.h" // for Type, Type::Qualifiers 48 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution 49 #include "SynTree/Visitor.h" // for Visitor 38 50 39 51 #if 0 … … 44 56 45 57 namespace Tuples { 58 class TupleAssignSpotter_old { 59 public: 60 // dispatcher for Tuple (multiple and mass) assignment operations 61 TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & ); 62 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args ); 63 64 private: 65 void match(); 66 67 struct Matcher { 68 public: 69 Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs, 70 const ResolvExpr::AltList& rhs ); 71 virtual ~Matcher() {} 72 73 virtual void match( std::list< Expression * > &out ) = 0; 74 ObjectDecl * newObject( UniqueName & namer, Expression * expr ); 75 76 void combineState( const ResolvExpr::Alternative& alt ) { 77 compositeEnv.simpleCombine( alt.env ); 78 ResolvExpr::mergeOpenVars( openVars, alt.openVars ); 79 cloneAll( alt.need, need ); 80 } 81 82 void combineState( const ResolvExpr::AltList& alts ) { 83 for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); } 84 } 85 86 ResolvExpr::AltList lhs, rhs; 87 TupleAssignSpotter_old &spotter; 88 ResolvExpr::Cost baseCost; 89 std::list< ObjectDecl * > tmpDecls; 90 ResolvExpr::TypeEnvironment compositeEnv; 91 ResolvExpr::OpenVarSet openVars; 92 ResolvExpr::AssertionSet need; 93 }; 94 95 struct MassAssignMatcher : public Matcher { 96 public: 97 MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs, 98 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {} 99 virtual void match( std::list< Expression * > &out ); 100 }; 101 102 struct MultipleAssignMatcher : public Matcher { 103 public: 104 MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs, 105 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {} 106 virtual void match( std::list< Expression * > &out ); 107 }; 108 109 ResolvExpr::AlternativeFinder ¤tFinder; 110 std::string fname; 111 std::unique_ptr< Matcher > matcher; 112 }; 113 114 /// true if expr is an expression of tuple type 115 bool isTuple( Expression *expr ) { 116 if ( ! expr ) return false; 117 assert( expr->result ); 118 return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() ); 119 } 120 121 template< typename AltIter > 122 bool isMultAssign( AltIter begin, AltIter end ) { 123 // multiple assignment if more than one alternative in the range or if 124 // the alternative is a tuple 125 if ( begin == end ) return false; 126 if ( isTuple( begin->expr ) ) return true; 127 return ++begin != end; 128 } 129 130 bool refToTuple( Expression *expr ) { 131 assert( expr->get_result() ); 132 // also check for function returning tuple of reference types 133 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) { 134 return refToTuple( castExpr->get_arg() ); 135 } else { 136 return isTuple( expr ); 137 } 138 return false; 139 } 140 141 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, 142 std::vector<ResolvExpr::AlternativeFinder> &args ) { 143 TupleAssignSpotter_old spotter( currentFinder ); 144 spotter.spot( expr, args ); 145 } 146 147 TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f ) 148 : currentFinder(f) {} 149 150 void TupleAssignSpotter_old::spot( UntypedExpr * expr, 151 std::vector<ResolvExpr::AlternativeFinder> &args ) { 152 if ( NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) { 153 if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) { 154 fname = op->get_name(); 155 156 // AlternativeFinder will naturally handle this case case, if it's legal 157 if ( args.size() == 0 ) return; 158 159 // if an assignment only takes 1 argument, that's odd, but maybe someone wrote 160 // the function, in which case AlternativeFinder will handle it normally 161 if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return; 162 163 // look over all possible left-hand-sides 164 for ( ResolvExpr::Alternative& lhsAlt : args[0] ) { 165 // skip non-tuple LHS 166 if ( ! refToTuple(lhsAlt.expr) ) continue; 167 168 // explode is aware of casts - ensure every LHS expression is sent into explode 169 // with a reference cast 170 // xxx - this seems to change the alternatives before the normal 171 // AlternativeFinder flow; maybe this is desired? 172 if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) { 173 lhsAlt.expr = new CastExpr( lhsAlt.expr, 174 new ReferenceType( Type::Qualifiers(), 175 lhsAlt.expr->result->clone() ) ); 176 } 177 178 // explode the LHS so that each field of a tuple-valued-expr is assigned 179 ResolvExpr::AltList lhs; 180 explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true ); 181 for ( ResolvExpr::Alternative& alt : lhs ) { 182 // each LHS value must be a reference - some come in with a cast expression, 183 // if not just cast to reference here 184 if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) { 185 alt.expr = new CastExpr( alt.expr, 186 new ReferenceType( Type::Qualifiers(), 187 alt.expr->get_result()->clone() ) ); 188 } 189 } 190 191 if ( args.size() == 1 ) { 192 // mass default-initialization/destruction 193 ResolvExpr::AltList rhs{}; 194 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) ); 195 match(); 196 } else if ( args.size() > 2 ) { 197 // expand all possible RHS possibilities 198 // TODO build iterative version of this instead of using combos 199 std::vector< ResolvExpr::AltList > rhsAlts; 200 combos( std::next(args.begin(), 1), args.end(), 201 std::back_inserter( rhsAlts ) ); 202 for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) { 203 // multiple assignment 204 ResolvExpr::AltList rhs; 205 explode( rhsAlt, currentFinder.get_indexer(), 206 std::back_inserter(rhs), true ); 207 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) ); 208 match(); 209 } 210 } else { 211 for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) { 212 ResolvExpr::AltList rhs; 213 if ( isTuple(rhsAlt.expr) ) { 214 // multiple assignment 215 explode( rhsAlt, currentFinder.get_indexer(), 216 std::back_inserter(rhs), true ); 217 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) ); 218 } else { 219 // mass assignment 220 rhs.push_back( rhsAlt ); 221 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) ); 222 } 223 match(); 224 } 225 } 226 } 227 } 228 } 229 } 230 231 void TupleAssignSpotter_old::match() { 232 assert ( matcher != 0 ); 233 234 std::list< Expression * > new_assigns; 235 matcher->match( new_assigns ); 236 237 if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) { 238 // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty. 239 // if not the empty tuple case, return early so that no new alternatives are generated. 240 if ( new_assigns.empty() ) return; 241 } 242 ResolvExpr::AltList current; 243 // now resolve new assignments 244 for ( std::list< Expression * >::iterator i = new_assigns.begin(); 245 i != new_assigns.end(); ++i ) { 246 PRINT( 247 std::cerr << "== resolving tuple assign ==" << std::endl; 248 std::cerr << *i << std::endl; 249 ) 250 251 ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(), 252 matcher->compositeEnv }; 253 254 try { 255 finder.findWithAdjustment(*i); 256 } catch (...) { 257 return; // no match should not mean failure, it just means this particular tuple assignment isn't valid 258 } 259 // prune expressions that don't coincide with 260 ResolvExpr::AltList alts = finder.get_alternatives(); 261 assert( alts.size() == 1 ); 262 assert( alts.front().expr != 0 ); 263 current.push_back( alts.front() ); 264 } 265 266 // extract expressions from the assignment alternatives to produce a list of assignments 267 // that together form a single alternative 268 std::list< Expression *> solved_assigns; 269 for ( ResolvExpr::Alternative & alt : current ) { 270 solved_assigns.push_back( alt.expr->clone() ); 271 matcher->combineState( alt ); 272 } 273 274 // xxx -- was push_front 275 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{ 276 new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv, 277 matcher->openVars, 278 ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ), 279 ResolvExpr::sumCost( current ) + matcher->baseCost } ); 280 } 281 282 TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter, 283 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs ) 284 : lhs(lhs), rhs(rhs), spotter(spotter), 285 baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) { 286 combineState( lhs ); 287 combineState( rhs ); 288 } 289 290 UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) { 291 assert( left ); 292 std::list< Expression * > args; 293 args.push_back( new VariableExpr( left ) ); 294 // args.push_back( new AddressExpr( new VariableExpr( left ) ) ); 295 if ( right ) args.push_back( new VariableExpr( right ) ); 296 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) { 297 args.front() = new AddressExpr( args.front() ); 298 if ( right ) args.back() = new AddressExpr( args.back() ); 299 return new UntypedExpr( new NameExpr( "?=?" ), args ); 300 } else { 301 return new UntypedExpr( new NameExpr( fname ), args ); 302 } 303 } 304 305 // removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator, and adds the bindings to the compositeEnv 306 // xxx - maybe this should happen in alternative finder for every StmtExpr? 307 struct EnvRemover { 308 void previsit( ExprStmt * stmt ) { 309 assert( compositeEnv ); 310 if ( stmt->expr->env ) { 311 compositeEnv->add( *stmt->expr->env ); 312 delete stmt->expr->env; 313 stmt->expr->env = nullptr; 314 } 315 } 316 317 ResolvExpr::TypeEnvironment * compositeEnv = nullptr; 318 }; 319 320 ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) { 321 assert( expr->result && ! expr->get_result()->isVoid() ); 322 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) ); 323 // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient. 324 if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) { 325 ConstructorInit * ctorInit = InitTweak::genCtorInit( ret ); 326 ret->init = ctorInit; 327 ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object 328 PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs 329 rm.pass.compositeEnv = &compositeEnv; 330 ctorInit->accept( rm ); 331 } 332 PRINT( std::cerr << "new object: " << ret << std::endl; ) 333 return ret; 334 } 335 336 void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) { 337 static UniqueName lhsNamer( "__massassign_L" ); 338 static UniqueName rhsNamer( "__massassign_R" ); 339 // empty tuple case falls into this matcher, hence the second part of the assert 340 assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) ); 341 342 // xxx - may need to split this up into multiple declarations, because potential conversion to references 343 // probably should not reference local variable - see MultipleAssignMatcher::match 344 ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr; 345 for ( ResolvExpr::Alternative & lhsAlt : lhs ) { 346 // create a temporary object for each value in the lhs and create a call involving the rhs 347 ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr ); 348 out.push_back( createFunc( spotter.fname, ltmp, rtmp ) ); 349 tmpDecls.push_back( ltmp ); 350 } 351 if ( rtmp ) tmpDecls.push_back( rtmp ); 352 } 353 354 void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) { 355 static UniqueName lhsNamer( "__multassign_L" ); 356 static UniqueName rhsNamer( "__multassign_R" ); 357 358 if ( lhs.size() == rhs.size() ) { 359 // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls 360 std::list< ObjectDecl * > ltmp; 361 std::list< ObjectDecl * > rtmp; 362 for ( auto p : group_iterate( lhs, rhs ) ) { 363 ResolvExpr::Alternative & lhsAlt = std::get<0>(p); 364 ResolvExpr::Alternative & rhsAlt = std::get<1>(p); 365 // convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc. 366 ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result ); 367 rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() ); 368 ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr ); 369 ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr ); 370 out.push_back( createFunc(spotter.fname, lobj, robj) ); 371 ltmp.push_back( lobj ); 372 rtmp.push_back( robj ); 373 374 // resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment 375 ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv }; 376 finder.findWithAdjustment( rhsAlt.expr ); 377 assert( finder.get_alternatives().size() == 1 ); 378 compositeEnv = std::move( finder.get_alternatives().front().env ); 379 } 380 tmpDecls.splice( tmpDecls.end(), ltmp ); 381 tmpDecls.splice( tmpDecls.end(), rtmp ); 382 } 383 } 46 384 47 385 namespace { -
src/Tuples/TupleExpansion.cc
rfc12f05 r0030b508 23 23 #include "AST/Node.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd, WithGu... 25 26 #include "Common/ScopedMap.h" // for ScopedMap 26 27 #include "Common/utility.h" // for CodeLocation 27 28 #include "InitTweak/InitTweak.h" // for getFunction 29 #include "SynTree/LinkageSpec.h" // for Spec, C, Intrinsic 30 #include "SynTree/Constant.h" // for Constant 31 #include "SynTree/Declaration.h" // for StructDecl, DeclarationWithType 32 #include "SynTree/Expression.h" // for UntypedMemberExpr, Expression, Uniq... 33 #include "SynTree/Label.h" // for operator==, Label 34 #include "SynTree/Mutator.h" // for Mutator 35 #include "SynTree/Type.h" // for Type, Type::Qualifiers, TupleType 36 #include "SynTree/Visitor.h" // for Visitor 28 37 #include "Tuples.h" 29 38 39 class CompoundStmt; 40 class TypeSubstitution; 41 30 42 namespace Tuples { 31 43 namespace { 44 struct MemberTupleExpander final : public WithShortCircuiting, public WithVisitorRef<MemberTupleExpander> { 45 void premutate( UntypedMemberExpr * ) { visit_children = false; } 46 Expression * postmutate( UntypedMemberExpr * memberExpr ); 47 }; 48 49 struct UniqueExprExpander final : public WithDeclsToAdd { 50 Expression * postmutate( UniqueExpr * unqExpr ); 51 52 std::map< int, Expression * > decls; // not vector, because order added may not be increasing order 53 54 ~UniqueExprExpander() { 55 for ( std::pair<const int, Expression *> & p : decls ) { 56 delete p.second; 57 } 58 } 59 }; 60 61 struct TupleAssignExpander { 62 Expression * postmutate( TupleAssignExpr * tupleExpr ); 63 }; 64 65 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution { 66 Type * postmutate( TupleType * tupleType ); 67 68 void premutate( CompoundStmt * ) { 69 GuardScope( typeMap ); 70 } 71 private: 72 ScopedMap< int, StructDecl * > typeMap; 73 }; 74 75 struct TupleIndexExpander { 76 Expression * postmutate( TupleIndexExpr * tupleExpr ); 77 }; 78 79 struct TupleExprExpander final { 80 Expression * postmutate( TupleExpr * tupleExpr ); 81 }; 82 } 83 84 void expandMemberTuples( std::list< Declaration * > & translationUnit ) { 85 PassVisitor<MemberTupleExpander> expander; 86 mutateAll( translationUnit, expander ); 87 } 88 89 void expandUniqueExpr( std::list< Declaration * > & translationUnit ) { 90 PassVisitor<UniqueExprExpander> unqExpander; 91 mutateAll( translationUnit, unqExpander ); 92 } 93 94 void expandTuples( std::list< Declaration * > & translationUnit ) { 95 PassVisitor<TupleAssignExpander> assnExpander; 96 mutateAll( translationUnit, assnExpander ); 97 98 PassVisitor<TupleTypeReplacer> replacer; 99 mutateAll( translationUnit, replacer ); 100 101 PassVisitor<TupleIndexExpander> idxExpander; 102 mutateAll( translationUnit, idxExpander ); 103 104 PassVisitor<TupleExprExpander> exprExpander; 105 mutateAll( translationUnit, exprExpander ); 106 } 107 108 namespace { 109 /// given a expression representing the member and an expression representing the aggregate, 110 /// reconstructs a flattened UntypedMemberExpr with the right precedence 111 Expression * reconstructMemberExpr( Expression * member, Expression * aggr, CodeLocation & loc ) { 112 if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) { 113 // construct a new UntypedMemberExpr with the correct structure , and recursively 114 // expand that member expression. 115 PassVisitor<MemberTupleExpander> expander; 116 UntypedMemberExpr * inner = new UntypedMemberExpr( memberExpr->aggregate, aggr->clone() ); 117 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member, inner ); 118 inner->location = newMemberExpr->location = loc; 119 memberExpr->member = nullptr; 120 memberExpr->aggregate = nullptr; 121 delete memberExpr; 122 return newMemberExpr->acceptMutator( expander ); 123 } else { 124 // not a member expression, so there is nothing to do but attach and return 125 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( member, aggr->clone() ); 126 newMemberExpr->location = loc; 127 return newMemberExpr; 128 } 129 } 130 } 131 132 Expression * MemberTupleExpander::postmutate( UntypedMemberExpr * memberExpr ) { 133 if ( UntypedTupleExpr * tupleExpr = dynamic_cast< UntypedTupleExpr * > ( memberExpr->member ) ) { 134 Expression * aggr = memberExpr->aggregate->clone()->acceptMutator( *visitor ); 135 // aggregate expressions which might be impure must be wrapped in unique expressions 136 if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new UniqueExpr( aggr ); 137 for ( Expression *& expr : tupleExpr->exprs ) { 138 expr = reconstructMemberExpr( expr, aggr, memberExpr->location ); 139 expr->location = memberExpr->location; 140 } 141 delete aggr; 142 tupleExpr->location = memberExpr->location; 143 return tupleExpr; 144 } else { 145 // there may be a tuple expr buried in the aggregate 146 // xxx - this is a memory leak 147 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member->clone(), memberExpr->aggregate->acceptMutator( *visitor ) ); 148 newMemberExpr->location = memberExpr->location; 149 return newMemberExpr; 150 } 151 } 152 153 Expression * UniqueExprExpander::postmutate( UniqueExpr * unqExpr ) { 154 const int id = unqExpr->get_id(); 155 156 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID, 157 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable. 158 if ( ! decls.count( id ) ) { 159 Expression * assignUnq; 160 Expression * var = unqExpr->get_var(); 161 if ( unqExpr->get_object() ) { 162 // an object was generated to represent this unique expression -- it should be added to the list of declarations now 163 declsToAddBefore.push_back( unqExpr->get_object() ); 164 unqExpr->set_object( nullptr ); 165 // steal the expr from the unqExpr 166 assignUnq = UntypedExpr::createAssign( unqExpr->get_var()->clone(), unqExpr->get_expr() ); 167 unqExpr->set_expr( nullptr ); 168 } else { 169 // steal the already generated assignment to var from the unqExpr - this has been generated by FixInit 170 Expression * expr = unqExpr->get_expr(); 171 CommaExpr * commaExpr = strict_dynamic_cast< CommaExpr * >( expr ); 172 assignUnq = commaExpr->get_arg1(); 173 commaExpr->set_arg1( nullptr ); 174 } 175 ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ), 176 new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) ); 177 declsToAddBefore.push_back( finished ); 178 // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N)) 179 // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code. 180 Expression * assignFinished = UntypedExpr::createAssign( new VariableExpr(finished), new ConstantExpr( Constant::from_int( 1 ) ) ); 181 ConditionalExpr * condExpr = new ConditionalExpr( new VariableExpr( finished ), var->clone(), 182 new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) ); 183 condExpr->set_result( var->get_result()->clone() ); 184 condExpr->set_env( maybeClone( unqExpr->get_env() ) ); 185 decls[id] = condExpr; 186 } 187 delete unqExpr; 188 return decls[id]->clone(); 189 } 190 191 Expression * TupleAssignExpander::postmutate( TupleAssignExpr * assnExpr ) { 192 StmtExpr * ret = assnExpr->get_stmtExpr(); 193 assnExpr->set_stmtExpr( nullptr ); 194 // move env to StmtExpr 195 ret->set_env( assnExpr->get_env() ); 196 assnExpr->set_env( nullptr ); 197 delete assnExpr; 198 return ret; 199 } 200 201 Type * TupleTypeReplacer::postmutate( TupleType * tupleType ) { 202 unsigned tupleSize = tupleType->size(); 203 if ( ! typeMap.count( tupleSize ) ) { 204 // generate struct type to replace tuple type based on the number of components in the tuple 205 StructDecl * decl = new StructDecl( toString( "_tuple", tupleSize, "_" ) ); 206 decl->location = tupleType->location; 207 decl->set_body( true ); 208 for ( size_t i = 0; i < tupleSize; ++i ) { 209 TypeDecl * tyParam = new TypeDecl( toString( "tuple_param_", tupleSize, "_", i ), Type::StorageClasses(), nullptr, TypeDecl::Dtype, true ); 210 decl->get_members().push_back( new ObjectDecl( toString("field_", i ), Type::StorageClasses(), LinkageSpec::C, nullptr, new TypeInstType( Type::Qualifiers(), tyParam->get_name(), tyParam ), nullptr ) ); 211 decl->get_parameters().push_back( tyParam ); 212 } 213 if ( tupleSize == 0 ) { 214 // empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created. 215 decl->get_members().push_back( new ObjectDecl( "dummy", Type::StorageClasses(), LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) ); 216 } 217 typeMap[tupleSize] = decl; 218 declsToAddBefore.push_back( decl ); 219 } 220 Type::Qualifiers qualifiers = tupleType->get_qualifiers(); 221 222 StructDecl * decl = typeMap[tupleSize]; 223 StructInstType * newType = new StructInstType( qualifiers, decl ); 224 for ( auto p : group_iterate( tupleType->get_types(), decl->get_parameters() ) ) { 225 Type * t = std::get<0>(p); 226 newType->get_parameters().push_back( new TypeExpr( t->clone() ) ); 227 } 228 delete tupleType; 229 return newType; 230 } 231 232 Expression * TupleIndexExpander::postmutate( TupleIndexExpr * tupleExpr ) { 233 Expression * tuple = tupleExpr->tuple; 234 assert( tuple ); 235 tupleExpr->tuple = nullptr; 236 unsigned int idx = tupleExpr->index; 237 TypeSubstitution * env = tupleExpr->env; 238 tupleExpr->env = nullptr; 239 delete tupleExpr; 240 241 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( tuple ) ) { 242 if ( ! maybeImpureIgnoreUnique( tupleExpr ) ) { 243 // optimization: definitely pure tuple expr => can reduce to the only relevant component. 244 assert( tupleExpr->exprs.size() > idx ); 245 Expression *& expr = *std::next(tupleExpr->exprs.begin(), idx); 246 Expression * ret = expr; 247 ret->env = env; 248 expr = nullptr; // remove from list so it can safely be deleted 249 delete tupleExpr; 250 return ret; 251 } 252 } 253 254 StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->result ); 255 StructDecl * structDecl = type->baseStruct; 256 assert( structDecl->members.size() > idx ); 257 Declaration * member = *std::next(structDecl->members.begin(), idx); 258 MemberExpr * memExpr = new MemberExpr( strict_dynamic_cast< DeclarationWithType * >( member ), tuple ); 259 memExpr->env = env; 260 return memExpr; 261 } 262 263 Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs, TypeSubstitution * env ) { 264 if ( result->isVoid() ) { 265 // void result - don't need to produce a value for cascading - just output a chain of comma exprs 266 assert( ! exprs.empty() ); 267 std::list< Expression * >::const_iterator iter = exprs.begin(); 268 Expression * expr = new CastExpr( *iter++ ); 269 for ( ; iter != exprs.end(); ++iter ) { 270 expr = new CommaExpr( expr, new CastExpr( *iter ) ); 271 } 272 expr->set_env( env ); 273 return expr; 274 } else { 275 // typed tuple expression - produce a compound literal which performs each of the expressions 276 // as a distinct part of its initializer - the produced compound literal may be used as part of 277 // another expression 278 std::list< Initializer * > inits; 279 for ( Expression * expr : exprs ) { 280 inits.push_back( new SingleInit( expr ) ); 281 } 282 Expression * expr = new CompoundLiteralExpr( result, new ListInit( inits ) ); 283 expr->set_env( env ); 284 return expr; 285 } 286 } 287 288 Expression * TupleExprExpander::postmutate( TupleExpr * tupleExpr ) { 289 Type * result = tupleExpr->get_result(); 290 std::list< Expression * > exprs = tupleExpr->get_exprs(); 291 assert( result ); 292 TypeSubstitution * env = tupleExpr->get_env(); 293 294 // remove data from shell and delete it 295 tupleExpr->set_result( nullptr ); 296 tupleExpr->get_exprs().clear(); 297 tupleExpr->set_env( nullptr ); 298 delete tupleExpr; 299 300 return replaceTupleExpr( result, exprs, env ); 301 } 302 303 Type * makeTupleType( const std::list< Expression * > & exprs ) { 304 // produce the TupleType which aggregates the types of the exprs 305 std::list< Type * > types; 306 Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic | Type::Mutex ); 307 for ( Expression * expr : exprs ) { 308 assert( expr->get_result() ); 309 if ( expr->get_result()->isVoid() ) { 310 // if the type of any expr is void, the type of the entire tuple is void 311 return new VoidType( Type::Qualifiers() ); 312 } 313 Type * type = expr->get_result()->clone(); 314 types.push_back( type ); 315 // the qualifiers on the tuple type are the qualifiers that exist on all component types 316 qualifiers &= type->get_qualifiers(); 317 } // for 318 if ( exprs.empty() ) qualifiers = Type::Qualifiers(); 319 return new TupleType( qualifiers, types ); 320 } 32 321 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) { 33 322 // produce the TupleType which aggregates the types of the exprs … … 52 341 } 53 342 343 TypeInstType * isTtype( Type * type ) { 344 if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( type ) ) { 345 if ( inst->get_baseType() && inst->get_baseType()->get_kind() == TypeDecl::Ttype ) { 346 return inst; 347 } 348 } 349 return nullptr; 350 } 351 352 const TypeInstType * isTtype( const Type * type ) { 353 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type ) ) { 354 if ( inst->baseType && inst->baseType->kind == TypeDecl::Ttype ) { 355 return inst; 356 } 357 } 358 return nullptr; 359 } 360 54 361 const ast::TypeInstType * isTtype( const ast::Type * type ) { 55 362 if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) { -
src/Tuples/Tuples.cc
rfc12f05 r0030b508 19 19 #include "AST/Inspect.hpp" 20 20 #include "AST/LinkageSpec.hpp" 21 #include "Common/PassVisitor.h" 21 22 #include "InitTweak/InitTweak.h" 22 23 … … 24 25 25 26 namespace { 27 /// Checks if impurity (read: side-effects) may exist in a piece of code. 28 /// Currently gives a very crude approximation, wherein any function 29 /// call expression means the code may be impure. 30 struct ImpurityDetector_old : public WithShortCircuiting { 31 bool const ignoreUnique; 32 bool maybeImpure; 33 34 ImpurityDetector_old( bool ignoreUnique ) : 35 ignoreUnique( ignoreUnique ), maybeImpure( false ) 36 {} 37 38 void previsit( const ApplicationExpr * appExpr ) { 39 visit_children = false; 40 if ( const DeclarationWithType * function = 41 InitTweak::getFunction( appExpr ) ) { 42 if ( function->linkage == LinkageSpec::Intrinsic ) { 43 if ( function->name == "*?" || function->name == "?[?]" ) { 44 // intrinsic dereference, subscript are pure, 45 // but need to recursively look for impurity 46 visit_children = true; 47 return; 48 } 49 } 50 } 51 maybeImpure = true; 52 } 53 54 void previsit( const UntypedExpr * ) { 55 maybeImpure = true; 56 visit_children = false; 57 } 58 59 void previsit( const UniqueExpr * ) { 60 if ( ignoreUnique ) { 61 // bottom out at unique expression. 62 // The existence of a unique expression doesn't change the purity of an expression. 63 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression. 64 visit_children = false; 65 return; 66 } 67 } 68 }; 69 70 bool detectImpurity( const Expression * expr, bool ignoreUnique ) { 71 PassVisitor<ImpurityDetector_old> detector( ignoreUnique ); 72 expr->accept( detector ); 73 return detector.pass.maybeImpure; 74 } 26 75 27 76 /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives … … 61 110 } 62 111 112 bool maybeImpure( const Expression * expr ) { 113 return detectImpurity( expr, false ); 114 } 115 116 bool maybeImpureIgnoreUnique( const Expression * expr ) { 117 return detectImpurity( expr, true ); 118 } 119 63 120 } // namespace Tuples 64 121 -
src/Tuples/Tuples.h
rfc12f05 r0030b508 21 21 #include "AST/Fwd.hpp" 22 22 #include "AST/Node.hpp" 23 #include "SynTree/Expression.h" 24 #include "SynTree/Declaration.h" 25 #include "SynTree/Type.h" 26 27 #include "ResolvExpr/AlternativeFinder.h" 23 28 #include "ResolvExpr/CandidateFinder.hpp" 24 29 25 30 namespace Tuples { 26 31 // TupleAssignment.cc 32 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 33 std::vector< ResolvExpr::AlternativeFinder >& args ); 27 34 void handleTupleAssignment( 28 35 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, … … 31 38 // TupleExpansion.cc 32 39 /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate 40 void expandMemberTuples( std::list< Declaration * > & translationUnit ); 33 41 void expandMemberTuples( ast::TranslationUnit & translationUnit ); 34 42 35 43 /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc. 44 void expandTuples( std::list< Declaration * > & translationUnit ); 36 45 void expandTuples( ast::TranslationUnit & translaionUnit ); 37 46 38 47 /// replaces UniqueExprs with a temporary variable and one call 48 void expandUniqueExpr( std::list< Declaration * > & translationUnit ); 39 49 void expandUniqueExpr( ast::TranslationUnit & translationUnit ); 40 50 41 51 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types 52 Type * makeTupleType( const std::list< Expression * > & exprs ); 42 53 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ); 43 54 44 55 /// returns a TypeInstType if `type` is a ttype, nullptr otherwise 56 TypeInstType * isTtype( Type * type ); 57 const TypeInstType * isTtype( const Type * type ); 45 58 const ast::TypeInstType * isTtype( const ast::Type * type ); 46 59 47 60 /// returns true if the expression may contain side-effects. 61 bool maybeImpure( const Expression * expr ); 48 62 bool maybeImpure( const ast::Expr * expr ); 49 63 50 64 /// Returns true if the expression may contain side-effect, 51 65 /// ignoring the presence of unique expressions. 66 bool maybeImpureIgnoreUnique( const Expression * expr ); 52 67 bool maybeImpureIgnoreUnique( const ast::Expr * expr ); 53 68 } // namespace Tuples -
src/Validate/FindSpecialDecls.h
rfc12f05 r0030b508 16 16 #pragma once 17 17 18 #include <list> // for list 19 20 class Declaration; 21 class FunctionDecl; 22 class StructDecl; 23 class Type; 24 18 25 namespace ast { 19 26 class TranslationUnit; … … 21 28 22 29 namespace Validate { 30 /// size_t type - set when size_t typedef is seen. Useful in a few places, 31 /// such as in determining array dimension type 32 extern Type * SizeType; 33 34 /// intrinsic dereference operator for unqualified types - set when *? function is seen in FindSpecialDeclarations. 35 /// Useful for creating dereference ApplicationExprs without a full resolver pass. 36 extern FunctionDecl * dereferenceOperator; 37 38 /// special built-in functions and data structures necessary for destructor generation 39 extern StructDecl * dtorStruct; 40 extern FunctionDecl * dtorStructDestroy; 41 42 /// find and remember some of the special declarations that are useful for generating code, so that they do not have to be discovered multiple times. 43 void findSpecialDecls( std::list< Declaration * > & translationUnit ); 23 44 24 45 /// Find and remember some of the special declarations that are useful for -
src/Validate/FixReturnTypes.cpp
rfc12f05 r0030b508 19 19 #include "AST/Pass.hpp" 20 20 #include "AST/Type.hpp" 21 #include "CodeGen/CodeGenerator New.hpp"21 #include "CodeGen/CodeGenerator.h" 22 22 #include "ResolvExpr/Unify.h" 23 23 -
src/Validate/module.mk
rfc12f05 r0030b508 16 16 17 17 SRC_VALIDATE = \ 18 Validate/FindSpecialDecls.cc \ 18 19 Validate/FindSpecialDecls.h 19 20 … … 36 37 Validate/GenericParameter.cpp \ 37 38 Validate/GenericParameter.hpp \ 39 Validate/HandleAttributes.cc \ 40 Validate/HandleAttributes.h \ 38 41 Validate/HoistStruct.cpp \ 39 42 Validate/HoistStruct.hpp \ -
src/Virtual/ExpandCasts.cc
rfc12f05 r0030b508 24 24 #include "AST/Expr.hpp" 25 25 #include "AST/Pass.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor 26 27 #include "Common/ScopedMap.h" // for ScopedMap 27 28 #include "Common/SemanticError.h" // for SemanticError 28 29 #include "SymTab/Mangler.h" // for mangleType 30 #include "SynTree/Declaration.h" // for ObjectDecl, StructDecl, FunctionDecl 31 #include "SynTree/Expression.h" // for VirtualCastExpr, CastExpr, Address... 32 #include "SynTree/Mutator.h" // for mutateAll 33 #include "SynTree/Type.h" // for Type, PointerType, StructInstType 34 #include "SynTree/Visitor.h" // for acceptAll 29 35 30 36 namespace Virtual { … … 37 43 } 38 44 45 bool is_type_id_object( const ObjectDecl * objectDecl ) { 46 const std::string & objectName = objectDecl->name; 47 return is_prefix( "__cfatid_", objectName ); 48 } 49 39 50 bool is_type_id_object( const ast::ObjectDecl * decl ) { 40 51 return is_prefix( "__cfatid_", decl->name ); … … 44 55 45 56 /// Maps virtual table types the instance for that type. 57 class VirtualTableMap final { 58 ScopedMap<std::string, ObjectDecl *> vtable_instances; 59 public: 60 void enterScope() { 61 vtable_instances.beginScope(); 62 } 63 void leaveScope() { 64 vtable_instances.endScope(); 65 } 66 67 ObjectDecl * insert( ObjectDecl * vtableDecl ) { 68 std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type ); 69 ObjectDecl *& value = vtable_instances[ mangledName ]; 70 if ( value ) { 71 if ( vtableDecl->storageClasses.is_extern ) { 72 return nullptr; 73 } else if ( ! value->storageClasses.is_extern ) { 74 return value; 75 } 76 } 77 value = vtableDecl; 78 return nullptr; 79 } 80 81 ObjectDecl * lookup( const Type * vtableType ) { 82 std::string const & mangledName = SymTab::Mangler::mangleType( vtableType ); 83 const auto it = vtable_instances.find( mangledName ); 84 return ( vtable_instances.end() == it ) ? nullptr : it->second; 85 } 86 }; 87 88 class VirtualCastCore { 89 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) { 90 Type * type = new StructInstType( 91 Type::Qualifiers( Type::Const ), pvt_decl ); 92 for (int i = 0 ; i < level_of_indirection ; ++i) { 93 type = new PointerType( noQualifiers, type ); 94 } 95 return new CastExpr( expr, type ); 96 } 97 98 public: 99 VirtualCastCore() : 100 indexer(), vcast_decl( nullptr ), pvt_decl( nullptr ) 101 {} 102 103 void premutate( FunctionDecl * functionDecl ); 104 void premutate( StructDecl * structDecl ); 105 void premutate( ObjectDecl * objectDecl ); 106 107 Expression * postmutate( VirtualCastExpr * castExpr ); 108 109 VirtualTableMap indexer; 110 private: 111 FunctionDecl *vcast_decl; 112 StructDecl *pvt_decl; 113 }; 114 115 void VirtualCastCore::premutate( FunctionDecl * functionDecl ) { 116 if ( (! vcast_decl) && 117 functionDecl->get_name() == "__cfavir_virtual_cast" ) { 118 vcast_decl = functionDecl; 119 } 120 } 121 122 void VirtualCastCore::premutate( StructDecl * structDecl ) { 123 if ( pvt_decl || ! structDecl->has_body() ) { 124 return; 125 } else if ( structDecl->get_name() == "__cfavir_type_info" ) { 126 pvt_decl = structDecl; 127 } 128 } 129 130 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) { 131 if ( is_type_id_object( objectDecl ) ) { 132 // Multiple definitions should be fine because of linkonce. 133 indexer.insert( objectDecl ); 134 } 135 } 136 137 /// Better error locations for generated casts. 138 CodeLocation castLocation( const VirtualCastExpr * castExpr ) { 139 if ( castExpr->location.isSet() ) { 140 return castExpr->location; 141 } else if ( castExpr->arg->location.isSet() ) { 142 return castExpr->arg->location; 143 } else if ( castExpr->result->location.isSet() ) { 144 return castExpr->result->location; 145 } else { 146 return CodeLocation(); 147 } 148 } 149 150 [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) { 151 SemanticError( castLocation( castExpr ), message ); 152 } 153 154 /// Get the base type from a pointer or reference. 155 const Type * getBaseType( const Type * type ) { 156 if ( auto target = dynamic_cast<const PointerType *>( type ) ) { 157 return target->base; 158 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) { 159 return target->base; 160 } else { 161 return nullptr; 162 } 163 } 164 165 /* Attempt to follow the "head" field of the structure to get the... 166 * Returns nullptr on error, otherwise owner must free returned node. 167 */ 168 StructInstType * followHeadPointerType( 169 const StructInstType * oldType, 170 const std::string& fieldName, 171 const CodeLocation& errorLocation ) { 172 173 // First section of the function is all about trying to fill this variable in. 174 StructInstType * newType = nullptr; 175 { 176 const StructDecl * oldDecl = oldType->baseStruct; 177 assert( oldDecl ); 178 179 // Helper function for throwing semantic errors. 180 auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) { 181 const std::string& context = "While following head pointer of " + 182 oldDecl->name + " named '" + fieldName + "': "; 183 SemanticError( errorLocation, context + message ); 184 }; 185 186 if ( oldDecl->members.empty() ) { 187 throwError( "Type has no fields." ); 188 } 189 const Declaration * memberDecl = oldDecl->members.front(); 190 assert( memberDecl ); 191 const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 192 assert( fieldDecl ); 193 if ( fieldName != fieldDecl->name ) { 194 throwError( "Head field did not have expected name." ); 195 } 196 197 const Type * fieldType = fieldDecl->type; 198 if ( nullptr == fieldType ) { 199 throwError( "Could not get head field." ); 200 } 201 const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType ); 202 if ( nullptr == ptrType ) { 203 throwError( "First field is not a pointer type." ); 204 } 205 assert( ptrType->base ); 206 newType = dynamic_cast<StructInstType *>( ptrType->base ); 207 if ( nullptr == newType ) { 208 throwError( "First field does not point to a structure type." ); 209 } 210 } 211 212 // Now we can look into copying it. 213 newType = newType->clone(); 214 if ( ! oldType->parameters.empty() ) { 215 deleteAll( newType->parameters ); 216 newType->parameters.clear(); 217 cloneAll( oldType->parameters, newType->parameters ); 218 } 219 return newType; 220 } 221 222 /// Get the type-id type from a virtual type. 223 StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) { 224 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type ); 225 if ( nullptr == typeInst ) { 226 return nullptr; 227 } 228 StructInstType * tableInst = 229 followHeadPointerType( typeInst, "virtual_table", errorLocation ); 230 if ( nullptr == tableInst ) { 231 return nullptr; 232 } 233 StructInstType * typeIdInst = 234 followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation ); 235 delete tableInst; 236 return typeIdInst; 237 } 238 239 Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) { 240 assertf( castExpr->result, "Virtual Cast target not found before expansion." ); 241 242 assert( vcast_decl ); 243 assert( pvt_decl ); 244 245 const Type * base_type = getBaseType( castExpr->result ); 246 if ( nullptr == base_type ) { 247 castError( castExpr, "Virtual cast target must be a pointer or reference type." ); 248 } 249 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) ); 250 if ( nullptr == type_id_type ) { 251 castError( castExpr, "Ill formed virtual cast target type." ); 252 } 253 ObjectDecl * type_id = indexer.lookup( type_id_type ); 254 delete type_id_type; 255 if ( nullptr == type_id ) { 256 castError( castExpr, "Virtual cast does not target a virtual type." ); 257 } 258 259 Expression * result = new CastExpr( 260 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), { 261 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ), 262 cast_to_type_id( castExpr->get_arg(), 2 ), 263 } ), 264 castExpr->get_result()->clone() 265 ); 266 267 castExpr->set_arg( nullptr ); 268 castExpr->set_result( nullptr ); 269 delete castExpr; 270 return result; 271 } 46 272 47 273 /// Better error locations for generated casts. … … 268 494 } // namespace 269 495 496 void expandCasts( std::list< Declaration * > & translationUnit ) { 497 PassVisitor<VirtualCastCore> translator; 498 mutateAll( translationUnit, translator ); 499 } 500 270 501 void expandCasts( ast::TranslationUnit & translationUnit ) { 271 502 ast::Pass<ExpandCastsCore>::run( translationUnit ); -
src/Virtual/Tables.cc
rfc12f05 r0030b508 21 21 #include "AST/Stmt.hpp" 22 22 #include "AST/Type.hpp" 23 #include <SynTree/Attribute.h> 24 #include <SynTree/Declaration.h> 25 #include <SynTree/Expression.h> 26 #include <SynTree/Statement.h> 27 #include <SynTree/Type.h> 23 28 24 29 namespace Virtual { … … 60 65 return 17 < name.size() && '_' == name[0] && 61 66 std::string("_vtable_instance") == name.substr(1, name.size() - 17); 67 } 68 69 static ObjectDecl * makeVtableDeclaration( 70 std::string const & name, 71 StructInstType * type, Initializer * init ) { 72 Type::StorageClasses storage = noStorageClasses; 73 if ( nullptr == init ) { 74 storage.is_extern = true; 75 } 76 return new ObjectDecl( 77 name, 78 storage, 79 LinkageSpec::Cforall, 80 nullptr, 81 type, 82 init 83 ); 62 84 } 63 85 … … 79 101 } 80 102 103 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) { 104 assert( type ); 105 return makeVtableDeclaration( name, type, nullptr ); 106 } 107 81 108 ast::ObjectDecl * makeVtableForward( 82 109 CodeLocation const & location, std::string const & name, … … 84 111 assert( vtableType ); 85 112 return makeVtableDeclaration( location, name, vtableType, nullptr ); 113 } 114 115 ObjectDecl * makeVtableInstance( 116 std::string const & name, StructInstType * vtableType, 117 Type * objectType, Initializer * init ) { 118 assert( vtableType ); 119 assert( objectType ); 120 StructDecl * vtableStruct = vtableType->baseStruct; 121 // Build the initialization 122 if ( nullptr == init ) { 123 std::list< Initializer * > inits; 124 125 // This is going to have to be run before the resolver to connect expressions. 126 for ( auto field : vtableStruct->members ) { 127 if ( std::string( "parent" ) == field->name ) { 128 // This will not work with polymorphic state. 129 auto oField = strict_dynamic_cast< ObjectDecl * >( field ); 130 auto fieldType = strict_dynamic_cast< PointerType * >( oField->type ); 131 auto parentType = strict_dynamic_cast< StructInstType * >( fieldType->base ); 132 std::string const & parentInstance = instanceName( parentType->name ); 133 inits.push_back( 134 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) ); 135 } else if ( std::string( "__cfavir_typeid" ) == field->name ) { 136 std::string const & baseType = baseTypeName( vtableType->name ); 137 std::string const & typeId = typeIdName( baseType ); 138 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) ); 139 } else if ( std::string( "size" ) == field->name ) { 140 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) ); 141 } else if ( std::string( "align" ) == field->name ) { 142 inits.push_back( new SingleInit( new AlignofExpr( objectType->clone() ) ) ); 143 } else { 144 inits.push_back( new SingleInit( new NameExpr( field->name ) ) ); 145 } 146 } 147 init = new ListInit( inits ); 148 // This should initialize everything except the parent pointer, the 149 // size-of and align-of fields. These should be inserted. 150 } else { 151 assert(false); 152 } 153 return makeVtableDeclaration( name, vtableType, init ); 86 154 } 87 155 … … 156 224 } 157 225 226 FunctionDecl * makeGetExceptionForward( 227 Type * vtableType, Type * exceptType ) { 228 assert( vtableType ); 229 assert( exceptType ); 230 FunctionType * type = new FunctionType( noQualifiers, false ); 231 vtableType->tq.is_const = true; 232 type->returnVals.push_back( new ObjectDecl( 233 "_retvalue", 234 noStorageClasses, 235 LinkageSpec::Cforall, 236 nullptr, 237 new ReferenceType( noQualifiers, vtableType ), 238 nullptr, 239 { new Attribute("unused") } 240 ) ); 241 type->parameters.push_back( new ObjectDecl( 242 "__unused", 243 noStorageClasses, 244 LinkageSpec::Cforall, 245 nullptr, 246 new PointerType( noQualifiers, exceptType ), 247 nullptr, 248 { new Attribute("unused") } 249 ) ); 250 return new FunctionDecl( 251 functionName, 252 noStorageClasses, 253 LinkageSpec::Cforall, 254 type, 255 nullptr 256 ); 257 } 258 158 259 ast::FunctionDecl * makeGetExceptionForward( 159 260 CodeLocation const & location, … … 183 284 } 184 285 286 FunctionDecl * makeGetExceptionFunction( 287 ObjectDecl * vtableInstance, Type * exceptType ) { 288 assert( vtableInstance ); 289 assert( exceptType ); 290 FunctionDecl * func = makeGetExceptionForward( 291 vtableInstance->type->clone(), exceptType ); 292 func->statements = new CompoundStmt( { 293 new ReturnStmt( new VariableExpr( vtableInstance ) ), 294 } ); 295 return func; 296 } 297 185 298 ast::FunctionDecl * makeGetExceptionFunction( 186 299 CodeLocation const & location, … … 196 309 } 197 310 311 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) { 312 assert( typeIdType ); 313 StructInstType * type = typeIdType->clone(); 314 type->tq.is_const = true; 315 std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name ); 316 return new ObjectDecl( 317 typeid_name, 318 noStorageClasses, 319 LinkageSpec::Cforall, 320 /* bitfieldWidth */ nullptr, 321 type, 322 new ListInit( { new SingleInit( 323 new AddressExpr( new NameExpr( "__cfatid_exception_t" ) ) 324 ) } ), 325 { new Attribute( "cfa_linkonce", {} ) }, 326 noFuncSpecifiers 327 ); 328 } 329 198 330 ast::ObjectDecl * makeTypeIdInstance( 199 331 CodeLocation const & location, -
src/Virtual/Tables.h
rfc12f05 r0030b508 18 18 #include <string> 19 19 #include "AST/Fwd.hpp" 20 class Declaration; 21 class Expression; 22 class FunctionDecl; 23 class Initializer; 24 class ObjectDecl; 25 class StructDecl; 26 class StructInstType; 27 class Type; 20 28 21 29 namespace Virtual { … … 29 37 bool isVTableInstanceName( std::string const & name ); 30 38 39 ObjectDecl * makeVtableForward( 40 std::string const & name, StructInstType * vtableType ); 31 41 /* Create a forward declaration of a vtable of the given type. 32 42 * vtableType node is consumed. … … 36 46 ast::StructInstType const * vtableType ); 37 47 48 ObjectDecl * makeVtableInstance( 49 std::string const & name, 50 StructInstType * vtableType, Type * objectType, 51 Initializer * init = nullptr ); 38 52 /* Create an initialized definition of a vtable. 39 53 * vtableType and init (if provided) nodes are consumed. … … 47 61 48 62 // Some special code for how exceptions interact with virtual tables. 49 63 FunctionDecl * makeGetExceptionForward( Type * vtableType, Type * exceptType ); 50 64 /* Create a forward declaration of the exception virtual function 51 65 * linking the vtableType to the exceptType. Both nodes are consumed. … … 56 70 ast::Type const * exceptType ); 57 71 72 FunctionDecl * makeGetExceptionFunction( 73 ObjectDecl * vtableInstance, Type * exceptType ); 58 74 /* Create the definition of the exception virtual function. 59 75 * exceptType node is consumed. … … 63 79 ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType ); 64 80 81 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ); 65 82 /* Build an instance of the type-id from the type of the type-id. 66 83 * TODO: Should take the parent type. Currently locked to the exception_t. -
src/main.cc
rfc12f05 r0030b508 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 1 21:12:58202313 // Update Count : 6 9012 // Last Modified On : Thu Sep 28 22:28:45 2023 13 // Update Count : 687 14 14 // 15 15 … … 29 29 #include <string> // for char_traits, operator<< 30 30 31 #include "AST/Convert.hpp" 31 32 #include "AST/Pass.hpp" // for pass_visitor_stats 32 #include "AST/Print.hpp" // for printAll33 33 #include "AST/TranslationUnit.hpp" // for TranslationUnit 34 34 #include "AST/Util.hpp" // for checkInvariants … … 39 39 #include "CodeGen/Generate.h" // for generate 40 40 #include "CodeGen/LinkOnce.h" // for translateLinkOnce 41 #include "CodeTools/TrackLoc.h" // for fillLocations 41 42 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 42 43 #include "Common/DeclStats.hpp" // for printDeclStats … … 64 65 #include "ResolvExpr/EraseWith.hpp" // for eraseWith 65 66 #include "ResolvExpr/Resolver.h" // for resolve 67 #include "SynTree/LinkageSpec.h" // for Spec, Cforall, Intrinsic 68 #include "SynTree/Declaration.h" // for Declaration 66 69 #include "Tuples/Tuples.h" // for expandMemberTuples, expan... 67 70 #include "Validate/Autogen.hpp" // for autogenerateRoutines … … 91 94 using namespace Stats::Counters; 92 95 { 93 static auto group = build<CounterGroup>( "Pass Visitor Template" );96 static auto group = build<CounterGroup>( "Pass Visitor" ); 94 97 auto pass = build<CounterGroup>( name, group ); 95 ast::pass_visitor_stats.depth = 0; 96 ast::pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass ); 97 ast::pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass ); 98 pass_visitor_stats.depth = 0; 99 pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass ); 100 pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass ); 101 } 102 { 103 static auto group = build<CounterGroup>( "Syntax Node" ); 104 auto pass = build<CounterGroup>( name, group ); 105 BaseSyntaxNode::new_nodes = build<SimpleCounter>( "Allocs", pass ); 98 106 } 99 107 } … … 124 132 125 133 static void parse_cmdline( int argc, char * argv[] ); 134 static void dump( list< Declaration * > & translationUnit, ostream & out = cout ); 126 135 static void dump( ast::TranslationUnit && transUnit, ostream & out = cout ); 127 136 … … 237 246 FILE * input; // use FILE rather than istream because yyin is FILE 238 247 ostream * output = & cout; 248 list< Declaration * > translationUnit; 239 249 ast::TranslationUnit transUnit; 240 250 … … 250 260 251 261 parse_cmdline( argc, argv ); // process command-line arguments 262 CodeGen::FixMain::setReplaceMain( !nomainp ); 252 263 253 264 if ( waiting_for_gdb ) { … … 279 290 280 291 // Read to gcc builtins, if not generating the cfa library 281 FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf a").c_str(), "r" );292 FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" ); 282 293 assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" ); 283 294 parse( gcc_builtins, ast::Linkage::Compiler ); 284 295 285 296 // read the extra prelude in, if not generating the cfa library 286 FILE * extras = fopen( (PreludeDirector + "/extras.cf a").c_str(), "r" );297 FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" ); 287 298 assertf( extras, "cannot open extras.cf\n" ); 288 299 parse( extras, ast::Linkage::BuiltinC ); … … 295 306 296 307 // Read to cfa builtins, if not generating the cfa library 297 FILE * builtins = fopen( (PreludeDirector + "/builtins.cf a").c_str(), "r" );308 FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" ); 298 309 assertf( builtins, "cannot open builtins.cf\n" ); 299 310 parse( builtins, ast::Linkage::BuiltinCFA ); … … 308 319 309 320 Stats::Time::StopBlock(); 321 322 if (Stats::Counters::enabled) { 323 ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New"); 324 ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New"); 325 } 310 326 311 327 PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit ); … … 393 409 PASS( "Translate Tries", ControlStruct::translateTries, transUnit ); 394 410 PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit ); 395 PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp );396 411 397 412 // Needs to happen before tuple types are expanded. … … 412 427 PASS( "Link-Once", CodeGen::translateLinkOnce, transUnit ); 413 428 429 translationUnit = convert( std::move( transUnit ) ); 430 414 431 // Code has been lowered to C, now we can start generation. 415 432 416 DUMP( bcodegenp, std::move( transUnit ));433 DUMP( bcodegenp, translationUnit ); 417 434 418 435 if ( optind < argc ) { // any commands after the flags and input file ? => output file name … … 420 437 } // if 421 438 422 PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false ); 423 CodeGen::fixMainInvoke( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() ); 424 439 CodeTools::fillLocations( translationUnit ); 440 PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ); 441 442 CodeGen::FixMain::fix( translationUnit, *output, 443 (PreludeDirector + "/bootloader.c").c_str() ); 425 444 if ( output != &cout ) { 426 445 delete output; … … 429 448 if ( errorp ) { 430 449 cerr << "---AST at error:---" << endl; 431 dump( std::move( transUnit ), cerr ); 450 // We check which section the errors came from without looking at 451 // transUnit because std::move means it could look like anything. 452 if ( !translationUnit.empty() ) { 453 dump( translationUnit, cerr ); 454 } else { 455 dump( std::move( transUnit ), cerr ); 456 } 432 457 cerr << endl << "---End of AST, begin error message:---\n" << endl; 433 458 } // if … … 455 480 } // try 456 481 482 deleteAll( translationUnit ); 457 483 Stats::print(); 458 484 return EXIT_SUCCESS; … … 684 710 } // parse_cmdline 685 711 686 static bool notPrelude( ast::ptr<ast::Decl> & decl ) { 687 return !decl->linkage.is_builtin; 688 } 689 690 static void dump( ast::TranslationUnit && unit, std::ostream & out ) { 691 // May filter out all prelude declarations. 712 static bool notPrelude( Declaration * decl ) { 713 return ! LinkageSpec::isBuiltin( decl->get_linkage() ); 714 } // notPrelude 715 716 static void dump( list< Declaration * > & translationUnit, ostream & out ) { 717 list< Declaration * > decls; 718 692 719 if ( genproto ) { 693 std::list<ast::ptr<ast::Decl>> decls; 694 std::copy_if( unit.decls.begin(), unit.decls.end(), 695 std::back_inserter( decls ), notPrelude ); 696 decls.swap( unit.decls ); 697 } 698 699 // May print as full dump or as code generation. 720 filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), notPrelude ); 721 } else { 722 decls = translationUnit; 723 } // if 724 725 // depending on commandline options, either generate code or dump the AST 700 726 if ( codegenp ) { 701 CodeGen::generate( unit, out, !genproto, prettycodegenp, false, false, false);727 CodeGen::generate( decls, out, ! genproto, prettycodegenp ); 702 728 } else { 703 ast::printAll( out, unit.decls ); 704 } 729 printAll( decls, out ); 730 } // if 731 deleteAll( translationUnit ); 732 } // dump 733 734 static void dump( ast::TranslationUnit && transUnit, ostream & out ) { 735 std::list< Declaration * > translationUnit = convert( std::move( transUnit ) ); 736 dump( translationUnit, out ); 705 737 } 706 738 -
tests/collections/.expect/string-istream-manip.txt
rfc12f05 r0030b508 69 69 13 wwwwwwww 70 70 14 cccc 71 15 q71 15 72 72 1 yyyyyyyyyyyyyyyyyyyy 73 73 2 abcxxx … … 84 84 13 wwwwwwww 85 85 14 cccc 86 15 q86 15 -
tests/collections/string-istream-manip.cfa
rfc12f05 r0030b508 38 38 void echoTillX(const char * casename) { 39 39 string s; 40 // loop assumes behaviour not tested until main-case #15:41 // on reading nothing, the prior string value is left alone42 40 do { 43 s = "";44 41 forceStringHeapFreeSpaceTo(9); 45 42 sin | s; … … 57 54 string s; 58 55 do { 59 s = "";60 56 sin | plainjane( s ); 61 57 sout | casename | s; … … 72 68 string_res s; 73 69 do { 74 s = "";75 70 sin | plainjane( s ); 76 71 sout | casename | s; … … 87 82 string s; 88 83 do { 89 s = "";90 84 sin | skip("-\n"); 91 85 sin | incl( ".:|# x", s ); … … 103 97 string s; 104 98 do { 105 s = "";106 99 sin | skip("-\n"); 107 100 sin | excl( "-\n", s ); … … 120 113 string s; 121 114 do { 122 s = "";123 115 sin | getline( s ); 124 116 sout | casename | s; … … 135 127 string s; 136 128 do { 137 s = "";138 129 sin | getline( s, '@' ); 139 130 sout | casename | s; -
tests/concurrency/actors/.expect/dynamic.txt
rfc12f05 r0030b508 1 1 starting 2 2 started 3 stopping 3 4 Done 4 5 stopped -
tests/concurrency/actors/.expect/static.txt
rfc12f05 r0030b508 1 1 starting 2 2 started 3 stopping 3 4 Done 4 5 stopped -
tests/concurrency/actors/dynamic.cfa
rfc12f05 r0030b508 58 58 *d_actor | *d_msg; 59 59 60 sout | "stopping"; 61 60 62 stop_actor_system(); 61 63 -
tests/concurrency/actors/static.cfa
rfc12f05 r0030b508 55 55 actor | msg; 56 56 57 sout | "stopping"; 58 57 59 stop_actor_system(); 58 60 -
tests/concurrency/cofor.cfa
rfc12f05 r0030b508 1 1 #include <cofor.hfa> 2 2 3 3 4 void add_num( long * total, long val ) { __atomic_fetch_add( total, (long)val, __ATOMIC_SEQ_CST ); } … … 7 8 processor p[4]; 8 9 long total = 0; 9 cofor( i; 10 ) { 10 __atomic_fetch_add( &total, i, __ATOMIC_SEQ_CST ); 11 } 10 COFOR( i, 0, 10, __atomic_fetch_add( &total, i, __ATOMIC_SEQ_CST ); ); 12 11 { 13 12 corun; // does nothing -
tests/concurrency/waitfor/parse.cfa
rfc12f05 r0030b508 10 10 // Created On : Wed Aug 30 17:53:29 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 1 07:28:19202313 // Update Count : 6 512 // Last Modified On : Mon Apr 10 22:52:18 2023 13 // Update Count : 64 14 14 // 15 15 … … 258 258 // Local Variables: // 259 259 // tab-width: 4 // 260 // compile-command: "cfa parse.cfa" //260 // compile-command: "cfa waitfor.cfa" // 261 261 // End: // -
tests/concurrency/waituntil/channel_close.cfa
rfc12f05 r0030b508 26 26 for( ;; ) { 27 27 if ( useAnd ) { 28 waituntil( (in << A) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST );assert( A_removes == in ); A_removes++; removes++; }29 and waituntil( (in2 << B) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST );assert( B_removes == in2 ); B_removes++; removes++; }28 waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; } 29 and waituntil( (in2 << B) ) { assert( B_removes == in2 ); B_removes++; removes++; } 30 30 continue; 31 31 } 32 waituntil( (in << A) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST );assert( A_removes == in ); A_removes++; removes++; }33 or waituntil( (in << B) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST );( B_removes == in ); B_removes++; removes++; }32 waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; } 33 or waituntil( (in << B) ) { assert( B_removes == in ); B_removes++; removes++; } 34 34 } 35 35 } catchResume ( channel_closed * e ) {} // continue to remove until would block … … 37 37 try { 38 38 for( ;; ) 39 waituntil( (in << A) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST );assert( A_removes == in ); A_removes++; removes++; }39 waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; } 40 40 } catchResume ( channel_closed * e ) {} // continue to remove until would block 41 41 catch ( channel_closed * e ) {} 42 42 try { 43 43 for( ;; ) 44 waituntil( (in << B) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST );assert( B_removes == in ); B_removes++; removes++; }44 waituntil( (in << B) ) { assert( B_removes == in ); B_removes++; removes++; } 45 45 } catchResume ( channel_closed * e ) {} // continue to remove until would block 46 46 catch ( channel_closed * e ) {} -
tests/genericUnion.cfa
rfc12f05 r0030b508 10 10 // Created On : Tue Dec 25 14:42:46 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Oct 20 09:13:26 202313 // Update Count : 1512 // Last Modified On : Tue Dec 25 14:46:33 2018 13 // Update Count : 2 14 14 // 15 15 16 #include <fstream.hfa>17 16 #include <limits.hfa> 18 17 19 forall( T)18 forall(T) 20 19 union ByteView { 21 20 T val; … … 24 23 25 24 forall(T) 26 void print( ByteView(T) x) {27 for ( i; sizeof(int) ) {// want to change to sizeof(T)28 sout | nobase( pad0( wd( 2, hex( x.bytes[i] & 0xff ) ) ) ) | nosep;25 void print(ByteView(T) x) { 26 for (int i = 0; i < sizeof(int); i++) { // want to change to sizeof(T) 27 printf("%02x", x.bytes[i] & 0xff); 29 28 } 30 29 } 31 30 32 31 forall(T) 33 void f( ByteView(T) x, T val) {34 print( x);35 sout | " ";32 void f(ByteView(T) x, T val) { 33 print(x); 34 printf(" "); 36 35 x.val = val; 37 print( x);38 sout | nl;36 print(x); 37 printf("\n"); 39 38 } 40 39 41 40 int main() { 42 sout | nlOff;43 41 ByteView(unsigned) u = { 0 }; 44 42 ByteView(int) i = { 0 }; 45 f( u, MAX);46 f( i, -1);43 f(u, MAX); 44 f(i, -1); 47 45 } 48 46 -
tests/io/.expect/manipulatorsInput.arm64.txt
rfc12f05 r0030b508 24 24 3 abcxxx 25 25 4 aaaaaaaa 26 5 26 5 aaaaaaaa 27 27 6 aabbccbb 28 28 7 dddwww 29 8 30 9 29 8 dddwww 30 9 dddwww 31 31 10 aaaaaaaa 32 32 11 wwwwwwww 33 12 34 13 33 12 wwwwwwww 34 13 wwwwwwww 35 35 14 cccc 36 36 15 -
tests/io/.expect/manipulatorsInput.x64.txt
rfc12f05 r0030b508 24 24 3 abcxxx 25 25 4 aaaaaaaa 26 5 26 5 aaaaaaaa 27 27 6 aabbccbb 28 28 7 dddwww 29 8 30 9 29 8 dddwww 30 9 dddwww 31 31 10 aaaaaaaa 32 32 11 wwwwwwww 33 12 34 13 33 12 wwwwwwww 34 13 wwwwwwww 35 35 14 cccc 36 36 15 -
tests/io/.expect/manipulatorsInput.x86.txt
rfc12f05 r0030b508 24 24 3 abcxxx 25 25 4 aaaaaaaa 26 5 26 5 aaaaaaaa 27 27 6 aabbccbb 28 28 7 dddwww 29 8 30 9 29 8 dddwww 30 9 dddwww 31 31 10 aaaaaaaa 32 32 11 wwwwwwww 33 12 34 13 33 12 wwwwwwww 34 13 wwwwwwww 35 35 14 cccc 36 36 15 -
tests/io/.expect/manipulatorsOutput4.txt
rfc12f05 r0030b508 225 225 -1.55051464826854e+28 -15.5051e27 -15.5051e27 -15.505e27 -15.505e27 -15.50515e27 -15.50515e27 -0015.505e27 -0015.505e27 -15.50515e27 -15.50515e27 -15.505e27 -15.505e27 -15.50515e27 -15.50515e27 -15.505e27 -15.505e27 -15.50515e27 -15.50515e27 226 226 -6.51216152272788e+29 -651.216e27 -651.216e27 -651.22e27 -651.22e27 -651.21615e27 -651.21615e27 -00651.22e27 -00651.22e27 -651.21615e27 -651.21615e27 -651.22e27 -651.22e27 -651.21615e27 -651.21615e27 -651.22e27 -651.22e27 -651.21615e27 -651.21615e27 227 0 1 1 1.0 1228 1 2 2 2.0 2229 2 4 4 4.0 4230 3 8 8 8.0 8231 4 16 16 16.0 16232 5 32 32 32.0 32233 6 64 64 64.0 64234 7 128 128 128.0 128235 8 256 256 256.0 256236 9 512 512 512.0 512237 10 1024 1.024K 1.0K 1K238 11 2048 2.048K 2.0K 2K239 12 4096 4.096K 4.1K 4K240 13 8192 8.192K 8.2K 8K241 14 16384 16.384K 16.4K 16K242 15 32768 32.768K 32.8K 33K243 16 65536 65.536K 65.5K 66K244 17 131072 131.072K 131.1K 131K245 18 262144 262.144K 262.1K 262K246 19 524288 524.288K 524.3K 524K247 20 1048576 1.04858M 1.0M 1M248 21 2097152 2.09715M 2.1M 2M249 22 4194304 4.1943M 4.2M 4M250 23 8388608 8.38861M 8.4M 8M251 24 16777216 16.7772M 16.8M 17M252 25 33554432 33.5544M 33.6M 34M253 26 67108864 67.1089M 67.1M 67M254 27 134217728 134.218M 134.2M 134M255 28 268435456 268.435M 268.4M 268M256 29 536870912 536.871M 536.9M 537M257 30 1073741824 1.07374G 1.1G 1G258 31 2147483648 2.14748G 2.1G 2G -
tests/io/manipulatorsOutput4.cfa
rfc12f05 r0030b508 7 7 // Created On : Tue Apr 13 17:55:02 2021 8 8 // Last Modified By : Peter A. Buhr 9 // Last Modified On : Tue Oct 17 08:37:42 202310 // Update Count : 59 // Last Modified On : Tue Apr 13 18:00:33 2021 10 // Update Count : 4 11 11 // 12 12 … … 42 42 | left(ws(12,5, eng(w) )) | left(sign(ws(12,5, eng(w) ))) | left(wd(12,5, eng(w) )) | left(sign(wd(12,5, eng(w) ))) | left(pad0(ws(12,5, eng(w) ))) | left(pad0(sign(ws(12,5, eng(w) )))) | left(pad0(wd(12,5, eng(w) ))) | left(pad0(sign(wd(12,5, eng(w) )))); 43 43 } // for 44 45 for ( exp; sizeof(int) * 8 ) {46 size_t pow2 = 1z << exp;47 sout | exp | pow2 | unit(eng(pow2)) | wd(0,1, unit(eng( pow2 ))) | wd(0,0, unit(eng(pow2)));48 } // for49 44 } // main 50 45
Note:
See TracChangeset
for help on using the changeset viewer.