Changeset fc12f05 for src/InitTweak
- Timestamp:
- Nov 13, 2023, 3:43:43 AM (2 years ago)
- Branches:
- master, stuck-waitfor-destruct
- Children:
- 25f2798
- Parents:
- 0030b508 (diff), 2174191 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- src/InitTweak
- Files:
-
- 1 deleted
- 7 edited
-
FixGlobalInit.cc (modified) (4 diffs)
-
FixInit.cc (deleted)
-
FixInitNew.cpp (modified) (3 diffs)
-
GenInit.cc (modified) (4 diffs)
-
GenInit.h (modified) (1 diff)
-
InitTweak.cc (modified) (19 diffs)
-
InitTweak.h (modified) (3 diffs)
-
module.mk (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/FixGlobalInit.cc
r0030b508 rfc12f05 20 20 #include <algorithm> // for replace_if 21 21 22 #include "Common/PassVisitor.h"23 #include "Common/UniqueName.h" // for UniqueName24 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt25 #include "SynTree/LinkageSpec.h" // for C26 #include "SynTree/Attribute.h" // for Attribute27 #include "SynTree/Constant.h" // for Constant28 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declaration29 #include "SynTree/Expression.h" // for ConstantExpr, Expression (ptr only)30 #include "SynTree/Initializer.h" // for ConstructorInit, Initializer31 #include "SynTree/Label.h" // for Label32 #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, Visitor35 36 22 #include "AST/Expr.hpp" 37 23 #include "AST/Node.hpp" 38 24 #include "AST/Pass.hpp" 25 #include "Common/UniqueName.h" // for UniqueName 26 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt 39 27 40 28 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 58 29 class GlobalFixer_new : public ast::WithShortCircuiting { 59 30 public: … … 69 40 std::list< ast::ptr<ast::Stmt> > destroyStmts; 70 41 }; 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 empty77 if ( fixer.initFunction->get_statements()->get_kids().empty() ) {78 delete fixer.initFunction;79 } else {80 translationUnit.push_back( fixer.initFunction );81 } // if82 83 if ( fixer.destroyFunction->get_statements()->get_kids().empty() ) {84 delete fixer.destroyFunction;85 } else {86 translationUnit.push_back( fixer.destroyFunction );87 } // if88 }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 which95 // is the priority, with lower numbers meaning higher priority.96 // Functions specified with priority are guaranteed to run before97 // functions without a priority. To ensure that constructors and destructors98 // 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 42 111 43 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { … … 141 73 } 142 74 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 expressions148 // xxx - this is an optimization. Need to first resolve constructors before we decide149 // 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-NULL154 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, but159 // non-intrinsic dtors must be called160 destroyStatements.push_front( dtor );161 ctorInit->dtor = nullptr;162 } // if163 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 okay173 objDecl->init = nullptr;174 } // if175 delete ctorInit;176 } // if177 }178 179 75 void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) { 180 76 auto mutDecl = mutate(objDecl); … … 207 103 } 208 104 209 // only modify global variables210 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 217 105 } // namespace InitTweak 218 106 -
src/InitTweak/FixInitNew.cpp
r0030b508 rfc12f05 33 33 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 34 34 35 extern bool ctordtorp; // print all debug36 extern bool ctorp; // print ctor debug37 extern bool cpctorp; // print copy ctor debug38 extern bool dtorp; // print dtor debug35 bool ctordtorp = false; // print all debug 36 bool ctorp = false; // print ctor debug 37 bool cpctorp = false; // print copy ctor debug 38 bool dtorp = false; // 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 183 180 InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {} 184 181 … … 194 191 ast::Pass<LabelFinder> & finder; 195 192 LabelFinder::LabelMap & labelVars; 196 OrderedDeclsStack reverseDeclOrder;197 193 }; 198 194 -
src/InitTweak/GenInit.cc
r0030b508 rfc12f05 29 29 #include "CompilationState.h" 30 30 #include "CodeGen/OperatorTable.h" 31 #include "Common/PassVisitor.h" // for PassVisitor, WithGuards, WithShort...32 31 #include "Common/SemanticError.h" // for SemanticError 33 32 #include "Common/ToString.hpp" // for toCString … … 38 37 #include "InitTweak.h" // for isConstExpr, InitExpander, checkIn... 39 38 #include "ResolvExpr/Resolver.h" 40 #include "SymTab/Autogen.h" // for genImplicitCall41 39 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 42 40 #include "SymTab/Mangler.h" // for Mangler 43 #include "SynTree/LinkageSpec.h" // for isOverridable, C44 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType45 #include "SynTree/Expression.h" // for VariableExpr, UntypedExpr, Address...46 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit, Initi...47 #include "SynTree/Label.h" // for Label48 #include "SynTree/Mutator.h" // for mutateAll49 #include "SynTree/Statement.h" // for CompoundStmt, ImplicitCtorDtorStmt50 #include "SynTree/Type.h" // for Type, ArrayType, Type::Qualifiers51 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept52 41 #include "Tuples/Tuples.h" // for maybeImpure 53 42 #include "Validate/FindSpecialDecls.h" // for SizeType 54 43 55 44 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 value63 /// of a function so that anything which the resolver decides can be constructed64 /// 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 run78 /// so that the initializer expression is only removed if a constructor is found79 /// 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 objects86 // that need to be constructed or destructed87 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 thus97 // 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 single105 /// const variable of type size_t, so that side effecting array dimensions are only106 /// 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 objects113 // that need to be constructed or destructed114 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 single129 /// const variable of type size_t, so that side effecting array dimensions are only130 /// 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 objects137 // that need to be constructed or destructed138 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 address171 // is being returned172 if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) {173 // explicitly construct the return value using the return expression and the retVal object174 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 again179 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 object186 returnStmt->expr = new VariableExpr( returnVals.front() );187 } // if188 }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 var217 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 constexpr227 ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );228 // array is variable-length when the dimension is not constexpr229 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 resolve232 // still try to detect constant expressions233 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 var270 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 resolve280 // still try to detect constant expressions281 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 }298 45 299 46 namespace { … … 526 273 } 527 274 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 constructed535 if ( dynamic_cast< ReferenceType * >( type ) ) return false;536 // need to clear and reset qualifiers when determining if a type is managed537 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 managed541 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 C553 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 managed574 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 that578 // polymorphic constructors make generic types managed types579 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 590 275 bool ManagedTypes_new::isManaged( const ast::Type * type ) const { 591 276 // references are never constructed … … 647 332 void ManagedTypes_new::endScope() { managedTypes.endScope(); } 648 333 649 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {650 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor651 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 660 334 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 661 335 assertf(objDecl, "genCtorDtor passed null objDecl"); 662 336 InitExpander_new srcParam(arg); 663 337 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/dtor668 // for each constructable object669 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 CompoundStmt678 // which wraps everything that needs to happen. As such, it's technically679 // possible to use a Statement ** in the above calls, but this is inherently680 // unsafe, so instead we take the slightly less efficient route, but will be681 // 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 genImplicitCall684 // itself. It is possible that genImplicitCall produces no statements (e.g. if685 // an array type does not have a dimension). In this case, it's fine to ignore686 // 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 exist690 // if ctor does exist, want to use ctor expression instead of init691 // push this decision to the resolver692 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 C702 if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) {703 // constructed objects cannot be designated704 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 deeply706 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 parameters714 GuardValue( inFunction );715 inFunction = true;716 717 managedTypes.handleDWT( functionDecl );718 719 GuardScope( managedTypes );720 // go through assertions and recursively add seen ctor/dtors721 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 members732 733 managedTypes.handleStruct( aggregateDecl );734 }735 736 void CtorDtor::previsit( CompoundStmt * ) {737 GuardScope( managedTypes );738 338 } 739 339 -
src/InitTweak/GenInit.h
r0030b508 rfc12f05 22 22 #include "Common/CodeLocation.h" 23 23 #include "GenPoly/ScopedSet.h" // for ScopedSet 24 #include "SynTree/SynTree.h" // for Visitor Nodes25 24 26 25 namespace InitTweak { 27 26 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 void genInit( std::list< Declaration * > & translationUnit );29 27 void genInit( ast::TranslationUnit & translationUnit ); 30 28 31 29 /// Converts return statements into copy constructor calls on the hidden return variable. 32 30 /// This pass must happen before auto-gen. 33 void fixReturnStatements( std::list< Declaration * > & translationUnit );34 31 void fixReturnStatements( ast::TranslationUnit & translationUnit ); 35 32 36 33 /// 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 );38 34 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 39 35 40 36 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 41 ConstructorInit * genCtorInit( ObjectDecl * objDecl );42 37 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 managed47 bool isManaged( Type * type ) const; // determine if type is managed48 49 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor50 void handleStruct( StructDecl * aggregateDecl ); // add type to managed if child is managed51 52 void beginScope();53 void endScope();54 private:55 GenPoly::ScopedSet< std::string > managedTypes;56 };57 38 58 39 class ManagedTypes_new { -
src/InitTweak/InitTweak.cc
r0030b508 rfc12f05 29 29 #include "AST/Type.hpp" 30 30 #include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto... 31 #include "Common/PassVisitor.h"32 31 #include "Common/SemanticError.h" // for SemanticError 33 32 #include "Common/UniqueName.h" // for UniqueName … … 36 35 #include "InitTweak.h" 37 36 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 38 #include "SymTab/Autogen.h"39 #include "SymTab/Indexer.h" // for Indexer40 #include "SynTree/LinkageSpec.h" // for Spec, isBuiltin, Intrinsic41 #include "SynTree/Attribute.h" // for Attribute42 #include "SynTree/Constant.h" // for Constant43 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType44 #include "SynTree/Expression.h" // for Expression, UntypedExpr, Applicati...45 #include "SynTree/Initializer.h" // for Initializer, ListInit, Designation46 #include "SynTree/Label.h" // for Label47 #include "SynTree/Statement.h" // for CompoundStmt, ExprStmt, BranchStmt48 #include "SynTree/Type.h" // for FunctionType, ArrayType, PointerType49 #include "SynTree/Visitor.h" // for Visitor, maybeAccept50 37 #include "Tuples/Tuples.h" // for Tuples::isTtype 51 38 52 39 namespace InitTweak { 53 40 namespace { 54 struct HasDesignations : public WithShortCircuiting {55 bool hasDesignations = false;56 57 void previsit( BaseSyntaxNode * ) {58 // short circuit if we already know there are designations59 if ( hasDesignations ) visit_children = false;60 }61 62 void previsit( Designation * des ) {63 // short circuit if we already know there are designations64 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 91 41 struct HasDesignations_new : public ast::WithShortCircuiting { 92 42 bool result = false; … … 107 57 }; 108 58 109 struct InitDepthChecker_new : public ast::WithGuards{59 struct InitDepthChecker_new { 110 60 bool result = true; 111 61 const ast::Type * type; … … 119 69 maxDepth++; 120 70 } 121 void previsit( ListInit * ) {71 void previsit( ast::ListInit const * ) { 122 72 curDepth++; 123 GuardAction( [this]() { curDepth--; } );124 73 if ( curDepth > maxDepth ) result = false; 125 74 } 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; 75 void postvisit( ast::ListInit const * ) { 76 curDepth--; 77 } 134 78 }; 135 79 … … 144 88 145 89 } // 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 }164 90 165 91 bool isDesignated( const ast::Init * init ) { … … 180 106 return std::move( flattener.core.argList ); 181 107 } 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 now197 // 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 statement248 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, generates269 /// if (i < d) f(..., init)270 /// ++i;271 /// so that only elements within the range of the array are constructed272 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 detect296 // that the number of elements exceeds to dimension of the array297 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 to312 // terminate without creating output, so should catch this error313 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 designations321 // if ( init-> ) {322 condition = new ConstantExpr( Constant::from_ulong( cond ) );323 ++cond;324 // } else {325 // condition = // ... take designation326 // cond = // ... take designation+1327 // }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 element341 // may have more initializers than elements in the array - need to check at each index that342 // we haven't exceeded size.343 // may have fewer initializers than elements in the array - need to default construct344 // remaining elements.345 // To accomplish this, generate switch statement, consuming all of expander's elements346 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 init355 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 }366 108 367 109 class InitExpander_new::ExpanderImpl { … … 535 277 } 536 278 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 544 279 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { 545 280 assertf( ftype, "getTypeofThis: nullptr ftype" ); … … 552 287 } 553 288 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 561 289 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 562 290 assertf( func, "getParamThis: nullptr ftype" ); … … 564 292 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str()); 565 293 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_extern574 && 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 );579 294 } 580 295 … … 593 308 } 594 309 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 619 310 struct CallFinder_new final { 620 311 std::vector< const ast::Expr * > matches; … … 634 325 }; 635 326 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 642 327 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 643 328 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; … … 646 331 } 647 332 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 655 333 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/dtor711 // 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 723 334 template <typename Predicate> 724 335 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { … … 726 337 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 727 338 } 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 });739 339 } 740 340 … … 749 349 return false; 750 350 }); 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 and827 // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction828 // 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 } );876 351 } 877 352 … … 905 380 return app; 906 381 } 907 908 struct ConstExprChecker : public WithShortCircuiting {909 // most expressions are not const expr910 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 constexpr916 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 children921 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 expr939 return;940 }941 }942 isConstExpr = false;943 }944 945 bool isConstExpr = true;946 };947 382 948 383 struct ConstExprChecker_new : public ast::WithShortCircuiting { … … 989 424 }; 990 425 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 } // if1006 // for all intents and purposes, no initializer means const expr1007 return true;1008 }1009 1010 426 bool isConstExpr( const ast::Expr * expr ) { 1011 427 if ( expr ) { … … 1027 443 } 1028 444 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 1047 445 bool isAssignment( const ast::FunctionDecl * decl ) { 1048 446 return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl ); … … 1071 469 return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 ); 1072 470 } 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 }1097 471 1098 472 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message … … 1103 477 static const char * const data_section = ".data" ASM_COMMENT; 1104 478 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 }1112 479 1113 480 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { -
src/InitTweak/InitTweak.h
r0030b508 rfc12f05 22 22 23 23 #include "AST/Fwd.hpp" // for AST nodes 24 #include "SynTree/SynTree.h" // for Visitor Nodes25 24 26 25 // helper functions for initialization 27 26 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 );33 27 bool isAssignment( const ast::FunctionDecl * decl ); 34 28 bool isDestructor( const ast::FunctionDecl * decl ); … … 38 32 39 33 /// returns the base type of the first parameter to a constructor/destructor/assignment function 40 Type * getTypeofThis( FunctionType * ftype );41 34 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 42 35 43 36 /// returns the first parameter of a constructor/destructor/assignment function 44 ObjectDecl * getParamThis( FunctionType * ftype );45 37 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 46 38 47 39 /// generate a bitwise assignment operation. 48 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );49 50 40 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 51 41 52 42 /// transform Initializer into an argument list that can be passed to a call expression 53 std::list< Expression * > makeInitList( Initializer * init );54 43 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ); 55 44 56 45 /// True if the resolver should try to construct dwt 57 bool tryConstruct( DeclarationWithType * dwt );58 46 bool tryConstruct( const ast::DeclWithType * dwt ); 59 47 60 48 /// True if the type can have a user-defined constructor 61 bool isConstructable( Type * t );62 49 bool isConstructable( const ast::Type * t ); 63 50 64 51 /// True if the Initializer contains designations 65 bool isDesignated( Initializer * init );66 52 bool isDesignated( const ast::Init * init ); 67 53 68 54 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 69 55 /// type, where the depth of its type is the number of nested ArrayTypes + 1 70 bool checkInitDepth( ObjectDecl * objDecl );71 56 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 intrinsic78 ApplicationExpr * isIntrinsicCallExpr( Expression * expr );79 57 80 58 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 81 59 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 82 60 /// Currently has assertions that make it less than fully general. 83 bool isIntrinsicSingleArgCallStmt( Statement * stmt );84 61 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ); 85 62 86 /// True if stmt is a call statement where the function called is intrinsic.87 bool isIntrinsicCallStmt( Statement * stmt );88 89 63 /// get all Ctor/Dtor call expressions from a Statement 90 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );91 64 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 92 65 93 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call94 Expression * getCtorDtorCall( Statement * stmt );95 96 /// returns the name of the function being called97 std::string getFunctionName( Expression * expr );98 99 /// returns the argument to a call expression in position N indexed from 0100 Expression *& getCallArg( Expression * callExpr, unsigned int pos );101 102 /// returns the base type of a PointerType or ArrayType, else returns NULL103 Type * getPointerBase( Type * );104 105 /// returns the argument if it is a PointerType or ArrayType, else returns NULL106 Type * isPointerType( Type * );107 108 66 /// returns true if expr is trivially a compile-time constant 109 bool isConstExpr( Expression * expr );110 bool isConstExpr( Initializer * init );111 112 67 bool isConstExpr( const ast::Expr * expr ); 113 68 bool isConstExpr( const ast::Init * init ); … … 122 77 /// .section .data#,"a" 123 78 /// to avoid assembler warning "ignoring changed section attributes for .data" 124 void addDataSectionAttribute( ObjectDecl * objDecl );125 126 79 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 127 128 class InitExpander_old {129 public:130 // expand by stepping through init to get each list of arguments131 InitExpander_old( Initializer * init );132 133 // always expand to expr134 InitExpander_old( Expression * expr );135 136 // iterator-like interface137 std::list< Expression * > operator*();138 InitExpander_old & operator++();139 140 // builds statement which has the same semantics as a C-style list initializer141 // (for array initializers) using callExpr as the base expression to perform initialization142 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 };157 80 158 81 class InitExpander_new { -
src/InitTweak/module.mk
r0030b508 rfc12f05 24 24 InitTweak/FixGlobalInit.cc \ 25 25 InitTweak/FixGlobalInit.h \ 26 InitTweak/FixInit.cc \27 26 InitTweak/FixInit.h \ 28 27 InitTweak/FixInitNew.cpp
Note:
See TracChangeset
for help on using the changeset viewer.