Changeset 17c6edeb for src/Tuples/TupleExpansionNew.cpp
- Timestamp:
- Aug 16, 2022, 2:52:24 PM (3 years ago)
- Branches:
- ADT, ast-experimental, master, pthread-emulation
- Children:
- 71cf630
- Parents:
- 32d1383 (diff), e116db3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Tuples/TupleExpansionNew.cpp
r32d1383 r17c6edeb 9 9 // Author : Henry Xue 10 10 // Created On : Mon Aug 23 15:36:09 2021 11 // Last Modified By : Henry Xue12 // Last Modified On : Mon Aug 23 15:36:09 202113 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Aug 15 17:00:00 2022 13 // Update Count : 3 14 14 // 15 15 16 16 #include "Tuples.h" 17 17 18 #include "AST/Pass.hpp" 19 #include "Common/ScopedMap.h" 20 18 21 namespace Tuples { 22 19 23 namespace { 20 struct MemberTupleExpander final : public ast::WithShortCircuiting, public ast::WithVisitorRef< MemberTupleExpander > { 21 void previsit( const ast::UntypedMemberExpr * ) { visit_children = false; } 22 const ast::Expr * postvisit( const ast::UntypedMemberExpr * memberExpr ); 23 }; 24 struct UniqueExprExpander final : public ast::WithDeclsToAdd<> { 25 const ast::Expr * postvisit( const ast::UniqueExpr * unqExpr ); 26 std::map< int, ast::ptr<ast::Expr> > decls; // not vector, because order added may not be increasing order 27 }; 24 25 struct MemberTupleExpander final : public ast::WithShortCircuiting, public ast::WithVisitorRef< MemberTupleExpander > { 26 void previsit( const ast::UntypedMemberExpr * ) { visit_children = false; } 27 const ast::Expr * postvisit( const ast::UntypedMemberExpr * memberExpr ); 28 }; 29 30 struct UniqueExprExpander final : public ast::WithDeclsToAdd<> { 31 const ast::Expr * postvisit( const ast::UniqueExpr * unqExpr ); 32 std::map< int, ast::ptr<ast::Expr> > decls; // not vector, because order added may not be increasing order 33 }; 34 35 /// given a expression representing the member and an expression representing the aggregate, 36 /// reconstructs a flattened UntypedMemberExpr with the right precedence 37 const ast::Expr * reconstructMemberExpr( const ast::Expr * member, const ast::Expr * aggr, const CodeLocation & loc ) { 38 if ( auto memberExpr = dynamic_cast< const ast::UntypedMemberExpr * >( member ) ) { 39 // construct a new UntypedMemberExpr with the correct structure , and recursively 40 // expand that member expression. 41 ast::Pass< MemberTupleExpander > expander; 42 auto inner = new ast::UntypedMemberExpr( loc, memberExpr->aggregate, aggr ); 43 auto newMemberExpr = new ast::UntypedMemberExpr( loc, memberExpr->member, inner ); 44 return newMemberExpr->accept( expander ); 45 } else { 46 // not a member expression, so there is nothing to do but attach and return 47 return new ast::UntypedMemberExpr( loc, member, aggr ); 48 } 49 } 50 51 const ast::Expr * MemberTupleExpander::postvisit( const ast::UntypedMemberExpr * memberExpr ) { 52 const CodeLocation loc = memberExpr->location; 53 if ( auto tupleExpr = memberExpr->member.as< ast::UntypedTupleExpr >() ) { 54 auto mutExpr = mutate( tupleExpr ); 55 ast::ptr< ast::Expr > aggr = memberExpr->aggregate->accept( *visitor ); 56 // aggregate expressions which might be impure must be wrapped in unique expressions 57 if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new ast::UniqueExpr( loc, aggr ); 58 for ( auto & expr : mutExpr->exprs ) { 59 expr = reconstructMemberExpr( expr, aggr, loc ); 60 } 61 return mutExpr; 62 } else { 63 // there may be a tuple expr buried in the aggregate 64 return new ast::UntypedMemberExpr( loc, memberExpr->member, memberExpr->aggregate->accept( *visitor ) ); 65 } 66 } 67 68 const ast::Expr * UniqueExprExpander::postvisit( const ast::UniqueExpr * unqExpr ) { 69 const CodeLocation loc = unqExpr->location; 70 const int id = unqExpr->id; 71 72 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID, 73 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable. 74 if ( ! decls.count( id ) ) { 75 ast::ptr< ast::Expr > assignUnq; 76 const ast::VariableExpr * var = unqExpr->var; 77 if ( unqExpr->object ) { 78 // an object was generated to represent this unique expression -- it should be added to the list of declarations now 79 declsToAddBefore.push_back( unqExpr->object.as< ast::Decl >() ); 80 // deep copy required due to unresolved issues with UniqueExpr 81 assignUnq = ast::UntypedExpr::createAssign( loc, var, unqExpr->expr ); 82 } else { 83 const auto commaExpr = unqExpr->expr.strict_as< ast::CommaExpr >(); 84 assignUnq = commaExpr->arg1; 85 } 86 auto finished = new ast::ObjectDecl( loc, toString( "_unq", id, "_finished_" ), new ast::BasicType( ast::BasicType::Kind::Bool ), 87 new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) ), {}, ast::Linkage::Cforall ); 88 declsToAddBefore.push_back( finished ); 89 // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N)) 90 // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code. 91 auto assignFinished = ast::UntypedExpr::createAssign( loc, new ast::VariableExpr( loc, finished ), 92 ast::ConstantExpr::from_int( loc, 1 ) ); 93 auto condExpr = new ast::ConditionalExpr( loc, new ast::VariableExpr( loc, finished ), var, 94 new ast::CommaExpr( loc, new ast::CommaExpr( loc, assignUnq, assignFinished ), var ) ); 95 condExpr->result = var->result; 96 condExpr->env = unqExpr->env; 97 decls[id] = condExpr; 98 } 99 return ast::deepCopy(decls[id].get()); 100 } 101 102 /// Replaces Tuple Assign & Index Expressions, and Tuple Types. 103 struct TupleMainExpander : 104 public ast::WithGuards, 105 public ast::WithVisitorRef<TupleMainExpander>, 106 public ast::WithDeclsToAdd<> { 107 ast::Expr const * postvisit( ast::TupleAssignExpr const * expr ) { 108 // Just move the env on the new top level expression. 109 return ast::mutate_field( expr->stmtExpr.get(), 110 &ast::TupleAssignExpr::env, expr->env.get() ); 111 } 112 113 void previsit( ast::ParseNode const * node ) { 114 GuardValue( location ) = &node->location; 115 } 116 117 void previsit( ast::CompoundStmt const * stmt ) { 118 previsit( (ast::ParseNode const *)stmt ); 119 GuardScope( typeMap ); 120 } 121 122 ast::Expr const * postvisit( ast::Expr const * expr ) { 123 if ( nullptr == expr->env ) { 124 return expr; 125 } 126 // TypeSubstitutions are never visited in the new Pass template, 127 // so it is done manually here, where all types have to be replaced. 128 return ast::mutate_field( expr, &ast::Expr::env, 129 expr->env->accept( *visitor ) ); 130 } 131 132 ast::Type const * postvisit( ast::TupleType const * type ) { 133 assert( location ); 134 unsigned tupleSize = type->size(); 135 if ( !typeMap.count( tupleSize ) ) { 136 ast::StructDecl * decl = new ast::StructDecl( *location, 137 toString( "_tuple", tupleSize, "_" ) 138 ); 139 decl->body = true; 140 141 for ( size_t i = 0 ; i < tupleSize ; ++i ) { 142 ast::TypeDecl * typeParam = new ast::TypeDecl( *location, 143 toString( "tuple_param_", tupleSize, "_", i ), 144 ast::Storage::Classes(), 145 nullptr, 146 ast::TypeDecl::Dtype, 147 true 148 ); 149 ast::ObjectDecl * member = new ast::ObjectDecl( *location, 150 toString( "field_", i ), 151 new ast::TypeInstType( typeParam ) 152 ); 153 decl->params.push_back( typeParam ); 154 decl->members.push_back( member ); 155 } 156 157 // Empty structures are not standard C. Add a dummy field to 158 // empty tuples to silence warnings when a compound literal 159 // `_tuple0_` is created. 160 if ( tupleSize == 0 ) { 161 decl->members.push_back( 162 new ast::ObjectDecl( *location, 163 "dummy", 164 new ast::BasicType( ast::BasicType::SignedInt ), 165 nullptr, 166 ast::Storage::Classes(), 167 // Does this have to be a C linkage? 168 ast::Linkage::C 169 ) 170 ); 171 } 172 typeMap[tupleSize] = decl; 173 declsToAddBefore.push_back( decl ); 174 } 175 176 ast::StructDecl const * decl = typeMap[ tupleSize ]; 177 ast::StructInstType * newType = 178 new ast::StructInstType( decl, type->qualifiers ); 179 for ( auto pair : group_iterate( type->types, decl->params ) ) { 180 ast::Type const * t = std::get<0>( pair ); 181 newType->params.push_back( 182 new ast::TypeExpr( *location, ast::deepCopy( t ) ) ); 183 } 184 return newType; 185 } 186 187 ast::Expr const * postvisit( ast::TupleIndexExpr const * expr ) { 188 CodeLocation const & location = expr->location; 189 ast::Expr const * tuple = expr->tuple.get(); 190 assert( tuple ); 191 unsigned int index = expr->index; 192 ast::TypeSubstitution const * env = expr->env.get(); 193 194 if ( auto tupleExpr = dynamic_cast<ast::TupleExpr const *>( tuple ) ) { 195 // Optimization: If it is a definitely pure tuple expr, 196 // then it can reduce to the only relevant component. 197 if ( !maybeImpureIgnoreUnique( tupleExpr ) ) { 198 assert( index < tupleExpr->exprs.size() ); 199 ast::ptr<ast::Expr> const & expr = 200 *std::next( tupleExpr->exprs.begin(), index ); 201 ast::Expr * ret = ast::mutate( expr.get() ); 202 ret->env = env; 203 return ret; 204 } 205 } 206 207 auto type = tuple->result.strict_as<ast::StructInstType>(); 208 ast::StructDecl const * structDecl = type->base; 209 assert( index < structDecl->members.size() ); 210 ast::ptr<ast::Decl> const & member = 211 *std::next( structDecl->members.begin(), index ); 212 ast::MemberExpr * memberExpr = new ast::MemberExpr( location, 213 member.strict_as<ast::DeclWithType>(), tuple ); 214 memberExpr->env = env; 215 return memberExpr; 216 } 217 private: 218 ScopedMap< int, ast::StructDecl const * > typeMap; 219 CodeLocation const * location = nullptr; 220 }; 221 222 ast::Expr const * replaceTupleExpr( 223 CodeLocation const & location, 224 ast::Type const * result, 225 std::vector<ast::ptr<ast::Expr>> const & exprs, 226 ast::TypeSubstitution const * env ) { 227 assert( result ); 228 // A void result: It doesn't need to produce a value for cascading, 229 // just output a chain of comma exprs. 230 if ( result->isVoid() ) { 231 assert( !exprs.empty() ); 232 std::vector<ast::ptr<ast::Expr>>::const_iterator iter = exprs.begin(); 233 ast::Expr * expr = new ast::CastExpr( *iter++ ); 234 for ( ; iter != exprs.end() ; ++iter ) { 235 expr = new ast::CommaExpr( location, 236 expr, new ast::CastExpr( *iter ) ); 237 } 238 expr->env = env; 239 return expr; 240 // Typed tuple expression: Produce a compound literal which performs 241 // each of the expressions as a distinct part of its initializer. The 242 // produced compound literal may be used as part of another expression. 243 } else { 244 auto inits = map_range<std::vector<ast::ptr<ast::Init>>>( exprs, 245 []( ast::Expr const * expr ) { 246 return new ast::SingleInit( expr->location, expr ); 247 } 248 ); 249 ast::Expr * expr = new ast::CompoundLiteralExpr( location, 250 result, new ast::ListInit( location, std::move( inits ) ) ); 251 expr->env = env; 252 return expr; 253 } 254 } 255 256 struct TupleExprExpander { 257 ast::Expr const * postvisit( ast::TupleExpr const * expr ) { 258 return replaceTupleExpr( expr->location, 259 expr->result, expr->exprs, expr->env ); 260 } 261 }; 262 28 263 } // namespace 29 264 … … 32 267 } 33 268 34 namespace {35 namespace {36 /// given a expression representing the member and an expression representing the aggregate,37 /// reconstructs a flattened UntypedMemberExpr with the right precedence38 const ast::Expr * reconstructMemberExpr( const ast::Expr * member, const ast::Expr * aggr, const CodeLocation & loc ) {39 if ( auto memberExpr = dynamic_cast< const ast::UntypedMemberExpr * >( member ) ) {40 // construct a new UntypedMemberExpr with the correct structure , and recursively41 // expand that member expression.42 ast::Pass< MemberTupleExpander > expander;43 auto inner = new ast::UntypedMemberExpr( loc, memberExpr->aggregate, aggr );44 auto newMemberExpr = new ast::UntypedMemberExpr( loc, memberExpr->member, inner );45 //delete memberExpr;46 return newMemberExpr->accept( expander );47 } else {48 // not a member expression, so there is nothing to do but attach and return49 return new ast::UntypedMemberExpr( loc, member, aggr );50 }51 }52 }53 54 const ast::Expr * MemberTupleExpander::postvisit( const ast::UntypedMemberExpr * memberExpr ) {55 const CodeLocation loc = memberExpr->location;56 if ( auto tupleExpr = memberExpr->member.as< ast::UntypedTupleExpr >() ) {57 auto mutExpr = mutate( tupleExpr );58 ast::ptr< ast::Expr > aggr = memberExpr->aggregate->accept( *visitor );59 // aggregate expressions which might be impure must be wrapped in unique expressions60 if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new ast::UniqueExpr( loc, aggr );61 for ( auto & expr : mutExpr->exprs ) {62 expr = reconstructMemberExpr( expr, aggr, loc );63 }64 //delete aggr;65 return mutExpr;66 } else {67 // there may be a tuple expr buried in the aggregate68 return new ast::UntypedMemberExpr( loc, memberExpr->member, memberExpr->aggregate->accept( *visitor ) );69 }70 }71 } // namespace72 73 269 void expandUniqueExpr( ast::TranslationUnit & translationUnit ) { 74 270 ast::Pass< UniqueExprExpander >::run( translationUnit ); 75 271 } 76 272 77 namespace { 78 const ast::Expr * UniqueExprExpander::postvisit( const ast::UniqueExpr * unqExpr ) { 79 const CodeLocation loc = unqExpr->location; 80 const int id = unqExpr->id; 81 82 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID, 83 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable. 84 if ( ! decls.count( id ) ) { 85 ast::ptr< ast::Expr > assignUnq; 86 const ast::VariableExpr * var = unqExpr->var; 87 if ( unqExpr->object ) { 88 // an object was generated to represent this unique expression -- it should be added to the list of declarations now 89 declsToAddBefore.push_back( unqExpr->object.as< ast::Decl >() ); 90 // deep copy required due to unresolved issues with UniqueExpr 91 assignUnq = ast::UntypedExpr::createAssign( loc, var, unqExpr->expr ); 92 } else { 93 const auto commaExpr = unqExpr->expr.strict_as< ast::CommaExpr >(); 94 assignUnq = commaExpr->arg1; 95 } 96 auto finished = new ast::ObjectDecl( loc, toString( "_unq", id, "_finished_" ), new ast::BasicType( ast::BasicType::Kind::Bool ), 97 new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) ), {}, ast::Linkage::Cforall ); 98 declsToAddBefore.push_back( finished ); 99 // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N)) 100 // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code. 101 auto assignFinished = ast::UntypedExpr::createAssign( loc, new ast::VariableExpr( loc, finished ), 102 ast::ConstantExpr::from_int( loc, 1 ) ); 103 auto condExpr = new ast::ConditionalExpr( loc, new ast::VariableExpr( loc, finished ), var, 104 new ast::CommaExpr( loc, new ast::CommaExpr( loc, assignUnq, assignFinished ), var ) ); 105 condExpr->result = var->result; 106 condExpr->env = unqExpr->env; 107 decls[id] = condExpr; 108 } 109 //delete unqExpr; 110 return ast::deepCopy(decls[id].get()); 111 } 112 } // namespace 273 void expandTuples( ast::TranslationUnit & translationUnit ) { 274 // These can't just be combined simply (there might be a way with work). 275 ast::Pass<TupleMainExpander>::run( translationUnit ); 276 ast::Pass<TupleExprExpander>::run( translationUnit ); 277 } 278 113 279 } // namespace Tuples
Note:
See TracChangeset
for help on using the changeset viewer.