Changeset c6b4432 for src/InitTweak
- Timestamp:
- Nov 8, 2023, 2:01:11 PM (2 years ago)
- Branches:
- master
- Children:
- 3e4bf0d, f5ec35a
- Parents:
- 790d835
- Location:
- src/InitTweak
- Files:
-
- 1 deleted
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/FixGlobalInit.cc
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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
r790d835 rc6b4432 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; … … 128 78 }; 129 79 130 struct InitFlattener_old : public WithShortCircuiting {131 void previsit( SingleInit * singleInit ) {132 visit_children = false;133 argList.push_back( singleInit->value->clone() );134 }135 std::list< Expression * > argList;136 };137 138 80 struct InitFlattener_new : public ast::WithShortCircuiting { 139 81 std::vector< ast::ptr< ast::Expr > > argList; … … 146 88 147 89 } // anonymous namespace 148 149 std::list< Expression * > makeInitList( Initializer * init ) {150 PassVisitor<InitFlattener_old> flattener;151 maybeAccept( init, flattener );152 return flattener.pass.argList;153 }154 155 bool isDesignated( Initializer * init ) {156 PassVisitor<HasDesignations> finder;157 maybeAccept( init, finder );158 return finder.pass.hasDesignations;159 }160 161 bool checkInitDepth( ObjectDecl * objDecl ) {162 PassVisitor<InitDepthChecker> checker( objDecl->type );163 maybeAccept( objDecl->init, checker );164 return checker.pass.depthOkay;165 }166 90 167 91 bool isDesignated( const ast::Init * init ) { … … 182 106 return std::move( flattener.core.argList ); 183 107 } 184 185 class InitExpander_old::ExpanderImpl {186 public:187 virtual ~ExpanderImpl() = default;188 virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0;189 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0;190 };191 192 class InitImpl_old : public InitExpander_old::ExpanderImpl {193 public:194 InitImpl_old( Initializer * init ) : init( init ) {}195 virtual ~InitImpl_old() = default;196 197 virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) {198 // this is wrong, but just a placeholder for now199 // if ( ! flattened ) flatten( indices );200 // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();201 return makeInitList( init );202 }203 204 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );205 private:206 Initializer * init;207 };208 209 class ExprImpl_old : public InitExpander_old::ExpanderImpl {210 public:211 ExprImpl_old( Expression * expr ) : arg( expr ) {}212 virtual ~ExprImpl_old() { delete arg; }213 214 virtual std::list< Expression * > next( std::list< Expression * > & indices ) {215 std::list< Expression * > ret;216 Expression * expr = maybeClone( arg );217 if ( expr ) {218 for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) {219 // go through indices and layer on subscript exprs ?[?]220 ++it;221 UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") );222 subscriptExpr->get_args().push_back( expr );223 subscriptExpr->get_args().push_back( (*it)->clone() );224 expr = subscriptExpr;225 }226 ret.push_back( expr );227 }228 return ret;229 }230 231 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );232 private:233 Expression * arg;234 };235 236 InitExpander_old::InitExpander_old( Initializer * init ) : expander( new InitImpl_old( init ) ) {}237 238 InitExpander_old::InitExpander_old( Expression * expr ) : expander( new ExprImpl_old( expr ) ) {}239 240 std::list< Expression * > InitExpander_old::operator*() {241 return cur;242 }243 244 InitExpander_old & InitExpander_old::operator++() {245 cur = expander->next( indices );246 return *this;247 }248 249 // use array indices list to build switch statement250 void InitExpander_old::addArrayIndex( Expression * index, Expression * dimension ) {251 indices.push_back( index );252 indices.push_back( dimension );253 }254 255 void InitExpander_old::clearArrayIndices() {256 deleteAll( indices );257 indices.clear();258 }259 260 bool InitExpander_old::addReference() {261 bool added = false;262 for ( Expression *& expr : cur ) {263 expr = new AddressExpr( expr );264 added = true;265 }266 return added;267 }268 269 namespace {270 /// given index i, dimension d, initializer init, and callExpr f, generates271 /// if (i < d) f(..., init)272 /// ++i;273 /// so that only elements within the range of the array are constructed274 template< typename OutIterator >275 void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) {276 UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );277 cond->get_args().push_back( index->clone() );278 cond->get_args().push_back( dimension->clone() );279 280 std::list< Expression * > args = makeInitList( init );281 callExpr->get_args().splice( callExpr->get_args().end(), args );282 283 *out++ = new IfStmt( cond, new ExprStmt( callExpr ), nullptr );284 285 UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );286 increment->get_args().push_back( index->clone() );287 *out++ = new ExprStmt( increment );288 }289 290 template< typename OutIterator >291 void build( UntypedExpr * callExpr, InitExpander_old::IndexList::iterator idx, InitExpander_old::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {292 if ( idx == idxEnd ) return;293 Expression * index = *idx++;294 assert( idx != idxEnd );295 Expression * dimension = *idx++;296 297 // xxx - may want to eventually issue a warning here if we can detect298 // that the number of elements exceeds to dimension of the array299 if ( idx == idxEnd ) {300 if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) {301 for ( Initializer * init : *listInit ) {302 buildCallExpr( callExpr->clone(), index, dimension, init, out );303 }304 } else {305 buildCallExpr( callExpr->clone(), index, dimension, init, out );306 }307 } else {308 std::list< Statement * > branches;309 310 unsigned long cond = 0;311 ListInit * listInit = dynamic_cast< ListInit * >( init );312 if ( ! listInit ) {313 // xxx - this shouldn't be an error, but need a way to314 // terminate without creating output, so should catch this error315 SemanticError( init->location, "unbalanced list initializers" );316 }317 318 static UniqueName targetLabel( "L__autogen__" );319 Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } );320 for ( Initializer * init : *listInit ) {321 Expression * condition;322 // check for designations323 // if ( init-> ) {324 condition = new ConstantExpr( Constant::from_ulong( cond ) );325 ++cond;326 // } else {327 // condition = // ... take designation328 // cond = // ... take designation+1329 // }330 std::list< Statement * > stmts;331 build( callExpr, idx, idxEnd, init, back_inserter( stmts ) );332 stmts.push_back( new BranchStmt( switchLabel, BranchStmt::Break ) );333 CaseStmt * caseStmt = new CaseStmt( condition, stmts );334 branches.push_back( caseStmt );335 }336 *out++ = new SwitchStmt( index->clone(), branches );337 *out++ = new NullStmt( { switchLabel } );338 }339 }340 }341 342 // if array came with an initializer list: initialize each element343 // may have more initializers than elements in the array - need to check at each index that344 // we haven't exceeded size.345 // may have fewer initializers than elements in the array - need to default construct346 // remaining elements.347 // To accomplish this, generate switch statement, consuming all of expander's elements348 Statement * InitImpl_old::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {349 if ( ! init ) return nullptr;350 CompoundStmt * block = new CompoundStmt();351 build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) );352 if ( block->get_kids().empty() ) {353 delete block;354 return nullptr;355 } else {356 init = nullptr; // init was consumed in creating the list init357 return block;358 }359 }360 361 Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) {362 return nullptr;363 }364 365 Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) {366 return expander->buildListInit( dst, indices );367 }368 108 369 109 class InitExpander_new::ExpanderImpl { … … 537 277 } 538 278 539 Type * getTypeofThis( FunctionType * ftype ) {540 assertf( ftype, "getTypeofThis: nullptr ftype" );541 ObjectDecl * thisParam = getParamThis( ftype );542 ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( thisParam->type );543 return refType->base;544 }545 546 279 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { 547 280 assertf( ftype, "getTypeofThis: nullptr ftype" ); … … 554 287 } 555 288 556 ObjectDecl * getParamThis( FunctionType * ftype ) {557 assertf( ftype, "getParamThis: nullptr ftype" );558 auto & params = ftype->parameters;559 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( ftype ).c_str() );560 return strict_dynamic_cast< ObjectDecl * >( params.front() );561 }562 563 289 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 564 290 assertf( func, "getParamThis: nullptr ftype" ); … … 566 292 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str()); 567 293 return params.front().strict_as<ast::ObjectDecl>(); 568 }569 570 bool tryConstruct( DeclarationWithType * dwt ) {571 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );572 if ( ! objDecl ) return false;573 return (objDecl->get_init() == nullptr ||574 ( objDecl->get_init() != nullptr && objDecl->get_init()->get_maybeConstructed() ))575 && ! objDecl->get_storageClasses().is_extern576 && isConstructable( objDecl->type );577 }578 579 bool isConstructable( Type * type ) {580 return ! dynamic_cast< VarArgsType * >( type ) && ! dynamic_cast< ReferenceType * >( type ) && ! dynamic_cast< FunctionType * >( type ) && ! Tuples::isTtype( type );581 294 } 582 295 … … 595 308 } 596 309 597 struct CallFinder_old {598 CallFinder_old( const std::list< std::string > & names ) : names( names ) {}599 600 void postvisit( ApplicationExpr * appExpr ) {601 handleCallExpr( appExpr );602 }603 604 void postvisit( UntypedExpr * untypedExpr ) {605 handleCallExpr( untypedExpr );606 }607 608 std::list< Expression * > * matches;609 private:610 const std::list< std::string > names;611 612 template< typename CallExpr >613 void handleCallExpr( CallExpr * expr ) {614 std::string fname = getFunctionName( expr );615 if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {616 matches->push_back( expr );617 }618 }619 };620 621 310 struct CallFinder_new final { 622 311 std::vector< const ast::Expr * > matches; … … 636 325 }; 637 326 638 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {639 static PassVisitor<CallFinder_old> finder( std::list< std::string >{ "?{}", "^?{}" } );640 finder.pass.matches = &matches;641 maybeAccept( stmt, finder );642 }643 644 327 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 645 328 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; … … 648 331 } 649 332 650 Expression * getCtorDtorCall( Statement * stmt ) {651 std::list< Expression * > matches;652 collectCtorDtorCalls( stmt, matches );653 assertf( matches.size() <= 1, "%zd constructor/destructors found in %s", matches.size(), toString( stmt ).c_str() );654 return matches.size() == 1 ? matches.front() : nullptr;655 }656 657 333 namespace { 658 DeclarationWithType * getCalledFunction( Expression * expr );659 660 template<typename CallExpr>661 DeclarationWithType * handleDerefCalledFunction( CallExpr * expr ) {662 // (*f)(x) => should get "f"663 std::string name = getFunctionName( expr );664 assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );665 assertf( ! expr->get_args().empty(), "Cannot get called function from dereference with no arguments" );666 return getCalledFunction( expr->get_args().front() );667 }668 669 DeclarationWithType * getCalledFunction( Expression * expr ) {670 assert( expr );671 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {672 return varExpr->var;673 } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( expr ) ) {674 return memberExpr->member;675 } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {676 return getCalledFunction( castExpr->arg );677 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( expr ) ) {678 return handleDerefCalledFunction( untypedExpr );679 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {680 return handleDerefCalledFunction( appExpr );681 } else if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {682 return getCalledFunction( addrExpr->arg );683 } else if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( expr ) ) {684 return getCalledFunction( commaExpr->arg2 );685 }686 return nullptr;687 }688 689 DeclarationWithType * getFunctionCore( const Expression * expr ) {690 if ( const auto * appExpr = dynamic_cast< const ApplicationExpr * >( expr ) ) {691 return getCalledFunction( appExpr->function );692 } else if ( const auto * untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {693 return getCalledFunction( untyped->function );694 }695 assertf( false, "getFunction with unknown expression: %s", toString( expr ).c_str() );696 }697 }698 699 DeclarationWithType * getFunction( Expression * expr ) {700 return getFunctionCore( expr );701 }702 703 const DeclarationWithType * getFunction( const Expression * expr ) {704 return getFunctionCore( expr );705 }706 707 ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) {708 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr );709 if ( ! appExpr ) return nullptr;710 DeclarationWithType * function = getCalledFunction( appExpr->get_function() );711 assertf( function, "getCalledFunction returned nullptr: %s", toString( appExpr->get_function() ).c_str() );712 // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor713 // will call all member dtors, and some members may have a user defined dtor.714 return function->get_linkage() == LinkageSpec::Intrinsic ? appExpr : nullptr;715 }716 717 namespace {718 template <typename Predicate>719 bool allofCtorDtor( Statement * stmt, const Predicate & pred ) {720 std::list< Expression * > callExprs;721 collectCtorDtorCalls( stmt, callExprs );722 return std::all_of( callExprs.begin(), callExprs.end(), pred);723 }724 725 334 template <typename Predicate> 726 335 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { … … 728 337 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 729 338 } 730 }731 732 bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {733 return allofCtorDtor( stmt, []( Expression * callExpr ){734 if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {735 FunctionType *funcType = GenPoly::getFunctionType( appExpr->function->result );736 assert( funcType );737 return funcType->get_parameters().size() == 1;738 }739 return false;740 });741 339 } 742 340 … … 751 349 return false; 752 350 }); 753 }754 755 bool isIntrinsicCallStmt( Statement * stmt ) {756 return allofCtorDtor( stmt, []( Expression * callExpr ) {757 return isIntrinsicCallExpr( callExpr );758 });759 }760 761 namespace {762 template<typename CallExpr>763 Expression *& callArg( CallExpr * callExpr, unsigned int pos ) {764 if ( pos >= callExpr->get_args().size() ) assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", pos, toString( callExpr ).c_str() );765 for ( Expression *& arg : callExpr->get_args() ) {766 if ( pos == 0 ) return arg;767 pos--;768 }769 assert( false );770 }771 }772 773 Expression *& getCallArg( Expression * callExpr, unsigned int pos ) {774 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr ) ) {775 return callArg( appExpr, pos );776 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( callExpr ) ) {777 return callArg( untypedExpr, pos );778 } else if ( TupleAssignExpr * tupleExpr = dynamic_cast< TupleAssignExpr * > ( callExpr ) ) {779 std::list< Statement * > & stmts = tupleExpr->get_stmtExpr()->get_statements()->get_kids();780 assertf( ! stmts.empty(), "TupleAssignExpr somehow has no statements." );781 ExprStmt * stmt = strict_dynamic_cast< ExprStmt * >( stmts.back() );782 TupleExpr * tuple = strict_dynamic_cast< TupleExpr * >( stmt->get_expr() );783 assertf( ! tuple->get_exprs().empty(), "TupleAssignExpr somehow has empty tuple expr." );784 return getCallArg( tuple->get_exprs().front(), pos );785 } else if ( ImplicitCopyCtorExpr * copyCtor = dynamic_cast< ImplicitCopyCtorExpr * >( callExpr ) ) {786 return getCallArg( copyCtor->callExpr, pos );787 } else {788 assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );789 }790 }791 792 namespace {793 std::string funcName( Expression * func );794 795 template<typename CallExpr>796 std::string handleDerefName( CallExpr * expr ) {797 // (*f)(x) => should get name "f"798 std::string name = getFunctionName( expr );799 assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );800 assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" );801 return funcName( expr->get_args().front() );802 }803 804 std::string funcName( Expression * func ) {805 if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( func ) ) {806 return nameExpr->get_name();807 } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) {808 return varExpr->get_var()->get_name();809 } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) {810 return funcName( castExpr->get_arg() );811 } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( func ) ) {812 return memberExpr->get_member()->get_name();813 } else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) {814 return funcName( memberExpr->get_member() );815 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( func ) ) {816 return handleDerefName( untypedExpr );817 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( func ) ) {818 return handleDerefName( appExpr );819 } else if ( ConstructorExpr * ctorExpr = dynamic_cast< ConstructorExpr * >( func ) ) {820 return funcName( getCallArg( ctorExpr->get_callExpr(), 0 ) );821 } else {822 assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );823 }824 }825 }826 827 std::string getFunctionName( Expression * expr ) {828 // there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and829 // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction830 // can't possibly do anything reasonable.831 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) {832 return funcName( appExpr->get_function() );833 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) {834 return funcName( untypedExpr->get_function() );835 } else {836 std::cerr << expr << std::endl;837 assertf( false, "Unexpected expression type passed to getFunctionName" );838 }839 }840 841 Type * getPointerBase( Type * type ) {842 if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) {843 return ptrType->get_base();844 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {845 return arrayType->get_base();846 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( type ) ) {847 return refType->get_base();848 } else {849 return nullptr;850 }851 }852 853 Type * isPointerType( Type * type ) {854 return getPointerBase( type ) ? type : nullptr;855 }856 857 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ) {858 static FunctionDecl * assign = nullptr;859 if ( ! assign ) {860 // temporary? Generate a fake assignment operator to represent bitwise assignments.861 // This operator could easily exist as a real function, but it's tricky because nothing should resolve to this function.862 TypeDecl * td = new TypeDecl( "T", noStorageClasses, nullptr, TypeDecl::Dtype, true );863 assign = new FunctionDecl( "?=?", noStorageClasses, LinkageSpec::Intrinsic, SymTab::genAssignType( new TypeInstType( noQualifiers, td->name, td ) ), nullptr );864 }865 if ( dynamic_cast< ReferenceType * >( dst->result ) ) {866 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {867 dst = new AddressExpr( dst );868 }869 } else {870 dst = new CastExpr( dst, new ReferenceType( noQualifiers, dst->result->clone() ) );871 }872 if ( dynamic_cast< ReferenceType * >( src->result ) ) {873 for (int depth = src->result->referenceDepth(); depth > 0; depth--) {874 src = new AddressExpr( src );875 }876 }877 return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } );878 351 } 879 352 … … 907 380 return app; 908 381 } 909 910 struct ConstExprChecker : public WithShortCircuiting {911 // most expressions are not const expr912 void previsit( Expression * ) { isConstExpr = false; visit_children = false; }913 914 void previsit( AddressExpr *addressExpr ) {915 visit_children = false;916 917 // address of a variable or member expression is constexpr918 Expression * arg = addressExpr->get_arg();919 if ( ! dynamic_cast< NameExpr * >( arg) && ! dynamic_cast< VariableExpr * >( arg ) && ! dynamic_cast< MemberExpr * >( arg ) && ! dynamic_cast< UntypedMemberExpr * >( arg ) ) isConstExpr = false;920 }921 922 // these expressions may be const expr, depending on their children923 void previsit( SizeofExpr * ) {}924 void previsit( AlignofExpr * ) {}925 void previsit( UntypedOffsetofExpr * ) {}926 void previsit( OffsetofExpr * ) {}927 void previsit( OffsetPackExpr * ) {}928 void previsit( CommaExpr * ) {}929 void previsit( LogicalExpr * ) {}930 void previsit( ConditionalExpr * ) {}931 void previsit( CastExpr * ) {}932 void previsit( ConstantExpr * ) {}933 934 void previsit( VariableExpr * varExpr ) {935 visit_children = false;936 937 if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( varExpr->result ) ) {938 long long int value;939 if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {940 // enumerators are const expr941 return;942 }943 }944 isConstExpr = false;945 }946 947 bool isConstExpr = true;948 };949 382 950 383 struct ConstExprChecker_new : public ast::WithShortCircuiting { … … 991 424 }; 992 425 993 bool isConstExpr( Expression * expr ) {994 if ( expr ) {995 PassVisitor<ConstExprChecker> checker;996 expr->accept( checker );997 return checker.pass.isConstExpr;998 }999 return true;1000 }1001 1002 bool isConstExpr( Initializer * init ) {1003 if ( init ) {1004 PassVisitor<ConstExprChecker> checker;1005 init->accept( checker );1006 return checker.pass.isConstExpr;1007 } // if1008 // for all intents and purposes, no initializer means const expr1009 return true;1010 }1011 1012 426 bool isConstExpr( const ast::Expr * expr ) { 1013 427 if ( expr ) { … … 1029 443 } 1030 444 1031 const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname ) {1032 const FunctionDecl * function = dynamic_cast< const FunctionDecl * >( decl );1033 if ( ! function ) return nullptr;1034 if ( function->name != fname ) return nullptr;1035 FunctionType * ftype = function->type;1036 if ( ftype->parameters.size() != 2 ) return nullptr;1037 1038 Type * t1 = getPointerBase( ftype->get_parameters().front()->get_type() );1039 Type * t2 = ftype->parameters.back()->get_type();1040 assert( t1 );1041 1042 if ( ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, SymTab::Indexer() ) ) {1043 return function;1044 } else {1045 return nullptr;1046 }1047 }1048 1049 445 bool isAssignment( const ast::FunctionDecl * decl ) { 1050 446 return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl ); … … 1073 469 return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 ); 1074 470 } 1075 1076 1077 const FunctionDecl * isAssignment( const Declaration * decl ) {1078 return isCopyFunction( decl, "?=?" );1079 }1080 const FunctionDecl * isDestructor( const Declaration * decl ) {1081 if ( CodeGen::isDestructor( decl->name ) ) {1082 return dynamic_cast< const FunctionDecl * >( decl );1083 }1084 return nullptr;1085 }1086 const FunctionDecl * isDefaultConstructor( const Declaration * decl ) {1087 if ( CodeGen::isConstructor( decl->name ) ) {1088 if ( const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl ) ) {1089 if ( func->type->parameters.size() == 1 ) {1090 return func;1091 }1092 }1093 }1094 return nullptr;1095 }1096 const FunctionDecl * isCopyConstructor( const Declaration * decl ) {1097 return isCopyFunction( decl, "?{}" );1098 }1099 471 1100 472 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message … … 1105 477 static const char * const data_section = ".data" ASM_COMMENT; 1106 478 static const char * const tlsd_section = ".tdata" ASM_COMMENT; 1107 void addDataSectionAttribute( ObjectDecl * objDecl ) {1108 const bool is_tls = objDecl->get_storageClasses().is_threadlocal_any();1109 const char * section = is_tls ? tlsd_section : data_section;1110 objDecl->attributes.push_back(new Attribute("section", {1111 new ConstantExpr( Constant::from_string( section ) )1112 }));1113 }1114 479 1115 480 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { -
src/InitTweak/InitTweak.h
r790d835 rc6b4432 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
r790d835 rc6b4432 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.