Changeset 65660bd


Ignore:
Timestamp:
Sep 22, 2016, 8:14:56 AM (8 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
ac9ca96
Parents:
1132b62
git-author:
Rob Schluntz <rschlunt@…> (09/21/16 23:43:37)
git-committer:
Rob Schluntz <rschlunt@…> (09/22/16 08:14:56)
Message:

replace multiple-returning functions with tuple-returning functions, implement tuple ctor/dtor, allow N-arg tuple assignment

Location:
src
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r1132b62 r65660bd  
    6969
    7070                        /// create and resolve ctor/dtor expression: fname(var, [cpArg])
    71                         ApplicationExpr * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL );
    72                         ApplicationExpr * makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg = NULL );
     71                        Expression * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL );
     72                        Expression * makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg = NULL );
    7373                        /// true if type does not need to be copy constructed to ensure correctness
    7474                        bool skipCopyConstruct( Type * type );
     
    360360                }
    361361
    362                 ApplicationExpr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) {
     362                Expression * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) {
    363363                        assert( var );
    364364                        return makeCtorDtor( fname, new AddressExpr( new VariableExpr( var ) ), cpArg );
    365365                }
    366366
    367                 ApplicationExpr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg ) {
     367                Expression * ResolveCopyCtors::makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg ) {
    368368                        assert( thisArg );
    369369                        UntypedExpr * untyped = new UntypedExpr( new NameExpr( fname ) );
     
    375375                        // (VariableExpr and already resolved expression)
    376376                        CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; )
    377                         ApplicationExpr * resolved = dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untyped, *this ) );
     377                        Expression * resolved = ResolvExpr::findVoidExpression( untyped, *this );
     378                        assert( resolved );
    378379                        if ( resolved->get_env() ) {
    379380                                env->add( *resolved->get_env() );
    380381                        } // if
    381382
    382                         assert( resolved );
    383383                        delete untyped;
    384384                        return resolved;
     
    392392                        if ( skipCopyConstruct( result ) ) return; // skip certain non-copyable types
    393393
    394                         if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( arg ) ) {
    395                                 for ( Expression * & expr : tupleExpr->get_exprs() ) {
    396                                         copyConstructArg( expr, impCpCtorExpr );
    397                                 }
    398                                 return;
    399                         }
    400 
    401394                        // type may involve type variables, so apply type substitution to get temporary variable's actual type
    402395                        result = result->clone();
     
    407400                        // create and resolve copy constructor
    408401                        CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; )
    409                         ApplicationExpr * cpCtor = makeCtorDtor( "?{}", tmp, arg );
    410 
    411                         // if the chosen constructor is intrinsic, the copy is unnecessary, so
    412                         // don't create the temporary and don't call the copy constructor
    413                         VariableExpr * function = dynamic_cast< VariableExpr * >( cpCtor->get_function() );
    414                         assert( function );
    415                         if ( function->get_var()->get_linkage() != LinkageSpec::Intrinsic ) {
    416                                 // replace argument to function call with temporary
    417                                 arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
    418                                 impCpCtorExpr->get_tempDecls().push_back( tmp );
    419                                 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) );
    420                         } // if
     402                        Expression * cpCtor = makeCtorDtor( "?{}", tmp, arg );
     403
     404                        if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( cpCtor ) ) {
     405                                // if the chosen constructor is intrinsic, the copy is unnecessary, so
     406                                // don't create the temporary and don't call the copy constructor
     407                                VariableExpr * function = dynamic_cast< VariableExpr * >( appExpr->get_function() );
     408                                assert( function );
     409                                if ( function->get_var()->get_linkage() == LinkageSpec::Intrinsic ) return;
     410                        }
     411
     412                        // replace argument to function call with temporary
     413                        arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
     414                        impCpCtorExpr->get_tempDecls().push_back( tmp );
     415                        impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) );
    421416                }
    422417
    423418                void ResolveCopyCtors::destructRet( Expression * ret, ImplicitCopyCtorExpr * impCpCtorExpr ) {
    424                         if ( TupleType * tupleType = dynamic_cast< TupleType * > ( ret->get_result() ) ) {
    425                                 int idx = 0;
    426                                 for ( Type *& t : tupleType->get_types() ) {
    427                                         (void)t;
    428                                         destructRet( new TupleIndexExpr( ret->clone(), idx++ ), impCpCtorExpr );
    429                                 }
    430                                 return;
    431                         }
    432419                        impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", new AddressExpr( ret ) ) );
    433420                }
  • src/InitTweak/GenInit.cc

    r1132b62 r65660bd  
    2929#include "GenPoly/DeclMutator.h"
    3030#include "GenPoly/ScopedSet.h"
     31#include "ResolvExpr/typeops.h"
    3132
    3233namespace InitTweak {
     
    5051
    5152          protected:
    52                 std::list<DeclarationWithType*> returnVals;
     53                FunctionType * ftype;
    5354                UniqueName tempNamer;
    5455                std::string funcName;
     
    8687
    8788                bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed
     89                bool isManaged( Type * type ) const; // determine if type is managed
    8890                void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor
    8991                GenPoly::ScopedSet< std::string > managedTypes;
     
    134136
    135137        Statement *ReturnFixer::mutate( ReturnStmt *returnStmt ) {
    136                 // update for multiple return values
     138                std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
    137139                assert( returnVals.size() == 0 || returnVals.size() == 1 );
    138140                // hands off if the function returns an lvalue - we don't want to allocate a temporary if a variable's address
     
    156158
    157159        DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) {
    158                 ValueGuard< std::list<DeclarationWithType*> > oldReturnVals( returnVals );
     160                // xxx - need to handle named return values - this pass may need to happen
     161                // after resolution? the ordering is tricky because return statements must be
     162                // constructed - the simplest way to do that (while also handling multiple
     163                // returns) is to structure the returnVals into a tuple, as done here.
     164                // however, if the tuple return value is structured before resolution,
     165                // it's difficult to resolve named return values, since the name is lost
     166                // in conversion to a tuple. this might be easiest to deal with
     167                // after reference types are added, as it may then be possible to
     168                // uniformly move named return values to the parameter list directly
     169                ValueGuard< FunctionType * > oldFtype( ftype );
    159170                ValueGuard< std::string > oldFuncName( funcName );
    160171
    161                 FunctionType * type = functionDecl->get_functionType();
    162                 returnVals = type->get_returnVals();
     172                ftype = functionDecl->get_functionType();
     173                std::list< DeclarationWithType * > & retVals = ftype->get_returnVals();
     174                if ( retVals.size() > 1 ) {
     175                        TupleType * tupleType = safe_dynamic_cast< TupleType * >( ResolvExpr::extractResultType( ftype ) );
     176                        ObjectDecl * newRet = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, tupleType, new ListInit( std::list<Initializer*>(), noDesignators, false ) );
     177                        retVals.clear();
     178                        retVals.push_back( newRet );
     179                }
    163180                funcName = functionDecl->get_name();
    164181                DeclarationWithType * decl = Mutator::mutate( functionDecl );
     
    220237        }
    221238
     239        bool CtorDtor::isManaged( Type * type ) const {
     240                return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();
     241        }
     242
    222243        bool CtorDtor::isManaged( ObjectDecl * objDecl ) const {
    223244                Type * type = objDecl->get_type();
     
    225246                        type = at->get_base();
    226247                }
    227                 return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();
     248                if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
     249                        return std::any_of( tupleType->get_types().begin(), tupleType->get_types().end(), [&](Type * type) { return isManaged( type ); });
     250                }
     251                return isManaged( type );
    228252        }
    229253
  • src/ResolvExpr/Alternative.h

    r1132b62 r65660bd  
    4545                TypeEnvironment env;
    4646        };
    47 
    48         /// helper function used by explode
    49         template< typename OutputIterator >
    50         void explodeUnique( Expression * expr, const Alternative & alt, OutputIterator out ) {
    51                 Type * res = expr->get_result();
    52                 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
    53                         if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {
    54                                 // can open tuple expr and dump its exploded components
    55                                 for ( Expression * expr : tupleExpr->get_exprs() ) {
    56                                         explodeUnique( expr, alt, out );
    57                                 }
    58                         } else {
    59                                 // tuple type, but not tuple expr - need to refer to single instance of the argument
    60                                 // expression and index into its components
    61                                 UniqueExpr * unq = new UniqueExpr( expr->clone() );
    62                                 for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
    63                                         TupleIndexExpr * idx = new TupleIndexExpr( unq->clone(), i );
    64                                         explodeUnique( idx, alt, out );
    65                                         delete idx;
    66                                 }
    67                                 delete unq;
    68                         }
    69                 } else {
    70                         // atomic (non-tuple) type - output a clone of the expression in a new alternative
    71                         *out++ = Alternative( expr->clone(), alt.env, alt.cost, alt.cvtCost );
    72                 }
    73         }
    74 
    75         /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
    76         template< typename OutputIterator >
    77         void explode( const Alternative &alt, OutputIterator out ) {
    78                 explodeUnique( alt.expr, alt, out );
    79         }
    80 
    81         // explode list of alternatives
    82         template< typename OutputIterator >
    83         void explode( const AltList & alts, OutputIterator out ) {
    84                 for ( const Alternative & alt : alts ) {
    85                         explode( alt, out );
    86                 }
    87         }
    8847} // namespace ResolvExpr
    8948
  • src/ResolvExpr/AlternativeFinder.cc

    r1132b62 r65660bd  
    435435                // flatten actuals so that each actual has an atomic (non-tuple) type
    436436                AltList exploded;
    437                 explode( actuals, back_inserter( exploded ) );
     437                Tuples::explode( actuals, back_inserter( exploded ) );
    438438
    439439                AltList::iterator actualExpr = exploded.begin();
  • src/ResolvExpr/Resolver.cc

    r1132b62 r65660bd  
    3838
    3939                virtual void visit( FunctionDecl *functionDecl );
    40                 virtual void visit( ObjectDecl *functionDecl );
     40                virtual void visit( ObjectDecl *objectDecl );
    4141                virtual void visit( TypeDecl *typeDecl );
    4242                virtual void visit( EnumDecl * enumDecl );
     
    442442                                (*iter)->accept( *this );
    443443                        } // for
     444                } else if ( TupleType * tt = dynamic_cast< TupleType * > ( initContext ) ) {
     445                        for ( Type * t : *tt ) {
     446                                if ( iter == end ) break;
     447                                initContext = t;
     448                                (*iter++)->accept( *this );
     449                        }
    444450                } else if ( StructInstType * st = dynamic_cast< StructInstType * >( initContext ) ) {
    445451                        resolveAggrInit( st->get_baseStruct(), iter, end );
  • src/SynTree/Expression.h

    r1132b62 r65660bd  
    696696};
    697697
    698 /// TupleAssignExpr represents a multiple assignment operation, where both sides of the assignment have tuple type, e.g. [a, b, c] = [d, e, f];, or a mass assignment operation, where the left hand side has tuple type and the right hand side does not, e.g. [a, b, c] = 5.0;
     698/// TupleAssignExpr represents a multiple assignment operation, where both sides of the assignment have tuple type, e.g. [a, b, c] = [d, e, f];, a mass assignment operation, where the left hand side has tuple type and the right hand side does not, e.g. [a, b, c] = 5.0;, or a tuple ctor/dtor expression
    699699class TupleAssignExpr : public Expression {
    700700  public:
  • src/SynTree/TupleExpr.cc

    r1132b62 r65660bd  
    8888
    8989TupleAssignExpr::TupleAssignExpr( const std::list< Expression * > & assigns, const std::list< ObjectDecl * > & tempDecls, Expression * _aname ) : Expression( _aname ), assigns( assigns ), tempDecls( tempDecls ) {
    90         TupleType * type = new TupleType( Type::Qualifiers() );
    91         for ( Expression * expr : assigns ) {
    92                 assert( expr->has_result() );
    93                 type->get_types().push_back( expr->get_result()->clone() );
    94         }
    95         set_result( type );
     90        set_result( Tuples::makeTupleType( assigns ) );
    9691}
    9792
  • src/Tuples/TupleAssignment.cc

    r1132b62 r65660bd  
    2121#include "Tuples.h"
    2222#include "Common/SemanticError.h"
     23#include "InitTweak/InitTweak.h"
    2324
    2425#include <functional>
     
    3536                // dispatcher for Tuple (multiple and mass) assignment operations
    3637                TupleAssignSpotter( ResolvExpr::AlternativeFinder & );
    37                 void spot( UntypedExpr * expr, std::list<ResolvExpr::AltList> &possibilities );
     38                void spot( UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities );
    3839
    3940          private:
     
    4243                struct Matcher {
    4344                  public:
    44                         Matcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs );
     45                        Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
    4546                        virtual ~Matcher() {}
    4647                        virtual void match( std::list< Expression * > &out ) = 0;
     
    5253                struct MassAssignMatcher : public Matcher {
    5354                  public:
    54                         MassAssignMatcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs );
     55                        MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
    5556                        virtual void match( std::list< Expression * > &out );
    5657                };
     
    5859                struct MultipleAssignMatcher : public Matcher {
    5960                  public:
    60                         MultipleAssignMatcher( TupleAssignSpotter &spot, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs );
     61                        MultipleAssignMatcher( TupleAssignSpotter &spot, const ResolvExpr::AltList & alts );
    6162                        virtual void match( std::list< Expression * > &out );
    6263                };
    6364
    6465                ResolvExpr::AlternativeFinder &currentFinder;
    65                 // Expression *rhs, *lhs;
    66                 Matcher *matcher = nullptr;
     66                std::string fname;
     67                std::unique_ptr< Matcher > matcher;
    6768        };
    6869
     
    7475        }
    7576
     77        template< typename AltIter >
     78        bool isMultAssign( AltIter begin, AltIter end ) {
     79                // multiple assignment if more than one alternative in the range or if
     80                // the alternative is a tuple
     81                if ( begin == end ) return false;
     82                if ( isTuple( begin->expr ) ) return true;
     83                return ++begin != end;
     84        }
     85
    7686        bool pointsToTuple( Expression *expr ) {
    7787                // also check for function returning tuple of reference types
    78                 if ( AddressExpr *addr = dynamic_cast< AddressExpr * >( expr) ) {
     88                if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
     89                        return pointsToTuple( castExpr->get_arg() );
     90                } else if ( AddressExpr *addr = dynamic_cast< AddressExpr * >( expr) ) {
    7991                        return isTuple( addr->get_arg() );
    8092                }
     
    8294        }
    8395
    84         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, std::list<ResolvExpr::AltList> &possibilities ) {
     96        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities ) {
    8597                TupleAssignSpotter spotter( currentFinder );
    8698                spotter.spot( expr, possibilities );
     
    90102                : currentFinder(f) {}
    91103
    92         void TupleAssignSpotter::spot( UntypedExpr * expr, std::list<ResolvExpr::AltList> &possibilities ) {
    93                 if (  NameExpr *assgnop = dynamic_cast< NameExpr * >(expr->get_function()) ) {
    94                         if ( assgnop->get_name() == "?=?" ) {
    95                                 for ( std::list<ResolvExpr::AltList>::iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
    96                                         if ( ali->size() != 2 ) continue; // what does it mean if an assignment takes >2 arguments? grab args 2-N and group into a TupleExpr, then proceed?
    97                                         ResolvExpr::Alternative & alt1 = ali->front(), & alt2 = ali->back();
    98 
     104        void TupleAssignSpotter::spot( UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities ) {
     105                if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
     106                        if ( InitTweak::isCtorDtorAssign( op->get_name() ) ) {
     107                                fname = op->get_name();
     108                                for ( std::list<ResolvExpr::AltList>::const_iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
     109                                        if ( ali->size() == 0 ) continue; // AlternativeFinder will natrually handle this case, if it's legal
     110                                        if ( ali->size() <= 1 && InitTweak::isAssignment( op->get_name() ) ) {
     111                                                // what does it mean if an assignment takes 1 argument? maybe someone defined such a function, in which case AlternativeFinder will naturally handle it
     112                                                continue;
     113                                        }
     114
     115                                        assert( ! ali->empty() );
     116                                        // grab args 2-N and group into a TupleExpr
     117                                        const ResolvExpr::Alternative & alt1 = ali->front();
     118                                        auto begin = std::next(ali->begin(), 1), end = ali->end();
    99119                                        if ( pointsToTuple(alt1.expr) ) {
    100                                                 MultipleAssignMatcher multiMatcher( *this, alt1, alt2 );
    101                                                 MassAssignMatcher massMatcher( *this,  alt1, alt2 );
    102                                                 if ( isTuple( alt2.expr ) ) {
    103                                                         matcher = &multiMatcher;
     120                                                if ( isMultAssign( begin, end ) ) {
     121                                                        matcher.reset( new MultipleAssignMatcher( *this, *ali ) );
    104122                                                } else {
    105123                                                        // mass assignment
    106                                                         matcher = &massMatcher;
     124                                                        matcher.reset( new MassAssignMatcher( *this,  *ali ) );
    107125                                                }
    108126                                                match();
    109                                         } else if ( isTuple( alt2.expr ) ) {
    110                                                 throw SemanticError("Cannot assign a tuple value into a non-tuple lvalue.", expr);
    111127                                        }
    112128                                }
     
    146162        }
    147163
    148         TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs ) : spotter(spotter) {
    149                 if (AddressExpr *addr = dynamic_cast<AddressExpr *>(lhs.expr) ) {
    150                         // xxx - not every assignment NEEDS to have the first argument as address-taken, e.g. a manual call to assignment. What to do in this case? skip it as a possibility for TupleAssignment, since the type will always be T*, where T can never be a tuple? Is this true?
    151 
    152                         // explode the lhs so that each field of the tuple-valued-expr is assigned.
    153                         ResolvExpr::Alternative lhsAlt( addr->get_arg()->clone(), lhs.env, lhs.cost, lhs.cvtCost );
    154                         explode( lhsAlt, back_inserter(this->lhs) );
    155                 }
    156         }
    157 
    158         TupleAssignSpotter::MassAssignMatcher::MassAssignMatcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs ) : Matcher( spotter, lhs, rhs ) {
    159                 this->rhs.push_back( rhs );
    160         }
    161 
    162         TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs ) : Matcher( spotter, lhs, rhs ) {
    163 
     164        TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList &alts ) : spotter(spotter) {
     165                assert( ! alts.empty() );
     166                ResolvExpr::Alternative lhsAlt = alts.front();
     167                // peel off the cast that exists on ctor/dtor expressions
     168                bool isCast = false;
     169                if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( lhsAlt.expr ) ) {
     170                        lhsAlt.expr = castExpr->get_arg();
     171                        castExpr->set_arg( nullptr );
     172                        delete castExpr;
     173                        isCast = true;
     174                }
     175
     176                // explode the lhs so that each field of the tuple-valued-expr is assigned.
     177                explode( lhsAlt, back_inserter(lhs) );
     178                // and finally, re-add the cast to each lhs expr, so that qualified tuple fields can be constructed
     179                if ( isCast ) {
     180                        for ( ResolvExpr::Alternative & alt : lhs ) {
     181                                Expression *& expr = alt.expr;
     182                                Type * castType = expr->get_result()->clone();
     183                                Type * type = InitTweak::getPointerBase( castType );
     184                                assert( type );
     185                                type->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, true);
     186                                type->set_isLvalue( true ); // xxx - might not need this
     187                                expr = new CastExpr( expr, castType );
     188                        }
     189                }
     190                // }
     191        }
     192
     193        TupleAssignSpotter::MassAssignMatcher::MassAssignMatcher( TupleAssignSpotter &spotter,const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
     194                assert( alts.size() == 1 || alts.size() == 2 );
     195                if ( alts.size() == 2 ) {
     196                        rhs.push_back( alts.back() );
     197                }
     198        }
     199
     200        TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
    164201                // explode the rhs so that each field of the tuple-valued-expr is assigned.
    165                 explode( rhs, back_inserter(this->rhs) );
    166         }
    167 
    168         UntypedExpr * createAssgn( ObjectDecl *left, ObjectDecl *right ) {
    169                 assert( left && right );
     202                explode( std::next(alts.begin(), 1), alts.end(), back_inserter(rhs) );
     203        }
     204
     205        UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {
     206                assert( left );
    170207                std::list< Expression * > args;
    171208                args.push_back( new AddressExpr( new UntypedExpr( new NameExpr("*?"), std::list< Expression * >{ new VariableExpr( left ) } ) ) );
    172                 args.push_back( new VariableExpr( right ) );
    173                 return new UntypedExpr( new NameExpr( "?=?" ), args );
     209                // args.push_back( new AddressExpr( new VariableExpr( left ) ) );
     210                if ( right ) args.push_back( new VariableExpr( right ) );
     211                return new UntypedExpr( new NameExpr( fname ), args );
    174212        }
    175213
     
    182220                static UniqueName lhsNamer( "__massassign_L" );
    183221                static UniqueName rhsNamer( "__massassign_R" );
    184                 assert ( ! lhs.empty() && rhs.size() == 1);
    185 
    186                 ObjectDecl * rtmp = newObject( rhsNamer, rhs.front().expr );
     222                assert ( ! lhs.empty() && rhs.size() <= 1);
     223
     224                ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
    187225                for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
    188                         ObjectDecl * ltmp = newObject( lhsNamer, new AddressExpr( lhsAlt.expr ) );
    189                         out.push_back( createAssgn( ltmp, rtmp ) );
     226                        ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
     227                        out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
    190228                        tmpDecls.push_back( ltmp );
    191229                }
    192                 tmpDecls.push_back( rtmp );
     230                if ( rtmp ) tmpDecls.push_back( rtmp );
    193231        }
    194232
     
    201239                        std::list< ObjectDecl * > rtmp;
    202240                        std::transform( lhs.begin(), lhs.end(), back_inserter( ltmp ), []( ResolvExpr::Alternative & alt ){
    203                                 return newObject( lhsNamer, new AddressExpr( alt.expr ) );
     241                                return newObject( lhsNamer, alt.expr );
    204242                        });
    205243                        std::transform( rhs.begin(), rhs.end(), back_inserter( rtmp ), []( ResolvExpr::Alternative & alt ){
    206244                                return newObject( rhsNamer, alt.expr );
    207245                        });
    208                         zipWith( ltmp.begin(), ltmp.end(), rtmp.begin(), rtmp.end(), back_inserter(out), createAssgn );
     246                        zipWith( ltmp.begin(), ltmp.end(), rtmp.begin(), rtmp.end(), back_inserter(out), [&](ObjectDecl * obj1, ObjectDecl * obj2 ) { return createFunc(spotter.fname, obj1, obj2); } );
    209247                        tmpDecls.splice( tmpDecls.end(), ltmp );
    210248                        tmpDecls.splice( tmpDecls.end(), rtmp );
  • src/Tuples/TupleExpansion.cc

    r1132b62 r65660bd  
    4949
    5050                        virtual Type * mutate( TupleType * tupleType );
    51                         virtual Type * mutate( FunctionType * ftype );
    5251
    5352                        virtual CompoundStmt * mutate( CompoundStmt * stmt ) {
     
    119118                delete assnExpr;
    120119                return new StmtExpr( compoundStmt );
    121         }
    122 
    123         Type * TupleTypeReplacer::mutate( FunctionType * ftype ) {
    124                 // replace multiple-returning functions with functions which return a tuple
    125                 if ( ftype->get_returnVals().size() > 1 ) {
    126                         TupleType * tupleType = safe_dynamic_cast<TupleType *>( ResolvExpr::extractResultType( ftype ) );
    127                         ObjectDecl * retVal = new ObjectDecl( "__tuple_ret", DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, tupleType, nullptr );
    128                         // xxx - replace all uses of return vals with appropriate tuple index expr
    129                         deleteAll( ftype->get_returnVals() );
    130                         ftype->get_returnVals().clear();
    131                         ftype->get_returnVals().push_back( retVal );
    132                 }
    133                 return Parent::mutate( ftype );
    134120        }
    135121
     
    167153        }
    168154
     155        Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs ) {
     156                if ( result->isVoid() ) {
     157                        // void result - don't need to produce a value for cascading - just output a chain of comma exprs
     158                        assert( ! exprs.empty() );
     159                        std::list< Expression * >::const_iterator iter = exprs.begin();
     160                        Expression * expr = *iter++;
     161                        for ( ; iter != exprs.end(); ++iter ) {
     162                                expr = new CommaExpr( expr, *iter );
     163                        }
     164                        return expr;
     165                } else {
     166                        // typed tuple expression - produce a compound literal which performs each of the expressions
     167                        // as a distinct part of its initializer - the produced compound literal may be used as part of
     168                        // another expression
     169                        std::list< Initializer * > inits;
     170                        for ( Expression * expr : exprs ) {
     171                                inits.push_back( new SingleInit( expr ) );
     172                        }
     173                        return new CompoundLiteralExpr( result, new ListInit( inits ) );
     174                }
     175        }
     176
    169177        Expression * TupleExprExpander::mutate( TupleExpr * tupleExpr ) {
    170                 assert( tupleExpr->get_result() );
    171                 std::list< Initializer * > inits;
    172                 for ( Expression * expr : tupleExpr->get_exprs() ) {
    173                         inits.push_back( new SingleInit( expr ) );
    174                 }
    175                 return new CompoundLiteralExpr( tupleExpr->get_result(), new ListInit( inits ) );
    176         }
    177 
    178         TupleType * makeTupleType( const std::list< Expression * > & exprs ) {
     178                Type * result = tupleExpr->get_result();
     179                std::list< Expression * > exprs = tupleExpr->get_exprs();
     180                assert( result );
     181
     182                tupleExpr->set_result( nullptr );
     183                tupleExpr->get_exprs().clear();
     184                delete tupleExpr;
     185
     186                return replaceTupleExpr( result, exprs );
     187        }
     188
     189        Type * makeTupleType( const std::list< Expression * > & exprs ) {
     190                // produce the TupleType which aggregates the types of the exprs
    179191                TupleType *tupleType = new TupleType( Type::Qualifiers(true, true, true, true, true, false) );
    180192                Type::Qualifiers &qualifiers = tupleType->get_qualifiers();
    181193                for ( Expression * expr : exprs ) {
    182194                        assert( expr->get_result() );
     195                        if ( expr->get_result()->isVoid() ) {
     196                                // if the type of any expr is void, the type of the entire tuple is void
     197                                delete tupleType;
     198                                return new VoidType( Type::Qualifiers() );
     199                        }
    183200                        Type * type = expr->get_result()->clone();
    184201                        tupleType->get_types().push_back( type );
     202                        // the qualifiers on the tuple type are the qualifiers that exist on all component types
    185203                        qualifiers &= type->get_qualifiers();
    186204                } // for
    187205                return tupleType;
     206        }
     207
     208        namespace {
     209                /// determines if impurity (read: side-effects) may exist in a piece of code. Currently gives a very crude approximation, wherein any function call expression means the code may be impure
     210                class ImpurityDetector : public Visitor {
     211                public:
     212                        typedef Visitor Parent;
     213                        virtual void visit( ApplicationExpr * appExpr ) { maybeImpure = true;   }
     214                        virtual void visit( UntypedExpr * untypedExpr ) { maybeImpure = true; }
     215                        bool maybeImpure = false;
     216                };
     217        } // namespace
     218
     219        bool maybeImpure( Expression * expr ) {
     220                ImpurityDetector detector;
     221                expr->accept( detector );
     222                return detector.maybeImpure;
    188223        }
    189224} // namespace Tuples
  • src/Tuples/Tuples.h

    r1132b62 r65660bd  
    1515
    1616#ifndef _TUPLES_H_
    17 #define _TUPLE_H_
     17#define _TUPLES_H_
    1818
    1919#include <string>
     
    2727namespace Tuples {
    2828        // TupleAssignment.cc
    29         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, std::list<ResolvExpr::AltList> & possibilities );
     29        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, const std::list<ResolvExpr::AltList> & possibilities );
    3030
    3131        // TupleExpansion.cc
     
    3434  void expandUniqueExpr( std::list< Declaration * > & translationUnit );
    3535
    36   TupleType * makeTupleType( const std::list< Expression * > & exprs );
     36  /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
     37  Type * makeTupleType( const std::list< Expression * > & exprs );
     38
     39  bool maybeImpure( Expression * expr );
     40
     41
     42        /// helper function used by explode
     43        template< typename OutputIterator >
     44        void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt, OutputIterator out ) {
     45                Type * res = expr->get_result();
     46                if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
     47                        ResolvExpr::AltList alts;
     48                        explodeUnique( addrExpr->get_arg(), alt, back_inserter( alts ) );
     49                        for ( ResolvExpr::Alternative & alt : alts ) {
     50                                // distribute '&' over all components
     51                                alt.expr = new AddressExpr( alt.expr );
     52                                *out++ = alt;
     53                        }
     54                } else if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
     55                        if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {
     56                                // can open tuple expr and dump its exploded components
     57                                for ( Expression * expr : tupleExpr->get_exprs() ) {
     58                                        explodeUnique( expr, alt, out );
     59                                }
     60                        } else {
     61                                // tuple type, but not tuple expr - recursively index into its components
     62                                Expression * arg = expr->clone();
     63                                if ( Tuples::maybeImpure( arg ) ) {
     64                                        // expressions which may contain side effects require a single unique instance of the expression
     65                                        arg = new UniqueExpr( arg );
     66                                }
     67                                for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
     68                                        TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );
     69                                        explodeUnique( idx, alt, out );
     70                                        delete idx;
     71                                }
     72                                delete arg;
     73                        }
     74                } else {
     75                        // atomic (non-tuple) type - output a clone of the expression in a new alternative
     76                        *out++ = ResolvExpr::Alternative( expr->clone(), alt.env, alt.cost, alt.cvtCost );
     77                }
     78        }
     79
     80        /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
     81        template< typename OutputIterator >
     82        void explode( const ResolvExpr::Alternative &alt, OutputIterator out ) {
     83                explodeUnique( alt.expr, alt, out );
     84        }
     85
     86        // explode list of alternatives
     87        template< typename AltIterator, typename OutputIterator >
     88        void explode( AltIterator altBegin, AltIterator altEnd, OutputIterator out ) {
     89                for ( ; altBegin != altEnd; ++altBegin ) {
     90                        explode( *altBegin, out );
     91                }
     92        }
     93
     94        template< typename OutputIterator >
     95        void explode( const ResolvExpr::AltList & alts, OutputIterator out ) {
     96                explode( alts.begin(), alts.end(), out );
     97        }
    3798} // namespace Tuples
    3899
Note: See TracChangeset for help on using the changeset viewer.