source: src/GenPoly/Box.cpp@ dd1ebb1

Last change on this file since dd1ebb1 was 59c8dff, checked in by JiadaL <j82liang@…>, 20 months ago

Draft Implementation for enum position pesudo function (posE). EnumPosExpr is mostly irrelevant for now. It is used in development/code probing and will be removed later

  • Property mode set to 100644
File size: 81.6 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// 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 : Peter A. Buhr
12// Last Modified On : Thu Dec 14 17:42:17 2023
13// Update Count : 7
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->location, "\nunbound type variable %s in application %s",
780 toString( typeSubs ).c_str(), typeVar->typeString().c_str() );
781 }
782 arg = expr->args.insert( arg,
783 new ast::SizeofExpr( expr->location, ast::deepCopy( concrete ) ) );
784 arg++;
785 arg = expr->args.insert( arg,
786 new ast::AlignofExpr( expr->location, ast::deepCopy( concrete ) ) );
787 arg++;
788 }
789 return arg;
790}
791
792ast::Expr const * CallAdapter::addRetParam(
793 ast::ApplicationExpr * expr, ast::Type const * retType ) {
794 // Create temporary to hold return value of polymorphic function and
795 // produce that temporary as a result using a comma expression.
796 assert( retType );
797
798 ast::Expr * paramExpr = nullptr;
799 // Try to use existing return value parameter if it exists,
800 // otherwise create a new temporary.
801 if ( retVals.count( expr ) ) {
802 paramExpr = ast::deepCopy( retVals[ expr ] );
803 } else {
804 auto newObj = makeTemporary( expr->location, ast::deepCopy( retType ) );
805 paramExpr = new ast::VariableExpr( expr->location, newObj );
806 }
807 ast::Expr * retExpr = ast::deepCopy( paramExpr );
808
809 // If the type of the temporary is not polpmorphic, box temporary by
810 // taking its address; otherwise the temporary is already boxed and can
811 // be used directly.
812 if ( !isPolyType( paramExpr->result, scopeTypeVars, typeSubs ) ) {
813 paramExpr = new ast::AddressExpr( paramExpr->location, paramExpr );
814 }
815 // Add argument to function call.
816 expr->args.insert( expr->args.begin(), paramExpr );
817 // Build a comma expression to call the function and return a value.
818 ast::CommaExpr * comma = new ast::CommaExpr(
819 expr->location, expr, retExpr );
820 comma->env = expr->env;
821 expr->env = nullptr;
822 return comma;
823}
824
825ast::Expr const * CallAdapter::addDynRetParam(
826 ast::ApplicationExpr * expr, ast::Type const * polyType ) {
827 assert( typeSubs );
828 ast::Type const * concrete = replaceWithConcrete( polyType, *typeSubs );
829 // Add out-parameter for return value.
830 return addRetParam( expr, concrete );
831}
832
833ast::Expr const * CallAdapter::applyAdapter(
834 ast::ApplicationExpr * expr,
835 ast::FunctionType const * function ) {
836 ast::Expr const * ret = expr;
837 if ( isDynRet( function, scopeTypeVars ) ) {
838 ret = addRetParam( expr, function->returns.front() );
839 }
840 std::string mangleName = mangleAdapterName( function, scopeTypeVars );
841 std::string adapterName = makeAdapterName( mangleName );
842
843 // Cast adaptee to `void (*)()`, since it may have any type inside a
844 // polymorphic function.
845 ast::Type const * adapteeType = new ast::PointerType(
846 new ast::FunctionType( ast::VariableArgs ) );
847 expr->args.insert( expr->args.begin(),
848 new ast::CastExpr( expr->location, expr->func, adapteeType ) );
849 // The result field is never set on NameExpr. / Now it is.
850 auto head = new ast::NameExpr( expr->location, adapterName );
851 head->result = ast::deepCopy( adapteeType );
852 expr->func = head;
853
854 return ret;
855}
856
857/// Cast parameters to polymorphic functions so that types are replaced with
858/// `void *` if they are type parameters in the formal type.
859/// This gets rid of warnings from gcc.
860void addCast(
861 ast::ptr<ast::Expr> & actual,
862 ast::Type const * formal,
863 TypeVarMap const & typeVars ) {
864 // Type contains polymorphism, but isn't exactly a polytype, in which
865 // case it has some real actual type (ex. unsigned int) and casting to
866 // `void *` is wrong.
867 if ( hasPolymorphism( formal, typeVars )
868 && !isPolyType( formal, typeVars ) ) {
869 ast::Type const * newType = ast::deepCopy( formal );
870 newType = scrubTypeVars( newType, typeVars );
871 actual = new ast::CastExpr( actual->location, actual, newType );
872 }
873}
874
875void CallAdapter::boxParam( ast::ptr<ast::Expr> & arg,
876 ast::Type const * param, TypeVarMap const & exprTypeVars ) {
877 assertf( arg->result, "arg does not have result: %s", toCString( arg ) );
878 addCast( arg, param, exprTypeVars );
879 if ( !needsBoxing( param, arg->result, exprTypeVars, typeSubs ) ) {
880 return;
881 }
882 CodeLocation const & location = arg->location;
883
884 if ( arg->get_lvalue() ) {
885 // The argument expression may be CFA lvalue, but not C lvalue,
886 // so apply generalizedLvalue transformations.
887 // if ( auto var = dynamic_cast<ast::VariableExpr const *>( arg ) ) {
888 // if ( dynamic_cast<ast::ArrayType const *>( varExpr->var->get_type() ) ){
889 // // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
890 // return;
891 // }
892 // }
893 arg = generalizedLvalue( new ast::AddressExpr( arg->location, arg ) );
894 if ( !ResolvExpr::typesCompatible( param, arg->result ) ) {
895 // Silence warnings by casting boxed parameters when the actually
896 // type does not match up with the formal type.
897 arg = new ast::CastExpr( location, arg, ast::deepCopy( param ) );
898 }
899 } else {
900 // Use type computed in unification to declare boxed variables.
901 ast::ptr<ast::Type> newType = ast::deepCopy( param );
902 if ( typeSubs ) typeSubs->apply( newType );
903 ast::ObjectDecl * newObj = makeTemporary( location, newType );
904 auto assign = ast::UntypedExpr::createCall( location, "?=?", {
905 new ast::VariableExpr( location, newObj ),
906 arg,
907 } );
908 stmtsToAddBefore.push_back( new ast::ExprStmt( location, assign ) );
909 arg = new ast::AddressExpr(
910 new ast::VariableExpr( location, newObj ) );
911 }
912}
913
914void CallAdapter::boxParams(
915 ast::ApplicationExpr const * expr,
916 ast::vector<ast::Expr>::iterator arg,
917 ast::FunctionType const * function,
918 const TypeVarMap & typeVars ) {
919 for ( auto param : function->params ) {
920 assertf( arg != expr->args.end(),
921 "boxParams: missing argument for param %s to %s in %s",
922 toCString( param ), toCString( function ), toCString( expr ) );
923 boxParam( *arg, param, typeVars );
924 ++arg;
925 }
926}
927
928void CallAdapter::addInferredParams(
929 ast::ApplicationExpr * expr,
930 ast::vector<ast::Expr>::iterator arg,
931 ast::FunctionType const * functionType,
932 TypeVarMap const & typeVars ) {
933 ast::vector<ast::Expr>::iterator cur = arg;
934 for ( auto assertion : functionType->assertions ) {
935 auto inferParam = expr->inferred.inferParams().find(
936 assertion->var->uniqueId );
937 assertf( inferParam != expr->inferred.inferParams().end(),
938 "addInferredParams missing inferred parameter: %s in: %s",
939 toCString( assertion ), toCString( expr ) );
940 ast::ptr<ast::Expr> newExpr = ast::deepCopy( inferParam->second.expr );
941 boxParam( newExpr, assertion->result, typeVars );
942 cur = expr->args.insert( cur, newExpr.release() );
943 ++cur;
944 }
945}
946
947/// Modifies the ApplicationExpr to accept adapter functions for its
948/// assertion and parameters, declares the required adapters.
949void CallAdapter::passAdapters(
950 ast::ApplicationExpr * expr,
951 ast::FunctionType const * type,
952 const TypeVarMap & exprTypeVars ) {
953 // Collect a list of function types passed as parameters or implicit
954 // parameters (assertions).
955 ast::vector<ast::Type> const & paramList = type->params;
956 ast::vector<ast::FunctionType> functions;
957
958 for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
959 findFunction( assertion->result, functions, exprTypeVars, needsAdapter );
960 }
961 for ( ast::ptr<ast::Type> const & arg : paramList ) {
962 findFunction( arg, functions, exprTypeVars, needsAdapter );
963 }
964
965 // Parameter function types for which an appropriate adapter has been
966 // generated. We cannot use the types after applying substitutions,
967 // since two different parameter types may be unified to the same type.
968 std::set<std::string> adaptersDone;
969
970 CodeLocation const & location = expr->location;
971
972 for ( ast::ptr<ast::FunctionType> const & funcType : functions ) {
973 std::string mangleName = Mangle::mangle( funcType );
974
975 // Only attempt to create an adapter or pass one as a parameter if we
976 // haven't already done so for this pre-substitution parameter
977 // function type.
978 // The second part of the result if is if the element was inserted.
979 if ( !adaptersDone.insert( mangleName ).second ) continue;
980
981 // Apply substitution to type variables to figure out what the
982 // adapter's type should look like. (Copy to make the release safe.)
983 assert( typeSubs );
984 auto result = typeSubs->apply( ast::deepCopy( funcType ) );
985 ast::FunctionType * realType = ast::mutate( result.node.release() );
986 mangleName = Mangle::mangle( realType );
987 mangleName += makePolyMonoSuffix( funcType, exprTypeVars );
988
989 // Check if the adapter has already been created, or has to be.
990 using AdapterIter = decltype(adapters)::iterator;
991 AdapterIter adapter = adapters.find( mangleName );
992 if ( adapter == adapters.end() ) {
993 ast::FunctionDecl * newAdapter = makeAdapter(
994 funcType, realType, mangleName, exprTypeVars, location );
995 std::pair<AdapterIter, bool> answer =
996 adapters.insert( mangleName, newAdapter );
997 adapter = answer.first;
998 stmtsToAddBefore.push_back(
999 new ast::DeclStmt( location, newAdapter ) );
1000 }
1001 assert( adapter != adapters.end() );
1002
1003 // Add the approprate adapter as a parameter.
1004 expr->args.insert( expr->args.begin(),
1005 new ast::VariableExpr( location, adapter->second ) );
1006 }
1007}
1008
1009// Parameter and argument may be used wrong around here.
1010ast::Expr * makeAdapterArg(
1011 ast::DeclWithType const * param,
1012 ast::Type const * arg,
1013 ast::Type const * realParam,
1014 TypeVarMap const & typeVars,
1015 CodeLocation const & location ) {
1016 assert( param );
1017 assert( arg );
1018 assert( realParam );
1019 if ( isPolyType( realParam, typeVars ) && !isPolyType( arg ) ) {
1020 ast::UntypedExpr * deref = ast::UntypedExpr::createDeref(
1021 location,
1022 new ast::CastExpr( location,
1023 new ast::VariableExpr( location, param ),
1024 new ast::PointerType( ast::deepCopy( arg ) )
1025 )
1026 );
1027 deref->result = ast::deepCopy( arg );
1028 return deref;
1029 }
1030 return new ast::VariableExpr( location, param );
1031}
1032
1033// This seems to be one of the problematic functions.
1034void addAdapterParams(
1035 ast::ApplicationExpr * adaptee,
1036 ast::vector<ast::Type>::const_iterator arg,
1037 ast::vector<ast::DeclWithType>::iterator param,
1038 ast::vector<ast::DeclWithType>::iterator paramEnd,
1039 ast::vector<ast::Type>::const_iterator realParam,
1040 TypeVarMap const & typeVars,
1041 CodeLocation const & location ) {
1042 UniqueName paramNamer( "_p" );
1043 for ( ; param != paramEnd ; ++param, ++arg, ++realParam ) {
1044 if ( "" == (*param)->name ) {
1045 auto mutParam = (*param).get_and_mutate();
1046 mutParam->name = paramNamer.newName();
1047 mutParam->linkage = ast::Linkage::C;
1048 }
1049 adaptee->args.push_back(
1050 makeAdapterArg( *param, *arg, *realParam, typeVars, location ) );
1051 }
1052}
1053
1054ast::FunctionDecl * CallAdapter::makeAdapter(
1055 ast::FunctionType const * adaptee,
1056 ast::FunctionType const * realType,
1057 std::string const & mangleName,
1058 TypeVarMap const & typeVars,
1059 CodeLocation const & location ) const {
1060 ast::FunctionType * adapterType = makeAdapterType( adaptee, typeVars );
1061 adapterType = ast::mutate( scrubTypeVars( adapterType, typeVars ) );
1062
1063 // Some of these names will be overwritten, but it gives a default.
1064 UniqueName pNamer( "_param" );
1065 UniqueName rNamer( "_ret" );
1066
1067 bool first = true;
1068
1069 ast::FunctionDecl * adapterDecl = new ast::FunctionDecl( location,
1070 makeAdapterName( mangleName ),
1071 {}, // forall
1072 {}, // assertions
1073 map_range<ast::vector<ast::DeclWithType>>( adapterType->params,
1074 [&pNamer, &location, &first]( ast::ptr<ast::Type> const & param ) {
1075 // [Trying to make the generated code match exactly more often.]
1076 if ( first ) {
1077 first = false;
1078 return new ast::ObjectDecl( location, "_adaptee", param );
1079 }
1080 return new ast::ObjectDecl( location, pNamer.newName(), param );
1081 } ),
1082 map_range<ast::vector<ast::DeclWithType>>( adapterType->returns,
1083 [&rNamer, &location]( ast::ptr<ast::Type> const & retval ) {
1084 return new ast::ObjectDecl( location, rNamer.newName(), retval );
1085 } ),
1086 nullptr, // stmts
1087 {}, // storage
1088 ast::Linkage::C
1089 );
1090
1091 ast::DeclWithType * adapteeDecl =
1092 adapterDecl->params.front().get_and_mutate();
1093 adapteeDecl->name = "_adaptee";
1094
1095 // Do not carry over attributes to real type parameters/return values.
1096 auto mutRealType = ast::mutate( realType );
1097 for ( ast::ptr<ast::Type> & decl : mutRealType->params ) {
1098 if ( decl->attributes.empty() ) continue;
1099 auto mut = ast::mutate( decl.get() );
1100 mut->attributes.clear();
1101 decl = mut;
1102 }
1103 for ( ast::ptr<ast::Type> & decl : mutRealType->returns ) {
1104 if ( decl->attributes.empty() ) continue;
1105 auto mut = ast::mutate( decl.get() );
1106 mut->attributes.clear();
1107 decl = mut;
1108 }
1109 realType = mutRealType;
1110
1111 ast::ApplicationExpr * adapteeApp = new ast::ApplicationExpr( location,
1112 new ast::CastExpr( location,
1113 new ast::VariableExpr( location, adapteeDecl ),
1114 new ast::PointerType( realType )
1115 )
1116 );
1117
1118 for ( auto group : group_iterate( realType->assertions,
1119 adapterType->assertions, adaptee->assertions ) ) {
1120 auto assertArg = std::get<0>( group );
1121 auto assertParam = std::get<1>( group );
1122 auto assertReal = std::get<2>( group );
1123 adapteeApp->args.push_back( makeAdapterArg(
1124 assertParam->var, assertArg->var->get_type(),
1125 assertReal->var->get_type(), typeVars, location
1126 ) );
1127 }
1128
1129 ast::vector<ast::Type>::const_iterator
1130 arg = realType->params.begin(),
1131 param = adapterType->params.begin(),
1132 realParam = adaptee->params.begin();
1133 ast::vector<ast::DeclWithType>::iterator
1134 paramDecl = adapterDecl->params.begin();
1135 // Skip adaptee parameter in the adapter type.
1136 ++param;
1137 ++paramDecl;
1138
1139 ast::Stmt * bodyStmt;
1140 // Returns void/nothing.
1141 if ( realType->returns.empty() ) {
1142 addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1143 realParam, typeVars, location );
1144 bodyStmt = new ast::ExprStmt( location, adapteeApp );
1145 // Returns a polymorphic type.
1146 } else if ( isDynType( adaptee->returns.front(), typeVars ) ) {
1147 ast::UntypedExpr * assign = new ast::UntypedExpr( location,
1148 new ast::NameExpr( location, "?=?" ) );
1149 ast::UntypedExpr * deref = ast::UntypedExpr::createDeref( location,
1150 new ast::CastExpr( location,
1151 new ast::VariableExpr( location, *paramDecl++ ),
1152 new ast::PointerType(
1153 ast::deepCopy( realType->returns.front() ) ) ) );
1154 assign->args.push_back( deref );
1155 addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1156 realParam, typeVars, location );
1157 assign->args.push_back( adapteeApp );
1158 bodyStmt = new ast::ExprStmt( location, assign );
1159 // Adapter for a function that returns a monomorphic value.
1160 } else {
1161 addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1162 realParam, typeVars, location );
1163 bodyStmt = new ast::ReturnStmt( location, adapteeApp );
1164 }
1165
1166 adapterDecl->stmts = new ast::CompoundStmt( location, { bodyStmt } );
1167 return adapterDecl;
1168}
1169
1170ast::Expr const * makeIncrDecrExpr(
1171 CodeLocation const & location,
1172 ast::ApplicationExpr const * expr,
1173 ast::Type const * polyType,
1174 bool isIncr ) {
1175 ast::NameExpr * opExpr =
1176 new ast::NameExpr( location, isIncr ? "?+=?" : "?-=?" );
1177 ast::UntypedExpr * addAssign = new ast::UntypedExpr( location, opExpr );
1178 if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1179 addAssign->args.push_back( address->arg );
1180 } else {
1181 addAssign->args.push_back( expr->args.front() );
1182 }
1183 addAssign->args.push_back( new ast::NameExpr( location,
1184 sizeofName( Mangle::mangleType( polyType ) ) ) );
1185 addAssign->result = ast::deepCopy( expr->result );
1186 addAssign->env = expr->env ? expr->env : addAssign->env;
1187 return addAssign;
1188}
1189
1190/// Handles intrinsic functions for postvisit ApplicationExpr.
1191ast::Expr const * CallAdapter::handleIntrinsics(
1192 ast::ApplicationExpr const * expr ) {
1193 auto varExpr = expr->func.as<ast::VariableExpr>();
1194 if ( !varExpr || varExpr->var->linkage != ast::Linkage::Intrinsic ) {
1195 return nullptr;
1196 }
1197 std::string const & varName = varExpr->var->name;
1198
1199 // Index Intrinsic:
1200 if ( "?[?]" == varName ) {
1201 assert( expr->result );
1202 assert( 2 == expr->args.size() );
1203
1204 ast::Type const * baseType1 =
1205 isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1206 ast::Type const * baseType2 =
1207 isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1208 // If neither argument is a polymorphic pointer, do nothing.
1209 if ( !baseType1 && !baseType2 ) {
1210 return expr;
1211 }
1212 // The arguments cannot both be polymorphic pointers.
1213 assert( !baseType1 || !baseType2 );
1214 // (So exactly one of the arguments is a polymorphic pointer.)
1215
1216 CodeLocation const & location = expr->location;
1217 CodeLocation const & location1 = expr->args.front()->location;
1218 CodeLocation const & location2 = expr->args.back()->location;
1219
1220 ast::UntypedExpr * ret = new ast::UntypedExpr( location,
1221 new ast::NameExpr( location, "?+?" ) );
1222 if ( baseType1 ) {
1223 auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1224 expr->args.back(),
1225 new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1226 } );
1227 ret->args.push_back( expr->args.front() );
1228 ret->args.push_back( multiply );
1229 } else {
1230 assert( baseType2 );
1231 auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1232 expr->args.front(),
1233 new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1234 } );
1235 ret->args.push_back( multiply );
1236 ret->args.push_back( expr->args.back() );
1237 }
1238 ret->result = ast::deepCopy( expr->result );
1239 ret->env = expr->env ? expr->env : ret->env;
1240 return ret;
1241 // Dereference Intrinsic:
1242 } else if ( "*?" == varName ) {
1243 assert( expr->result );
1244 assert( 1 == expr->args.size() );
1245
1246 // If this isn't for a poly type, then do nothing.
1247 if ( !isPolyType( expr->result, scopeTypeVars, typeSubs ) ) {
1248 return expr;
1249 }
1250
1251 // Remove dereference from polymorphic types since they are boxed.
1252 ast::Expr * ret = ast::deepCopy( expr->args.front() );
1253 // Fix expression type to remove pointer.
1254 ret->result = expr->result;
1255 ret->env = expr->env ? expr->env : ret->env;
1256 return ret;
1257 // Post-Increment/Decrement Intrinsics:
1258 } else if ( "?++" == varName || "?--" == varName ) {
1259 assert( expr->result );
1260 assert( 1 == expr->args.size() );
1261
1262 ast::Type const * baseType =
1263 isPolyType( expr->result, scopeTypeVars, typeSubs );
1264 if ( nullptr == baseType ) {
1265 return expr;
1266 }
1267 ast::Type * tempType = ast::deepCopy( expr->result );
1268 if ( typeSubs ) {
1269 auto result = typeSubs->apply( tempType );
1270 tempType = ast::mutate( result.node.release() );
1271 }
1272 CodeLocation const & location = expr->location;
1273 ast::ObjectDecl * newObj = makeTemporary( location, tempType );
1274 ast::VariableExpr * tempExpr =
1275 new ast::VariableExpr( location, newObj );
1276 ast::UntypedExpr * assignExpr = new ast::UntypedExpr( location,
1277 new ast::NameExpr( location, "?=?" ) );
1278 assignExpr->args.push_back( ast::deepCopy( tempExpr ) );
1279 if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1280 assignExpr->args.push_back( ast::deepCopy( address->arg ) );
1281 } else {
1282 assignExpr->args.push_back( ast::deepCopy( expr->args.front() ) );
1283 }
1284 return new ast::CommaExpr( location,
1285 new ast::CommaExpr( location,
1286 assignExpr,
1287 makeIncrDecrExpr( location, expr, baseType, "?++" == varName )
1288 ),
1289 tempExpr
1290 );
1291 // Pre-Increment/Decrement Intrinsics:
1292 } else if ( "++?" == varName || "--?" == varName ) {
1293 assert( expr->result );
1294 assert( 1 == expr->args.size() );
1295
1296 ast::Type const * baseType =
1297 isPolyType( expr->result, scopeTypeVars, typeSubs );
1298 if ( nullptr == baseType ) {
1299 return expr;
1300 }
1301 return makeIncrDecrExpr(
1302 expr->location, expr, baseType, "++?" == varName );
1303 // Addition and Subtration Intrinsics:
1304 } else if ( "?+?" == varName || "?-?" == varName ) {
1305 assert( expr->result );
1306 assert( 2 == expr->args.size() );
1307
1308 auto baseType1 =
1309 isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1310 auto baseType2 =
1311 isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1312
1313 CodeLocation const & location = expr->location;
1314 CodeLocation const & location1 = expr->args.front()->location;
1315 CodeLocation const & location2 = expr->args.back()->location;
1316 // LHS op RHS -> (LHS op RHS) / sizeof(LHS)
1317 if ( baseType1 && baseType2 ) {
1318 auto divide = ast::UntypedExpr::createCall( location, "?/?", {
1319 expr,
1320 new ast::SizeofExpr( location, deepCopy( baseType1 ) ),
1321 } );
1322 if ( expr->env ) divide->env = expr->env;
1323 return divide;
1324 // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1325 } else if ( baseType1 ) {
1326 auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1327 expr->args.back(),
1328 new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1329 } );
1330 return ast::mutate_field_index(
1331 expr, &ast::ApplicationExpr::args, 1, multiply );
1332 // LHS op RHS -> (LHS * sizeof(RHS)) op RHS
1333 } else if ( baseType2 ) {
1334 auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1335 expr->args.front(),
1336 new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1337 } );
1338 return ast::mutate_field_index(
1339 expr, &ast::ApplicationExpr::args, 0, multiply );
1340 }
1341 // Addition and Subtration Relative Assignment Intrinsics:
1342 } else if ( "?+=?" == varName || "?-=?" == varName ) {
1343 assert( expr->result );
1344 assert( 2 == expr->args.size() );
1345
1346 CodeLocation const & location1 = expr->args.front()->location;
1347 CodeLocation const & location2 = expr->args.back()->location;
1348 auto baseType = isPolyPtr( expr->result, scopeTypeVars, typeSubs );
1349 // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1350 if ( baseType ) {
1351 auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1352 expr->args.back(),
1353 new ast::SizeofExpr( location1, deepCopy( baseType ) ),
1354 } );
1355 return ast::mutate_field_index(
1356 expr, &ast::ApplicationExpr::args, 1, multiply );
1357 }
1358 }
1359 return expr;
1360}
1361
1362ast::ObjectDecl * CallAdapter::makeTemporary(
1363 CodeLocation const & location, ast::Type const * type ) {
1364 auto newObj = new ast::ObjectDecl( location, tmpNamer.newName(), type );
1365 stmtsToAddBefore.push_back( new ast::DeclStmt( location, newObj ) );
1366 return newObj;
1367}
1368
1369// --------------------------------------------------------------------------
1370/// Modifies declarations to accept implicit parameters.
1371/// * Move polymorphic returns in function types to pointer-type parameters.
1372/// * Adds type size and assertion parameters to parameter lists.
1373struct DeclAdapter final {
1374 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
1375 ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
1376private:
1377 void addAdapters( ast::FunctionDecl * decl, TypeVarMap & localTypeVars );
1378};
1379
1380ast::ObjectDecl * makeObj(
1381 CodeLocation const & location, std::string const & name ) {
1382 // The size/align parameters may be unused, so add the unused attribute.
1383 return new ast::ObjectDecl( location, name,
1384 makeLayoutCType(),
1385 nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr,
1386 { new ast::Attribute( "unused" ) } );
1387}
1388
1389/// A modified and specialized version of ast::add_qualifiers.
1390ast::Type const * addConst( ast::Type const * type ) {
1391 ast::CV::Qualifiers cvq = { ast::CV::Const };
1392 if ( ( type->qualifiers & cvq ) != 0 ) return type;
1393 auto mutType = ast::mutate( type );
1394 mutType->qualifiers |= cvq;
1395 return mutType;
1396}
1397
1398ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
1399 TypeVarMap localTypeVars;
1400 makeTypeVarMap( decl, localTypeVars );
1401
1402 auto mutDecl = mutate( decl );
1403
1404 // Move polymorphic return type to parameter list.
1405 if ( isDynRet( mutDecl->type ) ) {
1406 auto ret = strict_dynamic_cast<ast::ObjectDecl *>(
1407 mutDecl->returns.front().get_and_mutate() );
1408 ret->set_type( new ast::PointerType( ret->type ) );
1409 mutDecl->params.insert( mutDecl->params.begin(), ret );
1410 mutDecl->returns.erase( mutDecl->returns.begin() );
1411 ret->init = nullptr;
1412 }
1413
1414 // Add size/align and assertions for type parameters to parameter list.
1415 ast::vector<ast::DeclWithType> inferredParams;
1416 ast::vector<ast::DeclWithType> layoutParams;
1417 for ( ast::ptr<ast::TypeDecl> & typeParam : mutDecl->type_params ) {
1418 auto mutParam = mutate( typeParam.get() );
1419 // Add all size and alignment parameters to parameter list.
1420 if ( mutParam->isComplete() ) {
1421 ast::TypeInstType paramType( mutParam );
1422 std::string paramName = Mangle::mangleType( &paramType );
1423
1424 auto sizeParam = makeObj( typeParam->location, sizeofName( paramName ) );
1425 layoutParams.emplace_back( sizeParam );
1426
1427 auto alignParam = makeObj( typeParam->location, alignofName( paramName ) );
1428 layoutParams.emplace_back( alignParam );
1429 }
1430 // Assertions should be stored in the main list.
1431 assert( mutParam->assertions.empty() );
1432 typeParam = mutParam;
1433 }
1434 for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
1435 ast::DeclWithType * mutAssert = ast::mutate( assert.get() );
1436 // Assertion parameters may not be used in body,
1437 // pass along with unused attribute.
1438 mutAssert->attributes.push_back( new ast::Attribute( "unused" ) );
1439 mutAssert->set_type( addConst( mutAssert->get_type() ) );
1440 inferredParams.emplace_back( mutAssert );
1441 }
1442 mutDecl->assertions.clear();
1443
1444 // Prepend each argument group. From last group to first. addAdapters
1445 // does do the same, it just does it itself and see all other parameters.
1446 spliceBegin( mutDecl->params, inferredParams );
1447 spliceBegin( mutDecl->params, layoutParams );
1448 addAdapters( mutDecl, localTypeVars );
1449
1450 // Now have to update the type to match the declaration.
1451 ast::FunctionType * type = new ast::FunctionType(
1452 mutDecl->type->isVarArgs, mutDecl->type->qualifiers );
1453 // The forall clauses don't match until Eraser. The assertions are empty.
1454 for ( auto param : mutDecl->params ) {
1455 type->params.emplace_back( param->get_type() );
1456 }
1457 for ( auto retval : mutDecl->returns ) {
1458 type->returns.emplace_back( retval->get_type() );
1459 }
1460 mutDecl->type = type;
1461
1462 return mutDecl;
1463}
1464
1465ast::FunctionDecl const * DeclAdapter::postvisit(
1466 ast::FunctionDecl const * decl ) {
1467 ast::FunctionDecl * mutDecl = mutate( decl );
1468 if ( !mutDecl->returns.empty() && mutDecl->stmts
1469 // Intrinsic functions won't be using the _retval so no need to
1470 // generate it.
1471 && mutDecl->linkage != ast::Linkage::Intrinsic
1472 // Remove check for prefix once thunks properly use ctor/dtors.
1473 && !isPrefix( mutDecl->name, "_thunk" )
1474 && !isPrefix( mutDecl->name, "_adapter" ) ) {
1475 assert( 1 == mutDecl->returns.size() );
1476 ast::DeclWithType const * retval = mutDecl->returns.front();
1477 if ( "" == retval->name ) {
1478 retval = ast::mutate_field(
1479 retval, &ast::DeclWithType::name, "_retval" );
1480 mutDecl->returns.front() = retval;
1481 }
1482 auto stmts = mutDecl->stmts.get_and_mutate();
1483 stmts->kids.push_front( new ast::DeclStmt( retval->location, retval ) );
1484 ast::DeclWithType * newRet = ast::deepCopy( retval );
1485 mutDecl->returns.front() = newRet;
1486 }
1487 // Errors should have been caught by this point, remove initializers from
1488 // parameters to allow correct codegen of default arguments.
1489 for ( ast::ptr<ast::DeclWithType> & param : mutDecl->params ) {
1490 if ( auto obj = param.as<ast::ObjectDecl>() ) {
1491 param = ast::mutate_field( obj, &ast::ObjectDecl::init, nullptr );
1492 }
1493 }
1494 return mutDecl;
1495}
1496
1497void DeclAdapter::addAdapters(
1498 ast::FunctionDecl * mutDecl, TypeVarMap & localTypeVars ) {
1499 ast::vector<ast::FunctionType> functions;
1500 for ( ast::ptr<ast::DeclWithType> & arg : mutDecl->params ) {
1501 ast::Type const * type = arg->get_type();
1502 type = findAndReplaceFunction( type, functions, localTypeVars, needsAdapter );
1503 arg.get_and_mutate()->set_type( type );
1504 }
1505 std::set<std::string> adaptersDone;
1506 for ( ast::ptr<ast::FunctionType> const & func : functions ) {
1507 std::string mangleName = mangleAdapterName( func, localTypeVars );
1508 if ( adaptersDone.find( mangleName ) != adaptersDone.end() ) {
1509 continue;
1510 }
1511 std::string adapterName = makeAdapterName( mangleName );
1512 // The adapter may not actually be used, so make sure it has unused.
1513 mutDecl->params.insert( mutDecl->params.begin(), new ast::ObjectDecl(
1514 mutDecl->location, adapterName,
1515 new ast::PointerType( makeAdapterType( func, localTypeVars ) ),
1516 nullptr, {}, {}, nullptr,
1517 { new ast::Attribute( "unused" ) } ) );
1518 adaptersDone.insert( adaptersDone.begin(), mangleName );
1519 }
1520}
1521
1522// --------------------------------------------------------------------------
1523// TODO: Ideally, there would be no floating nodes at all.
1524/// Corrects the floating nodes created in CallAdapter.
1525struct RewireAdapters final : public ast::WithGuards {
1526 ScopedMap<std::string, ast::ObjectDecl const *> adapters;
1527 void beginScope() { adapters.beginScope(); }
1528 void endScope() { adapters.endScope(); }
1529 void previsit( ast::FunctionDecl const * decl );
1530 ast::VariableExpr const * previsit( ast::VariableExpr const * expr );
1531};
1532
1533void RewireAdapters::previsit( ast::FunctionDecl const * decl ) {
1534 GuardScope( adapters );
1535 for ( ast::ptr<ast::DeclWithType> const & param : decl->params ) {
1536 if ( auto objectParam = param.as<ast::ObjectDecl>() ) {
1537 adapters.insert( objectParam->name, objectParam );
1538 }
1539 }
1540}
1541
1542ast::VariableExpr const * RewireAdapters::previsit(
1543 ast::VariableExpr const * expr ) {
1544 // If the node is not floating, we can skip.
1545 if ( expr->var->isManaged() ) return expr;
1546 auto it = adapters.find( expr->var->name );
1547 assertf( it != adapters.end(), "Could not correct floating node." );
1548 return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
1549}
1550
1551// --------------------------------------------------------------------------
1552/// Inserts code to access polymorphic layout inforation.
1553/// * Replaces member and size/alignment/offsetof expressions on polymorphic
1554/// generic types with calculated expressions.
1555/// * Replaces member expressions for polymorphic types with calculated
1556/// add-field-offset-and-dereference.
1557/// * Calculates polymorphic offsetof expressions from offset array.
1558/// * Inserts dynamic calculation of polymorphic type layouts where needed.
1559struct PolyGenericCalculator final :
1560 public ast::WithConstTypeSubstitution,
1561 public ast::WithDeclsToAdd<>,
1562 public ast::WithGuards,
1563 public ast::WithStmtsToAdd<>,
1564 public ast::WithVisitorRef<PolyGenericCalculator> {
1565 PolyGenericCalculator();
1566
1567 void previsit( ast::FunctionDecl const * decl );
1568 void previsit( ast::TypedefDecl const * decl );
1569 void previsit( ast::TypeDecl const * decl );
1570 ast::Decl const * postvisit( ast::TypeDecl const * decl );
1571 ast::StructDecl const * previsit( ast::StructDecl const * decl );
1572 ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
1573 ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
1574 ast::Expr const * postvisit( ast::MemberExpr const * expr );
1575 void previsit( ast::AddressExpr const * expr );
1576 ast::Expr const * postvisit( ast::AddressExpr const * expr );
1577 ast::Expr const * postvisit( ast::SizeofExpr const * expr );
1578 ast::Expr const * postvisit( ast::AlignofExpr const * expr );
1579 ast::Expr const * postvisit( ast::OffsetofExpr const * expr );
1580 ast::Expr const * postvisit( ast::OffsetPackExpr const * expr );
1581
1582 ast::Expr const * postvisit( ast::EnumPosExpr const * expr );
1583
1584 void beginScope();
1585 void endScope();
1586private:
1587 /// Makes a new variable in the current scope with the given name,
1588 /// type and optional initializer.
1589 ast::ObjectDecl * makeVar(
1590 CodeLocation const & location, std::string const & name,
1591 ast::Type const * type, ast::Init const * init = nullptr );
1592 /// Returns true if the type has a dynamic layout;
1593 /// such a layout will be stored in appropriately-named local variables
1594 /// when the function returns.
1595 bool findGeneric( CodeLocation const & location, ast::Type const * );
1596 /// Adds type parameters to the layout call; will generate the
1597 /// appropriate parameters if needed.
1598 void addSTypeParamsToLayoutCall(
1599 ast::UntypedExpr * layoutCall,
1600 const ast::vector<ast::Type> & otypeParams );
1601 /// Change the type of generic aggregate members to char[].
1602 void mutateMembers( ast::AggregateDecl * aggr );
1603 /// Returns the calculated sizeof expression for type, or nullptr for use
1604 /// C sizeof().
1605 ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
1606 /// Enters a new scope for type-variables,
1607 /// adding the type variables from the provided type.
1608 void beginTypeScope( ast::Type const * );
1609
1610 /// The type variables and polymorphic parameters currently in scope.
1611 TypeVarMap scopeTypeVars;
1612 /// Set of generic type layouts known in the current scope,
1613 /// indexed by sizeofName.
1614 ScopedSet<std::string> knownLayouts;
1615 /// Set of non-generic types for which the offset array exists in the
1616 /// current scope, indexed by offsetofName.
1617 ScopedSet<std::string> knownOffsets;
1618 /// Namer for VLA (variable length array) buffers.
1619 UniqueName bufNamer;
1620 /// If the argument of an AddressExpr is MemberExpr, it is stored here.
1621 ast::MemberExpr const * addrMember = nullptr;
1622};
1623
1624PolyGenericCalculator::PolyGenericCalculator() :
1625 knownLayouts(), knownOffsets(), bufNamer( "_buf" )
1626{}
1627
1628/// Converts polymorphic type into a suitable monomorphic representation.
1629/// Currently: __attribute__(( aligned(8) )) char[size_T];
1630ast::Type * polyToMonoType( CodeLocation const & location,
1631 ast::Type const * declType ) {
1632 auto charType = new ast::BasicType( ast::BasicType::Char );
1633 auto size = new ast::NameExpr( location,
1634 sizeofName( Mangle::mangleType( declType ) ) );
1635 auto ret = new ast::ArrayType( charType, size,
1636 ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
1637 ret->attributes.emplace_back( new ast::Attribute( "aligned",
1638 { ast::ConstantExpr::from_int( location, 8 ) } ) );
1639 return ret;
1640}
1641
1642void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
1643 GuardScope( *this );
1644 beginTypeScope( decl->type );
1645}
1646
1647void PolyGenericCalculator::previsit( ast::TypedefDecl const * decl ) {
1648 assertf( false, "All typedef declarations should be removed." );
1649 beginTypeScope( decl->base );
1650}
1651
1652void PolyGenericCalculator::previsit( ast::TypeDecl const * decl ) {
1653 addToTypeVarMap( decl, scopeTypeVars );
1654}
1655
1656ast::Decl const * PolyGenericCalculator::postvisit(
1657 ast::TypeDecl const * decl ) {
1658 ast::Type const * base = decl->base;
1659 if ( nullptr == base ) return decl;
1660
1661 // Add size/align variables for opaque type declarations.
1662 ast::TypeInstType inst( decl->name, decl );
1663 std::string typeName = Mangle::mangleType( &inst );
1664
1665 ast::ObjectDecl * sizeDecl = new ast::ObjectDecl( decl->location,
1666 sizeofName( typeName ), makeLayoutCType(),
1667 new ast::SingleInit( decl->location,
1668 new ast::SizeofExpr( decl->location, deepCopy( base ) )
1669 )
1670 );
1671 ast::ObjectDecl * alignDecl = new ast::ObjectDecl( decl->location,
1672 alignofName( typeName ), makeLayoutCType(),
1673 new ast::SingleInit( decl->location,
1674 new ast::AlignofExpr( decl->location, deepCopy( base ) )
1675 )
1676 );
1677
1678 // Ensure that the initializing sizeof/alignof exprs are properly mutated.
1679 sizeDecl->accept( *visitor );
1680 alignDecl->accept( *visitor );
1681
1682 // A little trick to replace this with two declarations.
1683 // Adding after makes sure that there is no conflict with adding stmts.
1684 declsToAddAfter.push_back( alignDecl );
1685 return sizeDecl;
1686}
1687
1688ast::StructDecl const * PolyGenericCalculator::previsit(
1689 ast::StructDecl const * decl ) {
1690 auto mutDecl = mutate( decl );
1691 mutateMembers( mutDecl );
1692 return mutDecl;
1693}
1694
1695ast::UnionDecl const * PolyGenericCalculator::previsit(
1696 ast::UnionDecl const * decl ) {
1697 auto mutDecl = mutate( decl );
1698 mutateMembers( mutDecl );
1699 return mutDecl;
1700}
1701
1702ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1703 ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
1704 if ( !decl || !findGeneric( decl->location, decl->type ) ) {
1705 return stmt;
1706 }
1707
1708 // Change initialization of a polymorphic value object to allocate via a
1709 // variable-length-array (alloca cannot be safely used in loops).
1710 ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
1711 bufNamer.newName(),
1712 polyToMonoType( decl->location, decl->type ),
1713 nullptr, {}, ast::Linkage::C
1714 );
1715 stmtsToAddBefore.push_back( new ast::DeclStmt( stmt->location, newBuf ) );
1716
1717 // If the object has a cleanup attribute, the clean-up should be on the
1718 // buffer, not the pointer. [Perhaps this should be lifted?]
1719 auto matchAndMove = [newBuf]( ast::ptr<ast::Attribute> & attr ) {
1720 if ( "cleanup" == attr->name ) {
1721 newBuf->attributes.push_back( attr );
1722 return true;
1723 }
1724 return false;
1725 };
1726
1727 auto mutDecl = mutate( decl );
1728
1729 // Forally, side effects are not safe in this function. But it works.
1730 erase_if( mutDecl->attributes, matchAndMove );
1731
1732 mutDecl->init = new ast::SingleInit( decl->location,
1733 new ast::VariableExpr( decl->location, newBuf ) );
1734
1735 return ast::mutate_field( stmt, &ast::DeclStmt::decl, mutDecl );
1736}
1737
1738/// Checks if memberDecl matches the decl from an aggregate.
1739bool isMember( ast::DeclWithType const * memberDecl, ast::Decl const * decl ) {
1740 // No matter the field, if the name is different it is not the same.
1741 if ( memberDecl->name != decl->name ) {
1742 return false;
1743 }
1744
1745 if ( memberDecl->name.empty() ) {
1746 // Plan-9 Field: Match on unique_id.
1747 return ( memberDecl->uniqueId == decl->uniqueId );
1748 }
1749
1750 ast::DeclWithType const * declWithType =
1751 strict_dynamic_cast<ast::DeclWithType const *>( decl );
1752
1753 if ( memberDecl->mangleName.empty() || declWithType->mangleName.empty() ) {
1754 // Tuple-Element Field: Expect neither had mangled name;
1755 // accept match on simple name (like field_2) only.
1756 assert( memberDecl->mangleName.empty() );
1757 assert( declWithType->mangleName.empty() );
1758 return true;
1759 }
1760
1761 // Ordinary Field: Use full name to accommodate overloading.
1762 return ( memberDecl->mangleName == declWithType->mangleName );
1763}
1764
1765/// Finds the member in the base list that matches the given declaration;
1766/// returns its index, or -1 if not present.
1767long findMember( ast::DeclWithType const * memberDecl,
1768 const ast::vector<ast::Decl> & baseDecls ) {
1769 for ( auto const & [index, value] : enumerate( baseDecls ) ) {
1770 if ( isMember( memberDecl, value.get() ) ) {
1771 return index;
1772 }
1773 }
1774 return -1;
1775}
1776
1777/// Returns an index expression into the offset array for a type.
1778ast::Expr * makeOffsetIndex( CodeLocation const & location,
1779 ast::Type const * objectType, long i ) {
1780 std::string name = offsetofName( Mangle::mangleType( objectType ) );
1781 return ast::UntypedExpr::createCall( location, "?[?]", {
1782 new ast::NameExpr( location, name ),
1783 ast::ConstantExpr::from_ulong( location, i ),
1784 } );
1785}
1786
1787ast::Expr const * PolyGenericCalculator::postvisit(
1788 ast::MemberExpr const * expr ) {
1789 // Only mutate member expressions for polymorphic types.
1790 ast::Type const * objectType = hasPolyBase(
1791 expr->aggregate->result, scopeTypeVars
1792 );
1793 if ( !objectType ) return expr;
1794 // Ensure layout for this type is available.
1795 // The boolean result is ignored.
1796 findGeneric( expr->location, objectType );
1797
1798 // Replace member expression with dynamically-computed layout expression.
1799 ast::Expr * newMemberExpr = nullptr;
1800 if ( auto structType = dynamic_cast<ast::StructInstType const *>( objectType ) ) {
1801 long offsetIndex = findMember( expr->member, structType->base->members );
1802 if ( -1 == offsetIndex ) return expr;
1803
1804 // Replace member expression with pointer to struct plus offset.
1805 ast::UntypedExpr * fieldLoc = new ast::UntypedExpr( expr->location,
1806 new ast::NameExpr( expr->location, "?+?" ) );
1807 ast::Expr * aggr = deepCopy( expr->aggregate );
1808 aggr->env = nullptr;
1809 fieldLoc->args.push_back( aggr );
1810 fieldLoc->args.push_back(
1811 makeOffsetIndex( expr->location, objectType, offsetIndex ) );
1812 fieldLoc->result = deepCopy( expr->result );
1813 newMemberExpr = fieldLoc;
1814 // Union members are all at offset zero, so just use the aggregate expr.
1815 } else if ( dynamic_cast<ast::UnionInstType const *>( objectType ) ) {
1816 ast::Expr * aggr = deepCopy( expr->aggregate );
1817 aggr->env = nullptr;
1818 aggr->result = deepCopy( expr->result );
1819 newMemberExpr = aggr;
1820 } else {
1821 return expr;
1822 }
1823 assert( newMemberExpr );
1824
1825 // Must apply the generic substitution to the member type to handle cases
1826 // where the member is a generic parameter subsituted by a known concrete
1827 // type. [ex]
1828 // forall( T ) struct Box { T x; }
1829 // forall( T ) void f() {
1830 // Box( T * ) b; b.x;
1831 // }
1832 // TODO: expr->result should be exactly expr->member->get_type() after
1833 // substitution, so it doesn't seem like it should be necessary to apply
1834 // the substitution manually. For some reason this is not currently the
1835 // case. This requires more investigation.
1836 ast::ptr<ast::Type> memberType = deepCopy( expr->member->get_type() );
1837 ast::TypeSubstitution sub = genericSubstitution( objectType );
1838 sub.apply( memberType );
1839
1840 // Not all members of a polymorphic type are themselves of a polymorphic
1841 // type; in this cas the member expression should be wrapped and
1842 // dereferenced to form an lvalue.
1843 if ( !isPolyType( memberType, scopeTypeVars ) ) {
1844 auto ptrCastExpr = new ast::CastExpr( expr->location, newMemberExpr,
1845 new ast::PointerType( memberType ) );
1846 auto derefExpr = ast::UntypedExpr::createDeref( expr->location,
1847 ptrCastExpr );
1848 newMemberExpr = derefExpr;
1849 }
1850
1851 return newMemberExpr;
1852}
1853
1854void PolyGenericCalculator::previsit( ast::AddressExpr const * expr ) {
1855 GuardValue( addrMember ) = expr->arg.as<ast::MemberExpr>();
1856}
1857
1858ast::Expr const * PolyGenericCalculator::postvisit(
1859 ast::AddressExpr const * expr ) {
1860 // arg has to have been a MemberExpr and has been mutated.
1861 if ( nullptr == addrMember || expr->arg == addrMember ) {
1862 return expr;
1863 }
1864 ast::UntypedExpr const * untyped = expr->arg.as<ast::UntypedExpr>();
1865 if ( !untyped || getFunctionName( untyped ) != "?+?" ) {
1866 return expr;
1867 }
1868 // MemberExpr was converted to pointer + offset; and it is not valid C to
1869 // take the address of an addition, so strip away the address-of.
1870 // It also preserves the env value.
1871 return ast::mutate_field( expr->arg.get(), &ast::Expr::env, expr->env );
1872}
1873
1874ast::Expr const * PolyGenericCalculator::postvisit(
1875 ast::SizeofExpr const * expr ) {
1876 ast::Type const * type = expr->type ? expr->type : expr->expr->result;
1877 ast::Expr const * gen = genSizeof( expr->location, type );
1878 return ( gen ) ? gen : expr;
1879}
1880
1881ast::Expr const * PolyGenericCalculator::postvisit(
1882 ast::AlignofExpr const * expr ) {
1883 ast::Type const * type = expr->type ? expr->type : expr->expr->result;
1884 if ( findGeneric( expr->location, type ) ) {
1885 return new ast::NameExpr( expr->location,
1886 alignofName( Mangle::mangleType( type ) ) );
1887 } else {
1888 return expr;
1889 }
1890}
1891
1892ast::Expr const * PolyGenericCalculator::postvisit(
1893 ast::OffsetofExpr const * expr ) {
1894 ast::Type const * type = expr->type;
1895 if ( !findGeneric( expr->location, type ) ) return expr;
1896
1897 // Structures replace offsetof expression with an index into offset array.
1898 if ( auto structType = dynamic_cast<ast::StructInstType const *>( type ) ) {
1899 long offsetIndex = findMember( expr->member, structType->base->members );
1900 if ( -1 == offsetIndex ) return expr;
1901
1902 return makeOffsetIndex( expr->location, type, offsetIndex );
1903 // All union members are at offset zero.
1904 } else if ( dynamic_cast<ast::UnionInstType const *>( type ) ) {
1905 return ast::ConstantExpr::from_ulong( expr->location, 0 );
1906 } else {
1907 return expr;
1908 }
1909}
1910
1911ast::Expr const * PolyGenericCalculator::postvisit(
1912 ast::OffsetPackExpr const * expr ) {
1913 ast::StructInstType const * type = expr->type;
1914
1915 // Pull offset back from generated type information.
1916 if ( findGeneric( expr->location, type ) ) {
1917 return new ast::NameExpr( expr->location,
1918 offsetofName( Mangle::mangleType( type ) ) );
1919 }
1920
1921 std::string offsetName = offsetofName( Mangle::mangleType( type ) );
1922 // Use the already generated offsets for this type.
1923 if ( knownOffsets.contains( offsetName ) ) {
1924 return new ast::NameExpr( expr->location, offsetName );
1925 }
1926
1927 knownOffsets.insert( offsetName );
1928
1929 // Build initializer list for offset array.
1930 ast::vector<ast::Init> inits;
1931 for ( ast::ptr<ast::Decl> const & member : type->base->members ) {
1932 auto memberDecl = member.as<ast::DeclWithType>();
1933 assertf( memberDecl, "Requesting offset of non-DWT member: %s",
1934 toCString( member ) );
1935 inits.push_back( new ast::SingleInit( expr->location,
1936 new ast::OffsetofExpr( expr->location,
1937 deepCopy( type ),
1938 memberDecl
1939 )
1940 ) );
1941 }
1942
1943 auto offsetArray = makeVar( expr->location, offsetName,
1944 new ast::ArrayType(
1945 makeLayoutType(),
1946 ast::ConstantExpr::from_ulong( expr->location, inits.size() ),
1947 ast::FixedLen,
1948 ast::DynamicDim
1949 ),
1950 new ast::ListInit( expr->location, std::move( inits ) )
1951 );
1952
1953 return new ast::VariableExpr( expr->location, offsetArray );
1954}
1955
1956// TODO
1957ast::Expr const * PolyGenericCalculator::postvisit( ast::EnumPosExpr const * expr ) {
1958 return expr;
1959}
1960
1961void PolyGenericCalculator::beginScope() {
1962 knownLayouts.beginScope();
1963 knownOffsets.beginScope();
1964}
1965
1966void PolyGenericCalculator::endScope() {
1967 knownOffsets.endScope();
1968 knownLayouts.endScope();
1969}
1970
1971ast::ObjectDecl * PolyGenericCalculator::makeVar(
1972 CodeLocation const & location, std::string const & name,
1973 ast::Type const * type, ast::Init const * init ) {
1974 ast::ObjectDecl * ret = new ast::ObjectDecl( location, name, type, init );
1975 stmtsToAddBefore.push_back( new ast::DeclStmt( location, ret ) );
1976 return ret;
1977}
1978
1979/// Returns true if any of the otype parameters have a dynamic layout; and
1980/// puts all otype parameters in the output list.
1981bool findGenericParams(
1982 ast::vector<ast::Type> & out,
1983 ast::vector<ast::TypeDecl> const & baseParams,
1984 ast::vector<ast::Expr> const & typeParams ) {
1985 bool hasDynamicLayout = false;
1986
1987 for ( auto pair : group_iterate( baseParams, typeParams ) ) {
1988 auto baseParam = std::get<0>( pair );
1989 auto typeParam = std::get<1>( pair );
1990 if ( !baseParam->isComplete() ) continue;
1991 ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
1992 assertf( typeExpr, "All type parameters should be type expressions." );
1993
1994 ast::Type const * type = typeExpr->type.get();
1995 out.push_back( type );
1996 if ( isPolyType( type ) ) hasDynamicLayout = true;
1997 }
1998
1999 return hasDynamicLayout;
2000}
2001
2002bool PolyGenericCalculator::findGeneric(
2003 CodeLocation const & location, ast::Type const * type ) {
2004 type = replaceTypeInst( type, typeSubs );
2005
2006 if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
2007 // Assumes that getting put in the scopeTypeVars includes having the
2008 // layout variables set.
2009 if ( scopeTypeVars.contains( *inst ) ) {
2010 return true;
2011 }
2012 } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
2013 // Check if this type already has a layout generated for it.
2014 std::string typeName = Mangle::mangleType( type );
2015 if ( knownLayouts.contains( typeName ) ) return true;
2016
2017 // Check if any type parameters have dynamic layout;
2018 // If none do, this type is (or will be) monomorphized.
2019 ast::vector<ast::Type> sizedParams;
2020 if ( !findGenericParams( sizedParams,
2021 inst->base->params, inst->params ) ) {
2022 return false;
2023 }
2024
2025 // Insert local variables for layout and generate call to layout
2026 // function.
2027 // Done early so as not to interfere with the later addition of
2028 // parameters to the layout call.
2029 knownLayouts.insert( typeName );
2030
2031 int memberCount = inst->base->members.size();
2032 if ( 0 == memberCount ) {
2033 // All empty structures have the same layout (size 1, align 1).
2034 makeVar( location,
2035 sizeofName( typeName ), makeLayoutType(),
2036 new ast::SingleInit( location,
2037 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2038 makeVar( location,
2039 alignofName( typeName ), makeLayoutType(),
2040 new ast::SingleInit( location,
2041 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2042 // Since 0-length arrays are forbidden in C, skip the offset array.
2043 } else {
2044 ast::ObjectDecl const * sizeofVar = makeVar( location,
2045 sizeofName( typeName ), makeLayoutType(), nullptr );
2046 ast::ObjectDecl const * alignofVar = makeVar( location,
2047 alignofName( typeName ), makeLayoutType(), nullptr );
2048 ast::ObjectDecl const * offsetofVar = makeVar( location,
2049 offsetofName( typeName ),
2050 new ast::ArrayType(
2051 makeLayoutType(),
2052 ast::ConstantExpr::from_int( location, memberCount ),
2053 ast::FixedLen,
2054 ast::DynamicDim
2055 ),
2056 nullptr
2057 );
2058
2059 // Generate call to layout function.
2060 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2061 new ast::NameExpr( location, layoutofName( inst->base ) ),
2062 {
2063 new ast::AddressExpr(
2064 new ast::VariableExpr( location, sizeofVar ) ),
2065 new ast::AddressExpr(
2066 new ast::VariableExpr( location, alignofVar ) ),
2067 new ast::VariableExpr( location, offsetofVar ),
2068 } );
2069
2070 addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2071
2072 stmtsToAddBefore.emplace_back(
2073 new ast::ExprStmt( location, layoutCall ) );
2074 }
2075
2076 return true;
2077 } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
2078 // Check if this type already has a layout generated for it.
2079 std::string typeName = Mangle::mangleType( type );
2080 if ( knownLayouts.contains( typeName ) ) return true;
2081
2082 // Check if any type parameters have dynamic layout;
2083 // If none do, this type is (or will be) monomorphized.
2084 ast::vector<ast::Type> sizedParams;
2085 if ( !findGenericParams( sizedParams,
2086 inst->base->params, inst->params ) ) {
2087 return false;
2088 }
2089
2090 // Insert local variables for layout and generate call to layout
2091 // function.
2092 // Done early so as not to interfere with the later addition of
2093 // parameters to the layout call.
2094 knownLayouts.insert( typeName );
2095
2096 ast::ObjectDecl * sizeofVar = makeVar( location,
2097 sizeofName( typeName ), makeLayoutType() );
2098 ast::ObjectDecl * alignofVar = makeVar( location,
2099 alignofName( typeName ), makeLayoutType() );
2100
2101 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2102 new ast::NameExpr( location, layoutofName( inst->base ) ),
2103 {
2104 new ast::AddressExpr(
2105 new ast::VariableExpr( location, sizeofVar ) ),
2106 new ast::AddressExpr(
2107 new ast::VariableExpr( location, alignofVar ) ),
2108 } );
2109
2110 addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2111
2112 stmtsToAddBefore.emplace_back(
2113 new ast::ExprStmt( location, layoutCall ) );
2114
2115 return true;
2116 }
2117 return false;
2118}
2119
2120void PolyGenericCalculator::addSTypeParamsToLayoutCall(
2121 ast::UntypedExpr * layoutCall,
2122 const ast::vector<ast::Type> & otypeParams ) {
2123 CodeLocation const & location = layoutCall->location;
2124 ast::vector<ast::Expr> & args = layoutCall->args;
2125 for ( ast::ptr<ast::Type> const & param : otypeParams ) {
2126 if ( findGeneric( location, param ) ) {
2127 // Push size/align vars for a generic parameter back.
2128 std::string paramName = Mangle::mangleType( param );
2129 args.emplace_back(
2130 new ast::NameExpr( location, sizeofName( paramName ) ) );
2131 args.emplace_back(
2132 new ast::NameExpr( location, alignofName( paramName ) ) );
2133 } else {
2134 args.emplace_back(
2135 new ast::SizeofExpr( location, ast::deepCopy( param ) ) );
2136 args.emplace_back(
2137 new ast::AlignofExpr( location, ast::deepCopy( param ) ) );
2138 }
2139 }
2140}
2141
2142void PolyGenericCalculator::mutateMembers( ast::AggregateDecl * aggr ) {
2143 std::set<std::string> genericParams;
2144 for ( ast::ptr<ast::TypeDecl> const & decl : aggr->params ) {
2145 genericParams.insert( decl->name );
2146 }
2147 for ( ast::ptr<ast::Decl> & decl : aggr->members ) {
2148 auto field = decl.as<ast::ObjectDecl>();
2149 if ( nullptr == field ) continue;
2150
2151 ast::Type const * type = replaceTypeInst( field->type, typeSubs );
2152 auto typeInst = dynamic_cast<ast::TypeInstType const *>( type );
2153 if ( nullptr == typeInst ) continue;
2154
2155 // Do not try to monoporphize generic parameters.
2156 if ( scopeTypeVars.contains( ast::TypeEnvKey( *typeInst ) ) &&
2157 !genericParams.count( typeInst->name ) ) {
2158 // Polymorphic aggregate members should be converted into
2159 // monomorphic members. Using char[size_T] here respects
2160 // the expected sizing rules of an aggregate type.
2161 decl = ast::mutate_field( field, &ast::ObjectDecl::type,
2162 polyToMonoType( field->location, field->type ) );
2163 }
2164 }
2165}
2166
2167ast::Expr const * PolyGenericCalculator::genSizeof(
2168 CodeLocation const & location, ast::Type const * type ) {
2169 if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
2170 // Generate calculated size for possibly generic array.
2171 ast::Expr const * sizeofBase = genSizeof( location, array->base );
2172 if ( nullptr == sizeofBase ) return nullptr;
2173 ast::Expr const * dim = array->dimension;
2174 return makeOp( location, "?*?", sizeofBase, dim );
2175 } else if ( findGeneric( location, type ) ) {
2176 // Generate calculated size for generic type.
2177 return new ast::NameExpr( location, sizeofName(
2178 Mangle::mangleType( type ) ) );
2179 } else {
2180 return nullptr;
2181 }
2182}
2183
2184void PolyGenericCalculator::beginTypeScope( ast::Type const * type ) {
2185 GuardScope( scopeTypeVars );
2186 makeTypeVarMap( type, scopeTypeVars );
2187}
2188
2189// --------------------------------------------------------------------------
2190/// Removes unneeded or incorrect type information.
2191/// * Replaces initialization of polymorphic values with alloca.
2192/// * Replaces declaration of dtype/ftype with appropriate void expression.
2193/// * Replaces sizeof expressions of polymorphic types with a variable.
2194/// * Strips fields from generic structure declarations.
2195struct Eraser final :
2196 public ast::WithGuards {
2197 void guardTypeVarMap( ast::Type const * type ) {
2198 GuardScope( scopeTypeVars );
2199 makeTypeVarMap( type, scopeTypeVars );
2200 }
2201
2202 ast::ObjectDecl const * previsit( ast::ObjectDecl const * decl );
2203 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
2204 ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
2205 ast::TypedefDecl const * previsit( ast::TypedefDecl const * decl );
2206 ast::StructDecl const * previsit( ast::StructDecl const * decl );
2207 ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
2208 void previsit( ast::TypeDecl const * decl );
2209 void previsit( ast::PointerType const * type );
2210 void previsit( ast::FunctionType const * type );
2211public:
2212 TypeVarMap scopeTypeVars;
2213};
2214
2215ast::ObjectDecl const * Eraser::previsit( ast::ObjectDecl const * decl ) {
2216 guardTypeVarMap( decl->type );
2217 return scrubAllTypeVars( decl );
2218}
2219
2220ast::FunctionDecl const * Eraser::previsit( ast::FunctionDecl const * decl ) {
2221 guardTypeVarMap( decl->type );
2222 return scrubAllTypeVars( decl );
2223}
2224
2225ast::FunctionDecl const * Eraser::postvisit( ast::FunctionDecl const * decl ) {
2226 if ( decl->type_params.empty() ) return decl;
2227 auto mutDecl = mutate( decl );
2228 mutDecl->type_params.clear();
2229 return mutDecl;
2230}
2231
2232ast::TypedefDecl const * Eraser::previsit( ast::TypedefDecl const * decl ) {
2233 guardTypeVarMap( decl->base );
2234 return scrubAllTypeVars( decl );
2235}
2236
2237/// Strips the members from a generic aggregate.
2238template<typename node_t>
2239node_t const * stripGenericMembers( node_t const * decl ) {
2240 if ( decl->params.empty() ) return decl;
2241 auto mutDecl = ast::mutate( decl );
2242 mutDecl->members.clear();
2243 return mutDecl;
2244}
2245
2246ast::StructDecl const * Eraser::previsit( ast::StructDecl const * decl ) {
2247 return stripGenericMembers( decl );
2248}
2249
2250ast::UnionDecl const * Eraser::previsit( ast::UnionDecl const * decl ) {
2251 return stripGenericMembers( decl );
2252}
2253
2254void Eraser::previsit( ast::TypeDecl const * decl ) {
2255 addToTypeVarMap( decl, scopeTypeVars );
2256}
2257
2258void Eraser::previsit( ast::PointerType const * type ) {
2259 guardTypeVarMap( type );
2260}
2261
2262void Eraser::previsit( ast::FunctionType const * type ) {
2263 guardTypeVarMap( type );
2264}
2265
2266} // namespace
2267
2268// --------------------------------------------------------------------------
2269void box( ast::TranslationUnit & translationUnit ) {
2270 ast::Pass<LayoutFunctionBuilder>::run( translationUnit );
2271 ast::Pass<CallAdapter>::run( translationUnit );
2272 ast::Pass<DeclAdapter>::run( translationUnit );
2273 ast::Pass<RewireAdapters>::run( translationUnit );
2274 ast::Pass<PolyGenericCalculator>::run( translationUnit );
2275 ast::Pass<Eraser>::run( translationUnit );
2276}
2277
2278} // namespace GenPoly
2279
2280// Local Variables: //
2281// tab-width: 4 //
2282// mode: c++ //
2283// compile-command: "make install" //
2284// End: //
Note: See TracBrowser for help on using the repository browser.