source: src/Tuples/TupleAssignment.cc @ 4b6ef70

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since 4b6ef70 was 4b6ef70, checked in by Aaron Moss <a3moss@…>, 8 years ago

Fix one tuple bug in resolver refactor

  • Property mode set to 100644
File size: 13.6 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// TupleAssignment.cc --
8//
9// Author           : Rodolfo G. Esteves
10// Created On       : Mon May 18 07:44:20 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Mar 17 09:43:03 2017
13// Update Count     : 8
14//
15
16#include <algorithm>                       // for transform
17#include <cassert>                         // for assert
18#include <iterator>                        // for back_insert_iterator, back...
19#include <list>                            // for _List_const_iterator, _Lis...
20#include <memory>                          // for unique_ptr, allocator_trai...
21#include <string>                          // for string
22
23#include "CodeGen/OperatorTable.h"
24#include "Common/UniqueName.h"             // for UniqueName
25#include "Common/utility.h"                // for zipWith
26#include "Explode.h"                       // for explode
27#include "InitTweak/GenInit.h"             // for genCtorInit
28#include "InitTweak/InitTweak.h"           // for getPointerBase, isAssignment
29#include "Parser/LinkageSpec.h"            // for Cforall
30#include "ResolvExpr/Alternative.h"        // for AltList, Alternative
31#include "ResolvExpr/AlternativeFinder.h"  // for AlternativeFinder, simpleC...
32#include "ResolvExpr/Cost.h"               // for Cost
33#include "ResolvExpr/Resolver.h"           // for resolveCtorInit
34#include "ResolvExpr/TypeEnvironment.h"    // for TypeEnvironment
35#include "ResolvExpr/typeops.h"            // for combos
36#include "SynTree/Declaration.h"           // for ObjectDecl
37#include "SynTree/Expression.h"            // for Expression, CastExpr, Name...
38#include "SynTree/Initializer.h"           // for ConstructorInit, SingleInit
39#include "SynTree/Statement.h"             // for ExprStmt
40#include "SynTree/Type.h"                  // for Type, Type::Qualifiers
41#include "SynTree/TypeSubstitution.h"      // for TypeSubstitution
42#include "SynTree/Visitor.h"               // for Visitor
43
44#if 0
45#define PRINT(x) x
46#else
47#define PRINT(x)
48#endif
49
50namespace Tuples {
51        class TupleAssignSpotter {
52          public:
53                // dispatcher for Tuple (multiple and mass) assignment operations
54                TupleAssignSpotter( ResolvExpr::AlternativeFinder & );
55                void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );
56
57          private:
58                void match();
59
60                struct Matcher {
61                  public:
62                        Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
63                        virtual ~Matcher() {}
64                        virtual void match( std::list< Expression * > &out ) = 0;
65                        ObjectDecl * newObject( UniqueName & namer, Expression * expr );
66                        ResolvExpr::AltList lhs, rhs;
67                        TupleAssignSpotter &spotter;
68                        ResolvExpr::Cost baseCost;
69                        std::list< ObjectDecl * > tmpDecls;
70                        ResolvExpr::TypeEnvironment compositeEnv;
71                };
72
73                struct MassAssignMatcher : public Matcher {
74                  public:
75                        MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
76                        virtual void match( std::list< Expression * > &out );
77                };
78
79                struct MultipleAssignMatcher : public Matcher {
80                  public:
81                        MultipleAssignMatcher( TupleAssignSpotter &spot, const ResolvExpr::AltList & alts );
82                        virtual void match( std::list< Expression * > &out );
83                };
84
85                ResolvExpr::AlternativeFinder &currentFinder;
86                std::string fname;
87                std::unique_ptr< Matcher > matcher;
88        };
89
90        /// true if expr is an expression of tuple type
91        bool isTuple( Expression *expr ) {
92                if ( ! expr ) return false;
93                assert( expr->result );
94                return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );
95        }
96
97        template< typename AltIter >
98        bool isMultAssign( AltIter begin, AltIter end ) {
99                // multiple assignment if more than one alternative in the range or if
100                // the alternative is a tuple
101                if ( begin == end ) return false;
102                if ( isTuple( begin->expr ) ) return true;
103                return ++begin != end;
104        }
105
106        bool refToTuple( Expression *expr ) {
107                assert( expr->get_result() );
108                // also check for function returning tuple of reference types
109                if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
110                        return refToTuple( castExpr->get_arg() );
111                } else {
112                        return isTuple( expr );
113                }
114                return false;
115        }
116
117        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, 
118                std::vector<ResolvExpr::AlternativeFinder> &args ) {
119        TupleAssignSpotter spotter( currentFinder );
120        spotter.spot( expr, args );
121        }
122
123        TupleAssignSpotter::TupleAssignSpotter( ResolvExpr::AlternativeFinder &f )
124                : currentFinder(f) {}
125
126        void TupleAssignSpotter::spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args ) {
127                std::list<ResolvExpr::AltList> possibilities;
128                combos( args.begin(), args.end(), back_inserter( possibilities ) );
129
130                if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
131                        if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {
132                               fname = op->get_name();
133                                PRINT( std::cerr << "TupleAssignment: " << fname << std::endl; )
134                                for ( std::list<ResolvExpr::AltList>::const_iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
135                                        if ( ali->size() == 0 ) continue; // AlternativeFinder will natrually handle this case, if it's legal
136                                        if ( ali->size() <= 1 && CodeGen::isAssignment( op->get_name() ) ) {
137                                                // what does it mean if an assignment takes 1 argument? maybe someone defined such a function, in which case AlternativeFinder will naturally handle it
138                                                continue;
139                                        }
140
141                                        assert( ! ali->empty() );
142                                        // grab args 2-N and group into a TupleExpr
143                                        const ResolvExpr::Alternative & alt1 = ali->front();
144                                        auto begin = std::next(ali->begin(), 1), end = ali->end();
145                                        PRINT( std::cerr << "alt1 is " << alt1.expr << std::endl; )
146                                        if ( refToTuple(alt1.expr) ) {
147                                                PRINT( std::cerr << "and is reference to tuple" << std::endl; )
148                                                if ( isMultAssign( begin, end ) ) {
149                                                        PRINT( std::cerr << "possible multiple assignment" << std::endl; )
150                                                        matcher.reset( new MultipleAssignMatcher( *this, *ali ) );
151                                                } else {
152                                                        // mass assignment
153                                                        PRINT( std::cerr << "possible mass assignment" << std::endl; )
154                                                        matcher.reset( new MassAssignMatcher( *this,  *ali ) );
155                                                }
156                                                match();
157                                        }
158                                }
159                        }
160                }
161        }
162
163        void TupleAssignSpotter::match() {
164                assert ( matcher != 0 );
165
166                std::list< Expression * > new_assigns;
167                matcher->match( new_assigns );
168
169                if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {
170                        // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.
171                        // if not the empty tuple case, return early so that no new alternatives are generated.
172                        if ( new_assigns.empty() ) return;
173                }
174                ResolvExpr::AltList current;
175                // now resolve new assignments
176                for ( std::list< Expression * >::iterator i = new_assigns.begin(); i != new_assigns.end(); ++i ) {
177                        PRINT(
178                                std::cerr << "== resolving tuple assign ==" << std::endl;
179                                std::cerr << *i << std::endl;
180                        )
181
182                        ResolvExpr::AlternativeFinder finder( currentFinder.get_indexer(), currentFinder.get_environ() );
183                        try {
184                                finder.findWithAdjustment(*i);
185                        } catch (...) {
186                                return; // no match should not mean failure, it just means this particular tuple assignment isn't valid
187                        }
188                        // prune expressions that don't coincide with
189                        ResolvExpr::AltList alts = finder.get_alternatives();
190                        assert( alts.size() == 1 );
191                        assert( alts.front().expr != 0 );
192                        current.push_back( alts.front() );
193                }
194
195                // extract expressions from the assignment alternatives to produce a list of assignments that
196                // together form a single alternative
197                std::list< Expression *> solved_assigns;
198                for ( ResolvExpr::Alternative & alt : current ) {
199                        solved_assigns.push_back( alt.expr->clone() );
200                }
201                // combine assignment environments into combined expression environment
202                simpleCombineEnvironments( current.begin(), current.end(), matcher->compositeEnv );
203                currentFinder.get_alternatives().push_front( ResolvExpr::Alternative(new TupleAssignExpr(solved_assigns, matcher->tmpDecls), matcher->compositeEnv, ResolvExpr::sumCost( current  ) + matcher->baseCost ) );
204        }
205
206        TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList &alts ) : spotter(spotter), baseCost( ResolvExpr::sumCost( alts ) ) {
207                assert( ! alts.empty() );
208                // combine argument environments into combined expression environment
209                simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
210
211                ResolvExpr::Alternative lhsAlt = alts.front();
212                // explode is aware of casts - ensure every LHS expression is sent into explode with a reference cast
213                if ( ! dynamic_cast< CastExpr * >( lhsAlt.expr ) ) {
214                        lhsAlt.expr = new CastExpr( lhsAlt.expr, new ReferenceType( Type::Qualifiers(), lhsAlt.expr->get_result()->clone() ) );
215                }
216
217                // explode the lhs so that each field of the tuple-valued-expr is assigned.
218                explode( lhsAlt, spotter.currentFinder.get_indexer(), back_inserter(lhs), true );
219
220                for ( ResolvExpr::Alternative & alt : lhs ) {
221                        // every LHS value must be a reference - some come in with a cast expression, if it doesn't just cast to reference here.
222                        if ( ! dynamic_cast< ReferenceType * >( alt.expr->get_result() ) ) {
223                                alt.expr = new CastExpr( alt.expr, new ReferenceType( Type::Qualifiers(), alt.expr->get_result()->clone() ) );
224                        }
225                }
226        }
227
228        TupleAssignSpotter::MassAssignMatcher::MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
229                assert( alts.size() == 1 || alts.size() == 2 );
230                if ( alts.size() == 2 ) {
231                        rhs.push_back( alts.back() );
232                }
233        }
234
235        TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
236                // explode the rhs so that each field of the tuple-valued-expr is assigned.
237                explode( std::next(alts.begin(), 1), alts.end(), spotter.currentFinder.get_indexer(), back_inserter(rhs), true );
238        }
239
240        UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {
241                assert( left );
242                std::list< Expression * > args;
243                args.push_back( new VariableExpr( left ) );
244                // args.push_back( new AddressExpr( new VariableExpr( left ) ) );
245                if ( right ) args.push_back( new VariableExpr( right ) );
246                return new UntypedExpr( new NameExpr( fname ), args );
247        }
248
249        // removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator.
250        // xxx - maybe this should happen in alternative finder for every StmtExpr?
251        // xxx - it's possible that these environments could contain some useful information. Maybe the right thing to do is aggregate the environments and pass the aggregate back to be added into the compositeEnv
252        struct EnvRemover : public Visitor {
253                virtual void visit( ExprStmt * stmt ) {
254                        delete stmt->get_expr()->get_env();
255                        stmt->get_expr()->set_env( nullptr );
256                        Visitor::visit( stmt );
257                }
258        };
259
260        ObjectDecl * TupleAssignSpotter::Matcher::newObject( UniqueName & namer, Expression * expr ) {
261                assert( expr->result && ! expr->get_result()->isVoid() );
262                ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->get_result()->clone(), new SingleInit( expr->clone() ) );
263                // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.
264                if ( ! dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
265                        ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
266                        ret->set_init( ctorInit );
267                        ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object
268                        EnvRemover rm; // remove environments from subexpressions of StmtExprs
269                        ctorInit->accept( rm );
270                }
271                PRINT( std::cerr << "new object: " << ret << std::endl; )
272                return ret;
273        }
274
275        void TupleAssignSpotter::MassAssignMatcher::match( std::list< Expression * > &out ) {
276                static UniqueName lhsNamer( "__massassign_L" );
277                static UniqueName rhsNamer( "__massassign_R" );
278                // empty tuple case falls into this matcher, hence the second part of the assert
279                assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );
280
281                ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
282                for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
283                        // create a temporary object for each value in the lhs and create a call involving the rhs
284                        ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
285                        out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
286                        tmpDecls.push_back( ltmp );
287                }
288                if ( rtmp ) tmpDecls.push_back( rtmp );
289        }
290
291        void TupleAssignSpotter::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
292                static UniqueName lhsNamer( "__multassign_L" );
293                static UniqueName rhsNamer( "__multassign_R" );
294
295                if ( lhs.size() == rhs.size() ) {
296                        // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls
297                        std::list< ObjectDecl * > ltmp;
298                        std::list< ObjectDecl * > rtmp;
299                        std::transform( lhs.begin(), lhs.end(), back_inserter( ltmp ), [&]( ResolvExpr::Alternative & alt ){
300                                return newObject( lhsNamer, alt.expr );
301                        });
302                        std::transform( rhs.begin(), rhs.end(), back_inserter( rtmp ), [&]( ResolvExpr::Alternative & alt ){
303                                return newObject( rhsNamer, alt.expr );
304                        });
305                        zipWith( ltmp.begin(), ltmp.end(), rtmp.begin(), rtmp.end(), back_inserter(out), [&](ObjectDecl * obj1, ObjectDecl * obj2 ) { return createFunc(spotter.fname, obj1, obj2); } );
306                        tmpDecls.splice( tmpDecls.end(), ltmp );
307                        tmpDecls.splice( tmpDecls.end(), rtmp );
308                }
309        }
310} // namespace Tuples
311
312// Local Variables: //
313// tab-width: 4 //
314// mode: c++ //
315// compile-command: "make install" //
316// End: //
Note: See TracBrowser for help on using the repository browser.