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

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 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.