source: src/Tuples/TupleAssignment.cc@ a64644c

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

combine environments and costs in tuple assignment, resolve ctor/dtors for tuple assignment temporaries

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