source: src/GenPoly/Box.cpp@ 77d46c7

Last change on this file since 77d46c7 was c4b9fa9, checked in by Andrew Beach <ajbeach@…>, 22 months ago

Just some random clean-up in Box pass while I was musing.

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