source: src/InitTweak/InitTweak.cc @ 8c13ca8

Last change on this file since 8c13ca8 was 0bd3faf, checked in by Andrew Beach <ajbeach@…>, 8 months ago

Removed forward declarations missed in the BaseSyntaxNode? removal. Removed code and modified names to support two versions of the ast.

  • Property mode set to 100644
File size: 16.3 KB
RevLine 
[2d11663]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// InitTweak.cc --
8//
9// Author           : Rob Schluntz
10// Created On       : Fri May 13 11:26:36 2016
[3cc1111]11// Last Modified By : Andrew Beach
[e01eb4a]12// Last Modified On : Wed Sep 22  9:50:00 2022
13// Update Count     : 21
[2d11663]14//
15
[d180746]16#include <algorithm>               // for find, all_of
[e3e16bc]17#include <cassert>                 // for assertf, assert, strict_dynamic_cast
[d180746]18#include <iostream>                // for ostream, cerr, endl
19#include <iterator>                // for back_insert_iterator, back_inserter
20#include <memory>                  // for __shared_ptr
[2d11663]21#include <vector>
[d180746]22
[9b4f329]23#include "AST/Expr.hpp"
[c1ed2ee]24#include "AST/Init.hpp"
[e01eb4a]25#include "AST/Inspect.hpp"
[b8524ca]26#include "AST/Node.hpp"
[c1ed2ee]27#include "AST/Pass.hpp"
[9b4f329]28#include "AST/Stmt.hpp"
[9e1d485]29#include "AST/Type.hpp"
[13d326ec]30#include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto...
[d180746]31#include "Common/SemanticError.h"  // for SemanticError
32#include "Common/UniqueName.h"     // for UniqueName
33#include "Common/utility.h"        // for toString, deleteAll, maybeClone
34#include "GenPoly/GenPoly.h"       // for getFunctionType
[2b46a13]35#include "InitTweak.h"
[e563edf]36#include "ResolvExpr/Unify.h"      // for typesCompatibleIgnoreQualifiers
[29bc63e]37#include "Tuples/Tuples.h"         // for Tuples::isTtype
[d180746]38
[2b46a13]39namespace InitTweak {
[64071c2]40        namespace {
[0bd3faf]41                struct HasDesignations : public ast::WithShortCircuiting {
[16ba4a6]42                        bool result = false;
43
44                        void previsit( const ast::Node * ) {
45                                // short circuit if we already know there are designations
46                                if ( result ) visit_children = false;
47                        }
48
49                        void previsit( const ast::Designation * des ) {
50                                // short circuit if we already know there are designations
51                                if ( result ) visit_children = false;
52                                else if ( ! des->designators.empty() ) {
53                                        result = true;
54                                        visit_children = false;
55                                }
56                        }
57                };
58
[0bd3faf]59                struct InitDepthChecker {
[16ba4a6]60                        bool result = true;
61                        const ast::Type * type;
62                        int curDepth = 0, maxDepth = 0;
[0bd3faf]63                        InitDepthChecker( const ast::Type * type ) : type( type ) {
[16ba4a6]64                                const ast::Type * t = type;
65                                while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) {
66                                        maxDepth++;
67                                        t = at->base;
68                                }
69                                maxDepth++;
70                        }
[3c714ad]71                        void previsit( ast::ListInit const * ) {
[16ba4a6]72                                curDepth++;
73                                if ( curDepth > maxDepth ) result = false;
[3c714ad]74                        }
75                        void postvisit( ast::ListInit const * ) {
76                                curDepth--;
[16ba4a6]77                        }
78                };
79
[0bd3faf]80                struct InitFlattener : public ast::WithShortCircuiting {
[c1ed2ee]81                        std::vector< ast::ptr< ast::Expr > > argList;
82
83                        void previsit( const ast::SingleInit * singleInit ) {
84                                visit_children = false;
85                                argList.emplace_back( singleInit->value );
86                        }
87                };
88
89        } // anonymous namespace
[2b46a13]90
[16ba4a6]91        bool isDesignated( const ast::Init * init ) {
[0bd3faf]92                ast::Pass<HasDesignations> finder;
[16ba4a6]93                maybe_accept( init, finder );
94                return finder.core.result;
95        }
96
97        bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
[0bd3faf]98                ast::Pass<InitDepthChecker> checker( objDecl->type );
[16ba4a6]99                maybe_accept( objDecl->init.get(), checker );
100                return checker.core.result;
101        }
102
[b8524ca]103std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
[0bd3faf]104        ast::Pass< InitFlattener > flattener;
[c1ed2ee]105        maybe_accept( init, flattener );
[7ff3e522]106        return std::move( flattener.core.argList );
[b8524ca]107}
108
[0bd3faf]109class InitExpander::ExpanderImpl {
[b8524ca]110public:
111        virtual ~ExpanderImpl() = default;
112        virtual std::vector< ast::ptr< ast::Expr > > next( IndexList & indices ) = 0;
[6f096d2]113        virtual ast::ptr< ast::Stmt > buildListInit(
[c1ed2ee]114                ast::UntypedExpr * callExpr, IndexList & indices ) = 0;
[b8524ca]115};
116
117namespace {
[c1ed2ee]118        template< typename Out >
[6f096d2]119        void buildCallExpr(
120                ast::UntypedExpr * callExpr, const ast::Expr * index, const ast::Expr * dimension,
[c1ed2ee]121                const ast::Init * init, Out & out
122        ) {
123                const CodeLocation & loc = init->location;
124
[6f096d2]125                auto cond = new ast::UntypedExpr{
[c1ed2ee]126                        loc, new ast::NameExpr{ loc, "?<?" }, { index, dimension } };
[6f096d2]127
[c1ed2ee]128                std::vector< ast::ptr< ast::Expr > > args = makeInitList( init );
129                splice( callExpr->args, args );
130
131                out.emplace_back( new ast::IfStmt{ loc, cond, new ast::ExprStmt{ loc, callExpr } } );
132
[6f096d2]133                out.emplace_back( new ast::ExprStmt{
[c1ed2ee]134                        loc, new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, "++?" }, { index } } } );
135        }
136
137        template< typename Out >
138        void build(
[0bd3faf]139                ast::UntypedExpr * callExpr, const InitExpander::IndexList & indices,
[c1ed2ee]140                const ast::Init * init, Out & out
141        ) {
142                if ( indices.empty() ) return;
143
144                unsigned idx = 0;
145
146                const ast::Expr * index = indices[idx++];
147                assert( idx != indices.size() );
148                const ast::Expr * dimension = indices[idx++];
149
150                if ( idx == indices.size() ) {
151                        if ( auto listInit = dynamic_cast< const ast::ListInit * >( init ) ) {
152                                for ( const ast::Init * init : *listInit ) {
[16ba4a6]153                                        buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
[c1ed2ee]154                                }
155                        } else {
[16ba4a6]156                                buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
[c1ed2ee]157                        }
158                } else {
159                        const CodeLocation & loc = init->location;
160
161                        unsigned long cond = 0;
162                        auto listInit = dynamic_cast< const ast::ListInit * >( init );
163                        if ( ! listInit ) { SemanticError( loc, "unbalanced list initializers" ); }
164
165                        static UniqueName targetLabel( "L__autogen__" );
[6f096d2]166                        ast::Label switchLabel{
[c1ed2ee]167                                loc, targetLabel.newName(), { new ast::Attribute{ "unused" } } };
[6f096d2]168
[400b8be]169                        std::vector< ast::ptr< ast::CaseClause > > branches;
[c1ed2ee]170                        for ( const ast::Init * init : *listInit ) {
171                                auto condition = ast::ConstantExpr::from_ulong( loc, cond );
172                                ++cond;
173
174                                std::vector< ast::ptr< ast::Stmt > > stmts;
175                                build( callExpr, indices, init, stmts );
[6f096d2]176                                stmts.emplace_back(
[c1ed2ee]177                                        new ast::BranchStmt{ loc, ast::BranchStmt::Break, switchLabel } );
[400b8be]178                                branches.emplace_back( new ast::CaseClause{ loc, condition, std::move( stmts ) } );
[c1ed2ee]179                        }
180                        out.emplace_back( new ast::SwitchStmt{ loc, index, std::move( branches ) } );
181                        out.emplace_back( new ast::NullStmt{ loc, { switchLabel } } );
182                }
183        }
184
[0bd3faf]185        class InitImpl final : public InitExpander::ExpanderImpl {
[b8524ca]186                ast::ptr< ast::Init > init;
187        public:
[0bd3faf]188                InitImpl( const ast::Init * i ) : init( i ) {}
[b8524ca]189
[0bd3faf]190                std::vector< ast::ptr< ast::Expr > > next( InitExpander::IndexList & ) override {
[b8524ca]191                        return makeInitList( init );
192                }
[6f096d2]193
194                ast::ptr< ast::Stmt > buildListInit(
[0bd3faf]195                        ast::UntypedExpr * callExpr, InitExpander::IndexList & indices
[b8524ca]196                ) override {
[6f096d2]197                        // If array came with an initializer list, initialize each element. We may have more
198                        // initializers than elements of the array; need to check at each index that we have
199                        // not exceeded size. We may have fewer initializers than elements in the array; need
200                        // to default-construct remaining elements. To accomplish this, generate switch
[c1ed2ee]201                        // statement consuming all of expander's elements
202
203                        if ( ! init ) return {};
204
205                        std::list< ast::ptr< ast::Stmt > > stmts;
206                        build( callExpr, indices, init, stmts );
207                        if ( stmts.empty() ) {
208                                return {};
209                        } else {
210                                auto block = new ast::CompoundStmt{ init->location, std::move( stmts ) };
211                                init = nullptr;  // consumed in creating the list init
212                                return block;
213                        }
[b8524ca]214                }
215        };
216
[0bd3faf]217        class ExprImpl final : public InitExpander::ExpanderImpl {
[b8524ca]218                ast::ptr< ast::Expr > arg;
219        public:
[0bd3faf]220                ExprImpl( const ast::Expr * a ) : arg( a ) {}
[b8524ca]221
[6f096d2]222                std::vector< ast::ptr< ast::Expr > > next(
[0bd3faf]223                        InitExpander::IndexList & indices
[b8524ca]224                ) override {
[c1ed2ee]225                        if ( ! arg ) return {};
226
227                        const CodeLocation & loc = arg->location;
228                        const ast::Expr * expr = arg;
229                        for ( auto it = indices.rbegin(); it != indices.rend(); ++it ) {
230                                // go through indices and layer on subscript exprs ?[?]
231                                ++it;
[6f096d2]232                                expr = new ast::UntypedExpr{
[c1ed2ee]233                                        loc, new ast::NameExpr{ loc, "?[?]" }, { expr, *it } };
234                        }
235                        return { expr };
[b8524ca]236                }
[6f096d2]237
238                ast::ptr< ast::Stmt > buildListInit(
[0bd3faf]239                        ast::UntypedExpr *, InitExpander::IndexList &
[6f096d2]240                ) override {
[b8524ca]241                        return {};
242                }
243        };
244} // anonymous namespace
245
[0bd3faf]246InitExpander::InitExpander( const ast::Init * init )
247: expander( new InitImpl{ init } ), crnt(), indices() {}
[b8524ca]248
[0bd3faf]249InitExpander::InitExpander( const ast::Expr * expr )
250: expander( new ExprImpl{ expr } ), crnt(), indices() {}
[b8524ca]251
[0bd3faf]252std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }
[b8524ca]253
[0bd3faf]254InitExpander & InitExpander::operator++ () {
[b8524ca]255        crnt = expander->next( indices );
256        return *this;
257}
258
[6f096d2]259/// builds statement which has the same semantics as a C-style list initializer (for array
[b8524ca]260/// initializers) using callExpr as the base expression to perform initialization
[0bd3faf]261ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {
[b8524ca]262        return expander->buildListInit( callExpr, indices );
263}
264
[0bd3faf]265void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
[b8524ca]266        indices.emplace_back( index );
267        indices.emplace_back( dimension );
268}
269
[0bd3faf]270void InitExpander::clearArrayIndices() { indices.clear(); }
[b8524ca]271
[0bd3faf]272bool InitExpander::addReference() {
[b8524ca]273        for ( ast::ptr< ast::Expr > & expr : crnt ) {
274                expr = new ast::AddressExpr{ expr };
275        }
276        return ! crnt.empty();
277}
278
[3cc1111]279        const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
280                assertf( ftype, "getTypeofThis: nullptr ftype" );
281                const std::vector<ast::ptr<ast::Type>> & params = ftype->params;
282                assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s",
283                                toString( ftype ).c_str() );
284                const ast::ReferenceType * refType =
285                        params.front().strict_as<ast::ReferenceType>();
286                return refType->base;
287        }
288
[490fb92e]289        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
290                assertf( func, "getParamThis: nullptr ftype" );
291                auto & params = func->params;
292                assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());
293                return params.front().strict_as<ast::ObjectDecl>();
294        }
295
296        bool tryConstruct( const ast::DeclWithType * dwt ) {
297                auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );
298                if ( ! objDecl ) return false;
299                return (objDecl->init == nullptr ||
300                                ( objDecl->init != nullptr && objDecl->init->maybeConstructed ))
301                        && ! objDecl->storage.is_extern
302                        && isConstructable( objDecl->type );
303        }
304
305        bool isConstructable( const ast::Type * type ) {
[720f2fe2]306                return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type )
[490fb92e]307                && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type );
308        }
309
[0bd3faf]310        struct CallFinder final {
[490fb92e]311                std::vector< const ast::Expr * > matches;
[2d11663]312                const std::vector< std::string > names;
313
[0bd3faf]314                CallFinder( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}
[2d11663]315
316                void handleCallExpr( const ast::Expr * expr ) {
317                        std::string fname = getFunctionName( expr );
318                        if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
319                                matches.emplace_back( expr );
320                        }
321                }
322
323                void postvisit( const ast::ApplicationExpr * expr ) { handleCallExpr( expr ); }
324                void postvisit( const ast::UntypedExpr *     expr ) { handleCallExpr( expr ); }
325        };
326
[490fb92e]327        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
[0bd3faf]328                ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
[2d11663]329                maybe_accept( stmt, finder );
[7ff3e522]330                return std::move( finder.core.matches );
[2d11663]331        }
332
[aedfd91]333        namespace {
[2d11663]334                template <typename Predicate>
335                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
[490fb92e]336                        std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
[2d11663]337                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
338                }
[a465caf]339        }
340
[2d11663]341        bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) {
342                return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){
343                        if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
[6f096d2]344                                const ast::FunctionType * funcType =
[2d11663]345                                        GenPoly::getFunctionType( appExpr->func->result );
346                                assert( funcType );
347                                return funcType->params.size() == 1;
348                        }
349                        return false;
[4d2434a]350                });
[64071c2]351        }
[f1b1e4c]352
[490fb92e]353        // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards
354        // following passes may accidentally resolve this expression if returned as untyped...
355        ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) {
356                static ast::ptr<ast::FunctionDecl> assign = nullptr;
357                if (!assign) {
[4b8b2a4]358                        auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true);
[b7c53a9d]359                        assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td},
[4b8b2a4]360                        { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
361                          new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))},
362                        { new ast::ObjectDecl(CodeLocation(), "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic);
[490fb92e]363                }
364                if (dst->result.as<ast::ReferenceType>()) {
365                        for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
366                                dst = new ast::AddressExpr(dst);
367                        }
[14c0f7b]368                } else {
[490fb92e]369                        dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
370                }
371                if (src->result.as<ast::ReferenceType>()) {
372                        for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
373                                src = new ast::AddressExpr(src);
374                        }
375                }
[14c0f7b]376                auto var = ast::VariableExpr::functionPointer(dst->location, assign);
377                auto app = new ast::ApplicationExpr(dst->location, var, {dst, src});
378                // Skip the resolver, just set the result to the correct type.
379                app->result = ast::deepCopy( src->result );
380                return app;
[490fb92e]381        }
382
[0bd3faf]383        struct ConstExprChecker : public ast::WithShortCircuiting {
[16ba4a6]384                // most expressions are not const expr
385                void previsit( const ast::Expr * ) { result = false; visit_children = false; }
386
387                void previsit( const ast::AddressExpr *addressExpr ) {
388                        visit_children = false;
389                        const ast::Expr * arg = addressExpr->arg;
390
391                        // address of a variable or member expression is constexpr
[720f2fe2]392                        if ( ! dynamic_cast< const ast::NameExpr * >( arg )
393                        && ! dynamic_cast< const ast::VariableExpr * >( arg )
394                        && ! dynamic_cast< const ast::MemberExpr * >( arg )
[16ba4a6]395                        && ! dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;
396                }
397
398                // these expressions may be const expr, depending on their children
399                void previsit( const ast::SizeofExpr * ) {}
400                void previsit( const ast::AlignofExpr * ) {}
401                void previsit( const ast::UntypedOffsetofExpr * ) {}
402                void previsit( const ast::OffsetofExpr * ) {}
403                void previsit( const ast::OffsetPackExpr * ) {}
404                void previsit( const ast::CommaExpr * ) {}
405                void previsit( const ast::LogicalExpr * ) {}
406                void previsit( const ast::ConditionalExpr * ) {}
407                void previsit( const ast::CastExpr * ) {}
408                void previsit( const ast::ConstantExpr * ) {}
409
410                void previsit( const ast::VariableExpr * varExpr ) {
411                        visit_children = false;
412
413                        if ( auto inst = varExpr->result.as<ast::EnumInstType>() ) {
414                                long long int value;
415                                if ( inst->base->valueOf( varExpr->var, value ) ) {
416                                        // enumerators are const expr
417                                        return;
418                                }
419                        }
420                        result = false;
421                }
422
423                bool result = true;
424        };
425
426        bool isConstExpr( const ast::Expr * expr ) {
427                if ( expr ) {
[0bd3faf]428                        ast::Pass<ConstExprChecker> checker;
[16ba4a6]429                        expr->accept( checker );
430                        return checker.core.result;
431                }
432                return true;
433        }
434
435        bool isConstExpr( const ast::Init * init ) {
436                if ( init ) {
[0bd3faf]437                        ast::Pass<ConstExprChecker> checker;
[16ba4a6]438                        init->accept( checker );
439                        return checker.core.result;
440                } // if
441                // for all intents and purposes, no initializer means const expr
442                return true;
443        }
444
[00a8e19]445bool isAssignment( const ast::FunctionDecl * decl ) {
[13d326ec]446        return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
[00a8e19]447}
[d76c588]448
[00a8e19]449bool isDestructor( const ast::FunctionDecl * decl ) {
[13d326ec]450        return CodeGen::isDestructor( decl->name );
[00a8e19]451}
[6f096d2]452
[00a8e19]453bool isDefaultConstructor( const ast::FunctionDecl * decl ) {
[13d326ec]454        return CodeGen::isConstructor( decl->name ) && 1 == decl->params.size();
[00a8e19]455}
456
457bool isCopyConstructor( const ast::FunctionDecl * decl ) {
[13d326ec]458        return CodeGen::isConstructor( decl->name ) && 2 == decl->params.size();
[00a8e19]459}
460
461bool isCopyFunction( const ast::FunctionDecl * decl ) {
462        const ast::FunctionType * ftype = decl->type;
463        if ( ftype->params.size() != 2 ) return false;
464
[e01eb4a]465        const ast::Type * t1 = ast::getPointerBase( ftype->params.front() );
[00a8e19]466        if ( ! t1 ) return false;
467        const ast::Type * t2 = ftype->params.back();
468
[251ce80]469        return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
[00a8e19]470}
[d76c588]471
[720f2fe2]472        #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message
473                #define ASM_COMMENT "#"
474        #else // defined( __ARM_ARCH )
475                #define ASM_COMMENT "//"
476        #endif
477        static const char * const data_section =  ".data" ASM_COMMENT;
478        static const char * const tlsd_section = ".tdata" ASM_COMMENT;
[f1791a4]479
[7d651a6]480        void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
[ed9a1ae]481                const bool is_tls = objDecl->storage.is_threadlocal_any();
[720f2fe2]482                const char * section = is_tls ? tlsd_section : data_section;
[aff7e86]483                objDecl->attributes.push_back(new ast::Attribute("section", {
[720f2fe2]484                        ast::ConstantExpr::from_string(objDecl->location, section)
485                }));
[7d651a6]486        }
487
[0bd3faf]488} // namespace InitTweak
Note: See TracBrowser for help on using the repository browser.