Changeset c331406 for src/InitTweak
- Timestamp:
- Aug 5, 2016, 11:03:04 AM (10 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, stuck-waitfor-destruct, with_gc
- Children:
- a2f920f
- Parents:
- 5070fe4 (diff), 1b0020a (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:
-
- 6 edited
-
FixGlobalInit.cc (modified) (3 diffs)
-
FixInit.cc (modified) (11 diffs)
-
FixInit.h (modified) (1 diff)
-
GenInit.cc (modified) (5 diffs)
-
InitTweak.cc (modified) (7 diffs)
-
InitTweak.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/FixGlobalInit.cc
r5070fe4 rc331406 46 46 FunctionDecl * destroyFunction; 47 47 }; 48 49 class ConstExprChecker : public Visitor {50 public:51 ConstExprChecker() : isConstExpr( true ) {}52 53 virtual void visit( ApplicationExpr *applicationExpr ) { isConstExpr = false; }54 virtual void visit( UntypedExpr *untypedExpr ) { isConstExpr = false; }55 virtual void visit( NameExpr *nameExpr ) { isConstExpr = false; }56 virtual void visit( CastExpr *castExpr ) { isConstExpr = false; }57 virtual void visit( LabelAddressExpr *labAddressExpr ) { isConstExpr = false; }58 virtual void visit( UntypedMemberExpr *memberExpr ) { isConstExpr = false; }59 virtual void visit( MemberExpr *memberExpr ) { isConstExpr = false; }60 virtual void visit( VariableExpr *variableExpr ) { isConstExpr = false; }61 virtual void visit( ConstantExpr *constantExpr ) { /* bottom out */ }62 // these might be okay?63 // virtual void visit( SizeofExpr *sizeofExpr );64 // virtual void visit( AlignofExpr *alignofExpr );65 // virtual void visit( UntypedOffsetofExpr *offsetofExpr );66 // virtual void visit( OffsetofExpr *offsetofExpr );67 // virtual void visit( OffsetPackExpr *offsetPackExpr );68 // virtual void visit( AttrExpr *attrExpr );69 // virtual void visit( CommaExpr *commaExpr );70 // virtual void visit( LogicalExpr *logicalExpr );71 // virtual void visit( ConditionalExpr *conditionalExpr );72 virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; }73 virtual void visit( SolvedTupleExpr *tupleExpr ) { isConstExpr = false; }74 virtual void visit( TypeExpr *typeExpr ) { isConstExpr = false; }75 virtual void visit( AsmExpr *asmExpr ) { isConstExpr = false; }76 virtual void visit( UntypedValofExpr *valofExpr ) { isConstExpr = false; }77 virtual void visit( CompoundLiteralExpr *compLitExpr ) { isConstExpr = false; }78 79 bool isConstExpr;80 };81 82 bool isConstExpr( Initializer * init ) {83 if ( init ) {84 ConstExprChecker checker;85 init->accept( checker );86 return checker.isConstExpr;87 } // if88 // for all intents and purposes, no initializer means const expr89 return true;90 }91 48 92 49 void fixGlobalInit( std::list< Declaration * > & translationUnit, const std::string & name, bool inLibrary ) { … … 140 97 std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids(); 141 98 142 if ( ! tryConstruct( objDecl ) ) return; // don't construct @= or designated objects143 if ( objDecl->get_storageClass() == DeclarationNode::Extern ) return;144 99 // C allows you to initialize objects with constant expressions 145 100 // xxx - this is an optimization. Need to first resolve constructors before we decide … … 147 102 // if ( isConstExpr( objDecl->get_init() ) ) return; 148 103 149 if ( dynamic_cast< ArrayType * > ( objDecl->get_type() ) ) { 150 // xxx - initialize each element of the array 151 } else { 152 // steal initializer from object and attach it to a new temporary 153 ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, objDecl->get_type()->clone(), objDecl->get_init() ); 154 objDecl->set_init( NULL ); 155 initStatements.push_back( new DeclStmt( noLabels, newObj ) ); 104 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) { 105 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 106 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() ); 156 107 157 // copy construct objDecl using temporary 158 UntypedExpr * init = new UntypedExpr( new NameExpr( "?{}" ) ); 159 init->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) ); 160 init->get_args().push_back( new VariableExpr( newObj ) ); 161 initStatements.push_back( new ImplicitCtorDtorStmt( new ExprStmt( noLabels, init ) ) ); 162 163 // add destructor calls to global destroy function 164 UntypedExpr * destroy = new UntypedExpr( new NameExpr( "^?{}" ) ); 165 destroy->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) ); 166 destroyStatements.push_front( new ImplicitCtorDtorStmt( new ExprStmt( noLabels, destroy ) ) ); 108 Statement * dtor = ctorInit->get_dtor(); 109 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 110 // don't need to call intrinsic dtor, because it does nothing, but 111 // non-intrinsic dtors must be called 112 destroyStatements.push_front( dtor ); 113 ctorInit->set_dtor( NULL ); 114 } // if 115 if ( Statement * ctor = ctorInit->get_ctor() ) { 116 initStatements.push_back( ctor ); 117 objDecl->set_init( NULL ); 118 ctorInit->set_ctor( NULL ); 119 } else if ( Initializer * init = ctorInit->get_init() ) { 120 objDecl->set_init( init ); 121 ctorInit->set_init( NULL ); 122 } else { 123 // no constructor and no initializer, which is okay 124 objDecl->set_init( NULL ); 125 } // if 126 delete ctorInit; 167 127 } // if 168 128 } -
src/InitTweak/FixInit.cc
r5070fe4 rc331406 18 18 #include <iterator> 19 19 #include <algorithm> 20 #include "InitTweak.h" 20 21 #include "FixInit.h" 21 #include " InitTweak.h"22 #include "FixGlobalInit.h" 22 23 #include "ResolvExpr/Resolver.h" 23 24 #include "ResolvExpr/typeops.h" … … 25 26 #include "SynTree/Type.h" 26 27 #include "SynTree/Expression.h" 28 #include "SynTree/Attribute.h" 27 29 #include "SynTree/Statement.h" 28 30 #include "SynTree/Initializer.h" … … 83 85 }; 84 86 87 // debug 85 88 struct printSet { 86 89 typedef ObjDeclCollector::ObjectSet ObjectSet; … … 159 162 160 163 virtual DeclarationWithType * mutate( ObjectDecl *objDecl ); 164 165 std::list< Declaration * > staticDtorDecls; 161 166 }; 162 167 … … 171 176 } // namespace 172 177 173 void fix( std::list< Declaration * > & translationUnit ) { 178 void fix( std::list< Declaration * > & translationUnit, const std::string & filename, bool inLibrary ) { 179 // fixes ConstructorInit for global variables. should happen before fixInitializers. 180 InitTweak::fixGlobalInit( translationUnit, filename, inLibrary ); 181 174 182 InsertImplicitCalls::insert( translationUnit ); 175 183 ResolveCopyCtors::resolveImplicitCalls( translationUnit ); … … 194 202 void FixInit::fixInitializers( std::list< Declaration * > & translationUnit ) { 195 203 FixInit fixer; 196 mutateAll( translationUnit, fixer ); 204 205 // can't use mutateAll, because need to insert declarations at top-level 206 // can't use DeclMutator, because sometimes need to insert IfStmt, etc. 207 SemanticError errors; 208 for ( std::list< Declaration * >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) { 209 try { 210 *i = maybeMutate( *i, fixer ); 211 translationUnit.splice( i, fixer.staticDtorDecls ); 212 } catch( SemanticError &e ) { 213 errors.append( e ); 214 } // try 215 } // for 216 if ( ! errors.isEmpty() ) { 217 throw errors; 218 } // if 197 219 } 198 220 … … 422 444 if ( Statement * ctor = ctorInit->get_ctor() ) { 423 445 if ( objDecl->get_storageClass() == DeclarationNode::Static ) { 446 // originally wanted to take advantage of gcc nested functions, but 447 // we get memory errors with this approach. To remedy this, the static 448 // variable is hoisted when the destructor needs to be called. 449 // 424 450 // generate: 425 // static bool __objName_uninitialized = true; 426 // if (__objName_uninitialized) { 427 // __ctor(__objName); 428 // void dtor_atexit() { 429 // __dtor(__objName); 451 // static T __objName_static_varN; 452 // void __objName_dtor_atexitN() { 453 // __dtor__...; 454 // } 455 // int f(...) { 456 // ... 457 // static bool __objName_uninitialized = true; 458 // if (__objName_uninitialized) { 459 // __ctor(__objName); 460 // __objName_uninitialized = false; 461 // atexit(__objName_dtor_atexitN); 430 462 // } 431 // on_exit(dtorOnExit, &__objName); 432 // __objName_uninitialized = false; 463 // ... 433 464 // } 434 465 435 // generate first line 466 static UniqueName dtorCallerNamer( "_dtor_atexit" ); 467 468 // static bool __objName_uninitialized = true 436 469 BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool ); 437 470 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant( boolType->clone(), "1" ) ), noDesignators ); … … 439 472 isUninitializedVar->fixUniqueId(); 440 473 441 // void dtor_atexit(...) {...}442 FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + "_dtor_atexit", DeclarationNode::NoStorageClass, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false );443 dtorCaller->fixUniqueId();444 dtorCaller->get_statements()->get_kids().push_back( ctorInit->get_dtor()->clone() );445 446 // on_exit(dtor_atexit);447 UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) );448 callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) );449 450 474 // __objName_uninitialized = false; 451 475 UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) ); … … 457 481 std::list< Statement * > & body = initStmts->get_kids(); 458 482 body.push_back( ctor ); 459 body.push_back( new DeclStmt( noLabels, dtorCaller ) );460 body.push_back( new ExprStmt( noLabels, callAtexit ) );461 483 body.push_back( new ExprStmt( noLabels, setTrue ) ); 462 484 … … 465 487 stmtsToAddAfter.push_back( new DeclStmt( noLabels, isUninitializedVar ) ); 466 488 stmtsToAddAfter.push_back( ifStmt ); 489 490 if ( ctorInit->get_dtor() ) { 491 // if the object has a non-trivial destructor, have to 492 // hoist it and the object into the global space and 493 // call the destructor function with atexit. 494 495 Statement * dtorStmt = ctorInit->get_dtor()->clone(); 496 497 // void __objName_dtor_atexitN(...) {...} 498 FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + dtorCallerNamer.newName(), DeclarationNode::Static, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false ); 499 dtorCaller->fixUniqueId(); 500 dtorCaller->get_statements()->get_kids().push_back( dtorStmt ); 501 502 // atexit(dtor_atexit); 503 UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) ); 504 callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) ); 505 506 body.push_back( new ExprStmt( noLabels, callAtexit ) ); 507 508 // hoist variable and dtor caller decls to list of decls that will be added into global scope 509 staticDtorDecls.push_back( objDecl ); 510 staticDtorDecls.push_back( dtorCaller ); 511 512 // need to rename object uniquely since it now appears 513 // at global scope and there could be multiple function-scoped 514 // static variables with the same name in different functions. 515 static UniqueName staticNamer( "_static_var" ); 516 objDecl->set_mangleName( objDecl->get_mangleName() + staticNamer.newName() ); 517 518 objDecl->set_init( NULL ); 519 ctorInit->set_ctor( NULL ); 520 delete ctorInit; 521 522 // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope 523 // create a new object which is never used 524 static UniqueName dummyNamer( "_dummy" ); 525 ObjectDecl * dummy = new ObjectDecl( dummyNamer.newName(), DeclarationNode::Static, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), 0, std::list< Attribute * >{ new Attribute("unused") } ); 526 return dummy; 527 } 467 528 } else { 468 529 stmtsToAddAfter.push_back( ctor ); … … 524 585 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() ); 525 586 Statement * dtor = ctorInit->get_dtor(); 526 if ( dtor && ! isIn strinsicSingleArgCallStmt( dtor ) ) {587 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 527 588 // don't need to call intrinsic dtor, because it does nothing, but 528 589 // non-intrinsic dtors must be called -
src/InitTweak/FixInit.h
r5070fe4 rc331406 27 27 /// replace constructor initializers with expression statements 28 28 /// and unwrap basic C-style initializers 29 void fix( std::list< Declaration * > & translationUnit );29 void fix( std::list< Declaration * > & translationUnit, const std::string & name, bool inLibrary ); 30 30 } // namespace 31 31 -
src/InitTweak/GenInit.cc
r5070fe4 rc331406 26 26 #include "SymTab/Autogen.h" 27 27 #include "GenPoly/PolyMutator.h" 28 #include "GenPoly/DeclMutator.h" 28 29 29 30 namespace InitTweak { … … 55 56 public: 56 57 /// create constructor and destructor statements for object declarations. 57 /// Destructors are inserted directly into the code, whereas constructors58 /// will be added in after the resolver has run so that the initializer expression59 /// is only removed if a constructor is found58 /// the actual call statements will be added in after the resolver has run 59 /// so that the initializer expression is only removed if a constructor is found 60 /// and the same destructor call is inserted in all of the appropriate locations. 60 61 static void generateCtorDtor( std::list< Declaration * > &translationUnit ); 61 62 CtorDtor() : inFunction( false ) {}63 62 64 63 virtual DeclarationWithType * mutate( ObjectDecl * ); 65 64 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ); 66 virtual Declaration* mutate( StructDecl *aggregateDecl ); 67 virtual Declaration* mutate( UnionDecl *aggregateDecl ); 68 virtual Declaration* mutate( EnumDecl *aggregateDecl ); 69 virtual Declaration* mutate( TraitDecl *aggregateDecl ); 70 virtual TypeDecl* mutate( TypeDecl *typeDecl ); 71 virtual Declaration* mutate( TypedefDecl *typeDecl ); 72 73 virtual Type * mutate( FunctionType *funcType ); 65 // should not traverse into any of these declarations to find objects 66 // that need to be constructed or destructed 67 virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; } 68 virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; } 69 virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; } 70 virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; } 71 virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; } 72 virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; } 73 74 virtual Type * mutate( FunctionType *funcType ) { return funcType; } 74 75 75 76 protected: 76 bool inFunction; 77 }; 78 79 class HoistArrayDimension : public GenPoly::DeclMutator { 80 public: 81 typedef GenPoly::DeclMutator Parent; 82 83 /// hoist dimension from array types in object declaration so that it uses a single 84 /// const variable of type size_t, so that side effecting array dimensions are only 85 /// computed once. 86 static void hoistArrayDimension( std::list< Declaration * > & translationUnit ); 87 88 private: 89 virtual DeclarationWithType * mutate( ObjectDecl * objectDecl ); 90 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ); 91 // should not traverse into any of these declarations to find objects 92 // that need to be constructed or destructed 93 virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; } 94 virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; } 95 virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; } 96 virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; } 97 virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; } 98 virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; } 99 100 virtual Type* mutate( FunctionType *funcType ) { return funcType; } 101 102 void hoist( Type * type ); 103 104 DeclarationNode::StorageClass storageclass = DeclarationNode::NoStorageClass; 105 bool inFunction = false; 77 106 }; 78 107 79 108 void genInit( std::list< Declaration * > & translationUnit ) { 80 109 ReturnFixer::makeReturnTemp( translationUnit ); 110 HoistArrayDimension::hoistArrayDimension( translationUnit ); 81 111 CtorDtor::generateCtorDtor( translationUnit ); 82 112 } … … 124 154 } 125 155 156 // precompute array dimension expression, because constructor generation may duplicate it, 157 // which would be incorrect if it is a side-effecting computation. 158 void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) { 159 HoistArrayDimension hoister; 160 hoister.mutateDeclarationList( translationUnit ); 161 } 162 163 DeclarationWithType * HoistArrayDimension::mutate( ObjectDecl * objectDecl ) { 164 storageclass = objectDecl->get_storageClass(); 165 DeclarationWithType * temp = Parent::mutate( objectDecl ); 166 hoist( objectDecl->get_type() ); 167 storageclass = DeclarationNode::NoStorageClass; 168 return temp; 169 } 170 171 void HoistArrayDimension::hoist( Type * type ) { 172 // if in function, generate const size_t var 173 static UniqueName dimensionName( "_array_dim" ); 174 175 // C doesn't allow variable sized arrays at global scope or for static variables, 176 // so don't hoist dimension. 177 if ( ! inFunction ) return; 178 if ( storageclass == DeclarationNode::Static ) return; 179 180 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { 181 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist? 182 183 // don't need to hoist dimension if it's a constexpr - only need to if there's potential 184 // for side effects. 185 if ( isConstExpr( arrayType->get_dimension() ) ) return; 186 187 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageclass, LinkageSpec::C, 0, SymTab::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) ); 188 arrayDimension->get_type()->set_isConst( true ); 189 190 arrayType->set_dimension( new VariableExpr( arrayDimension ) ); 191 addDeclaration( arrayDimension ); 192 193 hoist( arrayType->get_base() ); 194 return; 195 } 196 } 197 198 DeclarationWithType * HoistArrayDimension::mutate( FunctionDecl *functionDecl ) { 199 bool oldInFunc = inFunction; 200 inFunction = true; 201 DeclarationWithType * decl = Parent::mutate( functionDecl ); 202 inFunction = oldInFunc; 203 return decl; 204 } 126 205 127 206 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) { … … 130 209 } 131 210 132 namespace {133 Expression * makeCtorDtorExpr( std::string name, ObjectDecl * objDecl, std::list< Expression * > args ) {134 UntypedExpr * expr = new UntypedExpr( new NameExpr( name ) );135 expr->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );136 expr->get_args().splice( expr->get_args().end(), args );137 return expr;138 }139 }140 141 211 DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) { 142 // hands off if designated or if @=212 // hands off if designated, if @=, or if extern 143 213 if ( tryConstruct( objDecl ) ) { 144 if ( inFunction ) { 145 if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->get_type() ) ) { 146 // call into makeArrayFunction from validate.cc to generate calls to ctor/dtor for each element of array 147 // TODO: walk initializer and generate appropriate copy ctor if element has initializer 148 std::list< Expression * > args = makeInitList( objDecl->get_init() ); 149 if ( args.empty() ) { 150 std::list< Statement * > ctor; 151 std::list< Statement * > dtor; 152 153 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "?{}", back_inserter( ctor ) ); 154 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "^?{}", front_inserter( dtor ), false ); 155 156 // Currently makeArrayFunction produces a single Statement - a CompoundStmt 157 // which wraps everything that needs to happen. As such, it's technically 158 // possible to use a Statement ** in the above calls, but this is inherently 159 // unsafe, so instead we take the slightly less efficient route, but will be 160 // immediately informed if somehow the above assumption is broken. In this case, 161 // we could always wrap the list of statements at this point with a CompoundStmt, 162 // but it seems reasonable at the moment for this to be done by makeArrayFunction 163 // itself 164 assert( ctor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( ctor.front() ) ); 165 assert( dtor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( dtor.front() ) ); 166 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) ); 167 } else { 168 // array came with an initializer list: initialize each element 169 // may have more initializers than elements in the array - need to check at each index that 170 // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting 171 // computation. 172 // may have fewer initializers than eleemnts in the array - need to default construct 173 // remaining elements. 174 // might be able to merge this with the case above. 175 } 176 } else { 177 // it's sufficient to attempt to call the ctor/dtor for the given object and its initializer 178 Expression * ctor = makeCtorDtorExpr( "?{}", objDecl, makeInitList( objDecl->get_init() ) ); 179 Expression * dtor = makeCtorDtorExpr( "^?{}", objDecl, std::list< Expression * >() ); 180 181 // need to remember init expression, in case no ctors exist 182 // if ctor does exist, want to use ctor expression instead of init 183 // push this decision to the resolver 184 ExprStmt * ctorStmt = new ExprStmt( noLabels, ctor ); 185 ExprStmt * dtorStmt = new ExprStmt( noLabels, dtor ); 186 objDecl->set_init( new ConstructorInit( new ImplicitCtorDtorStmt( ctorStmt ), new ImplicitCtorDtorStmt( dtorStmt ), objDecl->get_init() ) ); 187 } 214 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor 215 // for each constructable object 216 std::list< Statement * > ctor; 217 std::list< Statement * > dtor; 218 219 InitExpander srcParam( objDecl->get_init() ); 220 InitExpander nullParam( (Initializer *)NULL ); 221 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl ); 222 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false ); 223 224 // Currently genImplicitCall produces a single Statement - a CompoundStmt 225 // which wraps everything that needs to happen. As such, it's technically 226 // possible to use a Statement ** in the above calls, but this is inherently 227 // unsafe, so instead we take the slightly less efficient route, but will be 228 // immediately informed if somehow the above assumption is broken. In this case, 229 // we could always wrap the list of statements at this point with a CompoundStmt, 230 // but it seems reasonable at the moment for this to be done by genImplicitCall 231 // itself. It is possible that genImplicitCall produces no statements (e.g. if 232 // an array type does not have a dimension). In this case, it's fine to ignore 233 // the object for the purposes of construction. 234 assert( ctor.size() == dtor.size() && ctor.size() <= 1 ); 235 if ( ctor.size() == 1 ) { 236 // need to remember init expression, in case no ctors exist 237 // if ctor does exist, want to use ctor expression instead of init 238 // push this decision to the resolver 239 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) ); 240 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) ); 188 241 } 189 242 } … … 193 246 DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) { 194 247 // parameters should not be constructed and destructed, so don't mutate FunctionType 195 bool oldInFunc = inFunction;196 248 mutateAll( functionDecl->get_oldDecls(), *this ); 197 inFunction = true;198 249 functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) ); 199 inFunction = oldInFunc;200 250 return functionDecl; 201 251 } 202 203 // should not traverse into any of these declarations to find objects204 // that need to be constructed or destructed205 Declaration* CtorDtor::mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }206 Declaration* CtorDtor::mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }207 Declaration* CtorDtor::mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }208 Declaration* CtorDtor::mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }209 TypeDecl* CtorDtor::mutate( TypeDecl *typeDecl ) { return typeDecl; }210 Declaration* CtorDtor::mutate( TypedefDecl *typeDecl ) { return typeDecl; }211 Type* CtorDtor::mutate( FunctionType *funcType ) { return funcType; }212 213 252 } // namespace InitTweak 214 253 -
src/InitTweak/InitTweak.cc
r5070fe4 rc331406 1 #include <algorithm> 1 2 #include "InitTweak.h" 2 3 #include "SynTree/Visitor.h" … … 4 5 #include "SynTree/Initializer.h" 5 6 #include "SynTree/Expression.h" 7 #include "SynTree/Attribute.h" 6 8 #include "GenPoly/GenPoly.h" 7 9 … … 20 22 }; 21 23 22 class Init Expander : public Visitor {24 class InitFlattener : public Visitor { 23 25 public: 24 InitExpander() {}25 26 virtual void visit( SingleInit * singleInit ); 26 27 virtual void visit( ListInit * listInit ); … … 28 29 }; 29 30 30 void Init Expander::visit( SingleInit * singleInit ) {31 void InitFlattener::visit( SingleInit * singleInit ) { 31 32 argList.push_back( singleInit->get_value()->clone() ); 32 33 } 33 34 34 void Init Expander::visit( ListInit * listInit ) {35 // xxx - for now, assume nonested list inits36 std::list<Initializer*>::iterator it = listInit->begin _initializers();37 for ( ; it != listInit->end _initializers(); ++it ) {35 void InitFlattener::visit( ListInit * listInit ) { 36 // flatten nested list inits 37 std::list<Initializer*>::iterator it = listInit->begin(); 38 for ( ; it != listInit->end(); ++it ) { 38 39 (*it)->accept( *this ); 39 40 } … … 42 43 43 44 std::list< Expression * > makeInitList( Initializer * init ) { 44 Init Expander expander;45 maybeAccept( init, expander );46 return expander.argList;45 InitFlattener flattener; 46 maybeAccept( init, flattener ); 47 return flattener.argList; 47 48 } 48 49 … … 53 54 } 54 55 56 class InitExpander::ExpanderImpl { 57 public: 58 virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0; 59 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0; 60 }; 61 62 class InitImpl : public InitExpander::ExpanderImpl { 63 public: 64 InitImpl( Initializer * init ) : init( init ) {} 65 66 virtual std::list< Expression * > next( std::list< Expression * > & indices ) { 67 // this is wrong, but just a placeholder for now 68 // if ( ! flattened ) flatten( indices ); 69 // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >(); 70 return makeInitList( init ); 71 } 72 73 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ); 74 private: 75 Initializer * init; 76 }; 77 78 class ExprImpl : public InitExpander::ExpanderImpl { 79 public: 80 ExprImpl( Expression * expr ) : arg( expr ) {} 81 82 virtual std::list< Expression * > next( std::list< Expression * > & indices ) { 83 std::list< Expression * > ret; 84 Expression * expr = maybeClone( arg ); 85 if ( expr ) { 86 for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) { 87 // go through indices and layer on subscript exprs ?[?] 88 ++it; 89 UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") ); 90 subscriptExpr->get_args().push_back( expr ); 91 subscriptExpr->get_args().push_back( (*it)->clone() ); 92 expr = subscriptExpr; 93 } 94 ret.push_back( expr ); 95 } 96 return ret; 97 } 98 99 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ); 100 private: 101 Expression * arg; 102 }; 103 104 InitExpander::InitExpander( Initializer * init ) : expander( new InitImpl( init ) ) {} 105 106 InitExpander::InitExpander( Expression * expr ) : expander( new ExprImpl( expr ) ) {} 107 108 std::list< Expression * > InitExpander::operator*() { 109 return cur; 110 } 111 112 InitExpander & InitExpander::operator++() { 113 cur = expander->next( indices ); 114 return *this; 115 } 116 117 // use array indices list to build switch statement 118 void InitExpander::addArrayIndex( Expression * index, Expression * dimension ) { 119 indices.push_back( index ); 120 indices.push_back( dimension ); 121 } 122 123 void InitExpander::clearArrayIndices() { 124 indices.clear(); 125 } 126 127 namespace { 128 /// given index i, dimension d, initializer init, and callExpr f, generates 129 /// if (i < d) f(..., init) 130 /// ++i; 131 /// so that only elements within the range of the array are constructed 132 template< typename OutIterator > 133 void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) { 134 UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") ); 135 cond->get_args().push_back( index->clone() ); 136 cond->get_args().push_back( dimension->clone() ); 137 138 std::list< Expression * > args = makeInitList( init ); 139 callExpr->get_args().splice( callExpr->get_args().end(), args ); 140 141 *out++ = new IfStmt( noLabels, cond, new ExprStmt( noLabels, callExpr ), NULL ); 142 143 UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) ); 144 increment->get_args().push_back( new AddressExpr( index->clone() ) ); 145 *out++ = new ExprStmt( noLabels, increment ); 146 } 147 148 template< typename OutIterator > 149 void build( UntypedExpr * callExpr, InitExpander::IndexList::iterator idx, InitExpander::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) { 150 if ( idx == idxEnd ) return; 151 Expression * index = *idx++; 152 assert( idx != idxEnd ); 153 Expression * dimension = *idx++; 154 155 // xxx - may want to eventually issue a warning here if we can detect 156 // that the number of elements exceeds to dimension of the array 157 if ( idx == idxEnd ) { 158 if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) { 159 for ( Initializer * init : *listInit ) { 160 buildCallExpr( callExpr->clone(), index, dimension, init, out ); 161 } 162 } else { 163 buildCallExpr( callExpr->clone(), index, dimension, init, out ); 164 } 165 } else { 166 std::list< Statement * > branches; 167 168 unsigned long cond = 0; 169 ListInit * listInit = dynamic_cast< ListInit * >( init ); 170 if ( ! listInit ) { 171 // xxx - this shouldn't be an error, but need a way to 172 // terminate without creating output, so should catch this error 173 throw SemanticError( "unbalanced list initializers" ); 174 } 175 176 static UniqueName targetLabel( "L__autogen__" ); 177 Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } ); 178 for ( Initializer * init : *listInit ) { 179 Expression * condition; 180 // check for designations 181 // if ( init-> ) { 182 condition = new ConstantExpr( Constant::from_ulong( cond ) ); 183 ++cond; 184 // } else { 185 // condition = // ... take designation 186 // cond = // ... take designation+1 187 // } 188 std::list< Statement * > stmts; 189 build( callExpr, idx, idxEnd, init, back_inserter( stmts ) ); 190 stmts.push_back( new BranchStmt( noLabels, switchLabel, BranchStmt::Break ) ); 191 CaseStmt * caseStmt = new CaseStmt( noLabels, condition, stmts ); 192 branches.push_back( caseStmt ); 193 } 194 *out++ = new SwitchStmt( noLabels, index->clone(), branches ); 195 *out++ = new NullStmt( std::list<Label>{ switchLabel } ); 196 } 197 } 198 } 199 200 // if array came with an initializer list: initialize each element 201 // may have more initializers than elements in the array - need to check at each index that 202 // we haven't exceeded size. 203 // may have fewer initializers than elements in the array - need to default construct 204 // remaining elements. 205 // To accomplish this, generate switch statement, consuming all of expander's elements 206 Statement * InitImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) { 207 if ( ! init ) return NULL; 208 CompoundStmt * block = new CompoundStmt( noLabels ); 209 build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) ); 210 if ( block->get_kids().empty() ) { 211 delete block; 212 return NULL; 213 } else { 214 init = NULL; // init was consumed in creating the list init 215 return block; 216 } 217 } 218 219 Statement * ExprImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) { 220 return NULL; 221 } 222 223 Statement * InitExpander::buildListInit( UntypedExpr * dst ) { 224 return expander->buildListInit( dst, indices ); 225 } 226 55 227 bool tryConstruct( ObjectDecl * objDecl ) { 56 228 return ! LinkageSpec::isBuiltin( objDecl->get_linkage() ) && 57 229 (objDecl->get_init() == NULL || 58 230 ( objDecl->get_init() != NULL && objDecl->get_init()->get_maybeConstructed() )) && 59 ! isDesignated( objDecl->get_init() ); 231 ! isDesignated( objDecl->get_init() ) 232 && objDecl->get_storageClass() != DeclarationNode::Extern; 233 } 234 235 class CallFinder : public Visitor { 236 public: 237 typedef Visitor Parent; 238 CallFinder( const std::list< std::string > & names ) : names( names ) {} 239 240 virtual void visit( ApplicationExpr * appExpr ) { 241 handleCallExpr( appExpr ); 242 } 243 244 virtual void visit( UntypedExpr * untypedExpr ) { 245 handleCallExpr( untypedExpr ); 246 } 247 248 std::list< Expression * > * matches; 249 private: 250 const std::list< std::string > names; 251 252 template< typename CallExpr > 253 void handleCallExpr( CallExpr * expr ) { 254 Parent::visit( expr ); 255 std::string fname = getFunctionName( expr ); 256 if ( std::find( names.begin(), names.end(), fname ) != names.end() ) { 257 matches->push_back( expr ); 258 } 259 } 260 }; 261 262 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) { 263 static CallFinder finder( std::list< std::string >{ "?{}", "^?{}" } ); 264 finder.matches = &matches; 265 maybeAccept( stmt, finder ); 60 266 } 61 267 62 268 Expression * getCtorDtorCall( Statement * stmt ) { 63 if ( stmt == NULL ) return NULL; 64 if ( ExprStmt * exprStmt = dynamic_cast< ExprStmt * >( stmt ) ) { 65 return exprStmt->get_expr(); 66 } else if ( CompoundStmt * compoundStmt = dynamic_cast< CompoundStmt * >( stmt ) ) { 67 // could also be a compound statement with a loop, in the case of an array 68 if( compoundStmt->get_kids().size() == 2 ) { 69 // loop variable and loop 70 ForStmt * forStmt = dynamic_cast< ForStmt * >( compoundStmt->get_kids().back() ); 71 assert( forStmt && forStmt->get_body() ); 72 return getCtorDtorCall( forStmt->get_body() ); 73 } else if ( compoundStmt->get_kids().size() == 1 ) { 74 // should be the call statement, but in any case there's only one option 75 return getCtorDtorCall( compoundStmt->get_kids().front() ); 76 } else { 77 assert( false && "too many statements in compoundStmt for getCtorDtorCall" ); 78 } 79 } if ( ImplicitCtorDtorStmt * impCtorDtorStmt = dynamic_cast< ImplicitCtorDtorStmt * > ( stmt ) ) { 80 return getCtorDtorCall( impCtorDtorStmt->get_callStmt() ); 81 } else { 82 // should never get here 83 assert( false && "encountered unknown call statement" ); 84 } 85 } 86 87 bool isInstrinsicSingleArgCallStmt( Statement * stmt ) { 88 Expression * callExpr = getCtorDtorCall( stmt ); 89 if ( ! callExpr ) return false; 90 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr ); 91 assert( appExpr ); 92 VariableExpr * function = dynamic_cast< VariableExpr * >( appExpr->get_function() ); 269 std::list< Expression * > matches; 270 collectCtorDtorCalls( stmt, matches ); 271 assert( matches.size() <= 1 ); 272 return matches.size() == 1 ? matches.front() : NULL; 273 } 274 275 namespace { 276 VariableExpr * getCalledFunction( ApplicationExpr * appExpr ) { 277 assert( appExpr ); 278 // xxx - it's possible this can be other things, e.g. MemberExpr, so this is insufficient 279 return dynamic_cast< VariableExpr * >( appExpr->get_function() ); 280 } 281 } 282 283 ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) { 284 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ); 285 if ( ! appExpr ) return NULL; 286 VariableExpr * function = getCalledFunction( appExpr ); 93 287 assert( function ); 94 288 // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor 95 289 // will call all member dtors, and some members may have a user defined dtor. 96 FunctionType * funcType = GenPoly::getFunctionType( function->get_var()->get_type() ); 97 assert( funcType ); 98 return function->get_var()->get_linkage() == LinkageSpec::Intrinsic && funcType->get_parameters().size() == 1; 290 return function->get_var()->get_linkage() == LinkageSpec::Intrinsic ? appExpr : NULL; 291 } 292 293 bool isIntrinsicSingleArgCallStmt( Statement * stmt ) { 294 std::list< Expression * > callExprs; 295 collectCtorDtorCalls( stmt, callExprs ); 296 // if ( callExprs.empty() ) return false; // xxx - do I still need this check? 297 return std::all_of( callExprs.begin(), callExprs.end(), []( Expression * callExpr ){ 298 if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) { 299 assert( ! appExpr->get_function()->get_results().empty() ); 300 FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_results().front() ); 301 assert( funcType ); 302 return funcType->get_parameters().size() == 1; 303 } 304 return false; 305 }); 99 306 } 100 307 … … 160 367 else return NULL; 161 368 } 369 370 class ConstExprChecker : public Visitor { 371 public: 372 ConstExprChecker() : isConstExpr( true ) {} 373 374 virtual void visit( ApplicationExpr *applicationExpr ) { isConstExpr = false; } 375 virtual void visit( UntypedExpr *untypedExpr ) { isConstExpr = false; } 376 virtual void visit( NameExpr *nameExpr ) { isConstExpr = false; } 377 virtual void visit( CastExpr *castExpr ) { isConstExpr = false; } 378 virtual void visit( LabelAddressExpr *labAddressExpr ) { isConstExpr = false; } 379 virtual void visit( UntypedMemberExpr *memberExpr ) { isConstExpr = false; } 380 virtual void visit( MemberExpr *memberExpr ) { isConstExpr = false; } 381 virtual void visit( VariableExpr *variableExpr ) { isConstExpr = false; } 382 virtual void visit( ConstantExpr *constantExpr ) { /* bottom out */ } 383 // these might be okay? 384 // virtual void visit( SizeofExpr *sizeofExpr ); 385 // virtual void visit( AlignofExpr *alignofExpr ); 386 // virtual void visit( UntypedOffsetofExpr *offsetofExpr ); 387 // virtual void visit( OffsetofExpr *offsetofExpr ); 388 // virtual void visit( OffsetPackExpr *offsetPackExpr ); 389 // virtual void visit( AttrExpr *attrExpr ); 390 // virtual void visit( CommaExpr *commaExpr ); 391 // virtual void visit( LogicalExpr *logicalExpr ); 392 // virtual void visit( ConditionalExpr *conditionalExpr ); 393 virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; } 394 virtual void visit( SolvedTupleExpr *tupleExpr ) { isConstExpr = false; } 395 virtual void visit( TypeExpr *typeExpr ) { isConstExpr = false; } 396 virtual void visit( AsmExpr *asmExpr ) { isConstExpr = false; } 397 virtual void visit( UntypedValofExpr *valofExpr ) { isConstExpr = false; } 398 virtual void visit( CompoundLiteralExpr *compLitExpr ) { isConstExpr = false; } 399 400 bool isConstExpr; 401 }; 402 403 bool isConstExpr( Expression * expr ) { 404 if ( expr ) { 405 ConstExprChecker checker; 406 expr->accept( checker ); 407 return checker.isConstExpr; 408 } 409 return true; 410 } 411 412 bool isConstExpr( Initializer * init ) { 413 if ( init ) { 414 ConstExprChecker checker; 415 init->accept( checker ); 416 return checker.isConstExpr; 417 } // if 418 // for all intents and purposes, no initializer means const expr 419 return true; 420 } 421 162 422 } -
src/InitTweak/InitTweak.h
r5070fe4 rc331406 26 26 // helper functions for initialization 27 27 namespace InitTweak { 28 /// transform Initializer into an argument list that can be passed to a call expression29 std::list< Expression * > makeInitList( Initializer * init );28 /// transform Initializer into an argument list that can be passed to a call expression 29 std::list< Expression * > makeInitList( Initializer * init ); 30 30 31 /// True if the resolver should try to construct objDecl32 bool tryConstruct( ObjectDecl * objDecl );31 /// True if the resolver should try to construct objDecl 32 bool tryConstruct( ObjectDecl * objDecl ); 33 33 34 /// True if the Initializer contains designations35 bool isDesignated( Initializer * init );34 /// True if the Initializer contains designations 35 bool isDesignated( Initializer * init ); 36 36 37 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 38 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 39 /// Currently has assertions that make it less than fully general. 40 bool isInstrinsicSingleArgCallStmt( Statement * expr ); 37 /// Non-Null if expr is a call expression whose target function is intrinsic 38 ApplicationExpr * isIntrinsicCallExpr( Expression * expr ); 41 39 42 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call 43 Expression * getCtorDtorCall( Statement * stmt ); 40 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 41 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 42 /// Currently has assertions that make it less than fully general. 43 bool isIntrinsicSingleArgCallStmt( Statement * expr ); 44 44 45 /// returns the name of the function being called 46 std::string getFunctionName( Expression * expr);45 /// get all Ctor/Dtor call expressions from a Statement 46 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ); 47 47 48 /// returns the argument to a call expression in position N indexed from 0 49 Expression *& getCallArg( Expression * callExpr, unsigned int pos);48 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call 49 Expression * getCtorDtorCall( Statement * stmt ); 50 50 51 /// returns the base type of a PointerType or ArrayType, else returns NULL 52 Type * getPointerBase( Type *);51 /// returns the name of the function being called 52 std::string getFunctionName( Expression * expr ); 53 53 54 /// returns the argument if it is a PointerType or ArrayType, else returns NULL 55 Type * isPointerType( Type * ); 54 /// returns the argument to a call expression in position N indexed from 0 55 Expression *& getCallArg( Expression * callExpr, unsigned int pos ); 56 57 /// returns the base type of a PointerType or ArrayType, else returns NULL 58 Type * getPointerBase( Type * ); 59 60 /// returns the argument if it is a PointerType or ArrayType, else returns NULL 61 Type * isPointerType( Type * ); 62 63 /// returns true if expr is trivially a compile-time constant 64 bool isConstExpr( Expression * expr ); 65 bool isConstExpr( Initializer * init ); 66 67 class InitExpander { 68 public: 69 // expand by stepping through init to get each list of arguments 70 InitExpander( Initializer * init ); 71 72 // always expand to expr 73 InitExpander( Expression * expr ); 74 75 // iterator-like interface 76 std::list< Expression * > operator*(); 77 InitExpander & operator++(); 78 79 // builds statement which has the same semantics as a C-style list initializer 80 // (for array initializers) using callExpr as the base expression to perform initialization 81 Statement * buildListInit( UntypedExpr * callExpr ); 82 void addArrayIndex( Expression * index, Expression * dimension ); 83 void clearArrayIndices(); 84 85 class ExpanderImpl; 86 private: 87 std::shared_ptr< ExpanderImpl > expander; 88 std::list< Expression * > cur; 89 90 // invariant: list of size 2N (elements come in pairs [index, dimension]) 91 typedef std::list< Expression * > IndexList; 92 IndexList indices; 93 }; 56 94 } // namespace 57 95
Note:
See TracChangeset
for help on using the changeset viewer.