source: src/GenPoly/BoxNew.cpp@ 6bd9f9e

Last change on this file since 6bd9f9e was 61e5d99, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Boxing no longer passes layout information about polymorphic types in the signature of the function. This simplifies the sub-passes in the box pass that added the arguments to the calls, the parameters to the declarations, and used the information internally. The effects in functions are less well quantified, because there are cases were the information has to be generated instead of passed in, but it is also never passed in (or generated) when not needed at all.

  • Property mode set to 100644
File size: 83.6 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// BoxNew.cpp -- Implement polymorphic function calls and types.
8//
9// Author : Andrew Beach
10// Created On : Thr Oct 6 13:39:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Oct 2 17:00:00 2023
13// Update Count : 0
14//
15
16#include "Box.h"
17
18#include "AST/Decl.hpp" // for Decl, FunctionDecl, ...
19#include "AST/Expr.hpp" // for AlignofExpr, ConstantExpr, ...
20#include "AST/Init.hpp" // for Init, SingleInit
21#include "AST/Inspect.hpp" // for getFunctionName
22#include "AST/Pass.hpp" // for Pass, WithDeclsToAdd, ...
23#include "AST/Stmt.hpp" // for CompoundStmt, ExprStmt, ...
24#include "AST/Vector.hpp" // for vector
25#include "AST/GenericSubstitution.hpp" // for genericSubstitution
26#include "CodeGen/OperatorTable.h" // for isAssignment
27#include "Common/ScopedMap.h" // for ScopedMap
28#include "Common/UniqueName.h" // for UniqueName
29#include "Common/utility.h" // for toCString, group_iterate
30#include "GenPoly/FindFunction.h" // for findFunction
31#include "GenPoly/GenPoly.h" // for getFunctionType, ...
32#include "GenPoly/Lvalue.h" // for generalizedLvalue
33#include "GenPoly/ScopedSet.h" // for ScopedSet
34#include "GenPoly/ScrubTyVars.h" // for scrubTypeVars, scrubAllTypeVars
35#include "ResolvExpr/Unify.h" // for typesCompatible
36#include "SymTab/Mangler.h" // for mangle, mangleType
37
38namespace GenPoly {
39
40namespace {
41
42/// Common field of several sub-passes of box.
43struct BoxPass {
44 TypeVarMap scopeTypeVars;
45 BoxPass() : scopeTypeVars( ast::TypeData() ) {}
46};
47
48// TODO: Could this be a common helper somewhere?
49ast::FunctionType * makeFunctionType( ast::FunctionDecl const * decl ) {
50 ast::FunctionType * type = new ast::FunctionType(
51 decl->type->isVarArgs, decl->type->qualifiers
52 );
53 for ( auto type_param : decl->type_params ) {
54 type->forall.emplace_back( new ast::TypeInstType( type_param ) );
55 }
56 for ( auto assertion : decl->assertions ) {
57 type->assertions.emplace_back( new ast::VariableExpr(
58 assertion->location, assertion ) );
59 }
60 for ( auto param : decl->params ) {
61 type->params.emplace_back( param->get_type() );
62 }
63 for ( auto retval : decl->returns ) {
64 type->returns.emplace_back( retval->get_type() );
65 }
66 return type;
67}
68
69// --------------------------------------------------------------------------
70/// Adds layout-generation functions to polymorphic types.
71struct LayoutFunctionBuilder final :
72 public ast::WithDeclsToAdd<>,
73 public ast::WithShortCircuiting,
74 public ast::WithVisitorRef<LayoutFunctionBuilder> {
75 void previsit( ast::StructDecl const * decl );
76 void previsit( ast::UnionDecl const * decl );
77};
78
79/// Get all sized type declarations; those that affect a layout function.
80ast::vector<ast::TypeDecl> takeSizedParams(
81 ast::vector<ast::TypeDecl> const & decls ) {
82 ast::vector<ast::TypeDecl> sizedParams;
83 for ( ast::ptr<ast::TypeDecl> const & decl : decls ) {
84 if ( decl->isComplete() ) {
85 sizedParams.emplace_back( decl );
86 }
87 }
88 return sizedParams;
89}
90
91ast::BasicType * makeSizeAlignType() {
92 return new ast::BasicType( ast::BasicType::LongUnsignedInt );
93}
94
95/// Adds parameters for otype size and alignment to a function type.
96void addSTypeParams(
97 ast::vector<ast::DeclWithType> & params,
98 ast::vector<ast::TypeDecl> const & sizedParams ) {
99 for ( ast::ptr<ast::TypeDecl> const & sizedParam : sizedParams ) {
100 ast::TypeInstType inst( sizedParam );
101 std::string paramName = Mangle::mangleType( &inst );
102 params.emplace_back( new ast::ObjectDecl(
103 sizedParam->location,
104 sizeofName( paramName ),
105 makeSizeAlignType()
106 ) );
107 params.emplace_back( new ast::ObjectDecl(
108 sizedParam->location,
109 alignofName( paramName ),
110 makeSizeAlignType()
111 ) );
112 }
113}
114
115ast::Type * makeSizeAlignOutType() {
116 return new ast::PointerType( makeSizeAlignType() );
117}
118
119struct LayoutData {
120 ast::FunctionDecl * function;
121 ast::ObjectDecl * sizeofParam;
122 ast::ObjectDecl * alignofParam;
123 ast::ObjectDecl * offsetofParam;
124};
125
126LayoutData buildLayoutFunction(
127 CodeLocation const & location, ast::AggregateDecl const * aggr,
128 ast::vector<ast::TypeDecl> const & sizedParams,
129 bool isInFunction, bool isStruct ) {
130 ast::ObjectDecl * sizeParam = new ast::ObjectDecl(
131 location,
132 sizeofName( aggr->name ),
133 makeSizeAlignOutType()
134 );
135 ast::ObjectDecl * alignParam = new ast::ObjectDecl(
136 location,
137 alignofName( aggr->name ),
138 makeSizeAlignOutType()
139 );
140 ast::ObjectDecl * offsetParam = nullptr;
141 ast::vector<ast::DeclWithType> params = { sizeParam, alignParam };
142 if ( isStruct ) {
143 offsetParam = new ast::ObjectDecl(
144 location,
145 offsetofName( aggr->name ),
146 makeSizeAlignOutType()
147 );
148 params.push_back( offsetParam );
149 }
150 addSTypeParams( params, sizedParams );
151
152 // Routines at global scope marked "static" to prevent multiple
153 // definitions is separate translation units because each unit generates
154 // copies of the default routines for each aggregate.
155 ast::FunctionDecl * layoutDecl = new ast::FunctionDecl(
156 location,
157 layoutofName( aggr ),
158 {}, // forall
159 {}, // assertions
160 std::move( params ),
161 {}, // returns
162 new ast::CompoundStmt( location ),
163 isInFunction ? ast::Storage::Classes() : ast::Storage::Static,
164 ast::Linkage::AutoGen,
165 {}, // attrs
166 ast::Function::Inline,
167 ast::FixedArgs
168 );
169 layoutDecl->fixUniqueId();
170 return LayoutData{ layoutDecl, sizeParam, alignParam, offsetParam };
171}
172
173/// Makes a binary operation.
174ast::Expr * makeOp( CodeLocation const & location, std::string const & name,
175 ast::Expr const * lhs, ast::Expr const * rhs ) {
176 return new ast::UntypedExpr( location,
177 new ast::NameExpr( location, name ), { lhs, rhs } );
178}
179
180/// Make a binary operation and wrap it in a statement.
181ast::Stmt * makeOpStmt( CodeLocation const & location, std::string const & name,
182 ast::Expr const * lhs, ast::Expr const * rhs ) {
183 return new ast::ExprStmt( location, makeOp( location, name, lhs, rhs ) );
184}
185
186/// Returns the dereference of a local pointer variable.
187ast::Expr * derefVar(
188 CodeLocation const & location, ast::ObjectDecl const * var ) {
189 return ast::UntypedExpr::createDeref( location,
190 new ast::VariableExpr( location, var ) );
191}
192
193/// Makes an if-statement with a single-expression then and no else.
194ast::Stmt * makeCond( CodeLocation const & location,
195 ast::Expr const * cond, ast::Expr const * thenPart ) {
196 return new ast::IfStmt( location,
197 cond, new ast::ExprStmt( location, thenPart ), nullptr );
198}
199
200/// Makes a statement that aligns lhs to rhs (rhs should be an integer
201/// power of two).
202ast::Stmt * makeAlignTo( CodeLocation const & location,
203 ast::Expr const * lhs, ast::Expr const * rhs ) {
204 // Check that the lhs is zeroed out to the level of rhs.
205 ast::Expr * ifCond = makeOp( location, "?&?", lhs,
206 makeOp( location, "?-?", rhs,
207 ast::ConstantExpr::from_ulong( location, 1 ) ) );
208 // If not aligned, increment to alignment.
209 ast::Expr * ifExpr = makeOp( location, "?+=?", ast::deepCopy( lhs ),
210 makeOp( location, "?-?", ast::deepCopy( rhs ),
211 ast::deepCopy( ifCond ) ) );
212 return makeCond( location, ifCond, ifExpr );
213}
214
215/// Makes a statement that assigns rhs to lhs if lhs < rhs.
216ast::Stmt * makeAssignMax( CodeLocation const & location,
217 ast::Expr const * lhs, ast::Expr const * rhs ) {
218 return makeCond( location,
219 makeOp( location, "?<?", ast::deepCopy( lhs ), ast::deepCopy( rhs ) ),
220 makeOp( location, "?=?", lhs, rhs ) );
221}
222
223void LayoutFunctionBuilder::previsit( ast::StructDecl const * decl ) {
224 // Do not generate layout function for empty tag structures.
225 visit_children = false;
226 if ( decl->members.empty() ) return;
227
228 // Get parameters that can change layout, exiting early if none.
229 ast::vector<ast::TypeDecl> sizedParams =
230 takeSizedParams( decl->params );
231 if ( sizedParams.empty() ) return;
232
233 CodeLocation const & location = decl->location;
234
235 // Build layout function signature.
236 LayoutData layout = buildLayoutFunction(
237 location, decl, sizedParams, isInFunction(), true );
238 ast::FunctionDecl * layoutDecl = layout.function;
239 // Also return these or extract them from the parameter list?
240 ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
241 ast::ObjectDecl const * alignofParam = layout.alignofParam;
242 ast::ObjectDecl const * offsetofParam = layout.offsetofParam;
243 assert( nullptr != layout.offsetofParam );
244
245 // Calculate structure layout in function body.
246 // Initialize size and alignment to 0 and 1
247 // (Will have at least one member to update size).
248 auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
249 kids.emplace_back( makeOpStmt( location, "?=?",
250 derefVar( location, sizeofParam ),
251 ast::ConstantExpr::from_ulong( location, 0 )
252 ) );
253 kids.emplace_back( makeOpStmt( location, "?=?",
254 derefVar( location, alignofParam ),
255 ast::ConstantExpr::from_ulong( location, 1 )
256 ) );
257 // TODO: Polymorphic types will be out of the struct declaration scope.
258 // Should be removed by PolyGenericCalculator.
259 for ( auto const & member : enumerate( decl->members ) ) {
260 auto dwt = member.val.strict_as<ast::DeclWithType>();
261 ast::Type const * memberType = dwt->get_type();
262
263 if ( 0 < member.idx ) {
264 // Make sure all later members have padding to align them.
265 kids.emplace_back( makeAlignTo( location,
266 derefVar( location, sizeofParam ),
267 new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
268 ) );
269 }
270
271 // Place current size in the current offset index.
272 kids.emplace_back( makeOpStmt( location, "?=?",
273 makeOp( location, "?[?]",
274 new ast::VariableExpr( location, offsetofParam ),
275 ast::ConstantExpr::from_ulong( location, member.idx ) ),
276 derefVar( location, sizeofParam ) ) );
277
278 // Add member size to current size.
279 kids.emplace_back( makeOpStmt( location, "?+=?",
280 derefVar( location, sizeofParam ),
281 new ast::SizeofExpr( location, ast::deepCopy( memberType ) ) ) );
282
283 // Take max of member alignment and global alignment.
284 // (As align is always 2^n, this will always be a multiple of both.)
285 kids.emplace_back( makeAssignMax( location,
286 derefVar( location, alignofParam ),
287 new ast::AlignofExpr( location, ast::deepCopy( memberType ) ) ) );
288 }
289 // Make sure the type is end-padded to a multiple of its alignment.
290 kids.emplace_back( makeAlignTo( location,
291 derefVar( location, sizeofParam ),
292 derefVar( location, alignofParam ) ) );
293
294 declsToAddAfter.emplace_back( layoutDecl );
295}
296
297void LayoutFunctionBuilder::previsit( ast::UnionDecl const * decl ) {
298 visit_children = false;
299 // Do not generate layout function for empty tag unions.
300 if ( decl->members.empty() ) return;
301
302 // Get parameters that can change layout, exiting early if none.
303 ast::vector<ast::TypeDecl> sizedParams =
304 takeSizedParams( decl->params );
305 if ( sizedParams.empty() ) return;
306
307 CodeLocation const & location = decl->location;
308
309 // Build layout function signature.
310 LayoutData layout = buildLayoutFunction(
311 location, decl, sizedParams, isInFunction(), false );
312 ast::FunctionDecl * layoutDecl = layout.function;
313 // Also return these or extract them from the parameter list?
314 ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
315 ast::ObjectDecl const * alignofParam = layout.alignofParam;
316 assert( nullptr == layout.offsetofParam );
317
318 // Calculate union layout in function body.
319 // Both are simply the maximum for union (actually align is always the
320 // LCM, but with powers of two that is also the maximum).
321 auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
322 kids.emplace_back( makeOpStmt( location,
323 "?=?", derefVar( location, sizeofParam ),
324 ast::ConstantExpr::from_ulong( location, 1 )
325 ) );
326 kids.emplace_back( makeOpStmt( location,
327 "?=?", derefVar( location, alignofParam ),
328 ast::ConstantExpr::from_ulong( location, 1 )
329 ) );
330 // TODO: Polymorphic types will be out of the union declaration scope.
331 for ( auto const & member : decl->members ) {
332 auto dwt = member.strict_as<ast::DeclWithType>();
333 ast::Type const * memberType = dwt->get_type();
334
335 // Take max member size and global size.
336 kids.emplace_back( makeAssignMax( location,
337 derefVar( location, sizeofParam ),
338 new ast::SizeofExpr( location, ast::deepCopy( memberType ) )
339 ) );
340
341 // Take max of member alignment and global alignment.
342 kids.emplace_back( makeAssignMax( location,
343 derefVar( location, alignofParam ),
344 new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
345 ) );
346 }
347 kids.emplace_back( makeAlignTo( location,
348 derefVar( location, sizeofParam ),
349 derefVar( location, alignofParam ) ) );
350
351 declsToAddAfter.emplace_back( layoutDecl );
352}
353
354// --------------------------------------------------------------------------
355/// Application expression transformer.
356/// * Replaces polymorphic return types with out-parameters.
357/// * Replaces call to polymorphic functions with adapter calls which handles
358/// dynamic arguments and return values.
359/// * Adds appropriate type variables to the function calls.
360struct CallAdapter final :
361 public BoxPass,
362 public ast::WithConstTypeSubstitution,
363 public ast::WithGuards,
364 public ast::WithShortCircuiting,
365 public ast::WithStmtsToAdd<>,
366 public ast::WithVisitorRef<CallAdapter> {
367 CallAdapter();
368
369 void previsit( ast::Decl const * decl );
370 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
371 void previsit( ast::TypeDecl const * decl );
372 void previsit( ast::CommaExpr const * expr );
373 ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
374 ast::Expr const * postvisit( ast::UntypedExpr const * expr );
375 void previsit( ast::AddressExpr const * expr );
376 ast::Expr const * postvisit( ast::AddressExpr const * expr );
377 ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt );
378 void previsit( ast::PointerType const * type );
379 void previsit( ast::FunctionType const * type );
380
381 void beginScope();
382 void endScope();
383private:
384 // Many helpers here use a mutable ApplicationExpr as an in/out parameter
385 // instead of using the return value, to save on mutates and free up the
386 // return value.
387
388 /// Passes extra layout arguments for sized polymorphic type parameters.
389 ast::vector<ast::Expr>::iterator passTypeVars(
390 ast::ApplicationExpr * expr,
391 ast::FunctionType const * funcType );
392 /// Wraps a function application with a new temporary for the
393 /// out-parameter return value.
394 ast::Expr const * addRetParam(
395 ast::ApplicationExpr * expr, ast::Type const * retType );
396 /// Wraps a function application returning a polymorphic type with a new
397 /// temporary for the out-parameter return value.
398 ast::Expr const * addDynRetParam(
399 ast::ApplicationExpr * expr, ast::Type const * polyType );
400 /// Modify a call so it passes the function through the correct adapter.
401 ast::Expr const * applyAdapter(
402 ast::ApplicationExpr * expr,
403 ast::FunctionType const * function );
404 /// Convert a single argument into its boxed form to pass the parameter.
405 void boxParam( ast::ptr<ast::Expr> & arg,
406 ast::Type const * formal, TypeVarMap const & exprTyVars );
407 /// Box every argument from arg forward, matching the functionType
408 /// parameter list. arg should point into expr's argument list.
409 void boxParams(
410 ast::ApplicationExpr const * expr,
411 ast::vector<ast::Expr>::iterator arg,
412 ast::FunctionType const * function,
413 const TypeVarMap & typeVars );
414 /// Adds the inferred parameters derived from the assertions of the
415 /// expression to the call.
416 void addInferredParams(
417 ast::ApplicationExpr * expr,
418 ast::vector<ast::Expr>::iterator arg,
419 ast::FunctionType const * functionType,
420 const TypeVarMap & typeVars );
421 /// Stores assignment operators from assertion list in
422 /// local map of assignment operations.
423 void passAdapters(
424 ast::ApplicationExpr * expr,
425 ast::FunctionType const * type,
426 const TypeVarMap & typeVars );
427 /// Create an adapter function based on the type of the adaptee and the
428 /// real type with the type substitutions applied.
429 ast::FunctionDecl * makeAdapter(
430 ast::FunctionType const * adaptee,
431 ast::FunctionType const * realType,
432 std::string const & mangleName,
433 TypeVarMap const & typeVars,
434 CodeLocation const & location ) const;
435 /// Replaces intrinsic operator functions with their arithmetic desugaring.
436 ast::Expr const * handleIntrinsics( ast::ApplicationExpr const * );
437 /// Inserts a new temporary variable into the current scope with an
438 /// auto-generated name.
439 ast::ObjectDecl * makeTemporary(
440 CodeLocation const & location, ast::Type const * type );
441
442 /// Set of adapter functions in the current scope.
443 ScopedMap< std::string, ast::DeclWithType const * > adapters;
444 std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals;
445 ast::DeclWithType const * retval;
446 UniqueName tmpNamer;
447};
448
449/// Replaces a polymorphic type with its concrete equivalant under the
450/// current environment (returns itself if concrete).
451/// If `doClone` is set to false, will not clone interior types
452ast::Type const * replaceWithConcrete(
453 ast::Type const * type,
454 ast::TypeSubstitution const & typeSubs,
455 bool doCopy = true );
456
457/// Replaces all the type parameters of a generic type with their
458/// concrete equivalents under the current environment.
459void replaceParametersWithConcrete(
460 ast::vector<ast::Expr> & params,
461 ast::TypeSubstitution const & typeSubs ) {
462 for ( ast::ptr<ast::Expr> & paramExpr : params ) {
463 ast::TypeExpr const * param = paramExpr.as<ast::TypeExpr>();
464 assertf( param, "Aggregate parameters should be type expressions." );
465 paramExpr = ast::mutate_field( param, &ast::TypeExpr::type,
466 replaceWithConcrete( param->type.get(), typeSubs, false ) );
467 }
468}
469
470ast::Type const * replaceWithConcrete(
471 ast::Type const * type,
472 ast::TypeSubstitution const & typeSubs,
473 bool doCopy ) {
474 if ( auto instType = dynamic_cast<ast::TypeInstType const *>( type ) ) {
475 ast::Type const * concrete = typeSubs.lookup( instType );
476 return ( nullptr != concrete ) ? concrete : instType;
477 } else if ( auto structType =
478 dynamic_cast<ast::StructInstType const *>( type ) ) {
479 ast::StructInstType * newType =
480 doCopy ? ast::deepCopy( structType ) : ast::mutate( structType );
481 replaceParametersWithConcrete( newType->params, typeSubs );
482 return newType;
483 } else if ( auto unionType =
484 dynamic_cast<ast::UnionInstType const *>( type ) ) {
485 ast::UnionInstType * newType =
486 doCopy ? ast::deepCopy( unionType ) : ast::mutate( unionType );
487 replaceParametersWithConcrete( newType->params, typeSubs );
488 return newType;
489 } else {
490 return type;
491 }
492}
493
494std::string makePolyMonoSuffix(
495 ast::FunctionType const * function,
496 TypeVarMap const & typeVars ) {
497 // If the return type or a parameter type involved polymorphic types,
498 // then the adapter will need to take those polymorphic types as pointers.
499 // Therefore, there can be two different functions with the same mangled
500 // name, so we need to further mangle the names.
501 std::stringstream name;
502 for ( auto ret : function->returns ) {
503 name << ( isPolyType( ret, typeVars ) ? 'P' : 'M' );
504 }
505 name << '_';
506 for ( auto arg : function->params ) {
507 name << ( isPolyType( arg, typeVars ) ? 'P' : 'M' );
508 }
509 return name.str();
510}
511
512std::string mangleAdapterName(
513 ast::FunctionType const * function,
514 TypeVarMap const & typeVars ) {
515 return Mangle::mangle( function, {} )
516 + makePolyMonoSuffix( function, typeVars );
517}
518
519std::string makeAdapterName( std::string const & mangleName ) {
520 return "_adapter" + mangleName;
521}
522
523void makeRetParam( ast::FunctionType * type ) {
524 ast::ptr<ast::Type> & retParam = type->returns.front();
525
526 // Make a new parameter that is a pointer to the type of the old return value.
527 retParam = new ast::PointerType( retParam.get() );
528 type->params.emplace( type->params.begin(), retParam );
529
530 // We don't need the return value any more.
531 type->returns.clear();
532}
533
534ast::FunctionType * makeAdapterType(
535 ast::FunctionType const * adaptee,
536 TypeVarMap const & typeVars ) {
537 ast::FunctionType * adapter = ast::deepCopy( adaptee );
538 if ( isDynRet( adapter, typeVars ) ) {
539 makeRetParam( adapter );
540 }
541 adapter->params.emplace( adapter->params.begin(),
542 new ast::PointerType( new ast::FunctionType( ast::VariableArgs ) )
543 );
544 return adapter;
545}
546
547CallAdapter::CallAdapter() : tmpNamer( "_temp" ) {}
548
549void CallAdapter::previsit( ast::Decl const * ) {
550 // Prevent type declaration information from leaking out.
551 GuardScope( scopeTypeVars );
552}
553
554ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) {
555 if ( nullptr == decl->stmts ) {
556 // This may keep TypeDecls we don't ever want from sneaking in.
557 // Not visiting child nodes might just be faster.
558 GuardScope( scopeTypeVars );
559 return decl;
560 }
561
562 GuardScope( scopeTypeVars );
563 GuardValue( retval );
564
565 // Process polymorphic return value.
566 retval = nullptr;
567 ast::FunctionType const * type = decl->type;
568 if ( isDynRet( type ) && decl->linkage != ast::Linkage::C ) {
569 retval = decl->returns.front();
570
571 // Give names to unnamed return values.
572 if ( "" == retval->name ) {
573 auto mutRet = ast::mutate( retval );
574 mutRet->name = "_retparam";
575 mutRet->linkage = ast::Linkage::C;
576 retval = mutRet;
577 decl = ast::mutate_field_index( decl,
578 &ast::FunctionDecl::returns, 0, mutRet );
579 }
580 }
581
582 // The formal_usage/expr_id values may be off if we get them from the
583 // type, trying the declaration instead.
584 makeTypeVarMap( type, scopeTypeVars );
585
586 // Get all needed adapters from the call. We will forward them.
587 ast::vector<ast::FunctionType> functions;
588 for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
589 auto atype = assertion->result.get();
590 findFunction( atype, functions, scopeTypeVars, needsAdapter );
591 }
592
593 for ( ast::ptr<ast::Type> const & arg : type->params ) {
594 findFunction( arg, functions, scopeTypeVars, needsAdapter );
595 }
596
597 for ( auto funcType : functions ) {
598 std::string mangleName = mangleAdapterName( funcType, scopeTypeVars );
599 if ( adapters.contains( mangleName ) ) continue;
600 std::string adapterName = makeAdapterName( mangleName );
601 // TODO: The forwarding here is problematic because these
602 // declarations are not rooted anywhere in the translation unit.
603 adapters.insert(
604 mangleName,
605 new ast::ObjectDecl(
606 decl->location,
607 adapterName,
608 new ast::PointerType(
609 makeAdapterType( funcType, scopeTypeVars ) ),
610 nullptr, // init
611 ast::Storage::Classes(),
612 ast::Linkage::C
613 )
614 );
615 }
616
617 return decl;
618}
619
620void CallAdapter::previsit( ast::TypeDecl const * decl ) {
621 addToTypeVarMap( decl, scopeTypeVars );
622}
623
624void CallAdapter::previsit( ast::CommaExpr const * expr ) {
625 // Attempting to find application expressions that were mutated by the
626 // copy constructor passes to use an explicit return variable, so that
627 // the variable can be reused as a parameter to the call rather than
628 // creating a new temporary variable. Previously this step was an
629 // optimization, but with the introduction of tuples and UniqueExprs,
630 // it is necessary to ensure that they use the same variable.
631 // Essentially, looking for pattern:
632 // (x=f(...), x)
633 // To compound the issue, the right side can be *x, etc.
634 // because of lvalue-returning functions
635 if ( auto assign = expr->arg1.as<ast::UntypedExpr>() ) {
636 if ( CodeGen::isAssignment( ast::getFunctionName( assign ) ) ) {
637 assert( 2 == assign->args.size() );
638 if ( auto app = assign->args.back().as<ast::ApplicationExpr>() ) {
639 // First argument is assignable, so it must be an lvalue,
640 // so it should be legal to takes its address.
641 retVals.insert_or_assign( app, assign->args.front() );
642 }
643 }
644 }
645}
646
647ast::Expr const * CallAdapter::postvisit( ast::ApplicationExpr const * expr ) {
648 assert( expr->func->result );
649 ast::FunctionType const * function = getFunctionType( expr->func->result );
650 assertf( function, "ApplicationExpr has non-function type %s",
651 toCString( expr->func->result ) );
652
653 if ( auto newExpr = handleIntrinsics( expr ) ) {
654 return newExpr;
655 }
656
657 ast::ApplicationExpr * mutExpr = ast::mutate( expr );
658 ast::Expr const * ret = expr;
659
660 // TODO: This entire section should probably be refactored to do less
661 // pushing to the front/middle of a vector.
662 ptrdiff_t initArgCount = mutExpr->args.size();
663
664 TypeVarMap exprTypeVars = { ast::TypeData() };
665 // TODO: Should this take into account the variables already bound in
666 // scopeTypeVars ([ex] remove them from exprTypeVars)?
667 makeTypeVarMap( function, exprTypeVars );
668 auto dynRetType = isDynRet( function, exprTypeVars );
669
670 // NOTE: addDynRetParam needs to know the actual (generated) return type
671 // so it can make a temporary variable, so pass the result type form the
672 // `expr` `passTypeVars` needs to know the program-text return type ([ex]
673 // the distinction between _conc_T30 and T3(int)) concRetType may not be
674 // a good name in one or both of these places.
675 if ( dynRetType ) {
676 ast::Type const * result = mutExpr->result;
677 ast::Type const * concRetType = result->isVoid() ? nullptr : result;
678 // [Comment from before translation.]
679 // Used to use dynRetType instead of concRetType.
680 ret = addDynRetParam( mutExpr, concRetType );
681 } else if ( needsAdapter( function, scopeTypeVars )
682 && !needsAdapter( function, exprTypeVars ) ) {
683 // Change the application so it calls the adapter rather than the
684 // passed function.
685 ret = applyAdapter( mutExpr, function );
686 }
687
688 assert( typeSubs );
689 ast::Type const * concRetType = replaceWithConcrete( dynRetType, *typeSubs );
690 // Used to use dynRetType instead of concRetType; this changed so that
691 // the correct type parameters are passed for return types (it should be
692 // the concrete type's parameters, not the formal type's).
693 ast::vector<ast::Expr>::iterator argIt =
694 passTypeVars( mutExpr, function );
695 addInferredParams( mutExpr, argIt, function, exprTypeVars );
696
697 argIt = mutExpr->args.begin();
698 std::advance( argIt, ( mutExpr->args.size() - initArgCount ) );
699
700 boxParams( mutExpr, argIt, function, exprTypeVars );
701 passAdapters( mutExpr, function, exprTypeVars );
702
703 return ret;
704}
705
706bool isPolyDeref( ast::UntypedExpr const * expr,
707 TypeVarMap const & typeVars,
708 ast::TypeSubstitution const * typeSubs ) {
709 if ( expr->result && isPolyType( expr->result, typeVars, typeSubs ) ) {
710 if ( auto name = expr->func.as<ast::NameExpr>() ) {
711 if ( "*?" == name->name ) {
712 return true;
713 }
714 }
715 }
716 return false;
717}
718
719ast::Expr const * CallAdapter::postvisit( ast::UntypedExpr const * expr ) {
720 if ( isPolyDeref( expr, scopeTypeVars, typeSubs ) ) {
721 return expr->args.front();
722 }
723 return expr;
724}
725
726void CallAdapter::previsit( ast::AddressExpr const * ) {
727 visit_children = false;
728}
729
730ast::Expr const * CallAdapter::postvisit( ast::AddressExpr const * expr ) {
731 assert( expr->arg->result );
732 assert( !expr->arg->result->isVoid() );
733
734 bool doesNeedAdapter = false;
735 if ( auto un = expr->arg.as<ast::UntypedExpr>() ) {
736 if ( isPolyDeref( un, scopeTypeVars, typeSubs ) ) {
737 if ( auto app = un->args.front().as<ast::ApplicationExpr>() ) {
738 assert( app->func->result );
739 auto function = getFunctionType( app->func->result );
740 assert( function );
741 doesNeedAdapter = needsAdapter( function, scopeTypeVars );
742 }
743 }
744 }
745 // isPolyType check needs to happen before mutating expr arg,
746 // so pull it forward out of the if condition.
747 expr = ast::mutate_field( expr, &ast::AddressExpr::arg,
748 expr->arg->accept( *visitor ) );
749 // But must happen after mutate, since argument might change
750 // (ex. intrinsic *?, ?[?]) re-evaluate above comment.
751 bool polyType = isPolyType( expr->arg->result, scopeTypeVars, typeSubs );
752 if ( polyType || doesNeedAdapter ) {
753 ast::Expr * ret = ast::mutate( expr->arg.get() );
754 ret->result = ast::deepCopy( expr->result );
755 return ret;
756 } else {
757 return expr;
758 }
759}
760
761ast::ReturnStmt const * CallAdapter::previsit( ast::ReturnStmt const * stmt ) {
762 // Since retval is set when the return type is dynamic, this function
763 // should have been converted to void return & out parameter.
764 if ( retval && stmt->expr ) {
765 assert( stmt->expr->result );
766 assert( !stmt->expr->result->isVoid() );
767 return ast::mutate_field( stmt, &ast::ReturnStmt::expr, nullptr );
768 }
769 return stmt;
770}
771
772void CallAdapter::previsit( ast::PointerType const * type ) {
773 GuardScope( scopeTypeVars );
774 makeTypeVarMap( type, scopeTypeVars );
775}
776
777void CallAdapter::previsit( ast::FunctionType const * type ) {
778 GuardScope( scopeTypeVars );
779 makeTypeVarMap( type, scopeTypeVars );
780}
781
782void CallAdapter::beginScope() {
783 adapters.beginScope();
784}
785
786void CallAdapter::endScope() {
787 adapters.endScope();
788}
789
790/// Find instances of polymorphic type parameters.
791struct PolyFinder {
792 TypeVarMap const & typeVars;
793 bool result = false;
794 PolyFinder( TypeVarMap const & tvs ) : typeVars( tvs ) {}
795
796 void previsit( ast::TypeInstType const * type ) {
797 if ( isPolyType( type, typeVars ) ) result = true;
798 }
799};
800
801/// True if these is an instance of a polymorphic type parameter in the type.
802bool hasPolymorphism( ast::Type const * type, TypeVarMap const & typeVars ) {
803 return ast::Pass<PolyFinder>::read( type, typeVars );
804}
805
806ast::vector<ast::Expr>::iterator CallAdapter::passTypeVars(
807 ast::ApplicationExpr * expr,
808 ast::FunctionType const * function ) {
809 assert( typeSubs );
810 ast::vector<ast::Expr>::iterator arg = expr->args.begin();
811 // Pass size/align for type variables.
812 for ( ast::ptr<ast::TypeInstType> const & typeVar : function->forall ) {
813 if ( !typeVar->base->isComplete() ) continue;
814 ast::Type const * concrete = typeSubs->lookup( typeVar );
815 if ( !concrete ) {
816 // Should this be an assertion?
817 SemanticError( expr, toString( typeSubs,
818 "\nunbound type variable: ", typeVar->typeString(),
819 " in application " ) );
820 }
821 arg = expr->args.insert( arg,
822 new ast::SizeofExpr( expr->location, ast::deepCopy( concrete ) ) );
823 arg++;
824 arg = expr->args.insert( arg,
825 new ast::AlignofExpr( expr->location, ast::deepCopy( concrete ) ) );
826 arg++;
827 }
828 return arg;
829}
830
831ast::Expr const * CallAdapter::addRetParam(
832 ast::ApplicationExpr * expr, ast::Type const * retType ) {
833 // Create temporary to hold return value of polymorphic function and
834 // produce that temporary as a result using a comma expression.
835 assert( retType );
836
837 ast::Expr * paramExpr = nullptr;
838 // Try to use existing return value parameter if it exists,
839 // otherwise create a new temporary.
840 if ( retVals.count( expr ) ) {
841 paramExpr = ast::deepCopy( retVals[ expr ] );
842 } else {
843 auto newObj = makeTemporary( expr->location, ast::deepCopy( retType ) );
844 paramExpr = new ast::VariableExpr( expr->location, newObj );
845 }
846 ast::Expr * retExpr = ast::deepCopy( paramExpr );
847
848 // If the type of the temporary is not polpmorphic, box temporary by
849 // taking its address; otherwise the temporary is already boxed and can
850 // be used directly.
851 if ( !isPolyType( paramExpr->result, scopeTypeVars, typeSubs ) ) {
852 paramExpr = new ast::AddressExpr( paramExpr->location, paramExpr );
853 }
854 // Add argument to function call.
855 expr->args.insert( expr->args.begin(), paramExpr );
856 // Build a comma expression to call the function and return a value.
857 ast::CommaExpr * comma = new ast::CommaExpr(
858 expr->location, expr, retExpr );
859 comma->env = expr->env;
860 expr->env = nullptr;
861 return comma;
862}
863
864ast::Expr const * CallAdapter::addDynRetParam(
865 ast::ApplicationExpr * expr, ast::Type const * polyType ) {
866 assert( typeSubs );
867 ast::Type const * concrete = replaceWithConcrete( polyType, *typeSubs );
868 // Add out-parameter for return value.
869 return addRetParam( expr, concrete );
870}
871
872ast::Expr const * CallAdapter::applyAdapter(
873 ast::ApplicationExpr * expr,
874 ast::FunctionType const * function ) {
875 ast::Expr const * ret = expr;
876 if ( isDynRet( function, scopeTypeVars ) ) {
877 ret = addRetParam( expr, function->returns.front() );
878 }
879 std::string mangleName = mangleAdapterName( function, scopeTypeVars );
880 std::string adapterName = makeAdapterName( mangleName );
881
882 // Cast adaptee to `void (*)()`, since it may have any type inside a
883 // polymorphic function.
884 ast::Type const * adapteeType = new ast::PointerType(
885 new ast::FunctionType( ast::VariableArgs ) );
886 expr->args.insert( expr->args.begin(),
887 new ast::CastExpr( expr->location, expr->func, adapteeType ) );
888 // The result field is never set on NameExpr. / Now it is.
889 auto head = new ast::NameExpr( expr->location, adapterName );
890 head->result = ast::deepCopy( adapteeType );
891 expr->func = head;
892
893 return ret;
894}
895
896/// Cast parameters to polymorphic functions so that types are replaced with
897/// `void *` if they are type parameters in the formal type.
898/// This gets rid of warnings from gcc.
899void addCast(
900 ast::ptr<ast::Expr> & actual,
901 ast::Type const * formal,
902 TypeVarMap const & typeVars ) {
903 // Type contains polymorphism, but isn't exactly a polytype, in which
904 // case it has some real actual type (ex. unsigned int) and casting to
905 // `void *` is wrong.
906 if ( hasPolymorphism( formal, typeVars )
907 && !isPolyType( formal, typeVars ) ) {
908 ast::Type const * newType = ast::deepCopy( formal );
909 newType = scrubTypeVars( newType, typeVars );
910 actual = new ast::CastExpr( actual->location, actual, newType );
911 }
912}
913
914void CallAdapter::boxParam( ast::ptr<ast::Expr> & arg,
915 ast::Type const * param, TypeVarMap const & exprTypeVars ) {
916 assertf( arg->result, "arg does not have result: %s", toCString( arg ) );
917 addCast( arg, param, exprTypeVars );
918 if ( !needsBoxing( param, arg->result, exprTypeVars, typeSubs ) ) {
919 return;
920 }
921 CodeLocation const & location = arg->location;
922
923 if ( arg->get_lvalue() ) {
924 // The argument expression may be CFA lvalue, but not C lvalue,
925 // so apply generalizedLvalue transformations.
926 // if ( auto var = dynamic_cast<ast::VariableExpr const *>( arg ) ) {
927 // if ( dynamic_cast<ast::ArrayType const *>( varExpr->var->get_type() ) ){
928 // // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
929 // return;
930 // }
931 // }
932 arg = generalizedLvalue( new ast::AddressExpr( arg->location, arg ) );
933 if ( !ResolvExpr::typesCompatible( param, arg->result ) ) {
934 // Silence warnings by casting boxed parameters when the actually
935 // type does not match up with the formal type.
936 arg = new ast::CastExpr( location, arg, ast::deepCopy( param ) );
937 }
938 } else {
939 // Use type computed in unification to declare boxed variables.
940 ast::ptr<ast::Type> newType = ast::deepCopy( param );
941 if ( typeSubs ) typeSubs->apply( newType );
942 ast::ObjectDecl * newObj = makeTemporary( location, newType );
943 auto assign = ast::UntypedExpr::createCall( location, "?=?", {
944 new ast::VariableExpr( location, newObj ),
945 arg,
946 } );
947 stmtsToAddBefore.push_back( new ast::ExprStmt( location, assign ) );
948 arg = new ast::AddressExpr(
949 new ast::VariableExpr( location, newObj ) );
950 }
951}
952
953void CallAdapter::boxParams(
954 ast::ApplicationExpr const * expr,
955 ast::vector<ast::Expr>::iterator arg,
956 ast::FunctionType const * function,
957 const TypeVarMap & typeVars ) {
958 for ( auto param : function->params ) {
959 assertf( arg != expr->args.end(),
960 "boxParams: missing argument for param %s to %s in %s",
961 toCString( param ), toCString( function ), toCString( expr ) );
962 boxParam( *arg, param, typeVars );
963 ++arg;
964 }
965}
966
967void CallAdapter::addInferredParams(
968 ast::ApplicationExpr * expr,
969 ast::vector<ast::Expr>::iterator arg,
970 ast::FunctionType const * functionType,
971 TypeVarMap const & typeVars ) {
972 ast::vector<ast::Expr>::iterator cur = arg;
973 for ( auto assertion : functionType->assertions ) {
974 auto inferParam = expr->inferred.inferParams().find(
975 assertion->var->uniqueId );
976 assertf( inferParam != expr->inferred.inferParams().end(),
977 "addInferredParams missing inferred parameter: %s in: %s",
978 toCString( assertion ), toCString( expr ) );
979 ast::ptr<ast::Expr> newExpr = ast::deepCopy( inferParam->second.expr );
980 boxParam( newExpr, assertion->result, typeVars );
981 cur = expr->args.insert( cur, newExpr.release() );
982 ++cur;
983 }
984}
985
986/// Modifies the ApplicationExpr to accept adapter functions for its
987/// assertion and parameters, declares the required adapters.
988void CallAdapter::passAdapters(
989 ast::ApplicationExpr * expr,
990 ast::FunctionType const * type,
991 const TypeVarMap & exprTypeVars ) {
992 // Collect a list of function types passed as parameters or implicit
993 // parameters (assertions).
994 ast::vector<ast::Type> const & paramList = type->params;
995 ast::vector<ast::FunctionType> functions;
996
997 for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
998 findFunction( assertion->result, functions, exprTypeVars, needsAdapter );
999 }
1000 for ( ast::ptr<ast::Type> const & arg : paramList ) {
1001 findFunction( arg, functions, exprTypeVars, needsAdapter );
1002 }
1003
1004 // Parameter function types for which an appropriate adapter has been
1005 // generated. We cannot use the types after applying substitutions,
1006 // since two different parameter types may be unified to the same type.
1007 std::set<std::string> adaptersDone;
1008
1009 CodeLocation const & location = expr->location;
1010
1011 for ( ast::ptr<ast::FunctionType> const & funcType : functions ) {
1012 std::string mangleName = Mangle::mangle( funcType );
1013
1014 // Only attempt to create an adapter or pass one as a parameter if we
1015 // haven't already done so for this pre-substitution parameter
1016 // function type.
1017 // The second part of the result if is if the element was inserted.
1018 if ( !adaptersDone.insert( mangleName ).second ) continue;
1019
1020 // Apply substitution to type variables to figure out what the
1021 // adapter's type should look like. (Copy to make the release safe.)
1022 assert( typeSubs );
1023 auto result = typeSubs->apply( ast::deepCopy( funcType ) );
1024 ast::FunctionType * realType = ast::mutate( result.node.release() );
1025 mangleName = Mangle::mangle( realType );
1026 mangleName += makePolyMonoSuffix( funcType, exprTypeVars );
1027
1028 // Check if the adapter has already been created, or has to be.
1029 using AdapterIter = decltype(adapters)::iterator;
1030 AdapterIter adapter = adapters.find( mangleName );
1031 if ( adapter == adapters.end() ) {
1032 ast::FunctionDecl * newAdapter = makeAdapter(
1033 funcType, realType, mangleName, exprTypeVars, location );
1034 std::pair<AdapterIter, bool> answer =
1035 adapters.insert( mangleName, newAdapter );
1036 adapter = answer.first;
1037 stmtsToAddBefore.push_back(
1038 new ast::DeclStmt( location, newAdapter ) );
1039 }
1040 assert( adapter != adapters.end() );
1041
1042 // Add the approprate adapter as a parameter.
1043 expr->args.insert( expr->args.begin(),
1044 new ast::VariableExpr( location, adapter->second ) );
1045 }
1046}
1047
1048// Parameter and argument may be used wrong around here.
1049ast::Expr * makeAdapterArg(
1050 ast::DeclWithType const * param,
1051 ast::Type const * arg,
1052 ast::Type const * realParam,
1053 TypeVarMap const & typeVars,
1054 CodeLocation const & location ) {
1055 assert( param );
1056 assert( arg );
1057 assert( realParam );
1058 if ( isPolyType( realParam, typeVars ) && !isPolyType( arg ) ) {
1059 ast::UntypedExpr * deref = ast::UntypedExpr::createDeref(
1060 location,
1061 new ast::CastExpr( location,
1062 new ast::VariableExpr( location, param ),
1063 new ast::PointerType( ast::deepCopy( arg ) )
1064 )
1065 );
1066 deref->result = ast::deepCopy( arg );
1067 return deref;
1068 }
1069 return new ast::VariableExpr( location, param );
1070}
1071
1072// This seems to be one of the problematic functions.
1073void addAdapterParams(
1074 ast::ApplicationExpr * adaptee,
1075 ast::vector<ast::Type>::const_iterator arg,
1076 ast::vector<ast::DeclWithType>::iterator param,
1077 ast::vector<ast::DeclWithType>::iterator paramEnd,
1078 ast::vector<ast::Type>::const_iterator realParam,
1079 TypeVarMap const & typeVars,
1080 CodeLocation const & location ) {
1081 UniqueName paramNamer( "_p" );
1082 for ( ; param != paramEnd ; ++param, ++arg, ++realParam ) {
1083 if ( "" == (*param)->name ) {
1084 auto mutParam = (*param).get_and_mutate();
1085 mutParam->name = paramNamer.newName();
1086 mutParam->linkage = ast::Linkage::C;
1087 }
1088 adaptee->args.push_back(
1089 makeAdapterArg( *param, *arg, *realParam, typeVars, location ) );
1090 }
1091}
1092
1093ast::FunctionDecl * CallAdapter::makeAdapter(
1094 ast::FunctionType const * adaptee,
1095 ast::FunctionType const * realType,
1096 std::string const & mangleName,
1097 TypeVarMap const & typeVars,
1098 CodeLocation const & location ) const {
1099 ast::FunctionType * adapterType = makeAdapterType( adaptee, typeVars );
1100 adapterType = ast::mutate( scrubTypeVars( adapterType, typeVars ) );
1101
1102 // Some of these names will be overwritten, but it gives a default.
1103 UniqueName pNamer( "_param" );
1104 UniqueName rNamer( "_ret" );
1105
1106 bool first = true;
1107
1108 ast::FunctionDecl * adapterDecl = new ast::FunctionDecl( location,
1109 makeAdapterName( mangleName ),
1110 {}, // forall
1111 {}, // assertions
1112 map_range<ast::vector<ast::DeclWithType>>( adapterType->params,
1113 [&pNamer, &location, &first]( ast::ptr<ast::Type> const & param ) {
1114 // [Trying to make the generated code match exactly more often.]
1115 if ( first ) {
1116 first = false;
1117 return new ast::ObjectDecl( location, "_adaptee", param );
1118 }
1119 return new ast::ObjectDecl( location, pNamer.newName(), param );
1120 } ),
1121 map_range<ast::vector<ast::DeclWithType>>( adapterType->returns,
1122 [&rNamer, &location]( ast::ptr<ast::Type> const & retval ) {
1123 return new ast::ObjectDecl( location, rNamer.newName(), retval );
1124 } ),
1125 nullptr, // stmts
1126 {}, // storage
1127 ast::Linkage::C
1128 );
1129
1130 ast::DeclWithType * adapteeDecl =
1131 adapterDecl->params.front().get_and_mutate();
1132 adapteeDecl->name = "_adaptee";
1133
1134 // Do not carry over attributes to real type parameters/return values.
1135 auto mutRealType = ast::mutate( realType );
1136 for ( ast::ptr<ast::Type> & decl : mutRealType->params ) {
1137 if ( decl->attributes.empty() ) continue;
1138 auto mut = ast::mutate( decl.get() );
1139 mut->attributes.clear();
1140 decl = mut;
1141 }
1142 for ( ast::ptr<ast::Type> & decl : mutRealType->returns ) {
1143 if ( decl->attributes.empty() ) continue;
1144 auto mut = ast::mutate( decl.get() );
1145 mut->attributes.clear();
1146 decl = mut;
1147 }
1148 realType = mutRealType;
1149
1150 ast::ApplicationExpr * adapteeApp = new ast::ApplicationExpr( location,
1151 new ast::CastExpr( location,
1152 new ast::VariableExpr( location, adapteeDecl ),
1153 new ast::PointerType( realType )
1154 )
1155 );
1156
1157 for ( auto group : group_iterate( realType->assertions,
1158 adapterType->assertions, adaptee->assertions ) ) {
1159 auto assertArg = std::get<0>( group );
1160 auto assertParam = std::get<1>( group );
1161 auto assertReal = std::get<2>( group );
1162 adapteeApp->args.push_back( makeAdapterArg(
1163 assertParam->var, assertArg->var->get_type(),
1164 assertReal->var->get_type(), typeVars, location
1165 ) );
1166 }
1167
1168 ast::vector<ast::Type>::const_iterator
1169 arg = realType->params.begin(),
1170 param = adapterType->params.begin(),
1171 realParam = adaptee->params.begin();
1172 ast::vector<ast::DeclWithType>::iterator
1173 paramDecl = adapterDecl->params.begin();
1174 // Skip adaptee parameter in the adapter type.
1175 ++param;
1176 ++paramDecl;
1177
1178 ast::Stmt * bodyStmt;
1179 // Returns void/nothing.
1180 if ( realType->returns.empty() ) {
1181 addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1182 realParam, typeVars, location );
1183 bodyStmt = new ast::ExprStmt( location, adapteeApp );
1184 // Returns a polymorphic type.
1185 } else if ( isDynType( adaptee->returns.front(), typeVars ) ) {
1186 ast::UntypedExpr * assign = new ast::UntypedExpr( location,
1187 new ast::NameExpr( location, "?=?" ) );
1188 ast::UntypedExpr * deref = ast::UntypedExpr::createDeref( location,
1189 new ast::CastExpr( location,
1190 new ast::VariableExpr( location, *paramDecl++ ),
1191 new ast::PointerType(
1192 ast::deepCopy( realType->returns.front() ) ) ) );
1193 assign->args.push_back( deref );
1194 addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1195 realParam, typeVars, location );
1196 assign->args.push_back( adapteeApp );
1197 bodyStmt = new ast::ExprStmt( location, assign );
1198 // Adapter for a function that returns a monomorphic value.
1199 } else {
1200 addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1201 realParam, typeVars, location );
1202 bodyStmt = new ast::ReturnStmt( location, adapteeApp );
1203 }
1204
1205 adapterDecl->stmts = new ast::CompoundStmt( location, { bodyStmt } );
1206 return adapterDecl;
1207}
1208
1209ast::Expr const * makeIncrDecrExpr(
1210 CodeLocation const & location,
1211 ast::ApplicationExpr const * expr,
1212 ast::Type const * polyType,
1213 bool isIncr ) {
1214 ast::NameExpr * opExpr =
1215 new ast::NameExpr( location, isIncr ? "?+=?" : "?-=?" );
1216 ast::UntypedExpr * addAssign = new ast::UntypedExpr( location, opExpr );
1217 if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1218 addAssign->args.push_back( address->arg );
1219 } else {
1220 addAssign->args.push_back( expr->args.front() );
1221 }
1222 addAssign->args.push_back( new ast::NameExpr( location,
1223 sizeofName( Mangle::mangleType( polyType ) ) ) );
1224 addAssign->result = ast::deepCopy( expr->result );
1225 addAssign->env = expr->env ? expr->env : addAssign->env;
1226 return addAssign;
1227}
1228
1229/// Handles intrinsic functions for postvisit ApplicationExpr.
1230ast::Expr const * CallAdapter::handleIntrinsics(
1231 ast::ApplicationExpr const * expr ) {
1232 auto varExpr = expr->func.as<ast::VariableExpr>();
1233 if ( !varExpr || varExpr->var->linkage != ast::Linkage::Intrinsic ) {
1234 return nullptr;
1235 }
1236 std::string const & varName = varExpr->var->name;
1237
1238 // Index Intrinsic:
1239 if ( "?[?]" == varName ) {
1240 assert( expr->result );
1241 assert( 2 == expr->args.size() );
1242
1243 ast::Type const * baseType1 =
1244 isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1245 ast::Type const * baseType2 =
1246 isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1247 // If neither argument is a polymorphic pointer, do nothing.
1248 if ( !baseType1 && !baseType2 ) {
1249 return expr;
1250 }
1251 // The arguments cannot both be polymorphic pointers.
1252 assert( !baseType1 || !baseType2 );
1253 // (So exactly one of the arguments is a polymorphic pointer.)
1254
1255 CodeLocation const & location = expr->location;
1256 CodeLocation const & location1 = expr->args.front()->location;
1257 CodeLocation const & location2 = expr->args.back()->location;
1258
1259 ast::UntypedExpr * ret = new ast::UntypedExpr( location,
1260 new ast::NameExpr( location, "?+?" ) );
1261 if ( baseType1 ) {
1262 auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1263 expr->args.back(),
1264 new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1265 } );
1266 ret->args.push_back( expr->args.front() );
1267 ret->args.push_back( multiply );
1268 } else {
1269 assert( baseType2 );
1270 auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1271 expr->args.front(),
1272 new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1273 } );
1274 ret->args.push_back( multiply );
1275 ret->args.push_back( expr->args.back() );
1276 }
1277 ret->result = ast::deepCopy( expr->result );
1278 ret->env = expr->env ? expr->env : ret->env;
1279 return ret;
1280 // Dereference Intrinsic:
1281 } else if ( "*?" == varName ) {
1282 assert( expr->result );
1283 assert( 1 == expr->args.size() );
1284
1285 // If this isn't for a poly type, then do nothing.
1286 if ( !isPolyType( expr->result, scopeTypeVars, typeSubs ) ) {
1287 return expr;
1288 }
1289
1290 // Remove dereference from polymorphic types since they are boxed.
1291 ast::Expr * ret = ast::deepCopy( expr->args.front() );
1292 // Fix expression type to remove pointer.
1293 ret->result = expr->result;
1294 ret->env = expr->env ? expr->env : ret->env;
1295 return ret;
1296 // Post-Increment/Decrement Intrinsics:
1297 } else if ( "?++" == varName || "?--" == varName ) {
1298 assert( expr->result );
1299 assert( 1 == expr->args.size() );
1300
1301 ast::Type const * baseType =
1302 isPolyType( expr->result, scopeTypeVars, typeSubs );
1303 if ( nullptr == baseType ) {
1304 return expr;
1305 }
1306 ast::Type * tempType = ast::deepCopy( expr->result );
1307 if ( typeSubs ) {
1308 auto result = typeSubs->apply( tempType );
1309 tempType = ast::mutate( result.node.release() );
1310 }
1311 CodeLocation const & location = expr->location;
1312 ast::ObjectDecl * newObj = makeTemporary( location, tempType );
1313 ast::VariableExpr * tempExpr =
1314 new ast::VariableExpr( location, newObj );
1315 ast::UntypedExpr * assignExpr = new ast::UntypedExpr( location,
1316 new ast::NameExpr( location, "?=?" ) );
1317 assignExpr->args.push_back( ast::deepCopy( tempExpr ) );
1318 if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1319 assignExpr->args.push_back( ast::deepCopy( address->arg ) );
1320 } else {
1321 assignExpr->args.push_back( ast::deepCopy( expr->args.front() ) );
1322 }
1323 return new ast::CommaExpr( location,
1324 new ast::CommaExpr( location,
1325 assignExpr,
1326 makeIncrDecrExpr( location, expr, baseType, "?++" == varName )
1327 ),
1328 tempExpr
1329 );
1330 // Pre-Increment/Decrement Intrinsics:
1331 } else if ( "++?" == varName || "--?" == varName ) {
1332 assert( expr->result );
1333 assert( 1 == expr->args.size() );
1334
1335 ast::Type const * baseType =
1336 isPolyType( expr->result, scopeTypeVars, typeSubs );
1337 if ( nullptr == baseType ) {
1338 return expr;
1339 }
1340 return makeIncrDecrExpr(
1341 expr->location, expr, baseType, "++?" == varName );
1342 // Addition and Subtration Intrinsics:
1343 } else if ( "?+?" == varName || "?-?" == varName ) {
1344 assert( expr->result );
1345 assert( 2 == expr->args.size() );
1346
1347 auto baseType1 =
1348 isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1349 auto baseType2 =
1350 isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1351
1352 CodeLocation const & location = expr->location;
1353 CodeLocation const & location1 = expr->args.front()->location;
1354 CodeLocation const & location2 = expr->args.back()->location;
1355 // LHS op RHS -> (LHS op RHS) / sizeof(LHS)
1356 if ( baseType1 && baseType2 ) {
1357 auto divide = ast::UntypedExpr::createCall( location, "?/?", {
1358 expr,
1359 new ast::SizeofExpr( location, deepCopy( baseType1 ) ),
1360 } );
1361 if ( expr->env ) divide->env = expr->env;
1362 return divide;
1363 // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1364 } else if ( baseType1 ) {
1365 auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1366 expr->args.back(),
1367 new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1368 } );
1369 return ast::mutate_field_index(
1370 expr, &ast::ApplicationExpr::args, 1, multiply );
1371 // LHS op RHS -> (LHS * sizeof(RHS)) op RHS
1372 } else if ( baseType2 ) {
1373 auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1374 expr->args.front(),
1375 new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1376 } );
1377 return ast::mutate_field_index(
1378 expr, &ast::ApplicationExpr::args, 0, multiply );
1379 }
1380 // Addition and Subtration Relative Assignment Intrinsics:
1381 } else if ( "?+=?" == varName || "?-=?" == varName ) {
1382 assert( expr->result );
1383 assert( 2 == expr->args.size() );
1384
1385 CodeLocation const & location1 = expr->args.front()->location;
1386 CodeLocation const & location2 = expr->args.back()->location;
1387 auto baseType = isPolyPtr( expr->result, scopeTypeVars, typeSubs );
1388 // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1389 if ( baseType ) {
1390 auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1391 expr->args.back(),
1392 new ast::SizeofExpr( location1, deepCopy( baseType ) ),
1393 } );
1394 return ast::mutate_field_index(
1395 expr, &ast::ApplicationExpr::args, 1, multiply );
1396 }
1397 }
1398 return expr;
1399}
1400
1401ast::ObjectDecl * CallAdapter::makeTemporary(
1402 CodeLocation const & location, ast::Type const * type ) {
1403 auto newObj = new ast::ObjectDecl( location, tmpNamer.newName(), type );
1404 stmtsToAddBefore.push_back( new ast::DeclStmt( location, newObj ) );
1405 return newObj;
1406}
1407
1408// --------------------------------------------------------------------------
1409/// Modifies declarations to accept implicit parameters.
1410/// * Move polymorphic returns in function types to pointer-type parameters.
1411/// * Adds type size and assertion parameters to parameter lists.
1412struct DeclAdapter final {
1413 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
1414 ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
1415private:
1416 void addAdapters( ast::FunctionDecl * decl, TypeVarMap & localTypeVars );
1417};
1418
1419// size/align/offset parameters may not be used, so add the unused attribute.
1420ast::ObjectDecl * makeObj(
1421 CodeLocation const & location, std::string const & name ) {
1422 return new ast::ObjectDecl( location, name,
1423 makeSizeAlignType(),
1424 nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr,
1425 { new ast::Attribute( "unused" ) } );
1426}
1427
1428ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
1429 TypeVarMap localTypeVars = { ast::TypeData() };
1430 makeTypeVarMap( decl, localTypeVars );
1431
1432 auto mutDecl = mutate( decl );
1433
1434 // Move polymorphic return type to parameter list.
1435 if ( isDynRet( mutDecl->type ) ) {
1436 auto ret = strict_dynamic_cast<ast::ObjectDecl *>(
1437 mutDecl->returns.front().get_and_mutate() );
1438 ret->set_type( new ast::PointerType( ret->type ) );
1439 mutDecl->params.insert( mutDecl->params.begin(), ret );
1440 mutDecl->returns.erase( mutDecl->returns.begin() );
1441 ret->init = nullptr;
1442 }
1443
1444 // Add size/align and assertions for type parameters to parameter list.
1445 ast::vector<ast::DeclWithType> inferredParams;
1446 ast::vector<ast::DeclWithType> layoutParams;
1447 for ( ast::ptr<ast::TypeDecl> & typeParam : mutDecl->type_params ) {
1448 auto mutParam = mutate( typeParam.get() );
1449 // Add all size and alignment parameters to parameter list.
1450 if ( mutParam->isComplete() ) {
1451 ast::TypeInstType paramType( mutParam );
1452 std::string paramName = Mangle::mangleType( &paramType );
1453
1454 auto sizeParam = makeObj( typeParam->location, sizeofName( paramName ) );
1455 layoutParams.emplace_back( sizeParam );
1456
1457 auto alignParam = makeObj( typeParam->location, alignofName( paramName ) );
1458 layoutParams.emplace_back( alignParam );
1459 }
1460 // TODO: These should possibly all be gone.
1461 // More all assertions into parameter list.
1462 for ( ast::ptr<ast::DeclWithType> & assert : mutParam->assertions ) {
1463 // Assertion parameters may not be used in body,
1464 // pass along with unused attribute.
1465 assert.get_and_mutate()->attributes.push_back(
1466 new ast::Attribute( "unused" ) );
1467 inferredParams.push_back( assert );
1468 }
1469 mutParam->assertions.clear();
1470 typeParam = mutParam;
1471 }
1472 // TODO: New version of inner loop.
1473 for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
1474 // Assertion parameters may not be used in body,
1475 // pass along with unused attribute.
1476 assert.get_and_mutate()->attributes.push_back(
1477 new ast::Attribute( "unused" ) );
1478 inferredParams.push_back( assert );
1479 }
1480 mutDecl->assertions.clear();
1481
1482 // Prepend each argument group. From last group to first. addAdapters
1483 // does do the same, it just does it itself and see all other parameters.
1484 spliceBegin( mutDecl->params, inferredParams );
1485 spliceBegin( mutDecl->params, layoutParams );
1486 addAdapters( mutDecl, localTypeVars );
1487
1488 return mutDecl;
1489}
1490
1491ast::FunctionDecl const * DeclAdapter::postvisit(
1492 ast::FunctionDecl const * decl ) {
1493 ast::FunctionDecl * mutDecl = mutate( decl );
1494 if ( !mutDecl->returns.empty() && mutDecl->stmts
1495 // Intrinsic functions won't be using the _retval so no need to
1496 // generate it.
1497 && mutDecl->linkage != ast::Linkage::Intrinsic
1498 // Remove check for prefix once thunks properly use ctor/dtors.
1499 && !isPrefix( mutDecl->name, "_thunk" )
1500 && !isPrefix( mutDecl->name, "_adapter" ) ) {
1501 assert( 1 == mutDecl->returns.size() );
1502 ast::DeclWithType const * retval = mutDecl->returns.front();
1503 if ( "" == retval->name ) {
1504 retval = ast::mutate_field(
1505 retval, &ast::DeclWithType::name, "_retval" );
1506 mutDecl->returns.front() = retval;
1507 }
1508 auto stmts = mutDecl->stmts.get_and_mutate();
1509 stmts->kids.push_front( new ast::DeclStmt( retval->location, retval ) );
1510 ast::DeclWithType * newRet = ast::deepCopy( retval );
1511 mutDecl->returns.front() = newRet;
1512 }
1513 // Errors should have been caught by this point, remove initializers from
1514 // parameters to allow correct codegen of default arguments.
1515 for ( ast::ptr<ast::DeclWithType> & param : mutDecl->params ) {
1516 if ( auto obj = param.as<ast::ObjectDecl>() ) {
1517 param = ast::mutate_field( obj, &ast::ObjectDecl::init, nullptr );
1518 }
1519 }
1520 // TODO: Can this be updated as we go along?
1521 mutDecl->type = makeFunctionType( mutDecl );
1522 return mutDecl;
1523}
1524
1525void DeclAdapter::addAdapters(
1526 ast::FunctionDecl * mutDecl, TypeVarMap & localTypeVars ) {
1527 ast::vector<ast::FunctionType> functions;
1528 for ( ast::ptr<ast::DeclWithType> & arg : mutDecl->params ) {
1529 ast::Type const * type = arg->get_type();
1530 type = findAndReplaceFunction( type, functions, localTypeVars, needsAdapter );
1531 arg.get_and_mutate()->set_type( type );
1532 }
1533 std::set<std::string> adaptersDone;
1534 for ( ast::ptr<ast::FunctionType> const & func : functions ) {
1535 std::string mangleName = mangleAdapterName( func, localTypeVars );
1536 if ( adaptersDone.find( mangleName ) != adaptersDone.end() ) {
1537 continue;
1538 }
1539 std::string adapterName = makeAdapterName( mangleName );
1540 // The adapter may not actually be used, so make sure it has unused.
1541 mutDecl->params.insert( mutDecl->params.begin(), new ast::ObjectDecl(
1542 mutDecl->location, adapterName,
1543 new ast::PointerType( makeAdapterType( func, localTypeVars ) ),
1544 nullptr, {}, {}, nullptr,
1545 { new ast::Attribute( "unused" ) } ) );
1546 adaptersDone.insert( adaptersDone.begin(), mangleName );
1547 }
1548}
1549
1550// --------------------------------------------------------------------------
1551// TODO: Ideally, there would be no floating nodes at all.
1552/// Corrects the floating nodes created in CallAdapter.
1553struct RewireAdapters final : public ast::WithGuards {
1554 ScopedMap<std::string, ast::ObjectDecl const *> adapters;
1555 void beginScope() { adapters.beginScope(); }
1556 void endScope() { adapters.endScope(); }
1557 void previsit( ast::FunctionDecl const * decl );
1558 ast::VariableExpr const * previsit( ast::VariableExpr const * expr );
1559};
1560
1561void RewireAdapters::previsit( ast::FunctionDecl const * decl ) {
1562 GuardScope( adapters );
1563 for ( ast::ptr<ast::DeclWithType> const & param : decl->params ) {
1564 if ( auto objectParam = param.as<ast::ObjectDecl>() ) {
1565 adapters.insert( objectParam->name, objectParam );
1566 }
1567 }
1568}
1569
1570ast::VariableExpr const * RewireAdapters::previsit(
1571 ast::VariableExpr const * expr ) {
1572 // If the node is not floating, we can skip.
1573 if ( expr->var->isManaged() ) return expr;
1574 auto it = adapters.find( expr->var->name );
1575 assertf( it != adapters.end(), "Could not correct floating node." );
1576 return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
1577
1578}
1579
1580// --------------------------------------------------------------------------
1581/// Inserts code to access polymorphic layout inforation.
1582/// * Replaces member and size/alignment/offsetof expressions on polymorphic
1583/// generic types with calculated expressions.
1584/// * Replaces member expressions for polymorphic types with calculated
1585/// add-field-offset-and-dereference.
1586/// * Calculates polymorphic offsetof expressions from offset array.
1587/// * Inserts dynamic calculation of polymorphic type layouts where needed.
1588struct PolyGenericCalculator final :
1589 public BoxPass,
1590 public ast::WithConstTypeSubstitution,
1591 public ast::WithDeclsToAdd<>,
1592 public ast::WithGuards,
1593 public ast::WithStmtsToAdd<>,
1594 public ast::WithVisitorRef<PolyGenericCalculator> {
1595 PolyGenericCalculator();
1596
1597 void previsit( ast::ObjectDecl const * decl );
1598 void previsit( ast::FunctionDecl const * decl );
1599 void previsit( ast::TypedefDecl const * decl );
1600 void previsit( ast::TypeDecl const * decl );
1601 ast::Decl const * postvisit( ast::TypeDecl const * decl );
1602 ast::StructDecl const * previsit( ast::StructDecl const * decl );
1603 ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
1604 void previsit( ast::PointerType const * type );
1605 void previsit( ast::FunctionType const * type );
1606 ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
1607 ast::Expr const * postvisit( ast::MemberExpr const * expr );
1608 void previsit( ast::AddressExpr const * expr );
1609 ast::Expr const * postvisit( ast::AddressExpr const * expr );
1610 ast::Expr const * postvisit( ast::SizeofExpr const * expr );
1611 ast::Expr const * postvisit( ast::AlignofExpr const * expr );
1612 ast::Expr const * postvisit( ast::OffsetofExpr const * expr );
1613 ast::Expr const * postvisit( ast::OffsetPackExpr const * expr );
1614
1615 void beginScope();
1616 void endScope();
1617private:
1618 /// Makes a new variable in the current scope with the given name,
1619 /// type and optional initializer.
1620 ast::ObjectDecl * makeVar(
1621 CodeLocation const & location, std::string const & name,
1622 ast::Type const * type, ast::Init const * init = nullptr );
1623 /// Returns true if the type has a dynamic layout;
1624 /// such a layout will be stored in appropriately-named local variables
1625 /// when the function returns.
1626 bool findGeneric( CodeLocation const & location, ast::Type const * );
1627 /// Adds type parameters to the layout call; will generate the
1628 /// appropriate parameters if needed.
1629 void addSTypeParamsToLayoutCall(
1630 ast::UntypedExpr * layoutCall,
1631 const ast::vector<ast::Type> & otypeParams );
1632 /// Change the type of generic aggregate members to char[].
1633 void mutateMembers( ast::AggregateDecl * aggr );
1634 /// Returns the calculated sizeof expression for type, or nullptr for use
1635 /// C sizeof().
1636 ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
1637
1638 /// Enters a new scope for type-variables,
1639 /// adding the type variables from the provided type.
1640 void beginTypeScope( ast::Type const * );
1641 /// Enters a new scope for known layouts and offsets, and queues exit calls.
1642 void beginGenericScope();
1643
1644 /// Set of generic type layouts known in the current scope,
1645 /// indexed by sizeofName.
1646 ScopedSet<std::string> knownLayouts;
1647 /// Set of non-generic types for which the offset array exists in the
1648 /// current scope, indexed by offsetofName.
1649 ScopedSet<std::string> knownOffsets;
1650 /// Namer for VLA (variable length array) buffers.
1651 UniqueName bufNamer;
1652 /// If the argument of an AddressExpr is MemberExpr, it is stored here.
1653 ast::MemberExpr const * addrMember = nullptr;
1654 /// Used to avoid recursing too deep in type declarations.
1655 bool expect_func_type = false;
1656};
1657
1658PolyGenericCalculator::PolyGenericCalculator() :
1659 knownLayouts(), knownOffsets(), bufNamer( "_buf" )
1660{}
1661
1662/// Converts polymorphic type into a suitable monomorphic representation.
1663/// Currently: __attribute__((aligned(8) )) char[size_T];
1664ast::Type * polyToMonoType( CodeLocation const & location,
1665 ast::Type const * declType ) {
1666 auto charType = new ast::BasicType( ast::BasicType::Char );
1667 auto size = new ast::NameExpr( location,
1668 sizeofName( Mangle::mangleType( declType ) ) );
1669 auto aligned = new ast::Attribute( "aligned",
1670 { ast::ConstantExpr::from_int( location, 8 ) } );
1671 auto ret = new ast::ArrayType( charType, size,
1672 ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
1673 ret->attributes.push_back( aligned );
1674 return ret;
1675}
1676
1677void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) {
1678 beginTypeScope( decl->type );
1679}
1680
1681void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
1682 beginGenericScope();
1683 beginTypeScope( decl->type );
1684}
1685
1686void PolyGenericCalculator::previsit( ast::TypedefDecl const * decl ) {
1687 assertf( false, "All typedef declarations should be removed." );
1688 beginTypeScope( decl->base );
1689}
1690
1691void PolyGenericCalculator::previsit( ast::TypeDecl const * decl ) {
1692 addToTypeVarMap( decl, scopeTypeVars );
1693}
1694
1695ast::Decl const * PolyGenericCalculator::postvisit(
1696 ast::TypeDecl const * decl ) {
1697 ast::Type const * base = decl->base;
1698 if ( nullptr == base) return decl;
1699
1700 // Add size/align variables for opaque type declarations.
1701 ast::TypeInstType inst( decl->name, decl );
1702 std::string typeName = Mangle::mangleType( &inst );
1703 ast::Type * layoutType = new ast::BasicType(
1704 ast::BasicType::LongUnsignedInt );
1705
1706 ast::ObjectDecl * sizeDecl = new ast::ObjectDecl( decl->location,
1707 sizeofName( typeName ), layoutType,
1708 new ast::SingleInit( decl->location,
1709 new ast::SizeofExpr( decl->location, deepCopy( base ) )
1710 )
1711 );
1712 ast::ObjectDecl * alignDecl = new ast::ObjectDecl( decl->location,
1713 alignofName( typeName ), layoutType,
1714 new ast::SingleInit( decl->location,
1715 new ast::AlignofExpr( decl->location, deepCopy( base ) )
1716 )
1717 );
1718
1719 // Ensure that the initializing sizeof/alignof exprs are properly mutated.
1720 sizeDecl->accept( *visitor );
1721 alignDecl->accept( *visitor );
1722
1723 // Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls
1724 // can occur at global scope.
1725 declsToAddAfter.push_back( alignDecl );
1726 // replace with sizeDecl.
1727 return sizeDecl;
1728}
1729
1730ast::StructDecl const * PolyGenericCalculator::previsit(
1731 ast::StructDecl const * decl ) {
1732 auto mutDecl = mutate( decl );
1733 mutateMembers( mutDecl );
1734 return mutDecl;
1735}
1736
1737ast::UnionDecl const * PolyGenericCalculator::previsit(
1738 ast::UnionDecl const * decl ) {
1739 auto mutDecl = mutate( decl );
1740 mutateMembers( mutDecl );
1741 return mutDecl;
1742}
1743
1744void PolyGenericCalculator::previsit( ast::PointerType const * type ) {
1745 beginTypeScope( type );
1746}
1747
1748void PolyGenericCalculator::previsit( ast::FunctionType const * type ) {
1749 beginTypeScope( type );
1750
1751 GuardValue( expect_func_type );
1752 GuardScope( *this );
1753
1754 // The other functions type we will see in this scope are probably
1755 // function parameters they don't help us with the layout and offsets so
1756 // don't mark them as known in this scope.
1757 expect_func_type = false;
1758}
1759
1760//void PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1761ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1762 ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
1763 if ( !decl || !findGeneric( decl->location, decl->type ) ) {
1764 return stmt;
1765 }
1766
1767 // Change initialization of a polymorphic value object to allocate via a
1768 // variable-length-array (alloca was previouly used, but it cannot be
1769 // safely used in loops).
1770 ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
1771 bufNamer.newName(),
1772 polyToMonoType( decl->location, decl->type ),
1773 nullptr, {}, ast::Linkage::C
1774 );
1775 stmtsToAddBefore.push_back( new ast::DeclStmt( stmt->location, newBuf ) );
1776
1777 // If the object has a cleanup attribute, the clean-up should be on the
1778 // buffer, not the pointer. [Perhaps this should be lifted?]
1779 auto matchAndMove = [newBuf]( ast::ptr<ast::Attribute> & attr ) {
1780 if ( "cleanup" == attr->name ) {
1781 newBuf->attributes.push_back( attr );
1782 return true;
1783 }
1784 return false;
1785 };
1786
1787 auto mutDecl = mutate( decl );
1788
1789 // Forally, side effects are not safe in this function. But it works.
1790 erase_if( mutDecl->attributes, matchAndMove );
1791
1792 mutDecl->init = new ast::SingleInit( decl->location,
1793 new ast::VariableExpr( decl->location, newBuf ) );
1794
1795 return ast::mutate_field( stmt, &ast::DeclStmt::decl, mutDecl );
1796}
1797
1798/// Checks if memberDecl matches the decl from an aggregate.
1799bool isMember( ast::DeclWithType const * memberDecl, ast::Decl const * decl ) {
1800 // No matter the field, if the name is different it is not the same.
1801 if ( memberDecl->name != decl->name ) {
1802 return false;
1803 }
1804
1805 if ( memberDecl->name.empty() ) {
1806 // Plan-9 Field: Match on unique_id.
1807 return ( memberDecl->uniqueId == decl->uniqueId );
1808 }
1809
1810 ast::DeclWithType const * declWithType =
1811 strict_dynamic_cast<ast::DeclWithType const *>( decl );
1812
1813 if ( memberDecl->mangleName.empty() || declWithType->mangleName.empty() ) {
1814 // Tuple-Element Field: Expect neither had mangled name;
1815 // accept match on simple name (like field_2) only.
1816 assert( memberDecl->mangleName.empty() );
1817 assert( declWithType->mangleName.empty() );
1818 return true;
1819 }
1820
1821 // Ordinary Field: Use full name to accommodate overloading.
1822 return ( memberDecl->mangleName == declWithType->mangleName );
1823}
1824
1825/// Finds the member in the base list that matches the given declaration;
1826/// returns its index, or -1 if not present.
1827long findMember( ast::DeclWithType const * memberDecl,
1828 const ast::vector<ast::Decl> & baseDecls ) {
1829 for ( auto pair : enumerate( baseDecls ) ) {
1830 if ( isMember( memberDecl, pair.val.get() ) ) {
1831 return pair.idx;
1832 }
1833 }
1834 return -1;
1835}
1836
1837/// Returns an index expression into the offset array for a type.
1838ast::Expr * makeOffsetIndex( CodeLocation const & location,
1839 ast::Type const * objectType, long i ) {
1840 std::string name = offsetofName( Mangle::mangleType( objectType ) );
1841 return ast::UntypedExpr::createCall( location, "?[?]", {
1842 new ast::NameExpr( location, name ),
1843 ast::ConstantExpr::from_ulong( location, i ),
1844 } );
1845}
1846
1847ast::Expr const * PolyGenericCalculator::postvisit(
1848 ast::MemberExpr const * expr ) {
1849 // Only mutate member expressions for polymorphic types.
1850 ast::Type const * objectType = hasPolyBase(
1851 expr->aggregate->result, scopeTypeVars
1852 );
1853 if ( !objectType ) return expr;
1854 // Ensure layout for this type is available.
1855 // The boolean result is ignored.
1856 findGeneric( expr->location, objectType );
1857
1858 // Replace member expression with dynamically-computed layout expression.
1859 ast::Expr * newMemberExpr = nullptr;
1860 if ( auto structType = dynamic_cast<ast::StructInstType const *>( objectType ) ) {
1861 long offsetIndex = findMember( expr->member, structType->base->members );
1862 if ( -1 == offsetIndex ) return expr;
1863
1864 // Replace member expression with pointer to struct plus offset.
1865 ast::UntypedExpr * fieldLoc = new ast::UntypedExpr( expr->location,
1866 new ast::NameExpr( expr->location, "?+?" ) );
1867 ast::Expr * aggr = deepCopy( expr->aggregate );
1868 aggr->env = nullptr;
1869 fieldLoc->args.push_back( aggr );
1870 fieldLoc->args.push_back(
1871 makeOffsetIndex( expr->location, objectType, offsetIndex ) );
1872 fieldLoc->result = deepCopy( expr->result );
1873 newMemberExpr = fieldLoc;
1874 // Union members are all at offset zero, so just use the aggregate expr.
1875 } else if ( dynamic_cast<ast::UnionInstType const *>( objectType ) ) {
1876 ast::Expr * aggr = deepCopy( expr->aggregate );
1877 aggr->env = nullptr;
1878 aggr->result = deepCopy( expr->result );
1879 newMemberExpr = aggr;
1880 } else {
1881 return expr;
1882 }
1883 assert( newMemberExpr );
1884
1885 // Must apply the generic substitution to the member type to handle cases
1886 // where the member is a generic parameter subsituted by a known concrete
1887 // type. [ex]
1888 // forall( T ) struct Box { T x; }
1889 // forall( T ) void f() {
1890 // Box( T * ) b; b.x;
1891 // }
1892 // TODO: expr->result should be exactly expr->member->get_type() after
1893 // substitution, so it doesn't seem like it should be necessary to apply
1894 // the substitution manually. For some reason this is not currently the
1895 // case. This requires more investigation.
1896 ast::ptr<ast::Type> memberType = deepCopy( expr->member->get_type() );
1897 ast::TypeSubstitution sub = genericSubstitution( objectType );
1898 sub.apply( memberType );
1899
1900 // Not all members of a polymorphic type are themselves of a polymorphic
1901 // type; in this cas the member expression should be wrapped and
1902 // dereferenced to form an lvalue.
1903 if ( !isPolyType( memberType, scopeTypeVars ) ) {
1904 auto ptrCastExpr = new ast::CastExpr( expr->location, newMemberExpr,
1905 new ast::PointerType( memberType ) );
1906 auto derefExpr = ast::UntypedExpr::createDeref( expr->location,
1907 ptrCastExpr );
1908 newMemberExpr = derefExpr;
1909 }
1910
1911 return newMemberExpr;
1912}
1913
1914void PolyGenericCalculator::previsit( ast::AddressExpr const * expr ) {
1915 GuardValue( addrMember ) = expr->arg.as<ast::MemberExpr>();
1916}
1917
1918ast::Expr const * PolyGenericCalculator::postvisit(
1919 ast::AddressExpr const * expr ) {
1920 // arg has to have been a MemberExpr and has been mutated.
1921 if ( nullptr == addrMember || expr->arg == addrMember ) {
1922 return expr;
1923 }
1924 ast::UntypedExpr const * untyped = expr->arg.as<ast::UntypedExpr>();
1925 if ( !untyped || getFunctionName( untyped ) != "?+?" ) {
1926 return expr;
1927 }
1928 // MemberExpr was converted to pointer + offset; and it is not valid C to
1929 // take the address of an addition, so strip away the address-of.
1930 // It also preserves the env value.
1931 return ast::mutate_field( expr->arg.get(), &ast::Expr::env, expr->env );
1932}
1933
1934ast::Expr const * PolyGenericCalculator::postvisit(
1935 ast::SizeofExpr const * expr ) {
1936 ast::Type const * type = expr->type ? expr->type : expr->expr->result;
1937 ast::Expr const * gen = genSizeof( expr->location, type );
1938 return ( gen ) ? gen : expr;
1939}
1940
1941ast::Expr const * PolyGenericCalculator::postvisit(
1942 ast::AlignofExpr const * expr ) {
1943 ast::Type const * type = expr->type ? expr->type : expr->expr->result;
1944 if ( findGeneric( expr->location, type ) ) {
1945 return new ast::NameExpr( expr->location,
1946 alignofName( Mangle::mangleType( type ) ) );
1947 } else {
1948 return expr;
1949 }
1950}
1951
1952ast::Expr const * PolyGenericCalculator::postvisit(
1953 ast::OffsetofExpr const * expr ) {
1954 ast::Type const * type = expr->type;
1955 if ( !findGeneric( expr->location, type ) ) return expr;
1956
1957 // Structures replace offsetof expression with an index into offset array.
1958 if ( auto structType = dynamic_cast<ast::StructInstType const *>( type ) ) {
1959 long offsetIndex = findMember( expr->member, structType->base->members );
1960 if ( -1 == offsetIndex ) return expr;
1961
1962 return makeOffsetIndex( expr->location, type, offsetIndex );
1963 // All union members are at offset zero.
1964 } else if ( dynamic_cast<ast::UnionInstType const *>( type ) ) {
1965 return ast::ConstantExpr::from_ulong( expr->location, 0 );
1966 } else {
1967 return expr;
1968 }
1969}
1970
1971ast::Expr const * PolyGenericCalculator::postvisit(
1972 ast::OffsetPackExpr const * expr ) {
1973 ast::StructInstType const * type = expr->type;
1974
1975 // Pull offset back from generated type information.
1976 if ( findGeneric( expr->location, type ) ) {
1977 return new ast::NameExpr( expr->location,
1978 offsetofName( Mangle::mangleType( type ) ) );
1979 }
1980
1981 std::string offsetName = offsetofName( Mangle::mangleType( type ) );
1982 // Use the already generated offsets for this type.
1983 if ( knownOffsets.contains( offsetName ) ) {
1984 return new ast::NameExpr( expr->location, offsetName );
1985 }
1986
1987 knownOffsets.insert( offsetName );
1988
1989 auto baseMembers = type->base->members;
1990 ast::Type const * offsetType = new ast::BasicType(
1991 ast::BasicType::LongUnsignedInt );
1992
1993 // Build initializer list for offset array.
1994 ast::vector<ast::Init> inits;
1995 for ( ast::ptr<ast::Decl> & member : baseMembers ) {
1996 auto memberDecl = member.as<ast::DeclWithType>();
1997 assertf( memberDecl, "Requesting offset of non-DWT member: %s",
1998 toCString( member ) );
1999 inits.push_back( new ast::SingleInit( expr->location,
2000 new ast::OffsetofExpr( expr->location,
2001 deepCopy( type ),
2002 memberDecl
2003 )
2004 ) );
2005 }
2006
2007 auto offsetArray = makeVar( expr->location, offsetName,
2008 new ast::ArrayType(
2009 offsetType,
2010 ast::ConstantExpr::from_ulong( expr->location, baseMembers.size() ),
2011 ast::FixedLen,
2012 ast::DynamicDim
2013 ),
2014 new ast::ListInit( expr->location, std::move( inits ) )
2015 );
2016
2017 return new ast::VariableExpr( expr->location, offsetArray );
2018}
2019
2020void PolyGenericCalculator::beginScope() {
2021 knownLayouts.beginScope();
2022 knownOffsets.beginScope();
2023}
2024
2025void PolyGenericCalculator::endScope() {
2026 knownOffsets.endScope();
2027 knownLayouts.endScope();
2028}
2029
2030ast::ObjectDecl * PolyGenericCalculator::makeVar(
2031 CodeLocation const & location, std::string const & name,
2032 ast::Type const * type, ast::Init const * init ) {
2033 ast::ObjectDecl * ret = new ast::ObjectDecl( location, name, type, init );
2034 stmtsToAddBefore.push_back( new ast::DeclStmt( location, ret ) );
2035 return ret;
2036}
2037
2038/// Returns true if any of the otype parameters have a dynamic layout; and
2039/// puts all otype parameters in the output list.
2040bool findGenericParams(
2041 ast::vector<ast::Type> & out,
2042 ast::vector<ast::TypeDecl> const & baseParams,
2043 ast::vector<ast::Expr> const & typeParams ) {
2044 bool hasDynamicLayout = false;
2045
2046 for ( auto pair : group_iterate( baseParams, typeParams ) ) {
2047 auto baseParam = std::get<0>( pair );
2048 auto typeParam = std::get<1>( pair );
2049 if ( !baseParam->isComplete() ) continue;
2050 ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
2051 assertf( typeExpr, "All type parameters should be type expressions." );
2052
2053 ast::Type const * type = typeExpr->type.get();
2054 out.push_back( type );
2055 if ( isPolyType( type ) ) hasDynamicLayout = true;
2056 }
2057
2058 return hasDynamicLayout;
2059}
2060
2061bool PolyGenericCalculator::findGeneric(
2062 CodeLocation const & location, ast::Type const * type ) {
2063 type = replaceTypeInst( type, typeSubs );
2064
2065 if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
2066 // Assumes that getting put in the scopeTypeVars includes having the
2067 // layout variables set.
2068 if ( scopeTypeVars.contains( *inst ) ) {
2069 return true;
2070 }
2071 } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
2072 // Check if this type already has a layout generated for it.
2073 std::string typeName = Mangle::mangleType( type );
2074 if ( knownLayouts.contains( typeName ) ) return true;
2075
2076 // Check if any type parameters have dynamic layout;
2077 // If none do, this type is (or will be) monomorphized.
2078 ast::vector<ast::Type> sizedParams;
2079 if ( !findGenericParams( sizedParams,
2080 inst->base->params, inst->params ) ) {
2081 return false;
2082 }
2083
2084 // Insert local variables for layout and generate call to layout
2085 // function.
2086 // Done early so as not to interfere with the later addition of
2087 // parameters to the layout call.
2088 knownLayouts.insert( typeName );
2089 ast::Type const * layoutType = makeSizeAlignType();
2090
2091 int memberCount = inst->base->members.size();
2092 if ( 0 == memberCount ) {
2093 // All empty structures have the same layout (size 1, align 1).
2094 makeVar( location,
2095 sizeofName( typeName ), layoutType,
2096 new ast::SingleInit( location,
2097 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2098 makeVar( location,
2099 alignofName( typeName ), ast::deepCopy( layoutType ),
2100 new ast::SingleInit( location,
2101 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2102 // Since 0-length arrays are forbidden in C, skip the offset array.
2103 } else {
2104 ast::ObjectDecl const * sizeofVar = makeVar( location,
2105 sizeofName( typeName ), deepCopy( layoutType ), nullptr );
2106 ast::ObjectDecl const * alignofVar = makeVar( location,
2107 alignofName( typeName ), deepCopy( layoutType ), nullptr );
2108 ast::ObjectDecl const * offsetofVar = makeVar( location,
2109 offsetofName( typeName ),
2110 new ast::ArrayType(
2111 layoutType,
2112 ast::ConstantExpr::from_int( location, memberCount ),
2113 ast::FixedLen,
2114 ast::DynamicDim
2115 ),
2116 nullptr
2117 );
2118
2119 // Generate call to layout function.
2120 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2121 new ast::NameExpr( location, layoutofName( inst->base ) ),
2122 {
2123 new ast::AddressExpr(
2124 new ast::VariableExpr( location, sizeofVar ) ),
2125 new ast::AddressExpr(
2126 new ast::VariableExpr( location, alignofVar ) ),
2127 new ast::VariableExpr( location, offsetofVar ),
2128 } );
2129
2130 addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2131
2132 stmtsToAddBefore.emplace_back(
2133 new ast::ExprStmt( location, layoutCall ) );
2134 }
2135
2136 return true;
2137 } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
2138 // Check if this type already has a layout generated for it.
2139 std::string typeName = Mangle::mangleType( type );
2140 if ( knownLayouts.contains( typeName ) ) return true;
2141
2142 // Check if any type parameters have dynamic layout;
2143 // If none do, this type is (or will be) monomorphized.
2144 ast::vector<ast::Type> sizedParams;
2145 if ( !findGenericParams( sizedParams,
2146 inst->base->params, inst->params ) ) {
2147 return false;
2148 }
2149
2150 // Insert local variables for layout and generate call to layout
2151 // function.
2152 // Done early so as not to interfere with the later addition of
2153 // parameters to the layout call.
2154 knownLayouts.insert( typeName );
2155 ast::Type const * layoutType = makeSizeAlignType();
2156
2157 ast::ObjectDecl * sizeofVar = makeVar( location,
2158 sizeofName( typeName ), layoutType );
2159 ast::ObjectDecl * alignofVar = makeVar( location,
2160 alignofName( typeName ), ast::deepCopy( layoutType ) );
2161
2162 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2163 new ast::NameExpr( location, layoutofName( inst->base ) ),
2164 {
2165 new ast::AddressExpr(
2166 new ast::VariableExpr( location, sizeofVar ) ),
2167 new ast::AddressExpr(
2168 new ast::VariableExpr( location, alignofVar ) ),
2169 } );
2170
2171 addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2172
2173 stmtsToAddBefore.emplace_back(
2174 new ast::ExprStmt( location, layoutCall ) );
2175
2176 return true;
2177 }
2178 return false;
2179}
2180
2181void PolyGenericCalculator::addSTypeParamsToLayoutCall(
2182 ast::UntypedExpr * layoutCall,
2183 const ast::vector<ast::Type> & otypeParams ) {
2184 CodeLocation const & location = layoutCall->location;
2185 ast::vector<ast::Expr> & args = layoutCall->args;
2186 for ( ast::ptr<ast::Type> const & param : otypeParams ) {
2187 if ( findGeneric( location, param ) ) {
2188 // Push size/align vars for a generic parameter back.
2189 std::string paramName = Mangle::mangleType( param );
2190 args.emplace_back(
2191 new ast::NameExpr( location, sizeofName( paramName ) ) );
2192 args.emplace_back(
2193 new ast::NameExpr( location, alignofName( paramName ) ) );
2194 } else {
2195 args.emplace_back(
2196 new ast::SizeofExpr( location, ast::deepCopy( param ) ) );
2197 args.emplace_back(
2198 new ast::AlignofExpr( location, ast::deepCopy( param ) ) );
2199 }
2200 }
2201}
2202
2203void PolyGenericCalculator::mutateMembers( ast::AggregateDecl * aggr ) {
2204 std::set<std::string> genericParams;
2205 for ( ast::ptr<ast::TypeDecl> const & decl : aggr->params ) {
2206 genericParams.insert( decl->name );
2207 }
2208 for ( ast::ptr<ast::Decl> & decl : aggr->members ) {
2209 auto field = decl.as<ast::ObjectDecl>();
2210 if ( nullptr == field ) continue;
2211
2212 ast::Type const * type = replaceTypeInst( field->type, typeSubs );
2213 auto typeInst = dynamic_cast<ast::TypeInstType const *>( type );
2214 if ( nullptr == typeInst ) continue;
2215
2216 // Do not try to monoporphize generic parameters.
2217 if ( scopeTypeVars.contains( ast::TypeEnvKey( *typeInst ) ) &&
2218 !genericParams.count( typeInst->name ) ) {
2219 // Polymorphic aggregate members should be converted into
2220 // monomorphic members. Using char[size_T] here respects
2221 // the expected sizing rules of an aggregate type.
2222 decl = ast::mutate_field( field, &ast::ObjectDecl::type,
2223 polyToMonoType( field->location, field->type ) );
2224 }
2225 }
2226}
2227
2228ast::Expr const * PolyGenericCalculator::genSizeof(
2229 CodeLocation const & location, ast::Type const * type ) {
2230 if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
2231 // Generate calculated size for possibly generic array.
2232 ast::Expr const * sizeofBase = genSizeof( location, array->base );
2233 if ( nullptr == sizeofBase ) return nullptr;
2234 ast::Expr const * dim = array->dimension;
2235 return makeOp( location, "?*?", sizeofBase, dim );
2236 } else if ( findGeneric( location, type ) ) {
2237 // Generate calculated size for generic type.
2238 return new ast::NameExpr( location, sizeofName(
2239 Mangle::mangleType( type ) ) );
2240 } else {
2241 return nullptr;
2242 }
2243}
2244
2245void PolyGenericCalculator::beginTypeScope( ast::Type const * type ) {
2246 GuardScope( scopeTypeVars );
2247 makeTypeVarMap( type, scopeTypeVars );
2248}
2249
2250void PolyGenericCalculator::beginGenericScope() {
2251 GuardScope( *this );
2252 // We expect the first function type see to be the type relating to this
2253 // scope but any further type is probably some unrelated function pointer
2254 // keep track of whrich is the first.
2255 GuardValue( expect_func_type ) = true;
2256}
2257
2258// --------------------------------------------------------------------------
2259/// No common theme found.
2260/// * Replaces initialization of polymorphic values with alloca.
2261/// * Replaces declaration of dtype/ftype with appropriate void expression.
2262/// * Replaces sizeof expressions of polymorphic types with a variable.
2263/// * Strips fields from generic structure declarations.
2264struct Eraser final :
2265 public BoxPass,
2266 public ast::WithGuards {
2267 void guardTypeVarMap( ast::Type const * type ) {
2268 GuardScope( scopeTypeVars );
2269 makeTypeVarMap( type, scopeTypeVars );
2270 }
2271
2272 ast::ObjectDecl const * previsit( ast::ObjectDecl const * decl );
2273 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
2274 ast::TypedefDecl const * previsit( ast::TypedefDecl const * decl );
2275 ast::StructDecl const * previsit( ast::StructDecl const * decl );
2276 ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
2277 void previsit( ast::TypeDecl const * decl );
2278 void previsit( ast::PointerType const * type );
2279 void previsit( ast::FunctionType const * type );
2280};
2281
2282ast::ObjectDecl const * Eraser::previsit( ast::ObjectDecl const * decl ) {
2283 guardTypeVarMap( decl->type );
2284 return scrubAllTypeVars( decl );
2285}
2286
2287ast::FunctionDecl const * Eraser::previsit( ast::FunctionDecl const * decl ) {
2288 guardTypeVarMap( decl->type );
2289 return scrubAllTypeVars( decl );
2290}
2291
2292ast::TypedefDecl const * Eraser::previsit( ast::TypedefDecl const * decl ) {
2293 guardTypeVarMap( decl->base );
2294 return scrubAllTypeVars( decl );
2295}
2296
2297/// Strips the members from a generic aggregate.
2298template<typename node_t>
2299node_t const * stripGenericMembers( node_t const * decl ) {
2300 if ( decl->params.empty() ) return decl;
2301 auto mutDecl = ast::mutate( decl );
2302 mutDecl->members.clear();
2303 return mutDecl;
2304}
2305
2306ast::StructDecl const * Eraser::previsit( ast::StructDecl const * decl ) {
2307 return stripGenericMembers( decl );
2308}
2309
2310ast::UnionDecl const * Eraser::previsit( ast::UnionDecl const * decl ) {
2311 return stripGenericMembers( decl );
2312}
2313
2314void Eraser::previsit( ast::TypeDecl const * decl ) {
2315 addToTypeVarMap( decl, scopeTypeVars );
2316}
2317
2318void Eraser::previsit( ast::PointerType const * type ) {
2319 guardTypeVarMap( type );
2320}
2321
2322void Eraser::previsit( ast::FunctionType const * type ) {
2323 guardTypeVarMap( type );
2324}
2325
2326} // namespace
2327
2328// --------------------------------------------------------------------------
2329void box( ast::TranslationUnit & translationUnit ) {
2330 ast::Pass<LayoutFunctionBuilder>::run( translationUnit );
2331 ast::Pass<CallAdapter>::run( translationUnit );
2332 ast::Pass<DeclAdapter>::run( translationUnit );
2333 ast::Pass<RewireAdapters>::run( translationUnit );
2334 ast::Pass<PolyGenericCalculator>::run( translationUnit );
2335 ast::Pass<Eraser>::run( translationUnit );
2336}
2337
2338} // namespace GenPoly
2339
2340// Local Variables: //
2341// tab-width: 4 //
2342// mode: c++ //
2343// compile-command: "make install" //
2344// End: //
Note: See TracBrowser for help on using the repository browser.