Changeset 8984003 for src/InitTweak
- Timestamp:
- Nov 21, 2023, 4:47:58 PM (7 months ago)
- Branches:
- master
- Children:
- 53dac82
- Parents:
- c36a419
- Location:
- src/InitTweak
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/FixGlobalInit.cc
rc36a419 r8984003 27 27 28 28 namespace InitTweak { 29 class GlobalFixer : public ast::WithShortCircuiting {30 public:31 void previsit (const ast::ObjectDecl *);32 void previsit (const ast::FunctionDecl *) { visit_children = false; }33 void previsit (const ast::StructDecl *) { visit_children = false; }34 void previsit (const ast::UnionDecl *) { visit_children = false; }35 void previsit (const ast::EnumDecl *) { visit_children = false; }36 void previsit (const ast::TraitDecl *) { visit_children = false; }37 void previsit (const ast::TypeDecl *) { visit_children = false; }38 29 39 std::list< ast::ptr<ast::Stmt> > initStmts; 40 std::list< ast::ptr<ast::Stmt> > destroyStmts; 41 }; 30 namespace { 42 31 43 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { 44 ast::Pass<GlobalFixer> fixer; 45 accept_all(translationUnit, fixer); 32 class GlobalFixer : public ast::WithShortCircuiting { 33 public: 34 void previsit(const ast::ObjectDecl *); 35 void previsit(const ast::FunctionDecl *) { visit_children = false; } 36 void previsit(const ast::StructDecl *) { visit_children = false; } 37 void previsit(const ast::UnionDecl *) { visit_children = false; } 38 void previsit(const ast::EnumDecl *) { visit_children = false; } 39 void previsit(const ast::TraitDecl *) { visit_children = false; } 40 void previsit(const ast::TypeDecl *) { visit_children = false; } 46 41 47 // Say these magic declarations come at the end of the file. 48 CodeLocation const & location = translationUnit.decls.back()->location; 42 std::list< ast::ptr<ast::Stmt> > initStmts; 43 std::list< ast::ptr<ast::Stmt> > destroyStmts; 44 }; 49 45 50 if ( !fixer.core.initStmts.empty() ) { 51 std::vector<ast::ptr<ast::Expr>> ctorParams; 52 if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int(location, 200)); 53 auto initFunction = new ast::FunctionDecl(location, 54 "__global_init__", {}, {}, {}, 55 new ast::CompoundStmt(location, std::move(fixer.core.initStmts)), 56 ast::Storage::Static, ast::Linkage::C, 57 {new ast::Attribute("constructor", std::move(ctorParams))}); 46 void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) { 47 auto mutDecl = mutate(objDecl); 48 assertf(mutDecl == objDecl, "Global object decl must be unique"); 49 auto ctorInit = objDecl->init.as<ast::ConstructorInit>(); 50 if ( nullptr == ctorInit ) return; 58 51 59 translationUnit.decls.emplace_back( initFunction );60 } // if52 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 53 assert( !ctorInit->ctor || !ctorInit->init ); 61 54 62 if ( !fixer.core.destroyStmts.empty() ) { 63 std::vector<ast::ptr<ast::Expr>> dtorParams; 64 if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int(location, 200)); 65 auto destroyFunction = new ast::FunctionDecl( location, 66 "__global_destroy__", {}, {}, {}, 67 new ast::CompoundStmt(location, std::move(fixer.core.destroyStmts)), 68 ast::Storage::Static, ast::Linkage::C, 69 {new ast::Attribute("destructor", std::move(dtorParams))}); 55 const ast::Stmt * dtor = ctorInit->dtor; 56 if ( dtor && !isIntrinsicSingleArgCallStmt( dtor ) ) { 57 // don't need to call intrinsic dtor, because it does nothing, but 58 // non-intrinsic dtors must be called 59 destroyStmts.push_front( dtor ); 60 } // if 61 if ( const ast::Stmt * ctor = ctorInit->ctor ) { 62 addDataSectionAttribute(mutDecl); 63 initStmts.push_back( ctor ); 64 mutDecl->init = nullptr; 65 } else if ( const ast::Init * init = ctorInit->init ) { 66 mutDecl->init = init; 67 } else { 68 // no constructor and no initializer, which is okay 69 mutDecl->init = nullptr; 70 } 71 } 70 72 71 translationUnit.decls.emplace_back(destroyFunction); 72 } // if 73 } 73 } // namespace 74 74 75 void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) { 76 auto mutDecl = mutate(objDecl); 77 assertf(mutDecl == objDecl, "Global object decl must be unique"); 78 if ( auto ctorInit = objDecl->init.as<ast::ConstructorInit>() ) { 79 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 80 assert( ! ctorInit->ctor || ! ctorInit->init ); 75 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { 76 ast::Pass<GlobalFixer> fixer; 77 accept_all(translationUnit, fixer); 81 78 82 const ast::Stmt * dtor = ctorInit->dtor; 83 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 84 // don't need to call intrinsic dtor, because it does nothing, but 85 // non-intrinsic dtors must be called 86 destroyStmts.push_front( dtor ); 87 // ctorInit->dtor = nullptr; 88 } // if 89 if ( const ast::Stmt * ctor = ctorInit->ctor ) { 90 addDataSectionAttribute(mutDecl); 91 initStmts.push_back( ctor ); 92 mutDecl->init = nullptr; 93 // ctorInit->ctor = nullptr; 94 } else if ( const ast::Init * init = ctorInit->init ) { 95 mutDecl->init = init; 96 // ctorInit->init = nullptr; 97 } else { 98 // no constructor and no initializer, which is okay 99 mutDecl->init = nullptr; 100 } // if 101 // delete ctorInit; 102 } // if 103 } 79 // Say these magic declarations come at the end of the file. 80 CodeLocation const & location = translationUnit.decls.back()->location; 81 82 if ( !fixer.core.initStmts.empty() ) { 83 std::vector<ast::ptr<ast::Expr>> ctorParams; 84 if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int(location, 200)); 85 auto initFunction = new ast::FunctionDecl(location, 86 "__global_init__", {}, {}, {}, 87 new ast::CompoundStmt(location, std::move(fixer.core.initStmts)), 88 ast::Storage::Static, ast::Linkage::C, 89 {new ast::Attribute("constructor", std::move(ctorParams))}); 90 91 translationUnit.decls.emplace_back( initFunction ); 92 } // if 93 94 if ( !fixer.core.destroyStmts.empty() ) { 95 std::vector<ast::ptr<ast::Expr>> dtorParams; 96 if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int(location, 200)); 97 auto destroyFunction = new ast::FunctionDecl( location, 98 "__global_destroy__", {}, {}, {}, 99 new ast::CompoundStmt(location, std::move(fixer.core.destroyStmts)), 100 ast::Storage::Static, ast::Linkage::C, 101 {new ast::Attribute("destructor", std::move(dtorParams))}); 102 103 translationUnit.decls.emplace_back(destroyFunction); 104 } // if 105 } 104 106 105 107 } // namespace InitTweak -
src/InitTweak/FixGlobalInit.h
rc36a419 r8984003 16 16 #pragma once 17 17 18 #include <list> // for list 19 #include <string> // for string 20 21 #include <AST/Fwd.hpp> 22 23 24 class Declaration; 18 namespace ast { 19 class TranslationUnit; 20 } 25 21 26 22 namespace InitTweak { 27 /// Moves global initialization into an _init function that is unique to the translation unit. 28 /// Sets the priority of the initialization function depending on whether the initialization 29 /// function is for library code. 30 void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ); 31 void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary ); 23 24 /// Moves global initialization into an _init function that is unique to the translation unit. 25 /// Sets the priority of the initialization function depending on whether the initialization 26 /// function is for library code. 27 void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary ); 28 32 29 } // namespace 33 30 -
src/InitTweak/FixInit.h
rc36a419 r8984003 16 16 #pragma once 17 17 18 #include <list> // for list19 #include <string> // for string20 21 class Declaration;22 18 namespace ast { 23 19 class TranslationUnit; … … 25 21 26 22 namespace InitTweak { 27 /// replace constructor initializers with expression statements and unwrap basic C-style initializers28 void fix( std::list< Declaration * > & translationUnit, bool inLibrary );29 23 30 void fix( ast::TranslationUnit & translationUnit, bool inLibrary); 24 /// Replace constructor initializers with expression statements and unwrap basic C-style initializers. 25 void fix( ast::TranslationUnit & translationUnit, bool inLibrary); 26 31 27 } // namespace 32 28 -
src/InitTweak/GenInit.cc
rc36a419 r8984003 206 206 }; 207 207 208 209 210 211 208 struct ReturnFixer final : 212 209 public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting { … … 262 259 } // namespace 263 260 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 261 void genInit( ast::TranslationUnit & transUnit ) { 262 ast::Pass<HoistArrayDimension_NoResolve>::run( transUnit ); 263 ast::Pass<ReturnFixer>::run( transUnit ); 264 } 265 266 void fixReturnStatements( ast::TranslationUnit & transUnit ) { 267 ast::Pass<ReturnFixer>::run( transUnit ); 268 } 269 270 bool ManagedTypes::isManaged( const ast::Type * type ) const { 271 // references are never constructed 272 if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false; 273 if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) { 274 // tuple is also managed if any of its components are managed 275 for (auto & component : tupleType->types) { 276 if (isManaged(component)) return true; 277 } 278 } 279 // need to clear and reset qualifiers when determining if a type is managed 280 // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() ); 281 auto tmp = shallowCopy(type); 282 tmp->qualifiers = {}; 283 // delete tmp at return 284 ast::ptr<ast::Type> guard = tmp; 285 // 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) 286 return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp ); 287 } 288 289 bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const { 290 const ast::Type * type = objDecl->type; 291 while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) { 292 // must always construct VLAs with an initializer, since this is an error in C 293 if ( at->isVarLen && objDecl->init ) return true; 294 type = at->base; 295 } 296 return isManaged( type ); 297 } 298 299 void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) { 300 // if this function is a user-defined constructor or destructor, mark down the type as "managed" 301 if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) { 302 auto & params = GenPoly::getFunctionType( dwt->get_type())->params; 303 assert( ! params.empty() ); 304 // Type * type = InitTweak::getPointerBase( params.front() ); 305 // assert( type ); 306 managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ); 307 } 308 } 309 310 void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) { 311 // don't construct members, but need to take note if there is a managed member, 312 // because that means that this type is also managed 313 for ( auto & member : aggregateDecl->members ) { 314 if ( auto field = member.as<ast::ObjectDecl>() ) { 315 if ( isManaged( field ) ) { 316 // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that 317 // polymorphic constructors make generic types managed types 318 ast::StructInstType inst( aggregateDecl ); 319 managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ); 320 break; 321 } 322 } 323 } 324 } 325 326 void ManagedTypes::beginScope() { managedTypes.beginScope(); } 327 void ManagedTypes::endScope() { managedTypes.endScope(); } 328 329 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 330 assertf(objDecl, "genCtorDtor passed null objDecl"); 331 InitExpander srcParam(arg); 332 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl); 333 } 337 334 338 335 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) { -
src/InitTweak/GenInit.h
rc36a419 r8984003 24 24 25 25 namespace InitTweak { 26 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes27 void genInit( ast::TranslationUnit & translationUnit );28 26 29 /// Converts return statements into copy constructor calls on the hidden return variable. 30 /// This pass must happen before auto-gen. 31 void fixReturnStatements( ast::TranslationUnit & translationUnit ); 27 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 void genInit( ast::TranslationUnit & translationUnit ); 32 29 33 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 34 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 30 /// Converts return statements into copy constructor calls on the hidden return variable. 31 /// This pass must happen before auto-gen. 32 void fixReturnStatements( ast::TranslationUnit & translationUnit ); 35 33 36 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 37 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl);34 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 35 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 38 36 39 class ManagedTypes final { 40 public: 41 bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed 42 bool isManaged( const ast::Type * type ) const; // determine if type is managed 37 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 38 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ); 43 39 44 void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor 45 void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed 40 class ManagedTypes final { 41 public: 42 bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed 43 bool isManaged( const ast::Type * type ) const; // determine if type is managed 46 44 47 void beginScope(); 48 void endScope(); 49 private: 50 GenPoly::ScopedSet< std::string > managedTypes; 51 }; 45 void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor 46 void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed 47 48 void beginScope(); 49 void endScope(); 50 private: 51 GenPoly::ScopedSet< std::string > managedTypes; 52 }; 53 52 54 } // namespace 53 55 -
src/InitTweak/InitTweak.cc
rc36a419 r8984003 14 14 // 15 15 16 #include "InitTweak.h" 17 16 18 #include <algorithm> // for find, all_of 17 19 #include <cassert> // for assertf, assert, strict_dynamic_cast … … 30 32 #include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto... 31 33 #include "Common/SemanticError.h" // for SemanticError 34 #include "Common/ToString.hpp" // for toCString 32 35 #include "Common/UniqueName.h" // for UniqueName 33 #include "Common/utility.h" // for toString, deleteAll, maybeClone34 36 #include "GenPoly/GenPoly.h" // for getFunctionType 35 #include "InitTweak.h"36 37 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 37 38 #include "Tuples/Tuples.h" // for Tuples::isTtype 38 39 39 40 namespace InitTweak { 40 namespace { 41 struct HasDesignations : public ast::WithShortCircuiting { 42 bool result = false; 43 44 void previsit( const ast::Node * ) { 45 // short circuit if we already know there are designations 46 if ( result ) visit_children = false; 47 } 48 49 void previsit( const ast::Designation * des ) { 50 // short circuit if we already know there are designations 51 if ( result ) visit_children = false; 52 else if ( ! des->designators.empty() ) { 53 result = true; 54 visit_children = false; 55 } 56 } 57 }; 58 59 struct InitDepthChecker { 60 bool result = true; 61 const ast::Type * type; 62 int curDepth = 0, maxDepth = 0; 63 InitDepthChecker( const ast::Type * type ) : type( type ) { 64 const ast::Type * t = type; 65 while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) { 66 maxDepth++; 67 t = at->base; 68 } 69 maxDepth++; 70 } 71 void previsit( ast::ListInit const * ) { 72 curDepth++; 73 if ( curDepth > maxDepth ) result = false; 74 } 75 void postvisit( ast::ListInit const * ) { 76 curDepth--; 77 } 78 }; 79 80 struct InitFlattener : public ast::WithShortCircuiting { 81 std::vector< ast::ptr< ast::Expr > > argList; 82 83 void previsit( const ast::SingleInit * singleInit ) { 84 visit_children = false; 85 argList.emplace_back( singleInit->value ); 86 } 87 }; 88 89 } // anonymous namespace 90 91 bool isDesignated( const ast::Init * init ) { 92 ast::Pass<HasDesignations> finder; 93 maybe_accept( init, finder ); 94 return finder.core.result; 95 } 96 97 bool checkInitDepth( const ast::ObjectDecl * objDecl ) { 98 ast::Pass<InitDepthChecker> checker( objDecl->type ); 99 maybe_accept( objDecl->init.get(), checker ); 100 return checker.core.result; 101 } 102 103 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) { 104 ast::Pass< InitFlattener > flattener; 105 maybe_accept( init, flattener ); 106 return std::move( flattener.core.argList ); 107 } 108 41 42 // Forward declared, because it is used as a parent type. 109 43 class InitExpander::ExpanderImpl { 110 44 public: … … 116 50 117 51 namespace { 52 struct HasDesignations : public ast::WithShortCircuiting { 53 bool result = false; 54 55 void previsit( const ast::Node * ) { 56 // Short circuit if we already know there are designations. 57 if ( result ) visit_children = false; 58 } 59 60 void previsit( const ast::Designation * des ) { 61 // Short circuit if we already know there are designations. 62 if ( result ) visit_children = false; 63 else if ( !des->designators.empty() ) { 64 result = true; 65 visit_children = false; 66 } 67 } 68 }; 69 70 struct InitDepthChecker { 71 bool result = true; 72 const ast::Type * type; 73 int curDepth = 0, maxDepth = 0; 74 InitDepthChecker( const ast::Type * type ) : type( type ) { 75 const ast::Type * t = type; 76 while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) { 77 maxDepth++; 78 t = at->base; 79 } 80 maxDepth++; 81 } 82 void previsit( ast::ListInit const * ) { 83 curDepth++; 84 if ( curDepth > maxDepth ) result = false; 85 } 86 void postvisit( ast::ListInit const * ) { 87 curDepth--; 88 } 89 }; 90 91 struct InitFlattener : public ast::WithShortCircuiting { 92 std::vector< ast::ptr< ast::Expr > > argList; 93 94 void previsit( const ast::SingleInit * singleInit ) { 95 visit_children = false; 96 argList.emplace_back( singleInit->value ); 97 } 98 }; 99 118 100 template< typename Out > 119 101 void buildCallExpr( … … 223 205 InitExpander::IndexList & indices 224 206 ) override { 225 if ( ! 207 if ( !arg ) return {}; 226 208 227 209 const CodeLocation & loc = arg->location; 228 210 const ast::Expr * expr = arg; 229 211 for ( auto it = indices.rbegin(); it != indices.rend(); ++it ) { 230 // go through indices and layer on subscript exprs ?[?]212 // Go through indices and layer on subscript exprs ?[?]. 231 213 ++it; 232 214 expr = new ast::UntypedExpr{ … … 242 224 } 243 225 }; 244 } // anonymous namespace245 246 InitExpander::InitExpander( const ast::Init * init )247 : expander( new InitImpl{ init } ), crnt(), indices() {}248 249 InitExpander::InitExpander( const ast::Expr * expr )250 : expander( new ExprImpl{ expr } ), crnt(), indices() {}251 252 std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }253 254 InitExpander & InitExpander::operator++ () {255 crnt = expander->next( indices );256 return *this;257 }258 259 /// builds statement which has the same semantics as a C-style list initializer (for array260 /// initializers) using callExpr as the base expression to perform initialization261 ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {262 return expander->buildListInit( callExpr, indices );263 }264 265 void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {266 indices.emplace_back( index );267 indices.emplace_back( dimension );268 }269 270 void InitExpander::clearArrayIndices() { indices.clear(); }271 272 bool InitExpander::addReference() {273 for ( ast::ptr< ast::Expr > & expr : crnt ) {274 expr = new ast::AddressExpr{ expr };275 }276 return ! crnt.empty();277 }278 279 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {280 assertf( ftype, "getTypeofThis: nullptr ftype" );281 const std::vector<ast::ptr<ast::Type>> & params = ftype->params;282 assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s",283 toString( ftype ).c_str() );284 const ast::ReferenceType * refType =285 params.front().strict_as<ast::ReferenceType>();286 return refType->base;287 }288 289 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {290 assertf( func, "getParamThis: nullptr ftype" );291 auto & params = func->params;292 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());293 return params.front().strict_as<ast::ObjectDecl>();294 }295 296 bool tryConstruct( const ast::DeclWithType * dwt ) {297 auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );298 if ( ! objDecl ) return false;299 return (objDecl->init == nullptr ||300 ( objDecl->init != nullptr && objDecl->init->maybeConstructed ))301 && ! objDecl->storage.is_extern302 && isConstructable( objDecl->type );303 }304 305 bool isConstructable( const ast::Type * type ) {306 return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type )307 && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type );308 }309 226 310 227 struct CallFinder final { … … 325 242 }; 326 243 327 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 328 ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 329 maybe_accept( stmt, finder ); 330 return std::move( finder.core.matches ); 331 } 332 333 namespace { 334 template <typename Predicate> 335 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { 336 std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt ); 337 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 338 } 339 } 340 341 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) { 342 return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){ 343 if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) { 344 const ast::FunctionType * funcType = 345 GenPoly::getFunctionType( appExpr->func->result ); 346 assert( funcType ); 347 return funcType->params.size() == 1; 348 } 349 return false; 350 }); 351 } 352 353 // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards 354 // following passes may accidentally resolve this expression if returned as untyped... 355 ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) { 356 static ast::ptr<ast::FunctionDecl> assign = nullptr; 357 if (!assign) { 358 auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true); 359 assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td}, 360 { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))), 361 new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))}, 362 { new ast::ObjectDecl(CodeLocation(), "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic); 363 } 364 if (dst->result.as<ast::ReferenceType>()) { 365 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) { 366 dst = new ast::AddressExpr(dst); 367 } 368 } else { 369 dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {})); 370 } 371 if (src->result.as<ast::ReferenceType>()) { 372 for (int depth = src->result->referenceDepth(); depth > 0; depth--) { 373 src = new ast::AddressExpr(src); 374 } 375 } 376 auto var = ast::VariableExpr::functionPointer(dst->location, assign); 377 auto app = new ast::ApplicationExpr(dst->location, var, {dst, src}); 378 // Skip the resolver, just set the result to the correct type. 379 app->result = ast::deepCopy( src->result ); 380 return app; 244 template <typename Predicate> 245 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { 246 std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt ); 247 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 381 248 } 382 249 383 250 struct ConstExprChecker : public ast::WithShortCircuiting { 384 // most expressions are not const expr251 // Most expressions are not const-expr. 385 252 void previsit( const ast::Expr * ) { result = false; visit_children = false; } 386 253 … … 389 256 const ast::Expr * arg = addressExpr->arg; 390 257 391 // address of a variable or member expression is constexpr392 if ( ! 393 && !dynamic_cast< const ast::VariableExpr * >( arg )394 && !dynamic_cast< const ast::MemberExpr * >( arg )395 && !dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;396 } 397 398 // these expressions may be const expr, depending on their children258 // Address of a variable or member expression is const-expr. 259 if ( !dynamic_cast< const ast::NameExpr * >( arg ) 260 && !dynamic_cast< const ast::VariableExpr * >( arg ) 261 && !dynamic_cast< const ast::MemberExpr * >( arg ) 262 && !dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false; 263 } 264 265 // These expressions may be const expr, depending on their children. 399 266 void previsit( const ast::SizeofExpr * ) {} 400 267 void previsit( const ast::AlignofExpr * ) {} … … 423 290 bool result = true; 424 291 }; 425 426 bool isConstExpr( const ast::Expr * expr ) { 427 if ( expr ) { 428 ast::Pass<ConstExprChecker> checker; 429 expr->accept( checker ); 430 return checker.core.result; 431 } 432 return true; 433 } 434 435 bool isConstExpr( const ast::Init * init ) { 436 if ( init ) { 437 ast::Pass<ConstExprChecker> checker; 438 init->accept( checker ); 439 return checker.core.result; 440 } // if 441 // for all intents and purposes, no initializer means const expr 442 return true; 443 } 292 } // namespace 444 293 445 294 bool isAssignment( const ast::FunctionDecl * decl ) { … … 470 319 } 471 320 472 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message 473 #define ASM_COMMENT "#" 474 #else // defined( __ARM_ARCH ) 475 #define ASM_COMMENT "//" 476 #endif 477 static const char * const data_section = ".data" ASM_COMMENT; 478 static const char * const tlsd_section = ".tdata" ASM_COMMENT; 479 480 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { 481 const bool is_tls = objDecl->storage.is_threadlocal_any(); 482 const char * section = is_tls ? tlsd_section : data_section; 483 objDecl->attributes.push_back(new ast::Attribute("section", { 484 ast::ConstantExpr::from_string(objDecl->location, section) 485 })); 486 } 321 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { 322 assertf( ftype, "getTypeofThis: nullptr ftype" ); 323 const std::vector<ast::ptr<ast::Type>> & params = ftype->params; 324 assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s", 325 toCString( ftype ) ); 326 const ast::ReferenceType * refType = 327 params.front().strict_as<ast::ReferenceType>(); 328 return refType->base; 329 } 330 331 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 332 assertf( func, "getParamThis: nullptr ftype" ); 333 auto & params = func->params; 334 assertf( !params.empty(), "getParamThis: ftype with 0 parameters: %s", toCString( func )); 335 return params.front().strict_as<ast::ObjectDecl>(); 336 } 337 338 // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards 339 // following passes may accidentally resolve this expression if returned as untyped... 340 ast::Expr * createBitwiseAssignment(const ast::Expr * dst, const ast::Expr * src) { 341 static ast::ptr<ast::FunctionDecl> assign = nullptr; 342 if (!assign) { 343 auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true); 344 assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td}, 345 { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))), 346 new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))}, 347 { new ast::ObjectDecl(CodeLocation(), "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic); 348 } 349 if (dst->result.as<ast::ReferenceType>()) { 350 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) { 351 dst = new ast::AddressExpr(dst); 352 } 353 } else { 354 dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {})); 355 } 356 if (src->result.as<ast::ReferenceType>()) { 357 for (int depth = src->result->referenceDepth(); depth > 0; depth--) { 358 src = new ast::AddressExpr(src); 359 } 360 } 361 auto var = ast::VariableExpr::functionPointer(dst->location, assign); 362 auto app = new ast::ApplicationExpr(dst->location, var, {dst, src}); 363 // Skip the resolver, just set the result to the correct type. 364 app->result = ast::deepCopy( src->result ); 365 return app; 366 } 367 368 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) { 369 ast::Pass< InitFlattener > flattener; 370 maybe_accept( init, flattener ); 371 return std::move( flattener.core.argList ); 372 } 373 374 bool tryConstruct( const ast::DeclWithType * dwt ) { 375 auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt ); 376 if ( !objDecl ) return false; 377 return (objDecl->init == nullptr || 378 ( objDecl->init != nullptr && objDecl->init->maybeConstructed )) 379 && !objDecl->storage.is_extern 380 && isConstructable( objDecl->type ); 381 } 382 383 bool isConstructable( const ast::Type * type ) { 384 return !dynamic_cast< const ast::VarArgsType * >( type ) && !dynamic_cast< const ast::ReferenceType * >( type ) 385 && !dynamic_cast< const ast::FunctionType * >( type ) && !Tuples::isTtype( type ); 386 } 387 388 bool isDesignated( const ast::Init * init ) { 389 // return ( init ) ? ast::Pass<HasDesignations>::read( init ) : false; 390 ast::Pass<HasDesignations> finder; 391 maybe_accept( init, finder ); 392 return finder.core.result; 393 } 394 395 bool checkInitDepth( const ast::ObjectDecl * objDecl ) { 396 // return ( objDecl->init ) ? ast::Pass<InitDepthChecker::read( objDecl->init, objDecl->type ) : true; 397 ast::Pass<InitDepthChecker> checker( objDecl->type ); 398 maybe_accept( objDecl->init.get(), checker ); 399 return checker.core.result; 400 } 401 402 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) { 403 return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){ 404 if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) { 405 const ast::FunctionType * funcType = 406 GenPoly::getFunctionType( appExpr->func->result ); 407 assert( funcType ); 408 return funcType->params.size() == 1; 409 } 410 return false; 411 }); 412 } 413 414 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 415 ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 416 maybe_accept( stmt, finder ); 417 return std::move( finder.core.matches ); 418 } 419 420 bool isConstExpr( const ast::Expr * expr ) { 421 return ( expr ) ? ast::Pass<ConstExprChecker>::read( expr ) : true; 422 } 423 424 bool isConstExpr( const ast::Init * init ) { 425 // for all intents and purposes, no initializer means const expr 426 return ( init ) ? ast::Pass<ConstExprChecker>::read( init ) : true; 427 } 428 429 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message 430 #define ASM_COMMENT "#" 431 #else // defined( __ARM_ARCH ) 432 #define ASM_COMMENT "//" 433 #endif 434 static const char * const data_section = ".data" ASM_COMMENT; 435 static const char * const tlsd_section = ".tdata" ASM_COMMENT; 436 437 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { 438 const bool is_tls = objDecl->storage.is_threadlocal_any(); 439 const char * section = is_tls ? tlsd_section : data_section; 440 objDecl->attributes.push_back(new ast::Attribute("section", { 441 ast::ConstantExpr::from_string(objDecl->location, section) 442 })); 443 } 444 445 InitExpander::InitExpander( const ast::Init * init ) 446 : expander( new InitImpl{ init } ), crnt(), indices() {} 447 448 InitExpander::InitExpander( const ast::Expr * expr ) 449 : expander( new ExprImpl{ expr } ), crnt(), indices() {} 450 451 std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; } 452 453 InitExpander & InitExpander::operator++ () { 454 crnt = expander->next( indices ); 455 return *this; 456 } 457 458 /// builds statement which has the same semantics as a C-style list initializer (for array 459 /// initializers) using callExpr as the base expression to perform initialization 460 ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) { 461 return expander->buildListInit( callExpr, indices ); 462 } 463 464 void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) { 465 indices.emplace_back( index ); 466 indices.emplace_back( dimension ); 467 } 468 469 void InitExpander::clearArrayIndices() { indices.clear(); } 470 471 bool InitExpander::addReference() { 472 for ( ast::ptr< ast::Expr > & expr : crnt ) { 473 expr = new ast::AddressExpr{ expr }; 474 } 475 return !crnt.empty(); 476 } 487 477 488 478 } // namespace InitTweak -
src/InitTweak/InitTweak.h
rc36a419 r8984003 25 25 // helper functions for initialization 26 26 namespace InitTweak { 27 bool isAssignment( const ast::FunctionDecl * decl );28 bool isDestructor( const ast::FunctionDecl * decl );29 bool isDefaultConstructor( const ast::FunctionDecl * decl );30 bool isCopyConstructor( const ast::FunctionDecl * decl );31 bool isCopyFunction( const ast::FunctionDecl * decl );32 27 33 /// returns the base type of the first parameter to a constructor/destructor/assignment function 34 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 28 bool isAssignment( const ast::FunctionDecl * decl ); 29 bool isDestructor( const ast::FunctionDecl * decl ); 30 bool isDefaultConstructor( const ast::FunctionDecl * decl ); 31 bool isCopyConstructor( const ast::FunctionDecl * decl ); 32 bool isCopyFunction( const ast::FunctionDecl * decl ); 35 33 36 /// returns the first parameter ofa constructor/destructor/assignment function37 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);34 /// returns the base type of the first parameter to a constructor/destructor/assignment function 35 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 38 36 39 /// generate a bitwise assignment operation. 40 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);37 /// returns the first parameter of a constructor/destructor/assignment function 38 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 41 39 42 /// transform Initializer into an argument list that can be passed to a call expression 43 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init);40 /// generate a bitwise assignment operation. 41 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 44 42 45 /// True if the resolver should try to construct dwt 46 bool tryConstruct( const ast::DeclWithType * dwt );43 /// transform Initializer into an argument list that can be passed to a call expression 44 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ); 47 45 48 /// True if the type can have a user-defined constructor 49 bool isConstructable( const ast::Type *t );46 /// True if the resolver should try to construct dwt 47 bool tryConstruct( const ast::DeclWithType * dwt ); 50 48 51 /// True if the Initializer contains designations 52 bool isDesignated( const ast::Init * init );49 /// True if the type can have a user-defined constructor 50 bool isConstructable( const ast::Type * t ); 53 51 54 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 55 /// type, where the depth of its type is the number of nested ArrayTypes + 1 56 bool checkInitDepth( const ast::ObjectDecl * objDecl ); 52 /// True if the Initializer contains designations 53 bool isDesignated( const ast::Init * init ); 57 54 58 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 59 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 60 /// Currently has assertions that make it less than fully general. 61 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ); 55 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 56 /// type, where the depth of its type is the number of nested ArrayTypes + 1 57 bool checkInitDepth( const ast::ObjectDecl * objDecl ); 62 58 63 /// get all Ctor/Dtor call expressions from a Statement 64 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 59 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 60 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 61 /// Currently has assertions that make it less than fully general. 62 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ); 65 63 66 /// returns true if expr is trivially a compile-time constant 67 bool isConstExpr( const ast::Expr * expr ); 68 bool isConstExpr( const ast::Init * init ); 64 /// get all Ctor/Dtor call expressions from a Statement 65 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 69 66 70 /// Modifies objDecl to have: 71 /// __attribute__((section (".data#"))) 72 /// which makes gcc put the declared variable in the data section, 73 /// which is helpful for global constants on newer gcc versions, 74 /// so that CFA's generated initialization won't segfault when writing it via a const cast. 75 /// The trailing # is an injected assembly comment, to suppress the "a" in 76 /// .section .data,"a" 77 /// .section .data#,"a" 78 /// to avoid assembler warning "ignoring changed section attributes for .data" 79 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 67 /// returns true if expr is trivially a compile-time constant 68 bool isConstExpr( const ast::Expr * expr ); 69 bool isConstExpr( const ast::Init * init ); 80 70 81 class InitExpander final { 82 public: 83 using IndexList = std::vector< ast::ptr< ast::Expr > >; 84 class ExpanderImpl; 71 /// Modifies objDecl to have: 72 /// __attribute__((section (".data#"))) 73 /// which makes gcc put the declared variable in the data section, 74 /// which is helpful for global constants on newer gcc versions, 75 /// so that CFA's generated initialization won't segfault when writing it via a const cast. 76 /// The trailing # is an injected assembly comment, to suppress the "a" in 77 /// .section .data,"a" 78 /// .section .data#,"a" 79 /// to avoid assembler warning "ignoring changed section attributes for .data" 80 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 85 81 86 private: 87 std::shared_ptr< ExpanderImpl > expander; 88 std::vector< ast::ptr< ast::Expr > > crnt; 89 // invariant: list of size 2N (elements come in pairs [index, dimension]) 90 IndexList indices; 82 class InitExpander final { 83 public: 84 using IndexList = std::vector< ast::ptr< ast::Expr > >; 85 class ExpanderImpl; 91 86 92 public: 93 /// Expand by stepping through init to get each list of arguments 94 InitExpander( const ast::Init * init ); 87 private: 88 std::shared_ptr< ExpanderImpl > expander; 89 std::vector< ast::ptr< ast::Expr > > crnt; 90 // invariant: list of size 2N (elements come in pairs [index, dimension]) 91 IndexList indices; 95 92 96 /// Always expand to expression 97 InitExpander( const ast::Expr * expr ); 93 public: 94 /// Expand by stepping through init to get each list of arguments 95 InitExpander( const ast::Init * init ); 98 96 99 std::vector< ast::ptr< ast::Expr > > operator* ();100 InitExpander & operator++ ();97 /// Always expand to expression 98 InitExpander( const ast::Expr * expr ); 101 99 102 /// builds statement which has the same semantics as a C-style list initializer (for array 103 /// initializers) using callExpr as the base expression to perform initialization. 104 /// Mutates callExpr 105 ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr ); 100 std::vector< ast::ptr< ast::Expr > > operator* (); 101 InitExpander & operator++ (); 106 102 107 void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ); 103 /// builds statement which has the same semantics as a C-style list initializer (for array 104 /// initializers) using callExpr as the base expression to perform initialization. 105 /// Mutates callExpr 106 ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr ); 108 107 109 void clearArrayIndices();108 void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ); 110 109 111 bool addReference(); 112 }; 110 void clearArrayIndices(); 111 112 bool addReference(); 113 }; 114 113 115 } // namespace InitTweak 114 116
Note: See TracChangeset
for help on using the changeset viewer.