Changeset 4d2434a for src/InitTweak


Ignore:
Timestamp:
Aug 2, 2016, 6:37:08 PM (9 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
8a443f4
Parents:
39f84a4
Message:

major reorganization of constructor generation from initializer list so that it now works with multi-dimensional arrays

Location:
src/InitTweak
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/GenInit.cc

    r39f84a4 r4d2434a  
    154154        }
    155155
     156        // precompute array dimension expression, because constructor generation may duplicate it,
     157        // which would be incorrect if it is a side-effecting computation.
    156158        void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
    157159                HoistArrayDimension hoister;
     
    215217                // hands off if designated, if @=, or if extern
    216218                if ( tryConstruct( objDecl ) ) {
    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                                         InitExpander srcParam( (Expression *)NULL );
    228                                         SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    229                                         SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
    230 
    231                                         // Currently genImplicitCall produces a single Statement - a CompoundStmt
    232                                         // which  wraps everything that needs to happen. As such, it's technically
    233                                         // possible to use a Statement ** in the above calls, but this is inherently
    234                                         // unsafe, so instead we take the slightly less efficient route, but will be
    235                                         // immediately informed if somehow the above assumption is broken. In this case,
    236                                         // we could always wrap the list of statements at this point with a CompoundStmt,
    237                                         // but it seems reasonable at the moment for this to be done by genImplicitCall
    238                                         // itself. It is possible that genImplicitCall produces no statements (e.g. if
    239                                         // an array type does not have a dimension). In this case, it's fine to ignore
    240                                         // the object for the purposes of construction.
    241                                         assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
    242                                         if ( ctor.size() == 1 ) {
    243                                                 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
    244                                                 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
    245                                         }
    246                                 } else {
    247                                         // array came with an initializer list: initialize each element
    248                                         // may have more initializers than elements in the array - need to check at each index that
    249                                         // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting
    250                                         // computation.
    251                                         // may have fewer initializers than elements in the array - need to default construct
    252                                         // remaining elements.
    253                                         // might be able to merge this with the case above.
    254 
    255                                 }
    256                         } else {
    257                                 // it's sufficient to attempt to call the ctor/dtor for the given object and its initializer
    258                                 Expression * ctor = makeCtorDtorExpr( "?{}", objDecl, makeInitList( objDecl->get_init() ) );
    259                                 Expression * dtor = makeCtorDtorExpr( "^?{}", objDecl, std::list< Expression * >() );
    260 
     219                        // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
     220                        // for each constructable object
     221                        std::list< Statement * > ctor;
     222                        std::list< Statement * > dtor;
     223
     224                        InitExpander srcParam( objDecl->get_init() );
     225                        InitExpander nullParam( (Initializer *)NULL );
     226                        SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
     227                        SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     228
     229                        // Currently genImplicitCall produces a single Statement - a CompoundStmt
     230                        // which  wraps everything that needs to happen. As such, it's technically
     231                        // possible to use a Statement ** in the above calls, but this is inherently
     232                        // unsafe, so instead we take the slightly less efficient route, but will be
     233                        // immediately informed if somehow the above assumption is broken. In this case,
     234                        // we could always wrap the list of statements at this point with a CompoundStmt,
     235                        // but it seems reasonable at the moment for this to be done by genImplicitCall
     236                        // itself. It is possible that genImplicitCall produces no statements (e.g. if
     237                        // an array type does not have a dimension). In this case, it's fine to ignore
     238                        // the object for the purposes of construction.
     239                        assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
     240                        if ( ctor.size() == 1 ) {
    261241                                // need to remember init expression, in case no ctors exist
    262242                                // if ctor does exist, want to use ctor expression instead of init
    263243                                // push this decision to the resolver
    264                                 ExprStmt * ctorStmt = new ExprStmt( noLabels, ctor );
    265                                 ExprStmt * dtorStmt = new ExprStmt( noLabels, dtor );
    266                                 objDecl->set_init( new ConstructorInit( new ImplicitCtorDtorStmt( ctorStmt ), new ImplicitCtorDtorStmt( dtorStmt ), objDecl->get_init() ) );
     244                                assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
     245                                objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
    267246                        }
    268247                }
  • src/InitTweak/InitTweak.cc

    r39f84a4 r4d2434a  
     1#include <algorithm>
    12#include "InitTweak.h"
    23#include "SynTree/Visitor.h"
     
    2021                };
    2122
    22                 class InitExpander_OLD : public Visitor {
     23                class InitFlattener : public Visitor {
    2324                        public:
    2425                        virtual void visit( SingleInit * singleInit );
     
    2728                };
    2829
    29                 void InitExpander_OLD::visit( SingleInit * singleInit ) {
     30                void InitFlattener::visit( SingleInit * singleInit ) {
    3031                        argList.push_back( singleInit->get_value()->clone() );
    3132                }
    3233
    33                 void InitExpander_OLD::visit( ListInit * listInit ) {
    34                         // xxx - for now, assume no nested list inits
    35                         std::list<Initializer*>::iterator it = listInit->begin_initializers();
    36                         for ( ; it != listInit->end_initializers(); ++it ) {
     34                void InitFlattener::visit( ListInit * listInit ) {
     35                        // flatten nested list inits
     36                        std::list<Initializer*>::iterator it = listInit->begin();
     37                        for ( ; it != listInit->end(); ++it ) {
    3738                                (*it)->accept( *this );
    3839                        }
     
    4142
    4243        std::list< Expression * > makeInitList( Initializer * init ) {
    43                 InitExpander_OLD expander;
    44                 maybeAccept( init, expander );
    45                 return expander.argList;
     44                InitFlattener flattener;
     45                maybeAccept( init, flattener );
     46                return flattener.argList;
    4647        }
    4748
     
    5556        public:
    5657                virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0;
     58                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0;
    5759        };
    5860
    5961        class InitImpl : public InitExpander::ExpanderImpl {
    6062        public:
    61                 InitImpl( Initializer * init ) {
    62                         if ( init ) inits.push_back( init );
    63                 }
     63                InitImpl( Initializer * init ) : init( init ) {}
    6464
    6565                virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
    6666                        // this is wrong, but just a placeholder for now
    67                         return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();
    68                 }
     67                        // if ( ! flattened ) flatten( indices );
     68                        // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();
     69                        return makeInitList( init );
     70                }
     71
     72                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
    6973        private:
    70                 std::list< Initializer * > inits;
     74                Initializer * init;
    7175        };
    7276
     
    9195                        return ret;
    9296                }
     97
     98                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
    9399        private:
    94100                Expression * arg;
     
    114120        }
    115121
    116         template< typename OutIterator >
    117         void build( UntypedExpr * callExpr, InitExpander::IndexList::iterator idx, InitExpander::IndexList::iterator end, OutIterator out ) {
    118                 if ( idx == end ) return;
    119                 Expression * index = *idx++;
    120                 assert( idx != end );
    121                 Expression * dimension = *idx++;
    122 
    123                 // if ( idx == end ) {
    124                 //      // loop through list of expressions belonging to the current initializer
    125                 //      UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );
    126                 //      cond->get_args().push_back( index->clone() );
    127                 //      cond->get_args().push_back( dimension->clone() );
    128 
    129                 //      UntypedExpr * call = callExpr->clone();
    130                 //      std::list< Expression * > args = *++expander; // xxx - need a way to indentify the end of an init list
    131                 //      call->get_args().splice( args );
    132 
    133                 //      *out++ = new IfStmt( noLabels, cond, new ExprStmt( call ), NULL );
    134 
    135                 //      UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );
    136                 //      increment->get_args().push_back( index->clone() );
    137                 //      *out++ = new ExprStmt( increment );
    138                 // } else {
    139                 //      std::list< Statement * > branches;
    140                 //      for (...) { // loop over conditions?
    141                 //              std::list< Statement * > stmts;
    142                 //              build( idx, end, back_inserter( stmts ) );
    143                 //              CaseStmt * caseStmt = new CaseStmt( noLabels, condition, stmts );
    144                 //              branches.push_back( caseStmt );
    145                 //      }
    146                 //      *out++ = new SwitchStmt( noLabels, index->clone(), branches );
    147                 // }
    148         }
    149 
    150         // generate switch statement, consuming all of expander's elements
     122        void InitExpander::clearArrayIndices() {
     123                indices.clear();
     124        }
     125
     126        namespace {
     127                template< typename OutIterator >
     128                void dothething( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) {
     129                        UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );
     130                        cond->get_args().push_back( index->clone() );
     131                        cond->get_args().push_back( dimension->clone() );
     132
     133                        std::list< Expression * > args = makeInitList( init );
     134                        callExpr->get_args().splice( callExpr->get_args().end(), args );
     135
     136                        *out++ = new IfStmt( noLabels, cond, new ExprStmt( noLabels, callExpr ), NULL );
     137
     138                        UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );
     139                        increment->get_args().push_back( new AddressExpr( index->clone() ) );
     140                        *out++ = new ExprStmt( noLabels, increment );
     141                }
     142
     143                template< typename OutIterator >
     144                void build( UntypedExpr * callExpr, InitExpander::IndexList::iterator idx, InitExpander::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {
     145                        if ( idx == idxEnd ) return;
     146                        Expression * index = *idx++;
     147                        assert( idx != idxEnd );
     148                        Expression * dimension = *idx++;
     149
     150                        if ( idx == idxEnd ) {
     151                                if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) {
     152                                        for ( Initializer * init : *listInit ) {
     153                                                dothething( callExpr->clone(), index, dimension, init, out );
     154                                        }
     155                                } else {
     156                                        dothething( callExpr->clone(), index, dimension, init, out );
     157                                }
     158                        } else {
     159                                std::list< Statement * > branches;
     160
     161                                unsigned long cond = 0;
     162                                ListInit * listInit = dynamic_cast< ListInit * >( init );
     163                                if ( ! listInit ) {
     164                                        // xxx - this shouldn't be an error, but need a way to
     165                                        // terminate without creating output, so should catch this error
     166                                        throw SemanticError( "unbalanced list initializers" );
     167                                }
     168                                for ( Initializer * init : *listInit ) {
     169                                        Expression * condition;
     170                                        // check for designations
     171                                        // if ( init-> ) {
     172                                                condition = new ConstantExpr( Constant::from_ulong( cond ) );
     173                                                ++cond;
     174                                        // } else {
     175                                        //      condition = // ... take designation
     176                                        //      cond = // ... take designation+1
     177                                        // }
     178                                        std::list< Statement * > stmts;
     179                                        build( callExpr, idx, idxEnd, init, back_inserter( stmts ) );
     180                                        CaseStmt * caseStmt = new CaseStmt( noLabels, condition, stmts );
     181                                        branches.push_back( caseStmt );
     182                                }
     183                                *out++ = new SwitchStmt( noLabels, index->clone(), branches );
     184                        }
     185                }
     186        }
     187
     188        // if array came with an initializer list: initialize each element
     189        // may have more initializers than elements in the array - need to check at each index that
     190        // we haven't exceeded size.
     191        // may have fewer initializers than elements in the array - need to default construct
     192        // remaining elements.
     193        // To accomplish this, generate switch statement, consuming all of expander's elements
     194        Statement * InitImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
     195                if ( ! init ) return NULL;
     196                std::list< Statement * > results;
     197                build( dst, indices.begin(), indices.end(), init, back_inserter( results ) );
     198                assert( results.size() <= 1 );
     199                if ( results.empty() ) {
     200                        return NULL;
     201                } else {
     202                        init = NULL; // init was consumed in creating the list init
     203                        return results.front();
     204                }
     205                return ! results.empty() ? results.front() : NULL;
     206        }
     207
     208        Statement * ExprImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
     209                return NULL;
     210        }
     211
    151212        Statement * InitExpander::buildListInit( UntypedExpr * dst ) {
    152                 std::list< Statement * > results;
    153                 build( dst, indices.begin(), indices.end(), back_inserter( results ) );
    154                 assert( results.size() <= 1 );
    155                 return ! results.empty() ? results.front() : NULL;
     213                return expander->buildListInit( dst, indices );
    156214        }
    157215
     
    164222        }
    165223
     224        class CallFinder : public Visitor {
     225        public:
     226                typedef Visitor Parent;
     227                CallFinder( const std::list< std::string > & names ) : names( names ) {}
     228
     229                virtual void visit( ApplicationExpr * appExpr ) {
     230                        handleCallExpr( appExpr );
     231                }
     232
     233                virtual void visit( UntypedExpr * untypedExpr ) {
     234                        handleCallExpr( untypedExpr );
     235                }
     236
     237                std::list< Expression * > * matches;
     238        private:
     239                const std::list< std::string > names;
     240
     241                template< typename CallExpr >
     242                void handleCallExpr( CallExpr * expr ) {
     243                        Parent::visit( expr );
     244                        std::string fname = getFunctionName( expr );
     245                        if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
     246                                matches->push_back( expr );
     247                        }
     248                }
     249        };
     250
     251        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {
     252                static CallFinder finder( std::list< std::string >{ "?{}", "^?{}" } );
     253                finder.matches = &matches;
     254                maybeAccept( stmt, finder );
     255        }
     256
    166257        Expression * getCtorDtorCall( Statement * stmt ) {
    167                 if ( stmt == NULL ) return NULL;
    168                 if ( ExprStmt * exprStmt = dynamic_cast< ExprStmt * >( stmt ) ) {
    169                         return exprStmt->get_expr();
    170                 } else if ( CompoundStmt * compoundStmt = dynamic_cast< CompoundStmt * >( stmt ) ) {
    171                         // could also be a compound statement with a loop, in the case of an array
    172                         if( compoundStmt->get_kids().size() == 2 ) {
    173                                 // loop variable and loop
    174                                 ForStmt * forStmt = dynamic_cast< ForStmt * >( compoundStmt->get_kids().back() );
    175                                 assert( forStmt && forStmt->get_body() );
    176                                 return getCtorDtorCall( forStmt->get_body() );
    177                         } else if ( compoundStmt->get_kids().size() == 1 ) {
    178                                 // should be the call statement, but in any case there's only one option
    179                                 return getCtorDtorCall( compoundStmt->get_kids().front() );
    180                         } else {
    181                                 assert( false && "too many statements in compoundStmt for getCtorDtorCall" );
    182                         }
    183                 } if ( ImplicitCtorDtorStmt * impCtorDtorStmt = dynamic_cast< ImplicitCtorDtorStmt * > ( stmt ) ) {
    184                         return getCtorDtorCall( impCtorDtorStmt->get_callStmt() );
    185                 } else {
    186                         // should never get here
    187                         assert( false && "encountered unknown call statement" );
    188                 }
    189         }
     258                std::list< Expression * > matches;
     259                collectCtorDtorCalls( stmt, matches );
     260                assert( matches.size() <= 1 );
     261                return matches.size() == 1 ? matches.front() : NULL;
     262        }
     263
    190264        namespace {
    191265                VariableExpr * getCalledFunction( ApplicationExpr * appExpr ) {
    192266                        assert( appExpr );
     267                        // xxx - it's possible this can be other things, e.g. MemberExpr, so this is insufficient
    193268                        return dynamic_cast< VariableExpr * >( appExpr->get_function() );
    194269                }
     
    206281
    207282        bool isInstrinsicSingleArgCallStmt( Statement * stmt ) {
    208                 Expression * callExpr = getCtorDtorCall( stmt );
    209                 if ( ! callExpr ) return false;
    210                 if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
    211                         assert( ! appExpr->get_function()->get_results().empty() );
    212                         FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_results().front() );
    213                         assert( funcType );
    214                         return funcType->get_parameters().size() == 1;
    215                 }
    216                 return false;
     283                std::list< Expression * > callExprs;
     284                collectCtorDtorCalls( stmt, callExprs );
     285                // if ( callExprs.empty() ) return false; // xxx - do I still need this check?
     286                return std::all_of( callExprs.begin(), callExprs.end(), []( Expression * callExpr ){
     287                        if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
     288                                assert( ! appExpr->get_function()->get_results().empty() );
     289                                FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_results().front() );
     290                                assert( funcType );
     291                                return funcType->get_parameters().size() == 1;
     292                        }
     293                        return false;
     294                });
    217295        }
    218296
  • src/InitTweak/InitTweak.h

    r39f84a4 r4d2434a  
    4343        bool isInstrinsicSingleArgCallStmt( Statement * expr );
    4444
     45        /// get all Ctor/Dtor call expressions from a Statement
     46        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
     47
    4548        /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
    4649        Expression * getCtorDtorCall( Statement * stmt );
     
    7881                Statement * buildListInit( UntypedExpr * callExpr );
    7982                void addArrayIndex( Expression * index, Expression * dimension );
     83                void clearArrayIndices();
    8084
    8185                class ExpanderImpl;
Note: See TracChangeset for help on using the changeset viewer.