Changeset 2be1023


Ignore:
Timestamp:
Jul 18, 2016, 4:13:51 PM (8 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:
5f98ce5
Parents:
956a9c7
Message:

rework ctor/dtor generation to work properly with multidimensional arrays

Location:
src
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/GenInit.cc

    r956a9c7 r2be1023  
    145145                                if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->get_type() ) ) {
    146146                                        // call into makeArrayFunction from validate.cc to generate calls to ctor/dtor for each element of array
    147                                         // TODO: walk initializer and generate appropriate copy ctor if element has initializer
     147                                        // TODO: walk initializers and generate appropriate ctor if element has initializer.
     148                                        // Initializer could be nested (depends on the depth of the array type on the object)
     149
    148150                                        std::list< Expression * > args = makeInitList( objDecl->get_init() );
    149151                                        if ( args.empty() ) {
     
    151153                                                std::list< Statement * > dtor;
    152154
    153                                                 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "?{}", back_inserter( ctor ) );
    154                                                 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "^?{}", front_inserter( dtor ), false );
    155 
    156                                                 // Currently makeArrayFunction produces a single Statement - a CompoundStmt
     155                                                SymTab::genImplicitCall( NULL, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
     156                                                SymTab::genImplicitCall( NULL, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     157
     158                                                // Currently genArrayCall produces a single Statement - a CompoundStmt
    157159                                                // which  wraps everything that needs to happen. As such, it's technically
    158160                                                // possible to use a Statement ** in the above calls, but this is inherently
     
    160162                                                // immediately informed if somehow the above assumption is broken. In this case,
    161163                                                // we could always wrap the list of statements at this point with a CompoundStmt,
    162                                                 // but it seems reasonable at the moment for this to be done by makeArrayFunction
     164                                                // but it seems reasonable at the moment for this to be done by genArrayCall
    163165                                                // itself
    164166                                                assert( ctor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( ctor.front() ) );
     
    170172                                                // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting
    171173                                                // computation.
    172                                                 // may have fewer initializers than eleemnts in the array - need to default construct
     174                                                // may have fewer initializers than elements in the array - need to default construct
    173175                                                // remaining elements.
    174176                                                // might be able to merge this with the case above.
     177
    175178                                        }
    176179                                } else {
  • src/ResolvExpr/Resolver.cc

    r956a9c7 r2be1023  
    537537                assert( callExpr );
    538538                Expression *& constructee = InitTweak::getCallArg( callExpr, 0 );
    539                 Type * type = 0;
    540 
    541                 // need to find the type of the first argument, which is unfortunately not uniform since array construction
    542                 // includes an untyped '+' expression.
    543                 if ( UntypedExpr * plusExpr = dynamic_cast< UntypedExpr * >( constructee ) ) {
    544                         // constructee is <array>+<index>
    545                         // get Variable <array>, then get the base type of the VariableExpr - this is the type that needs to be fixed
    546                         Expression * arr = InitTweak::getCallArg( plusExpr, 0 );
    547                         assert( dynamic_cast< VariableExpr * >( arr ) || dynamic_cast< MemberExpr *>( arr ) );
    548                         assert( arr && arr->get_results().size() == 1 );
    549                         type = arr->get_results().front()->clone();
    550                 } else {
    551                         // otherwise, constructing a plain object, which means the object's address is being taken.
    552                         // Need to get the type of the VariableExpr object, because the AddressExpr is rebuilt and uses the
    553                         // type of the VariableExpr to do so.
    554                         assert( constructee->get_results().size() == 1 );
    555                         AddressExpr * addrExpr = dynamic_cast< AddressExpr * > ( constructee );
    556                         assert( addrExpr && addrExpr->get_results().size() == 1 );
    557                         type = addrExpr->get_results().front()->clone();
    558                 }
     539
     540                // the first argument will always be &<expr>
     541                AddressExpr * addrExpr = dynamic_cast< AddressExpr * > ( constructee );
     542                assert( addrExpr );
     543
     544                // need to find the type of the first argument. In the case of an array,
     545                // need to remove one ArrayType layer from the type for each subscript expression.
     546                Expression * addressee = addrExpr->get_arg();
     547                int numLayers = 0;
     548                while ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( addressee ) ) {
     549                        assert( InitTweak::getFunctionName( untypedExpr ) == "?[?]" );
     550                        addressee = InitTweak::getCallArg( untypedExpr, 0 );
     551                        numLayers++;
     552                }
     553                assert( addressee->get_results().size() == 1 );
     554                Type * type = addressee->get_results().front();
     555                for ( int i = 0; i < numLayers; i++ ) {
     556                        type = InitTweak::getPointerBase( type );
     557                        assert( type && "Expected pointer or array type. May have generated too many ?[?] calls." );
     558                }
     559
    559560                // cast to T* with qualifiers removed.
    560561                // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
     
    562563                // remove lvalue as a qualifier, this can change to
    563564                //   type->get_qualifiers() = Type::Qualifiers();
    564                 Type * base = InitTweak::getPointerBase( type );
    565                 assert( base );
    566                 base->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, true);
    567                 // if pointer has lvalue qualifier, cast won't appear in output
    568                 type->set_isLvalue( false );
     565                assert( type );
     566                type = type->clone();
     567                type->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, true);
     568                type = new PointerType( Type::Qualifiers(), type );
    569569                constructee = new CastExpr( constructee, type );
    570570
  • src/SymTab/Autogen.cc

    r956a9c7 r2be1023  
    6262
    6363        template< typename OutputIterator >
    64         void makeScalarFunction( Expression *src, ObjectDecl *dstParam, DeclarationWithType *member, std::string fname, OutputIterator out ) {
    65                 ObjectDecl *obj = dynamic_cast<ObjectDecl *>( member );
    66                 // unnamed bit fields are not copied as they cannot be accessed
    67                 if ( isUnnamedBitfield( obj ) ) return;
    68 
    69                 // want to be able to generate assignment, ctor, and dtor generically,
    70                 // so fname is either ?=?, ?{}, or ^?{}
    71                 UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
    72 
    73                 UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
    74                 derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
    75 
    76                 // do something special for unnamed members
    77                 Expression *dstselect = new AddressExpr( new MemberExpr( member, derefExpr ) );
    78                 fExpr->get_args().push_back( dstselect );
    79 
    80                 if ( src ) {
    81                         fExpr->get_args().push_back( src );
    82                 }
    83 
    84                 Statement * callStmt = new ExprStmt( noLabels, fExpr );
    85                 if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && obj->get_bitfieldWidth() == NULL ) ) ) {
    86                         // implicitly generated ctor/dtor calls should be wrapped
    87                         // so that later passes are aware they were generated.
    88                         // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield,
    89                         // because this causes the address to be taken at codegen, which is illegal in C.
    90                         callStmt = new ImplicitCtorDtorStmt( callStmt );
    91                 }
    92                 *out++ = callStmt;
    93         }
    94 
    95         template< typename OutputIterator >
    9664        void makeUnionFieldsAssignment( ObjectDecl *srcParam, ObjectDecl *dstParam, UnionInstType *unionType, OutputIterator out ) {
    9765                UntypedExpr *copy = new UntypedExpr( new NameExpr( "__builtin_memcpy" ) );
     
    220188
    221189                // assign to destination (and return value if generic)
    222                 if ( ArrayType *array = dynamic_cast< ArrayType * >( field->get_type() ) ) {
    223                         UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
    224                         derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
    225                         Expression *dstselect = new MemberExpr( field, derefExpr );
    226 
    227                         makeArrayFunction( src, dstselect, array, func->get_name(), back_inserter( func->get_statements()->get_kids() ), forward );
    228                         if ( isGeneric && returnVal ) {
    229                                 UntypedExpr *derefRet = new UntypedExpr( new NameExpr( "*?" ) );
    230                                 derefRet->get_args().push_back( new VariableExpr( returnVal ) );
    231                                 Expression *retselect = new MemberExpr( field, derefRet );
    232 
    233                                 makeArrayFunction( src, retselect, array, func->get_name(), back_inserter( func->get_statements()->get_kids() ), forward );
    234                         }
    235                 } else {
    236                         makeScalarFunction( src, dstParam, field, func->get_name(), back_inserter( func->get_statements()->get_kids() ) );
    237                         if ( isGeneric && returnVal ) makeScalarFunction( src, returnVal, field, func->get_name(), back_inserter( func->get_statements()->get_kids() ) );
     190                UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
     191                derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
     192                Expression *dstselect = new MemberExpr( field, derefExpr );
     193                genImplicitCall( src, dstselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
     194
     195                if ( isGeneric && returnVal ) {
     196                        UntypedExpr *derefRet = new UntypedExpr( new NameExpr( "*?" ) );
     197                        derefRet->get_args().push_back( new VariableExpr( returnVal ) );
     198                        Expression *retselect = new MemberExpr( field, derefRet );
     199                        genImplicitCall( src, retselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
    238200                } // if
    239201        }
  • src/SymTab/Autogen.h

    r956a9c7 r2be1023  
    2424
    2525namespace SymTab {
    26   /// Generates assignment operators, constructors, and destructor for aggregate types as required
    27   void autogenerateRoutines( std::list< Declaration * > &translationUnit );
     26        /// Generates assignment operators, constructors, and destructor for aggregate types as required
     27        void autogenerateRoutines( std::list< Declaration * > &translationUnit );
    2828
    29   // originally makeArrayAssignment - changed to Function because it is now used for ctors and dtors as well
    30   // admittedly not a great name change. This used to live in Validate.cc, but has been moved so it can be reused elsewhere
     29        /// returns true if obj's name is the empty string and it has a bitfield width
     30        bool isUnnamedBitfield( ObjectDecl * obj );
    3131
    32   /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
    33   /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
    34   template< typename OutputIterator >
    35   void makeArrayFunction( Expression *srcParam, Expression *dstParam, ArrayType *array, std::string fname, OutputIterator out, bool forward = true ) {
    36     static UniqueName indexName( "_index" );
     32        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
     33        template< typename OutputIterator >
     34        void genCall( Expression * srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool forward = true );
    3735
    38     // for a flexible array member nothing is done -- user must define own assignment
    39     if ( ! array->get_dimension() ) return;
     36        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
     37        template< typename OutputIterator >
     38        void genScalarCall( Expression *srcParam, Expression *dstParam, const std::string & fname, OutputIterator out ) {
     39                // want to be able to generate assignment, ctor, and dtor generically,
     40                // so fname is either ?=?, ?{}, or ^?{}
     41                UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
    4042
    41     Expression * begin, * end, * update, * cmp;
    42     if ( forward ) {
    43       // generate: for ( int i = 0; i < 0; ++i )
    44       begin = new NameExpr( "0" );
    45       end = array->get_dimension()->clone();
    46       cmp = new NameExpr( "?<?" );
    47       update = new NameExpr( "++?" );
    48     } else {
    49       // generate: for ( int i = N-1; i >= 0; --i )
    50       begin = new UntypedExpr( new NameExpr( "?-?" ) );
    51       ((UntypedExpr*)begin)->get_args().push_back( array->get_dimension()->clone() );
    52       ((UntypedExpr*)begin)->get_args().push_back( new NameExpr( "1" ) );
    53       end = new NameExpr( "0" );
    54       cmp = new NameExpr( "?>=?" );
    55       update = new NameExpr( "--?" );
    56     }
     43                // do something special for unnamed members
     44                fExpr->get_args().push_back( new AddressExpr( dstParam ) );
    5745
    58     ObjectDecl *index = new ObjectDecl( indexName.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), NULL );
     46                if ( srcParam ) {
     47                        fExpr->get_args().push_back( srcParam );
     48                }
    5949
    60     UntypedExpr *init = new UntypedExpr( new NameExpr( "?=?" ) );
    61     init->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
    62     init->get_args().push_back( begin );
    63     index->set_init( new SingleInit( init, std::list<Expression*>() ) );
     50                *out++ = new ExprStmt( noLabels, fExpr );
     51        }
    6452
    65     UntypedExpr *cond = new UntypedExpr( cmp );
    66     cond->get_args().push_back( new VariableExpr( index ) );
    67     cond->get_args().push_back( end );
     53        /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
     54        /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
     55        template< typename OutputIterator >
     56        void genArrayCall( Expression *srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, bool forward = true ) {
     57                static UniqueName indexName( "_index" );
    6858
    69     UntypedExpr *inc = new UntypedExpr( update );
    70     inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
     59                // for a flexible array member nothing is done -- user must define own assignment
     60                if ( ! array->get_dimension() ) return ;
    7161
    72     // want to be able to generate assignment, ctor, and dtor generically,
    73     // so fname is either ?=?, ?{}, or ^?{}
    74     UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
     62                Expression * begin, * end, * update, * cmp;
     63                if ( forward ) {
     64                        // generate: for ( int i = 0; i < 0; ++i )
     65                        begin = new NameExpr( "0" );
     66                        end = array->get_dimension()->clone();
     67                        cmp = new NameExpr( "?<?" );
     68                        update = new NameExpr( "++?" );
     69                } else {
     70                        // generate: for ( int i = N-1; i >= 0; --i )
     71                        begin = new UntypedExpr( new NameExpr( "?-?" ) );
     72                        ((UntypedExpr*)begin)->get_args().push_back( array->get_dimension()->clone() );
     73                        ((UntypedExpr*)begin)->get_args().push_back( new NameExpr( "1" ) );
     74                        end = new NameExpr( "0" );
     75                        cmp = new NameExpr( "?>=?" );
     76                        update = new NameExpr( "--?" );
     77                }
    7578
    76     UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?+?" ) );
    77     dstIndex->get_args().push_back( dstParam );
    78     dstIndex->get_args().push_back( new VariableExpr( index ) );
    79     fExpr->get_args().push_back( dstIndex );
     79                ObjectDecl *index = new ObjectDecl( indexName.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), NULL );
    8080
    81     // srcParam is NULL for default ctor/dtor
    82     if ( srcParam ) {
    83       UntypedExpr *srcIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
    84       srcIndex->get_args().push_back( srcParam );
    85       srcIndex->get_args().push_back( new VariableExpr( index ) );
    86       fExpr->get_args().push_back( srcIndex );
    87     }
     81                UntypedExpr *init = new UntypedExpr( new NameExpr( "?=?" ) );
     82                init->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
     83                init->get_args().push_back( begin );
     84                index->set_init( new SingleInit( init, std::list<Expression*>() ) );
    8885
    89     std::list<Statement *> initList;
    90     CompoundStmt * block = new CompoundStmt( noLabels );
    91     block->get_kids().push_back( new DeclStmt( noLabels, index ) );
    92     block->get_kids().push_back( new ForStmt( noLabels, initList, cond, inc, new ExprStmt( noLabels, fExpr ) ) );
     86                UntypedExpr *cond = new UntypedExpr( cmp );
     87                cond->get_args().push_back( new VariableExpr( index ) );
     88                cond->get_args().push_back( end );
    9389
    94     Statement * stmt = block;
    95     if ( fname == "?{}" || fname == "^?{}" ) {
    96       // implicitly generated ctor/dtor calls should be wrapped
    97       // so that later passes are aware they were generated
    98       stmt = new ImplicitCtorDtorStmt( stmt );
    99     }
    100     *out++ = stmt;
    101   }
     90                UntypedExpr *inc = new UntypedExpr( update );
     91                inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
     92
     93                UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
     94                dstIndex->get_args().push_back( dstParam );
     95                dstIndex->get_args().push_back( new VariableExpr( index ) );
     96                dstParam = dstIndex;
     97
     98                // srcParam is NULL for default ctor/dtor
     99                if ( srcParam ) {
     100                        UntypedExpr *srcIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
     101                        srcIndex->get_args().push_back( srcParam );
     102                        srcIndex->get_args().push_back( new VariableExpr( index ) );
     103                        srcParam = srcIndex;
     104                }
     105
     106                // for stmt's body, eventually containing call
     107                CompoundStmt * body = new CompoundStmt( noLabels );
     108                genCall( srcParam, dstParam, fname, back_inserter( body->get_kids() ), array->get_base(), forward );
     109
     110                // block containing for stmt and index variable
     111                std::list<Statement *> initList;
     112                CompoundStmt * block = new CompoundStmt( noLabels );
     113                block->get_kids().push_back( new DeclStmt( noLabels, index ) );
     114                block->get_kids().push_back( new ForStmt( noLabels, initList, cond, inc, body ) );
     115
     116                *out++ = block;
     117        }
     118
     119        template< typename OutputIterator >
     120        void genCall( Expression * srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool forward ) {
     121                if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
     122                        genArrayCall( srcParam, dstParam, fname, out, at, forward );
     123                } else {
     124                        genScalarCall( srcParam, dstParam, fname, out );
     125                }
     126        }
     127
     128        /// inserts into out a generated call expression to function fname with arguments dstParam
     129        /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the
     130        /// object being constructed. The function wraps constructor and destructor calls in an
     131        /// ImplicitCtorDtorStmt node.
     132        template< typename OutputIterator >
     133        void genImplicitCall( Expression * srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {
     134                ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl );
     135                assert( obj );
     136                // unnamed bit fields are not copied as they cannot be accessed
     137                if ( isUnnamedBitfield( obj ) ) return;
     138
     139                std::list< Statement * > stmts;
     140                genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->get_type(), forward );
     141
     142                // 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
     143                assert( stmts.size() == 1 );
     144                Statement * callStmt = stmts.front();
     145                if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && obj->get_bitfieldWidth() == NULL ) ) ) {
     146                        // implicitly generated ctor/dtor calls should be wrapped
     147                        // so that later passes are aware they were generated.
     148                        // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield,
     149                        // because this causes the address to be taken at codegen, which is illegal in C.
     150                        callStmt = new ImplicitCtorDtorStmt( callStmt );
     151                }
     152                *out++ = callStmt;
     153        }
    102154} // namespace SymTab
    103155#endif // AUTOGEN_H
Note: See TracChangeset for help on using the changeset viewer.