Changeset c6b4432 for src/Tuples
- Timestamp:
- Nov 8, 2023, 2:01:11 PM (16 months ago)
- Branches:
- master
- Children:
- 3e4bf0d, f5ec35a
- Parents:
- 790d835
- Location:
- src/Tuples
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Tuples/Explode.cc
r790d835 rc6b4432 15 15 16 16 #include "Explode.h" 17 #include <list> // for list18 17 19 18 #include "AST/Pass.hpp" // for Pass 20 #include "SynTree/Mutator.h" // for Mutator21 #include "Common/PassVisitor.h" // for PassVisitor22 19 23 20 namespace Tuples { 24 namespace {25 // remove one level of reference from a reference type -- may be useful elsewhere.26 Type * getReferenceBase( Type * t ) {27 if ( ReferenceType * refType = dynamic_cast<ReferenceType *>( t ) ) {28 return refType->get_base();29 } else {30 // for the moment, I want to know immediately if a non-reference type is ever passed in here.31 assertf( false, "getReferenceBase for non-ref: %s", toString( refType ).c_str() );32 return nullptr;33 }34 }35 36 struct CastExploder {37 bool castAdded = false;38 bool foundUniqueExpr = false;39 Expression * applyCast( Expression * expr, bool first = true ) {40 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ){41 foundUniqueExpr = true;42 std::list< Expression * > exprs;43 for ( Expression *& expr : tupleExpr->get_exprs() ) {44 // move cast into tuple exprs45 exprs.push_back( applyCast( expr, false ) );46 }47 // want the top-level expression to be cast to reference type, but not nested48 // tuple expressions49 if ( first ) {50 castAdded = true;51 Expression * tupleExpr = new TupleExpr( exprs );52 return new CastExpr( tupleExpr, new ReferenceType( Type::Qualifiers(), tupleExpr->result->clone() ) );53 } else {54 return new TupleExpr( exprs );55 }56 }57 if ( dynamic_cast<ReferenceType*>( expr->result ) ) {58 // don't need to cast reference type to another reference type59 return expr->clone();60 } else {61 // anything else should be cast to reference as normal62 castAdded = true;63 return new CastExpr( expr->clone(), new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );64 }65 }66 67 Expression * postmutate( UniqueExpr * uniqueExpr ) {68 // move cast into unique expr so that the unique expr has type T& rather than69 // type T. In particular, this transformation helps with generating the70 // correct code for reference-cast member tuple expressions, since the result71 // should now be a tuple of references rather than a reference to a tuple.72 // Still, this code is a bit awkward, and could use some improvement.73 UniqueExpr * newUniqueExpr = new UniqueExpr( applyCast( uniqueExpr->get_expr() ), uniqueExpr->get_id() );74 delete uniqueExpr;75 if ( castAdded ) {76 // if a cast was added by applyCast, then unique expr now has one more layer of reference77 // than it had coming into this function. To ensure types still match correctly, need to cast78 // to reference base so that outer expressions are still correct.79 castAdded = false;80 Type * toType = getReferenceBase( newUniqueExpr->result );81 return new CastExpr( newUniqueExpr, toType->clone() );82 }83 return newUniqueExpr;84 }85 86 87 Expression * postmutate( TupleIndexExpr * tupleExpr ) {88 // tuple index expr needs to be rebuilt to ensure that the type of the89 // field is consistent with the type of the tuple expr, since the field90 // may have changed from type T to T&.91 Expression * expr = tupleExpr->get_tuple();92 tupleExpr->set_tuple( nullptr );93 TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() );94 delete tupleExpr;95 return ret;96 }97 };98 } // namespace99 100 Expression * distributeReference( Expression * expr ) {101 PassVisitor<CastExploder> exploder;102 expr = expr->acceptMutator( exploder );103 if ( ! exploder.pass.foundUniqueExpr ) {104 // if a UniqueExpr was found, then the cast has already been added inside the UniqueExpr as appropriate105 expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );106 }107 return expr;108 }109 21 110 22 namespace { -
src/Tuples/Explode.h
r790d835 rc6b4432 20 20 21 21 #include "AST/Expr.hpp" 22 #include "ResolvExpr/Alternative.h" // for Alternative, AltList23 22 #include "ResolvExpr/Candidate.hpp" // for Candidate, CandidateList 24 #include "ResolvExpr/ExplodedActual.h" // for ExplodedActual25 23 #include "ResolvExpr/ExplodedArg.hpp" // for ExplodedArg 26 #include "SynTree/Expression.h" // for Expression, UniqueExpr, AddressExpr27 #include "SynTree/Type.h" // for TupleType, Type28 24 #include "Tuples.h" // for maybeImpure 29 25 … … 32 28 } 33 29 34 namespace SymTab {35 class Indexer;36 } // namespace SymTab37 38 30 namespace Tuples { 39 Expression * distributeReference( Expression * );40 41 static inline CastExpr * isReferenceCast( Expression * expr ) {42 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {43 if ( dynamic_cast< ReferenceType * >( castExpr->result ) ) {44 return castExpr;45 }46 }47 return nullptr;48 }49 50 /// Append alternative to an OutputIterator of Alternatives51 template<typename OutputIterator>52 void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env,53 const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need,54 const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {55 *out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost };56 }57 58 /// Append alternative to an ExplodedActual59 static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr,60 const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&,61 const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {62 ea.exprs.emplace_back( expr );63 /// xxx -- merge environment, openVars, need, cost?64 }65 66 /// helper function used by explode67 template< typename Output >68 void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt,69 const SymTab::Indexer & indexer, Output&& out, bool isTupleAssign ) {70 if ( isTupleAssign ) {71 // tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components72 if ( CastExpr * castExpr = isReferenceCast( expr ) ) {73 ResolvExpr::AltList alts;74 explodeUnique(75 castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );76 for ( ResolvExpr::Alternative & alt : alts ) {77 // distribute reference cast over all components78 append( std::forward<Output>(out), distributeReference( alt.release_expr() ),79 alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost );80 }81 // in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)82 return;83 }84 }85 Type * res = expr->get_result()->stripReferences();86 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {87 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {88 // can open tuple expr and dump its exploded components89 for ( Expression * expr : tupleExpr->get_exprs() ) {90 explodeUnique( expr, alt, indexer, std::forward<Output>(out), isTupleAssign );91 }92 } else {93 // tuple type, but not tuple expr - recursively index into its components.94 // if expr type is reference, convert to value type95 Expression * arg = expr->clone();96 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {97 // expressions which may contain side effects require a single unique instance of the expression.98 arg = new UniqueExpr( arg );99 }100 // cast reference to value type to facilitate further explosion101 if ( dynamic_cast<ReferenceType *>( arg->get_result() ) ) {102 arg = new CastExpr( arg, tupleType->clone() );103 }104 for ( unsigned int i = 0; i < tupleType->size(); i++ ) {105 TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );106 explodeUnique( idx, alt, indexer, std::forward<Output>(out), isTupleAssign );107 delete idx;108 }109 delete arg;110 }111 } else {112 // atomic (non-tuple) type - output a clone of the expression in a new alternative113 append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need,114 alt.cost, alt.cvtCost );115 }116 }117 118 /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type119 template< typename Output >120 void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer,121 Output&& out, bool isTupleAssign = false ) {122 explodeUnique( alt.expr, alt, indexer, std::forward<Output>(out), isTupleAssign );123 }124 125 // explode list of alternatives126 template< typename AltIterator, typename Output >127 void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer,128 Output&& out, bool isTupleAssign = false ) {129 for ( ; altBegin != altEnd; ++altBegin ) {130 explode( *altBegin, indexer, std::forward<Output>(out), isTupleAssign );131 }132 }133 134 template< typename Output >135 void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, Output&& out,136 bool isTupleAssign = false ) {137 explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );138 }139 31 140 32 const ast::Expr * distributeReference( const ast::Expr * ); -
src/Tuples/TupleAssignment.cc
r790d835 rc6b4432 28 28 #include "AST/TypeEnvironment.hpp" 29 29 #include "CodeGen/OperatorTable.h" 30 #include "Common/PassVisitor.h"31 30 #include "Common/UniqueName.h" // for UniqueName 32 31 #include "Common/utility.h" // for splice, zipWith … … 34 33 #include "InitTweak/GenInit.h" // for genCtorInit 35 34 #include "InitTweak/InitTweak.h" // for getPointerBase, isAssignment 36 #include "ResolvExpr/Alternative.h" // for AltList, Alternative37 #include "ResolvExpr/AlternativeFinder.h" // for AlternativeFinder, simpleC...38 35 #include "ResolvExpr/Cost.h" // for Cost 39 36 #include "ResolvExpr/Resolver.h" // for resolveCtorInit 40 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment41 37 #include "ResolvExpr/typeops.h" // for combos 42 #include "SynTree/LinkageSpec.h" // for Cforall43 #include "SynTree/Declaration.h" // for ObjectDecl44 #include "SynTree/Expression.h" // for Expression, CastExpr, Name...45 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit46 #include "SynTree/Statement.h" // for ExprStmt47 #include "SynTree/Type.h" // for Type, Type::Qualifiers48 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution49 #include "SynTree/Visitor.h" // for Visitor50 38 51 39 #if 0 … … 56 44 57 45 namespace Tuples { 58 class TupleAssignSpotter_old {59 public:60 // dispatcher for Tuple (multiple and mass) assignment operations61 TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );62 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );63 64 private:65 void match();66 67 struct Matcher {68 public:69 Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,70 const ResolvExpr::AltList& rhs );71 virtual ~Matcher() {}72 73 virtual void match( std::list< Expression * > &out ) = 0;74 ObjectDecl * newObject( UniqueName & namer, Expression * expr );75 76 void combineState( const ResolvExpr::Alternative& alt ) {77 compositeEnv.simpleCombine( alt.env );78 ResolvExpr::mergeOpenVars( openVars, alt.openVars );79 cloneAll( alt.need, need );80 }81 82 void combineState( const ResolvExpr::AltList& alts ) {83 for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); }84 }85 86 ResolvExpr::AltList lhs, rhs;87 TupleAssignSpotter_old &spotter;88 ResolvExpr::Cost baseCost;89 std::list< ObjectDecl * > tmpDecls;90 ResolvExpr::TypeEnvironment compositeEnv;91 ResolvExpr::OpenVarSet openVars;92 ResolvExpr::AssertionSet need;93 };94 95 struct MassAssignMatcher : public Matcher {96 public:97 MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,98 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}99 virtual void match( std::list< Expression * > &out );100 };101 102 struct MultipleAssignMatcher : public Matcher {103 public:104 MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,105 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}106 virtual void match( std::list< Expression * > &out );107 };108 109 ResolvExpr::AlternativeFinder ¤tFinder;110 std::string fname;111 std::unique_ptr< Matcher > matcher;112 };113 114 /// true if expr is an expression of tuple type115 bool isTuple( Expression *expr ) {116 if ( ! expr ) return false;117 assert( expr->result );118 return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );119 }120 121 template< typename AltIter >122 bool isMultAssign( AltIter begin, AltIter end ) {123 // multiple assignment if more than one alternative in the range or if124 // the alternative is a tuple125 if ( begin == end ) return false;126 if ( isTuple( begin->expr ) ) return true;127 return ++begin != end;128 }129 130 bool refToTuple( Expression *expr ) {131 assert( expr->get_result() );132 // also check for function returning tuple of reference types133 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {134 return refToTuple( castExpr->get_arg() );135 } else {136 return isTuple( expr );137 }138 return false;139 }140 141 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,142 std::vector<ResolvExpr::AlternativeFinder> &args ) {143 TupleAssignSpotter_old spotter( currentFinder );144 spotter.spot( expr, args );145 }146 147 TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )148 : currentFinder(f) {}149 150 void TupleAssignSpotter_old::spot( UntypedExpr * expr,151 std::vector<ResolvExpr::AlternativeFinder> &args ) {152 if ( NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {153 if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {154 fname = op->get_name();155 156 // AlternativeFinder will naturally handle this case case, if it's legal157 if ( args.size() == 0 ) return;158 159 // if an assignment only takes 1 argument, that's odd, but maybe someone wrote160 // the function, in which case AlternativeFinder will handle it normally161 if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;162 163 // look over all possible left-hand-sides164 for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {165 // skip non-tuple LHS166 if ( ! refToTuple(lhsAlt.expr) ) continue;167 168 // explode is aware of casts - ensure every LHS expression is sent into explode169 // with a reference cast170 // xxx - this seems to change the alternatives before the normal171 // AlternativeFinder flow; maybe this is desired?172 if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) {173 lhsAlt.expr = new CastExpr( lhsAlt.expr,174 new ReferenceType( Type::Qualifiers(),175 lhsAlt.expr->result->clone() ) );176 }177 178 // explode the LHS so that each field of a tuple-valued-expr is assigned179 ResolvExpr::AltList lhs;180 explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true );181 for ( ResolvExpr::Alternative& alt : lhs ) {182 // each LHS value must be a reference - some come in with a cast expression,183 // if not just cast to reference here184 if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) {185 alt.expr = new CastExpr( alt.expr,186 new ReferenceType( Type::Qualifiers(),187 alt.expr->get_result()->clone() ) );188 }189 }190 191 if ( args.size() == 1 ) {192 // mass default-initialization/destruction193 ResolvExpr::AltList rhs{};194 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );195 match();196 } else if ( args.size() > 2 ) {197 // expand all possible RHS possibilities198 // TODO build iterative version of this instead of using combos199 std::vector< ResolvExpr::AltList > rhsAlts;200 combos( std::next(args.begin(), 1), args.end(),201 std::back_inserter( rhsAlts ) );202 for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) {203 // multiple assignment204 ResolvExpr::AltList rhs;205 explode( rhsAlt, currentFinder.get_indexer(),206 std::back_inserter(rhs), true );207 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );208 match();209 }210 } else {211 for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) {212 ResolvExpr::AltList rhs;213 if ( isTuple(rhsAlt.expr) ) {214 // multiple assignment215 explode( rhsAlt, currentFinder.get_indexer(),216 std::back_inserter(rhs), true );217 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );218 } else {219 // mass assignment220 rhs.push_back( rhsAlt );221 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );222 }223 match();224 }225 }226 }227 }228 }229 }230 231 void TupleAssignSpotter_old::match() {232 assert ( matcher != 0 );233 234 std::list< Expression * > new_assigns;235 matcher->match( new_assigns );236 237 if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {238 // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.239 // if not the empty tuple case, return early so that no new alternatives are generated.240 if ( new_assigns.empty() ) return;241 }242 ResolvExpr::AltList current;243 // now resolve new assignments244 for ( std::list< Expression * >::iterator i = new_assigns.begin();245 i != new_assigns.end(); ++i ) {246 PRINT(247 std::cerr << "== resolving tuple assign ==" << std::endl;248 std::cerr << *i << std::endl;249 )250 251 ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),252 matcher->compositeEnv };253 254 try {255 finder.findWithAdjustment(*i);256 } catch (...) {257 return; // no match should not mean failure, it just means this particular tuple assignment isn't valid258 }259 // prune expressions that don't coincide with260 ResolvExpr::AltList alts = finder.get_alternatives();261 assert( alts.size() == 1 );262 assert( alts.front().expr != 0 );263 current.push_back( alts.front() );264 }265 266 // extract expressions from the assignment alternatives to produce a list of assignments267 // that together form a single alternative268 std::list< Expression *> solved_assigns;269 for ( ResolvExpr::Alternative & alt : current ) {270 solved_assigns.push_back( alt.expr->clone() );271 matcher->combineState( alt );272 }273 274 // xxx -- was push_front275 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{276 new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv,277 matcher->openVars,278 ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ),279 ResolvExpr::sumCost( current ) + matcher->baseCost } );280 }281 282 TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,283 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )284 : lhs(lhs), rhs(rhs), spotter(spotter),285 baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {286 combineState( lhs );287 combineState( rhs );288 }289 290 UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {291 assert( left );292 std::list< Expression * > args;293 args.push_back( new VariableExpr( left ) );294 // args.push_back( new AddressExpr( new VariableExpr( left ) ) );295 if ( right ) args.push_back( new VariableExpr( right ) );296 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {297 args.front() = new AddressExpr( args.front() );298 if ( right ) args.back() = new AddressExpr( args.back() );299 return new UntypedExpr( new NameExpr( "?=?" ), args );300 } else {301 return new UntypedExpr( new NameExpr( fname ), args );302 }303 }304 305 // removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator, and adds the bindings to the compositeEnv306 // xxx - maybe this should happen in alternative finder for every StmtExpr?307 struct EnvRemover {308 void previsit( ExprStmt * stmt ) {309 assert( compositeEnv );310 if ( stmt->expr->env ) {311 compositeEnv->add( *stmt->expr->env );312 delete stmt->expr->env;313 stmt->expr->env = nullptr;314 }315 }316 317 ResolvExpr::TypeEnvironment * compositeEnv = nullptr;318 };319 320 ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {321 assert( expr->result && ! expr->get_result()->isVoid() );322 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );323 // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.324 if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) {325 ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );326 ret->init = ctorInit;327 ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object328 PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs329 rm.pass.compositeEnv = &compositeEnv;330 ctorInit->accept( rm );331 }332 PRINT( std::cerr << "new object: " << ret << std::endl; )333 return ret;334 }335 336 void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {337 static UniqueName lhsNamer( "__massassign_L" );338 static UniqueName rhsNamer( "__massassign_R" );339 // empty tuple case falls into this matcher, hence the second part of the assert340 assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );341 342 // xxx - may need to split this up into multiple declarations, because potential conversion to references343 // probably should not reference local variable - see MultipleAssignMatcher::match344 ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;345 for ( ResolvExpr::Alternative & lhsAlt : lhs ) {346 // create a temporary object for each value in the lhs and create a call involving the rhs347 ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );348 out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );349 tmpDecls.push_back( ltmp );350 }351 if ( rtmp ) tmpDecls.push_back( rtmp );352 }353 354 void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {355 static UniqueName lhsNamer( "__multassign_L" );356 static UniqueName rhsNamer( "__multassign_R" );357 358 if ( lhs.size() == rhs.size() ) {359 // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls360 std::list< ObjectDecl * > ltmp;361 std::list< ObjectDecl * > rtmp;362 for ( auto p : group_iterate( lhs, rhs ) ) {363 ResolvExpr::Alternative & lhsAlt = std::get<0>(p);364 ResolvExpr::Alternative & rhsAlt = std::get<1>(p);365 // convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc.366 ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result );367 rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() );368 ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr );369 ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr );370 out.push_back( createFunc(spotter.fname, lobj, robj) );371 ltmp.push_back( lobj );372 rtmp.push_back( robj );373 374 // resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment375 ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv };376 finder.findWithAdjustment( rhsAlt.expr );377 assert( finder.get_alternatives().size() == 1 );378 compositeEnv = std::move( finder.get_alternatives().front().env );379 }380 tmpDecls.splice( tmpDecls.end(), ltmp );381 tmpDecls.splice( tmpDecls.end(), rtmp );382 }383 }384 46 385 47 namespace { -
src/Tuples/TupleExpansion.cc
r790d835 rc6b4432 23 23 #include "AST/Node.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd, WithGu...26 25 #include "Common/ScopedMap.h" // for ScopedMap 27 26 #include "Common/utility.h" // for CodeLocation 28 27 #include "InitTweak/InitTweak.h" // for getFunction 29 #include "SynTree/LinkageSpec.h" // for Spec, C, Intrinsic30 #include "SynTree/Constant.h" // for Constant31 #include "SynTree/Declaration.h" // for StructDecl, DeclarationWithType32 #include "SynTree/Expression.h" // for UntypedMemberExpr, Expression, Uniq...33 #include "SynTree/Label.h" // for operator==, Label34 #include "SynTree/Mutator.h" // for Mutator35 #include "SynTree/Type.h" // for Type, Type::Qualifiers, TupleType36 #include "SynTree/Visitor.h" // for Visitor37 28 #include "Tuples.h" 38 29 39 class CompoundStmt; 40 class TypeSubstitution; 30 namespace Tuples { 41 31 42 namespace Tuples {43 namespace {44 struct MemberTupleExpander final : public WithShortCircuiting, public WithVisitorRef<MemberTupleExpander> {45 void premutate( UntypedMemberExpr * ) { visit_children = false; }46 Expression * postmutate( UntypedMemberExpr * memberExpr );47 };48 49 struct UniqueExprExpander final : public WithDeclsToAdd {50 Expression * postmutate( UniqueExpr * unqExpr );51 52 std::map< int, Expression * > decls; // not vector, because order added may not be increasing order53 54 ~UniqueExprExpander() {55 for ( std::pair<const int, Expression *> & p : decls ) {56 delete p.second;57 }58 }59 };60 61 struct TupleAssignExpander {62 Expression * postmutate( TupleAssignExpr * tupleExpr );63 };64 65 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {66 Type * postmutate( TupleType * tupleType );67 68 void premutate( CompoundStmt * ) {69 GuardScope( typeMap );70 }71 private:72 ScopedMap< int, StructDecl * > typeMap;73 };74 75 struct TupleIndexExpander {76 Expression * postmutate( TupleIndexExpr * tupleExpr );77 };78 79 struct TupleExprExpander final {80 Expression * postmutate( TupleExpr * tupleExpr );81 };82 }83 84 void expandMemberTuples( std::list< Declaration * > & translationUnit ) {85 PassVisitor<MemberTupleExpander> expander;86 mutateAll( translationUnit, expander );87 }88 89 void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {90 PassVisitor<UniqueExprExpander> unqExpander;91 mutateAll( translationUnit, unqExpander );92 }93 94 void expandTuples( std::list< Declaration * > & translationUnit ) {95 PassVisitor<TupleAssignExpander> assnExpander;96 mutateAll( translationUnit, assnExpander );97 98 PassVisitor<TupleTypeReplacer> replacer;99 mutateAll( translationUnit, replacer );100 101 PassVisitor<TupleIndexExpander> idxExpander;102 mutateAll( translationUnit, idxExpander );103 104 PassVisitor<TupleExprExpander> exprExpander;105 mutateAll( translationUnit, exprExpander );106 }107 108 namespace {109 /// given a expression representing the member and an expression representing the aggregate,110 /// reconstructs a flattened UntypedMemberExpr with the right precedence111 Expression * reconstructMemberExpr( Expression * member, Expression * aggr, CodeLocation & loc ) {112 if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {113 // construct a new UntypedMemberExpr with the correct structure , and recursively114 // expand that member expression.115 PassVisitor<MemberTupleExpander> expander;116 UntypedMemberExpr * inner = new UntypedMemberExpr( memberExpr->aggregate, aggr->clone() );117 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member, inner );118 inner->location = newMemberExpr->location = loc;119 memberExpr->member = nullptr;120 memberExpr->aggregate = nullptr;121 delete memberExpr;122 return newMemberExpr->acceptMutator( expander );123 } else {124 // not a member expression, so there is nothing to do but attach and return125 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( member, aggr->clone() );126 newMemberExpr->location = loc;127 return newMemberExpr;128 }129 }130 }131 132 Expression * MemberTupleExpander::postmutate( UntypedMemberExpr * memberExpr ) {133 if ( UntypedTupleExpr * tupleExpr = dynamic_cast< UntypedTupleExpr * > ( memberExpr->member ) ) {134 Expression * aggr = memberExpr->aggregate->clone()->acceptMutator( *visitor );135 // aggregate expressions which might be impure must be wrapped in unique expressions136 if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new UniqueExpr( aggr );137 for ( Expression *& expr : tupleExpr->exprs ) {138 expr = reconstructMemberExpr( expr, aggr, memberExpr->location );139 expr->location = memberExpr->location;140 }141 delete aggr;142 tupleExpr->location = memberExpr->location;143 return tupleExpr;144 } else {145 // there may be a tuple expr buried in the aggregate146 // xxx - this is a memory leak147 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member->clone(), memberExpr->aggregate->acceptMutator( *visitor ) );148 newMemberExpr->location = memberExpr->location;149 return newMemberExpr;150 }151 }152 153 Expression * UniqueExprExpander::postmutate( UniqueExpr * unqExpr ) {154 const int id = unqExpr->get_id();155 156 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,157 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.158 if ( ! decls.count( id ) ) {159 Expression * assignUnq;160 Expression * var = unqExpr->get_var();161 if ( unqExpr->get_object() ) {162 // an object was generated to represent this unique expression -- it should be added to the list of declarations now163 declsToAddBefore.push_back( unqExpr->get_object() );164 unqExpr->set_object( nullptr );165 // steal the expr from the unqExpr166 assignUnq = UntypedExpr::createAssign( unqExpr->get_var()->clone(), unqExpr->get_expr() );167 unqExpr->set_expr( nullptr );168 } else {169 // steal the already generated assignment to var from the unqExpr - this has been generated by FixInit170 Expression * expr = unqExpr->get_expr();171 CommaExpr * commaExpr = strict_dynamic_cast< CommaExpr * >( expr );172 assignUnq = commaExpr->get_arg1();173 commaExpr->set_arg1( nullptr );174 }175 ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ),176 new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) );177 declsToAddBefore.push_back( finished );178 // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))179 // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.180 Expression * assignFinished = UntypedExpr::createAssign( new VariableExpr(finished), new ConstantExpr( Constant::from_int( 1 ) ) );181 ConditionalExpr * condExpr = new ConditionalExpr( new VariableExpr( finished ), var->clone(),182 new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) );183 condExpr->set_result( var->get_result()->clone() );184 condExpr->set_env( maybeClone( unqExpr->get_env() ) );185 decls[id] = condExpr;186 }187 delete unqExpr;188 return decls[id]->clone();189 }190 191 Expression * TupleAssignExpander::postmutate( TupleAssignExpr * assnExpr ) {192 StmtExpr * ret = assnExpr->get_stmtExpr();193 assnExpr->set_stmtExpr( nullptr );194 // move env to StmtExpr195 ret->set_env( assnExpr->get_env() );196 assnExpr->set_env( nullptr );197 delete assnExpr;198 return ret;199 }200 201 Type * TupleTypeReplacer::postmutate( TupleType * tupleType ) {202 unsigned tupleSize = tupleType->size();203 if ( ! typeMap.count( tupleSize ) ) {204 // generate struct type to replace tuple type based on the number of components in the tuple205 StructDecl * decl = new StructDecl( toString( "_tuple", tupleSize, "_" ) );206 decl->location = tupleType->location;207 decl->set_body( true );208 for ( size_t i = 0; i < tupleSize; ++i ) {209 TypeDecl * tyParam = new TypeDecl( toString( "tuple_param_", tupleSize, "_", i ), Type::StorageClasses(), nullptr, TypeDecl::Dtype, true );210 decl->get_members().push_back( new ObjectDecl( toString("field_", i ), Type::StorageClasses(), LinkageSpec::C, nullptr, new TypeInstType( Type::Qualifiers(), tyParam->get_name(), tyParam ), nullptr ) );211 decl->get_parameters().push_back( tyParam );212 }213 if ( tupleSize == 0 ) {214 // empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created.215 decl->get_members().push_back( new ObjectDecl( "dummy", Type::StorageClasses(), LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );216 }217 typeMap[tupleSize] = decl;218 declsToAddBefore.push_back( decl );219 }220 Type::Qualifiers qualifiers = tupleType->get_qualifiers();221 222 StructDecl * decl = typeMap[tupleSize];223 StructInstType * newType = new StructInstType( qualifiers, decl );224 for ( auto p : group_iterate( tupleType->get_types(), decl->get_parameters() ) ) {225 Type * t = std::get<0>(p);226 newType->get_parameters().push_back( new TypeExpr( t->clone() ) );227 }228 delete tupleType;229 return newType;230 }231 232 Expression * TupleIndexExpander::postmutate( TupleIndexExpr * tupleExpr ) {233 Expression * tuple = tupleExpr->tuple;234 assert( tuple );235 tupleExpr->tuple = nullptr;236 unsigned int idx = tupleExpr->index;237 TypeSubstitution * env = tupleExpr->env;238 tupleExpr->env = nullptr;239 delete tupleExpr;240 241 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( tuple ) ) {242 if ( ! maybeImpureIgnoreUnique( tupleExpr ) ) {243 // optimization: definitely pure tuple expr => can reduce to the only relevant component.244 assert( tupleExpr->exprs.size() > idx );245 Expression *& expr = *std::next(tupleExpr->exprs.begin(), idx);246 Expression * ret = expr;247 ret->env = env;248 expr = nullptr; // remove from list so it can safely be deleted249 delete tupleExpr;250 return ret;251 }252 }253 254 StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->result );255 StructDecl * structDecl = type->baseStruct;256 assert( structDecl->members.size() > idx );257 Declaration * member = *std::next(structDecl->members.begin(), idx);258 MemberExpr * memExpr = new MemberExpr( strict_dynamic_cast< DeclarationWithType * >( member ), tuple );259 memExpr->env = env;260 return memExpr;261 }262 263 Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs, TypeSubstitution * env ) {264 if ( result->isVoid() ) {265 // void result - don't need to produce a value for cascading - just output a chain of comma exprs266 assert( ! exprs.empty() );267 std::list< Expression * >::const_iterator iter = exprs.begin();268 Expression * expr = new CastExpr( *iter++ );269 for ( ; iter != exprs.end(); ++iter ) {270 expr = new CommaExpr( expr, new CastExpr( *iter ) );271 }272 expr->set_env( env );273 return expr;274 } else {275 // typed tuple expression - produce a compound literal which performs each of the expressions276 // as a distinct part of its initializer - the produced compound literal may be used as part of277 // another expression278 std::list< Initializer * > inits;279 for ( Expression * expr : exprs ) {280 inits.push_back( new SingleInit( expr ) );281 }282 Expression * expr = new CompoundLiteralExpr( result, new ListInit( inits ) );283 expr->set_env( env );284 return expr;285 }286 }287 288 Expression * TupleExprExpander::postmutate( TupleExpr * tupleExpr ) {289 Type * result = tupleExpr->get_result();290 std::list< Expression * > exprs = tupleExpr->get_exprs();291 assert( result );292 TypeSubstitution * env = tupleExpr->get_env();293 294 // remove data from shell and delete it295 tupleExpr->set_result( nullptr );296 tupleExpr->get_exprs().clear();297 tupleExpr->set_env( nullptr );298 delete tupleExpr;299 300 return replaceTupleExpr( result, exprs, env );301 }302 303 Type * makeTupleType( const std::list< Expression * > & exprs ) {304 // produce the TupleType which aggregates the types of the exprs305 std::list< Type * > types;306 Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic | Type::Mutex );307 for ( Expression * expr : exprs ) {308 assert( expr->get_result() );309 if ( expr->get_result()->isVoid() ) {310 // if the type of any expr is void, the type of the entire tuple is void311 return new VoidType( Type::Qualifiers() );312 }313 Type * type = expr->get_result()->clone();314 types.push_back( type );315 // the qualifiers on the tuple type are the qualifiers that exist on all component types316 qualifiers &= type->get_qualifiers();317 } // for318 if ( exprs.empty() ) qualifiers = Type::Qualifiers();319 return new TupleType( qualifiers, types );320 }321 32 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) { 322 33 // produce the TupleType which aggregates the types of the exprs … … 341 52 } 342 53 343 TypeInstType * isTtype( Type * type ) {344 if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( type ) ) {345 if ( inst->get_baseType() && inst->get_baseType()->get_kind() == TypeDecl::Ttype ) {346 return inst;347 }348 }349 return nullptr;350 }351 352 const TypeInstType * isTtype( const Type * type ) {353 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type ) ) {354 if ( inst->baseType && inst->baseType->kind == TypeDecl::Ttype ) {355 return inst;356 }357 }358 return nullptr;359 }360 361 54 const ast::TypeInstType * isTtype( const ast::Type * type ) { 362 55 if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) { -
src/Tuples/Tuples.cc
r790d835 rc6b4432 19 19 #include "AST/Inspect.hpp" 20 20 #include "AST/LinkageSpec.hpp" 21 #include "Common/PassVisitor.h"22 21 #include "InitTweak/InitTweak.h" 23 22 … … 25 24 26 25 namespace { 27 /// Checks if impurity (read: side-effects) may exist in a piece of code.28 /// Currently gives a very crude approximation, wherein any function29 /// call expression means the code may be impure.30 struct ImpurityDetector_old : public WithShortCircuiting {31 bool const ignoreUnique;32 bool maybeImpure;33 34 ImpurityDetector_old( bool ignoreUnique ) :35 ignoreUnique( ignoreUnique ), maybeImpure( false )36 {}37 38 void previsit( const ApplicationExpr * appExpr ) {39 visit_children = false;40 if ( const DeclarationWithType * function =41 InitTweak::getFunction( appExpr ) ) {42 if ( function->linkage == LinkageSpec::Intrinsic ) {43 if ( function->name == "*?" || function->name == "?[?]" ) {44 // intrinsic dereference, subscript are pure,45 // but need to recursively look for impurity46 visit_children = true;47 return;48 }49 }50 }51 maybeImpure = true;52 }53 54 void previsit( const UntypedExpr * ) {55 maybeImpure = true;56 visit_children = false;57 }58 59 void previsit( const UniqueExpr * ) {60 if ( ignoreUnique ) {61 // bottom out at unique expression.62 // The existence of a unique expression doesn't change the purity of an expression.63 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.64 visit_children = false;65 return;66 }67 }68 };69 70 bool detectImpurity( const Expression * expr, bool ignoreUnique ) {71 PassVisitor<ImpurityDetector_old> detector( ignoreUnique );72 expr->accept( detector );73 return detector.pass.maybeImpure;74 }75 26 76 27 /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives … … 110 61 } 111 62 112 bool maybeImpure( const Expression * expr ) {113 return detectImpurity( expr, false );114 }115 116 bool maybeImpureIgnoreUnique( const Expression * expr ) {117 return detectImpurity( expr, true );118 }119 120 63 } // namespace Tuples 121 64 -
src/Tuples/Tuples.h
r790d835 rc6b4432 21 21 #include "AST/Fwd.hpp" 22 22 #include "AST/Node.hpp" 23 #include "SynTree/Expression.h"24 #include "SynTree/Declaration.h"25 #include "SynTree/Type.h"26 27 #include "ResolvExpr/AlternativeFinder.h"28 23 #include "ResolvExpr/CandidateFinder.hpp" 29 24 30 25 namespace Tuples { 31 26 // TupleAssignment.cc 32 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,33 std::vector< ResolvExpr::AlternativeFinder >& args );34 27 void handleTupleAssignment( 35 28 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, … … 38 31 // TupleExpansion.cc 39 32 /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate 40 void expandMemberTuples( std::list< Declaration * > & translationUnit );41 33 void expandMemberTuples( ast::TranslationUnit & translationUnit ); 42 34 43 35 /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc. 44 void expandTuples( std::list< Declaration * > & translationUnit );45 36 void expandTuples( ast::TranslationUnit & translaionUnit ); 46 37 47 38 /// replaces UniqueExprs with a temporary variable and one call 48 void expandUniqueExpr( std::list< Declaration * > & translationUnit );49 39 void expandUniqueExpr( ast::TranslationUnit & translationUnit ); 50 40 51 41 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types 52 Type * makeTupleType( const std::list< Expression * > & exprs );53 42 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ); 54 43 55 44 /// returns a TypeInstType if `type` is a ttype, nullptr otherwise 56 TypeInstType * isTtype( Type * type );57 const TypeInstType * isTtype( const Type * type );58 45 const ast::TypeInstType * isTtype( const ast::Type * type ); 59 46 60 47 /// returns true if the expression may contain side-effects. 61 bool maybeImpure( const Expression * expr );62 48 bool maybeImpure( const ast::Expr * expr ); 63 49 64 50 /// Returns true if the expression may contain side-effect, 65 51 /// ignoring the presence of unique expressions. 66 bool maybeImpureIgnoreUnique( const Expression * expr );67 52 bool maybeImpureIgnoreUnique( const ast::Expr * expr ); 68 53 } // namespace Tuples
Note: See TracChangeset
for help on using the changeset viewer.