Changeset 6cf27a07


Ignore:
Timestamp:
Jul 21, 2016, 2:07:01 PM (5 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
aaron-thesis, arm-eh, cleanup-dtors, ctor, deferred_resn, demangler, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, resolv-new, with_gc
Children:
ccb447e
Parents:
b81adcc
Message:

reorganize global init so that it is simpler and generates less unnecessary code

Location:
src
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixGlobalInit.cc

    rb81adcc r6cf27a07  
    9797                std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids();
    9898
    99                 if ( ! tryConstruct( objDecl ) ) return; // don't construct @= or designated objects
    100                 if ( objDecl->get_storageClass() == DeclarationNode::Extern ) return;
    10199                // C allows you to initialize objects with constant expressions
    102100                // xxx - this is an optimization. Need to first resolve constructors before we decide
     
    104102                // if ( isConstExpr( objDecl->get_init() ) ) return;
    105103
    106                 if ( dynamic_cast< ArrayType * > ( objDecl->get_type() ) ) {
    107                         // xxx - initialize each element of the array
    108                 } else {
    109                         // insert constructor for objDecl into global init function
    110                         UntypedExpr * init = new UntypedExpr( new NameExpr( "?{}" ) );
    111                         init->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );
    112                         init->get_args().splice( init->get_args().end(), makeInitList( objDecl->get_init() ) );
    113                         objDecl->set_init( NULL );
    114                         initStatements.push_back( new ImplicitCtorDtorStmt( new ExprStmt( noLabels, init ) ) );
     104                if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
     105                        // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     106                        assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
    115107
    116                         // add destructor calls to global destroy function
    117                         UntypedExpr * destroy = new UntypedExpr( new NameExpr( "^?{}" ) );
    118                         destroy->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );
    119                         destroyStatements.push_front( new ImplicitCtorDtorStmt( new ExprStmt( noLabels, destroy ) ) );
     108                        Statement * dtor = ctorInit->get_dtor();
     109                        if ( dtor && ! isInstrinsicSingleArgCallStmt( dtor ) ) {
     110                                // don't need to call intrinsic dtor, because it does nothing, but
     111                                // non-intrinsic dtors must be called
     112                                destroyStatements.push_front( dtor );
     113                                ctorInit->set_dtor( NULL );
     114                        } // if
     115                        if ( Statement * ctor = ctorInit->get_ctor() ) {
     116                                initStatements.push_back( ctor );
     117                                objDecl->set_init( NULL );
     118                                ctorInit->set_ctor( NULL );
     119                        } else if ( Initializer * init = ctorInit->get_init() ) {
     120                                objDecl->set_init( init );
     121                                ctorInit->set_init( NULL );
     122                        } else {
     123                                // no constructor and no initializer, which is okay
     124                                objDecl->set_init( NULL );
     125                        } // if
     126                        delete ctorInit;
    120127                } // if
    121128        }
  • src/InitTweak/FixInit.cc

    rb81adcc r6cf27a07  
    1818#include <iterator>
    1919#include <algorithm>
     20#include "InitTweak.h"
    2021#include "FixInit.h"
    21 #include "InitTweak.h"
     22#include "FixGlobalInit.h"
    2223#include "ResolvExpr/Resolver.h"
    2324#include "ResolvExpr/typeops.h"
     
    8384                };
    8485
     86                // debug
    8587                struct printSet {
    8688                        typedef ObjDeclCollector::ObjectSet ObjectSet;
     
    171173        } // namespace
    172174
    173         void fix( std::list< Declaration * > & translationUnit ) {
     175        void fix( std::list< Declaration * > & translationUnit, const std::string & filename, bool inLibrary ) {
     176                // fixes ConstructorInit for global variables. should happen before fixInitializers.
     177                InitTweak::fixGlobalInit( translationUnit, filename, inLibrary );
     178
    174179                InsertImplicitCalls::insert( translationUnit );
    175180                ResolveCopyCtors::resolveImplicitCalls( translationUnit );
  • src/InitTweak/FixInit.h

    rb81adcc r6cf27a07  
    2727  /// replace constructor initializers with expression statements
    2828  /// and unwrap basic C-style initializers
    29         void fix( std::list< Declaration * > & translationUnit );
     29        void fix( std::list< Declaration * > & translationUnit, const std::string & name, bool inLibrary );
    3030} // namespace
    3131
  • src/InitTweak/GenInit.cc

    rb81adcc r6cf27a07  
    6161                static void generateCtorDtor( std::list< Declaration * > &translationUnit );
    6262
    63                 CtorDtor() : inFunction( false ) {}
    64 
    6563                virtual DeclarationWithType * mutate( ObjectDecl * );
    6664                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl );
     
    7775
    7876          protected:
    79                 bool inFunction;
    8077        };
    8178
     
    216213
    217214        DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) {
    218                 // hands off if designated or if @=
     215                // hands off if designated, if @=, or if extern
    219216                if ( tryConstruct( objDecl ) ) {
    220                         if ( inFunction ) {
    221                                 if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->get_type() ) ) {
    222                                         // call into makeArrayFunction from validate.cc to generate calls to ctor/dtor for each element of array
    223                                         // TODO: walk initializers and generate appropriate ctor if element has initializer.
    224                                         // Initializer could be nested (depends on the depth of the array type on the object)
    225 
    226                                         std::list< Expression * > args = makeInitList( objDecl->get_init() );
    227                                         if ( args.empty() ) {
    228                                                 std::list< Statement * > ctor;
    229                                                 std::list< Statement * > dtor;
    230 
    231                                                 SymTab::genImplicitCall( NULL, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    232                                                 SymTab::genImplicitCall( NULL, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
    233 
    234                                                 // Currently genArrayCall produces a single Statement - a CompoundStmt
    235                                                 // which  wraps everything that needs to happen. As such, it's technically
    236                                                 // possible to use a Statement ** in the above calls, but this is inherently
    237                                                 // unsafe, so instead we take the slightly less efficient route, but will be
    238                                                 // immediately informed if somehow the above assumption is broken. In this case,
    239                                                 // we could always wrap the list of statements at this point with a CompoundStmt,
    240                                                 // but it seems reasonable at the moment for this to be done by genArrayCall
    241                                                 // itself
    242                                                 assert( ctor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( ctor.front() ) );
    243                                                 assert( dtor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( dtor.front() ) );
     217                        if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->get_type() ) ) {
     218                                // call into makeArrayFunction from validate.cc to generate calls to ctor/dtor for each element of array
     219                                // TODO: walk initializers and generate appropriate ctor if element has initializer.
     220                                // Initializer could be nested (depends on the depth of the array type on the object)
     221
     222                                std::list< Expression * > args = makeInitList( objDecl->get_init() );
     223                                if ( args.empty() ) {
     224                                        std::list< Statement * > ctor;
     225                                        std::list< Statement * > dtor;
     226
     227                                        SymTab::genImplicitCall( NULL, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
     228                                        SymTab::genImplicitCall( NULL, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     229
     230                                        // Currently genImplicitCall produces a single Statement - a CompoundStmt
     231                                        // which  wraps everything that needs to happen. As such, it's technically
     232                                        // possible to use a Statement ** in the above calls, but this is inherently
     233                                        // unsafe, so instead we take the slightly less efficient route, but will be
     234                                        // immediately informed if somehow the above assumption is broken. In this case,
     235                                        // we could always wrap the list of statements at this point with a CompoundStmt,
     236                                        // but it seems reasonable at the moment for this to be done by genImplicitCall
     237                                        // itself. It is possible that genImplicitCall produces no statements (e.g. if
     238                                        // an array type does not have a dimension). In this case, it's fine to ignore
     239                                        // the object for the purposes of construction.
     240                                        assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
     241                                        if ( ctor.size() == 1 ) {
     242                                                assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
    244243                                                objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
    245                                         } else {
    246                                                 // array came with an initializer list: initialize each element
    247                                                 // may have more initializers than elements in the array - need to check at each index that
    248                                                 // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting
    249                                                 // computation.
    250                                                 // may have fewer initializers than elements in the array - need to default construct
    251                                                 // remaining elements.
    252                                                 // might be able to merge this with the case above.
    253 
    254244                                        }
    255245                                } else {
    256                                         // it's sufficient to attempt to call the ctor/dtor for the given object and its initializer
    257                                         Expression * ctor = makeCtorDtorExpr( "?{}", objDecl, makeInitList( objDecl->get_init() ) );
    258                                         Expression * dtor = makeCtorDtorExpr( "^?{}", objDecl, std::list< Expression * >() );
    259 
    260                                         // need to remember init expression, in case no ctors exist
    261                                         // if ctor does exist, want to use ctor expression instead of init
    262                                         // push this decision to the resolver
    263                                         ExprStmt * ctorStmt = new ExprStmt( noLabels, ctor );
    264                                         ExprStmt * dtorStmt = new ExprStmt( noLabels, dtor );
    265                                         objDecl->set_init( new ConstructorInit( new ImplicitCtorDtorStmt( ctorStmt ), new ImplicitCtorDtorStmt( dtorStmt ), objDecl->get_init() ) );
     246                                        // array came with an initializer list: initialize each element
     247                                        // may have more initializers than elements in the array - need to check at each index that
     248                                        // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting
     249                                        // computation.
     250                                        // may have fewer initializers than elements in the array - need to default construct
     251                                        // remaining elements.
     252                                        // might be able to merge this with the case above.
     253
    266254                                }
     255                        } else {
     256                                // it's sufficient to attempt to call the ctor/dtor for the given object and its initializer
     257                                Expression * ctor = makeCtorDtorExpr( "?{}", objDecl, makeInitList( objDecl->get_init() ) );
     258                                Expression * dtor = makeCtorDtorExpr( "^?{}", objDecl, std::list< Expression * >() );
     259
     260                                // need to remember init expression, in case no ctors exist
     261                                // if ctor does exist, want to use ctor expression instead of init
     262                                // push this decision to the resolver
     263                                ExprStmt * ctorStmt = new ExprStmt( noLabels, ctor );
     264                                ExprStmt * dtorStmt = new ExprStmt( noLabels, dtor );
     265                                objDecl->set_init( new ConstructorInit( new ImplicitCtorDtorStmt( ctorStmt ), new ImplicitCtorDtorStmt( dtorStmt ), objDecl->get_init() ) );
    267266                        }
    268267                }
     
    272271        DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) {
    273272                // parameters should not be constructed and destructed, so don't mutate FunctionType
    274                 bool oldInFunc = inFunction;
    275273                mutateAll( functionDecl->get_oldDecls(), *this );
    276                 inFunction = true;
    277274                functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) );
    278                 inFunction = oldInFunc;
    279275                return functionDecl;
    280276        }
  • src/InitTweak/InitTweak.cc

    rb81adcc r6cf27a07  
    5757                        (objDecl->get_init() == NULL ||
    5858                                ( objDecl->get_init() != NULL && objDecl->get_init()->get_maybeConstructed() )) &&
    59                         ! isDesignated( objDecl->get_init() );
     59                        ! isDesignated( objDecl->get_init() )
     60                        && objDecl->get_storageClass() != DeclarationNode::Extern;
    6061        }
    6162
  • src/SymTab/Autogen.h

    rb81adcc r6cf27a07  
    144144                genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->get_type(), forward );
    145145
    146                 // currently genCall should produce only one element, but if that changes then the next line needs to be updated to grab the statement which contains the call
    147                 assert( stmts.size() == 1 );
    148                 Statement * callStmt = stmts.front();
    149                 if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && obj->get_bitfieldWidth() == NULL ) ) ) {
    150                         // implicitly generated ctor/dtor calls should be wrapped
    151                         // so that later passes are aware they were generated.
    152                         // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield,
    153                         // because this causes the address to be taken at codegen, which is illegal in C.
    154                         callStmt = new ImplicitCtorDtorStmt( callStmt );
    155                 }
    156                 *out++ = callStmt;
     146                // currently genCall should produce at most one element, but if that changes then the next line needs to be updated to grab the statement which contains the call
     147                assert( stmts.size() <= 1 );
     148    if ( stmts.size() == 1 ) {
     149                Statement * callStmt = stmts.front();
     150                if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && obj->get_bitfieldWidth() == NULL ) ) ) {
     151                        // implicitly generated ctor/dtor calls should be wrapped
     152                        // so that later passes are aware they were generated.
     153                        // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield,
     154                        // because this causes the address to be taken at codegen, which is illegal in C.
     155                        callStmt = new ImplicitCtorDtorStmt( callStmt );
     156                }
     157                *out++ = callStmt;
     158    }
    157159        }
    158160} // namespace SymTab
  • src/main.cc

    rb81adcc r6cf27a07  
    4242#include "InitTweak/GenInit.h"
    4343#include "InitTweak/FixInit.h"
    44 #include "InitTweak/FixGlobalInit.h"
    4544//#include "Explain/GenProlog.h"
    4645//#include "Try/Visit.h"
     
    282281                OPTPRINT( "fixNames" )
    283282                CodeGen::fixNames( translationUnit );
    284                 OPTPRINT( "fixGlobalInit" );
    285                 InitTweak::fixGlobalInit( translationUnit, filename, libcfap || treep );
    286283                OPTPRINT( "tweakInit" )
    287284                InitTweak::genInit( translationUnit );
     
    304301                }
    305302
     303                // fix ObjectDecl - replaces ConstructorInit nodes
    306304                OPTPRINT( "fixInit" )
    307                 // fix ObjectDecl - replaces ConstructorInit nodes
    308                 InitTweak::fix( translationUnit );
     305                InitTweak::fix( translationUnit, filename, libcfap || treep );
    309306                if ( ctorinitp ) {
    310307                        dump ( translationUnit );
  • src/tests/.expect/extension.txt

    rb81adcc r6cf27a07  
    100100    ((void)((__extension__ __a__i_2 , __extension__ __b__i_2) , __extension__ __c__i_2));
    101101}
    102 __attribute__ ((constructor(),)) static void _init_extension(void){
    103     int _global_init0;
    104     ((void)((*((int *)(&__a__i_1)))=_global_init0) /* ?{} */);
    105     int _global_init1;
    106     ((void)((*((int *)(&__b__i_1)))=_global_init1) /* ?{} */);
    107     int _global_init2;
    108     ((void)((*((int *)(&__c__i_1)))=_global_init2) /* ?{} */);
    109 }
    110 __attribute__ ((destructor(),)) static void _destroy_extension(void){
    111     ((void)((*((int *)(&__c__i_1)))) /* ^?{} */);
    112     ((void)((*((int *)(&__b__i_1)))) /* ^?{} */);
    113     ((void)((*((int *)(&__a__i_1)))) /* ^?{} */);
    114 }
Note: See TracChangeset for help on using the changeset viewer.