source: src/Tuples/TupleExpansionNew.cpp @ b507dcd

ADTast-experimentalpthread-emulation
Last change on this file since b507dcd was b507dcd, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Converted the Expand Tuples pass to the new ast.

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