source: src/Tuples/TupleAssignment.cc@ d1685588

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since d1685588 was e6cee92, checked in by Rob Schluntz <rschlunt@…>, 8 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.