source: src/InitTweak/InitTweak.cc@ 1ccae59

Last change on this file since 1ccae59 was 0bd3faf, checked in by Andrew Beach <ajbeach@…>, 23 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
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// InitTweak.cc --
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 <algorithm> // for find, all_of
17#include <cassert> // for assertf, assert, strict_dynamic_cast
18#include <iostream> // for ostream, cerr, endl
19#include <iterator> // for back_insert_iterator, back_inserter
20#include <memory> // for __shared_ptr
21#include <vector>
22
23#include "AST/Expr.hpp"
24#include "AST/Init.hpp"
25#include "AST/Inspect.hpp"
26#include "AST/Node.hpp"
27#include "AST/Pass.hpp"
28#include "AST/Stmt.hpp"
29#include "AST/Type.hpp"
30#include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto...
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
35#include "InitTweak.h"
36#include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers
37#include "Tuples/Tuples.h" // for Tuples::isTtype
38
39namespace InitTweak {
40 namespace {
41 struct HasDesignations : public ast::WithShortCircuiting {
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
59 struct InitDepthChecker {
60 bool result = true;
61 const ast::Type * type;
62 int curDepth = 0, maxDepth = 0;
63 InitDepthChecker( const ast::Type * type ) : type( type ) {
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 }
71 void previsit( ast::ListInit const * ) {
72 curDepth++;
73 if ( curDepth > maxDepth ) result = false;
74 }
75 void postvisit( ast::ListInit const * ) {
76 curDepth--;
77 }
78 };
79
80 struct InitFlattener : public ast::WithShortCircuiting {
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
90
91 bool isDesignated( const ast::Init * init ) {
92 ast::Pass<HasDesignations> finder;
93 maybe_accept( init, finder );
94 return finder.core.result;
95 }
96
97 bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
98 ast::Pass<InitDepthChecker> checker( objDecl->type );
99 maybe_accept( objDecl->init.get(), checker );
100 return checker.core.result;
101 }
102
103std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
104 ast::Pass< InitFlattener > flattener;
105 maybe_accept( init, flattener );
106 return std::move( flattener.core.argList );
107}
108
109class InitExpander::ExpanderImpl {
110public:
111 virtual ~ExpanderImpl() = default;
112 virtual std::vector< ast::ptr< ast::Expr > > next( IndexList & indices ) = 0;
113 virtual ast::ptr< ast::Stmt > buildListInit(
114 ast::UntypedExpr * callExpr, IndexList & indices ) = 0;
115};
116
117namespace {
118 template< typename Out >
119 void buildCallExpr(
120 ast::UntypedExpr * callExpr, const ast::Expr * index, const ast::Expr * dimension,
121 const ast::Init * init, Out & out
122 ) {
123 const CodeLocation & loc = init->location;
124
125 auto cond = new ast::UntypedExpr{
126 loc, new ast::NameExpr{ loc, "?<?" }, { index, dimension } };
127
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
133 out.emplace_back( new ast::ExprStmt{
134 loc, new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, "++?" }, { index } } } );
135 }
136
137 template< typename Out >
138 void build(
139 ast::UntypedExpr * callExpr, const InitExpander::IndexList & indices,
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 ) {
153 buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
154 }
155 } else {
156 buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
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__" );
166 ast::Label switchLabel{
167 loc, targetLabel.newName(), { new ast::Attribute{ "unused" } } };
168
169 std::vector< ast::ptr< ast::CaseClause > > branches;
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 );
176 stmts.emplace_back(
177 new ast::BranchStmt{ loc, ast::BranchStmt::Break, switchLabel } );
178 branches.emplace_back( new ast::CaseClause{ loc, condition, std::move( stmts ) } );
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
185 class InitImpl final : public InitExpander::ExpanderImpl {
186 ast::ptr< ast::Init > init;
187 public:
188 InitImpl( const ast::Init * i ) : init( i ) {}
189
190 std::vector< ast::ptr< ast::Expr > > next( InitExpander::IndexList & ) override {
191 return makeInitList( init );
192 }
193
194 ast::ptr< ast::Stmt > buildListInit(
195 ast::UntypedExpr * callExpr, InitExpander::IndexList & indices
196 ) override {
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
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 }
214 }
215 };
216
217 class ExprImpl final : public InitExpander::ExpanderImpl {
218 ast::ptr< ast::Expr > arg;
219 public:
220 ExprImpl( const ast::Expr * a ) : arg( a ) {}
221
222 std::vector< ast::ptr< ast::Expr > > next(
223 InitExpander::IndexList & indices
224 ) override {
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;
232 expr = new ast::UntypedExpr{
233 loc, new ast::NameExpr{ loc, "?[?]" }, { expr, *it } };
234 }
235 return { expr };
236 }
237
238 ast::ptr< ast::Stmt > buildListInit(
239 ast::UntypedExpr *, InitExpander::IndexList &
240 ) override {
241 return {};
242 }
243 };
244} // anonymous namespace
245
246InitExpander::InitExpander( const ast::Init * init )
247: expander( new InitImpl{ init } ), crnt(), indices() {}
248
249InitExpander::InitExpander( const ast::Expr * expr )
250: expander( new ExprImpl{ expr } ), crnt(), indices() {}
251
252std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }
253
254InitExpander & InitExpander::operator++ () {
255 crnt = expander->next( indices );
256 return *this;
257}
258
259/// builds statement which has the same semantics as a C-style list initializer (for array
260/// initializers) using callExpr as the base expression to perform initialization
261ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {
262 return expander->buildListInit( callExpr, indices );
263}
264
265void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
266 indices.emplace_back( index );
267 indices.emplace_back( dimension );
268}
269
270void InitExpander::clearArrayIndices() { indices.clear(); }
271
272bool InitExpander::addReference() {
273 for ( ast::ptr< ast::Expr > & expr : crnt ) {
274 expr = new ast::AddressExpr{ expr };
275 }
276 return ! crnt.empty();
277}
278
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
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 ) {
306 return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type )
307 && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type );
308 }
309
310 struct CallFinder final {
311 std::vector< const ast::Expr * > matches;
312 const std::vector< std::string > names;
313
314 CallFinder( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}
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
327 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
328 ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
329 maybe_accept( stmt, finder );
330 return std::move( finder.core.matches );
331 }
332
333 namespace {
334 template <typename Predicate>
335 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
336 std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
337 return std::all_of( callExprs.begin(), callExprs.end(), pred );
338 }
339 }
340
341 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) {
342 return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){
343 if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
344 const ast::FunctionType * funcType =
345 GenPoly::getFunctionType( appExpr->func->result );
346 assert( funcType );
347 return funcType->params.size() == 1;
348 }
349 return false;
350 });
351 }
352
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) {
358 auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true);
359 assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td},
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);
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 }
368 } else {
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 }
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;
381 }
382
383 struct ConstExprChecker : public ast::WithShortCircuiting {
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
392 if ( ! dynamic_cast< const ast::NameExpr * >( arg )
393 && ! dynamic_cast< const ast::VariableExpr * >( arg )
394 && ! dynamic_cast< const ast::MemberExpr * >( arg )
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 ) {
428 ast::Pass<ConstExprChecker> checker;
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 ) {
437 ast::Pass<ConstExprChecker> checker;
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
445bool isAssignment( const ast::FunctionDecl * decl ) {
446 return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
447}
448
449bool isDestructor( const ast::FunctionDecl * decl ) {
450 return CodeGen::isDestructor( decl->name );
451}
452
453bool isDefaultConstructor( const ast::FunctionDecl * decl ) {
454 return CodeGen::isConstructor( decl->name ) && 1 == decl->params.size();
455}
456
457bool isCopyConstructor( const ast::FunctionDecl * decl ) {
458 return CodeGen::isConstructor( decl->name ) && 2 == decl->params.size();
459}
460
461bool isCopyFunction( const ast::FunctionDecl * decl ) {
462 const ast::FunctionType * ftype = decl->type;
463 if ( ftype->params.size() != 2 ) return false;
464
465 const ast::Type * t1 = ast::getPointerBase( ftype->params.front() );
466 if ( ! t1 ) return false;
467 const ast::Type * t2 = ftype->params.back();
468
469 return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
470}
471
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;
479
480 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
481 const bool is_tls = objDecl->storage.is_threadlocal_any();
482 const char * section = is_tls ? tlsd_section : data_section;
483 objDecl->attributes.push_back(new ast::Attribute("section", {
484 ast::ConstantExpr::from_string(objDecl->location, section)
485 }));
486 }
487
488} // namespace InitTweak
Note: See TracBrowser for help on using the repository browser.