source: src/GenPoly/BoxNew.cpp@ bf1cbde

Last change on this file since bf1cbde was 045cda3, checked in by Andrew Beach <ajbeach@…>, 2 years ago

First clean-up pass on box pass. Some of it is stuff that could have been done in the initial commit but there was just so much of it. The rest is mostly simple restructuring that makes the translation less direct.

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