source: src/GenPoly/BoxNew.cpp@ 3c4003b9

Last change on this file since 3c4003b9 was 3c4003b9, checked in by Andrew Beach <ajbeach@…>, 23 months ago

Box pass Eraser now removes the polymorphic arguments now that the functions are no longer actually polymorphic.

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