source: src/Tuples/TupleAssignment.cc @ e6cee92

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 e6cee92 was e6cee92, checked in by Rob Schluntz <rschlunt@…>, 7 years ago

Fix TupleAssignment? code for references

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