source: src/GenPoly/BoxNew.cpp@ 4d2d7e27

Last change on this file since 4d2d7e27 was e14d169, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Remove some cruft from the box pass. Some pieces left over from earlier versions that are no longer needed and some rejected notes.

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