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