Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Tuples/TupleExpansionNew.cpp

    re116db3 rbb9924c  
    88//
    99// Author           : Henry Xue
    10 // Created On       : Mon Aug 23 15:36:09 2021
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Aug 15 17:00:00 2022
    13 // Update Count     : 3
     10// Created On       : Wed Aug 18 12:54:02 2021
     11// Last Modified By : Henry Xue
     12// Last Modified On : Wed Aug 18 12:54:02 2021
     13// Update Count     : 1
    1414//
     15
     16// Currently not working due to unresolved issues with UniqueExpr
    1517
    1618#include "Tuples.h"
    1719
    18 #include "AST/Pass.hpp"
    19 #include "Common/ScopedMap.h"
    20 
    2120namespace Tuples {
    22 
    2321namespace {
    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 
     22        struct UniqueExprExpander final : public ast::WithDeclsToAdd<> {
     23                const ast::Expr * postvisit( const ast::UniqueExpr * unqExpr );
     24                std::map< int, ast::ptr<ast::Expr> > decls; // not vector, because order added may not be increasing order
     25        };
    26326} // namespace
    264 
    265 void expandMemberTuples( ast::TranslationUnit & translationUnit ) {
    266         ast::Pass< MemberTupleExpander >::run( translationUnit );
    267 }
    26827
    26928void expandUniqueExpr( ast::TranslationUnit & translationUnit ) {
     
    27130}
    27231
    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 }
     32namespace {
     33        const ast::Expr * UniqueExprExpander::postvisit( const ast::UniqueExpr * unqExpr ) {
     34                const CodeLocation loc = unqExpr->location;
     35                const int id = unqExpr->id;
    27836
     37                // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,
     38                // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.
     39                if ( ! decls.count( id ) ) {
     40                        ast::ptr< ast::Expr > assignUnq;
     41                        const ast::VariableExpr * var = unqExpr->var;
     42                        if ( unqExpr->object ) {
     43                                // an object was generated to represent this unique expression -- it should be added to the list of declarations now
     44                                declsToAddBefore.push_back( unqExpr->object.as< ast::Decl >() );
     45                                // deep copy required due to unresolved issues with UniqueExpr
     46                                assignUnq = ast::UntypedExpr::createAssign( loc, var, unqExpr->expr );
     47                        } else {
     48                                const auto commaExpr = unqExpr->expr.strict_as< ast::CommaExpr >();
     49                                assignUnq = commaExpr->arg1;
     50                        }
     51                        auto finished = new ast::ObjectDecl( loc, toString( "_unq", id, "_finished_" ), new ast::BasicType( ast::BasicType::Kind::Bool ),
     52                                new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) ), {}, ast::Linkage::Cforall );
     53                        declsToAddBefore.push_back( finished );
     54                        // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
     55                        // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
     56                        auto assignFinished = ast::UntypedExpr::createAssign( loc, new ast::VariableExpr( loc, finished ),
     57                                ast::ConstantExpr::from_int( loc, 1 ) );
     58                        auto condExpr = new ast::ConditionalExpr( loc, new ast::VariableExpr( loc, finished ), var,
     59                                new ast::CommaExpr( loc, new ast::CommaExpr( loc, assignUnq, assignFinished ), var ) );
     60                        condExpr->result = var->result;
     61                        condExpr->env = unqExpr->env;
     62                        decls[id] = condExpr;
     63                }
     64                //delete unqExpr;
     65                return ast::deepCopy(decls[id].get());
     66        }
     67} // namespace
    27968} // namespace Tuples
Note: See TracChangeset for help on using the changeset viewer.