source: src/GenPoly/BoxNew.cpp@ 1b41219

Last change on this file since 1b41219 was 52a5262e, checked in by Andrew Beach <ajbeach@…>, 2 years ago

TypeVarMap is now a subtype instead of an alias to remove the redundent constructor argument. Various bits of box pass clean-up.

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