source: src/InitTweak/InitTweak.cpp@ 115ac1ce

Last change on this file since 115ac1ce was c92bdcc, checked in by Andrew Beach <ajbeach@…>, 17 months ago

Updated the rest of the names in src/ (except for the generated files).

  • Property mode set to 100644
File size: 16.1 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//
[c92bdcc]7// InitTweak.cpp --
[2d11663]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
[c92bdcc]16#include "InitTweak.hpp"
[8984003]17
[c92bdcc]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
[2d11663]23#include <vector>
[d180746]24
[9b4f329]25#include "AST/Expr.hpp"
[c1ed2ee]26#include "AST/Init.hpp"
[e01eb4a]27#include "AST/Inspect.hpp"
[b8524ca]28#include "AST/Node.hpp"
[c1ed2ee]29#include "AST/Pass.hpp"
[9b4f329]30#include "AST/Stmt.hpp"
[9e1d485]31#include "AST/Type.hpp"
[c92bdcc]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
[d180746]39
[2b46a13]40namespace InitTweak {
[b8524ca]41
[8984003]42// Forward declared, because it is used as a parent type.
[0bd3faf]43class InitExpander::ExpanderImpl {
[b8524ca]44public:
45 virtual ~ExpanderImpl() = default;
46 virtual std::vector< ast::ptr< ast::Expr > > next( IndexList & indices ) = 0;
[6f096d2]47 virtual ast::ptr< ast::Stmt > buildListInit(
[c1ed2ee]48 ast::UntypedExpr * callExpr, IndexList & indices ) = 0;
[b8524ca]49};
50
51namespace {
[8984003]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
[c1ed2ee]100 template< typename Out >
[6f096d2]101 void buildCallExpr(
102 ast::UntypedExpr * callExpr, const ast::Expr * index, const ast::Expr * dimension,
[c1ed2ee]103 const ast::Init * init, Out & out
104 ) {
105 const CodeLocation & loc = init->location;
106
[6f096d2]107 auto cond = new ast::UntypedExpr{
[c1ed2ee]108 loc, new ast::NameExpr{ loc, "?<?" }, { index, dimension } };
[6f096d2]109
[c1ed2ee]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
[6f096d2]115 out.emplace_back( new ast::ExprStmt{
[c1ed2ee]116 loc, new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, "++?" }, { index } } } );
117 }
118
119 template< typename Out >
120 void build(
[0bd3faf]121 ast::UntypedExpr * callExpr, const InitExpander::IndexList & indices,
[c1ed2ee]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 ) {
[16ba4a6f]135 buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
[c1ed2ee]136 }
137 } else {
[16ba4a6f]138 buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
[c1ed2ee]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__" );
[6f096d2]148 ast::Label switchLabel{
[c1ed2ee]149 loc, targetLabel.newName(), { new ast::Attribute{ "unused" } } };
[6f096d2]150
[400b8be]151 std::vector< ast::ptr< ast::CaseClause > > branches;
[c1ed2ee]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 );
[6f096d2]158 stmts.emplace_back(
[c1ed2ee]159 new ast::BranchStmt{ loc, ast::BranchStmt::Break, switchLabel } );
[400b8be]160 branches.emplace_back( new ast::CaseClause{ loc, condition, std::move( stmts ) } );
[c1ed2ee]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
[0bd3faf]167 class InitImpl final : public InitExpander::ExpanderImpl {
[b8524ca]168 ast::ptr< ast::Init > init;
169 public:
[0bd3faf]170 InitImpl( const ast::Init * i ) : init( i ) {}
[b8524ca]171
[0bd3faf]172 std::vector< ast::ptr< ast::Expr > > next( InitExpander::IndexList & ) override {
[b8524ca]173 return makeInitList( init );
174 }
[6f096d2]175
176 ast::ptr< ast::Stmt > buildListInit(
[0bd3faf]177 ast::UntypedExpr * callExpr, InitExpander::IndexList & indices
[b8524ca]178 ) override {
[6f096d2]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
[c1ed2ee]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 {};
[58c5821]191 } else if ( 1 == stmts.size() ) {
192 return std::move( stmts.front() );
[c1ed2ee]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 }
[b8524ca]198 }
199 };
200
[0bd3faf]201 class ExprImpl final : public InitExpander::ExpanderImpl {
[b8524ca]202 ast::ptr< ast::Expr > arg;
203 public:
[0bd3faf]204 ExprImpl( const ast::Expr * a ) : arg( a ) {}
[b8524ca]205
[6f096d2]206 std::vector< ast::ptr< ast::Expr > > next(
[0bd3faf]207 InitExpander::IndexList & indices
[b8524ca]208 ) override {
[8984003]209 if ( !arg ) return {};
[c1ed2ee]210
211 const CodeLocation & loc = arg->location;
212 const ast::Expr * expr = arg;
213 for ( auto it = indices.rbegin(); it != indices.rend(); ++it ) {
[8984003]214 // Go through indices and layer on subscript exprs ?[?].
[c1ed2ee]215 ++it;
[6f096d2]216 expr = new ast::UntypedExpr{
[c1ed2ee]217 loc, new ast::NameExpr{ loc, "?[?]" }, { expr, *it } };
218 }
219 return { expr };
[b8524ca]220 }
[6f096d2]221
222 ast::ptr< ast::Stmt > buildListInit(
[0bd3faf]223 ast::UntypedExpr *, InitExpander::IndexList &
[6f096d2]224 ) override {
[b8524ca]225 return {};
226 }
227 };
[490fb92e]228
[0bd3faf]229 struct CallFinder final {
[490fb92e]230 std::vector< const ast::Expr * > matches;
[2d11663]231 const std::vector< std::string > names;
232
[0bd3faf]233 CallFinder( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}
[2d11663]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
[8984003]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 );
[490fb92e]250 }
251
[0bd3faf]252 struct ConstExprChecker : public ast::WithShortCircuiting {
[8984003]253 // Most expressions are not const-expr.
[16ba4a6f]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
[8984003]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;
[16ba4a6f]265 }
266
[8984003]267 // These expressions may be const expr, depending on their children.
[16ba4a6f]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 };
[8984003]294} // namespace
[16ba4a6f]295
[00a8e19]296bool isAssignment( const ast::FunctionDecl * decl ) {
[13d326ec]297 return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
[00a8e19]298}
[d76c588]299
[00a8e19]300bool isDestructor( const ast::FunctionDecl * decl ) {
[13d326ec]301 return CodeGen::isDestructor( decl->name );
[00a8e19]302}
[6f096d2]303
[00a8e19]304bool isDefaultConstructor( const ast::FunctionDecl * decl ) {
[13d326ec]305 return CodeGen::isConstructor( decl->name ) && 1 == decl->params.size();
[00a8e19]306}
307
308bool isCopyConstructor( const ast::FunctionDecl * decl ) {
[13d326ec]309 return CodeGen::isConstructor( decl->name ) && 2 == decl->params.size();
[00a8e19]310}
311
312bool isCopyFunction( const ast::FunctionDecl * decl ) {
313 const ast::FunctionType * ftype = decl->type;
314 if ( ftype->params.size() != 2 ) return false;
315
[e01eb4a]316 const ast::Type * t1 = ast::getPointerBase( ftype->params.front() );
[00a8e19]317 if ( ! t1 ) return false;
318 const ast::Type * t2 = ftype->params.back();
319
[251ce80]320 return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
[00a8e19]321}
[d76c588]322
[8984003]323const 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
333const 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...
342ast::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);
[37273c8]346 assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td}, {},
[8984003]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);
[7d651a66]350 }
[8984003]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
370std::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
376bool 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
385bool 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
390bool isDesignated( const ast::Init * init ) {
[58c5821]391 return ( init ) ? ast::Pass<HasDesignations>::read( init ) : false;
[8984003]392}
393
394bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
[58c5821]395 return ( objDecl->init ) ? ast::Pass<InitDepthChecker>::read(
396 objDecl->init.get(), objDecl->type.get() ) : true;
[8984003]397}
398
399bool 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
411std::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
417bool isConstExpr( const ast::Expr * expr ) {
418 return ( expr ) ? ast::Pass<ConstExprChecker>::read( expr ) : true;
419}
420
421bool 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
431static const char * const data_section = ".data" ASM_COMMENT;
432static const char * const tlsd_section = ".tdata" ASM_COMMENT;
433
434void 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
442InitExpander::InitExpander( const ast::Init * init )
443: expander( new InitImpl{ init } ), crnt(), indices() {}
444
445InitExpander::InitExpander( const ast::Expr * expr )
446: expander( new ExprImpl{ expr } ), crnt(), indices() {}
447
448std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }
449
450InitExpander & 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
457ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {
458 return expander->buildListInit( callExpr, indices );
459}
460
461void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
462 indices.emplace_back( index );
463 indices.emplace_back( dimension );
464}
465
466void InitExpander::clearArrayIndices() { indices.clear(); }
467
468bool InitExpander::addReference() {
469 for ( ast::ptr< ast::Expr > & expr : crnt ) {
470 expr = new ast::AddressExpr{ expr };
471 }
472 return !crnt.empty();
473}
[7d651a66]474
[0bd3faf]475} // namespace InitTweak
Note: See TracBrowser for help on using the repository browser.