source: src/GenPoly/BoxNew.cpp@ 0860d9c

Last change on this file since 0860d9c was 097c8d0, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Fixes to Box pass's DeclAdapter. The two largest are: Only local information in scopeTypeVars was used so it was replaced with localTypeVars, that greatly simplified the pass. The added parameters are also divided into groups more consistently.

  • Property mode set to 100644
File size: 90.5 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 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
1525 ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
1526private:
1527 void addAdapters( ast::FunctionDecl * decl, TypeVarMap & localTypeVars );
1528};
1529
1530// size/align/offset parameters may not be used, so add the unused attribute.
1531ast::ObjectDecl * makeObj(
1532 CodeLocation const & location, std::string const & name ) {
1533 return new ast::ObjectDecl( location, name,
1534 makeSizeAlignType(),
1535 nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr,
1536 { new ast::Attribute( "unused" ) } );
1537}
1538
1539ast::ObjectDecl * makePtr(
1540 CodeLocation const & location, std::string const & name ) {
1541 return new ast::ObjectDecl( location, name,
1542 new ast::PointerType( makeSizeAlignType() ),
1543 nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr );
1544}
1545
1546ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
1547 TypeVarMap localTypeVars = { ast::TypeData() };
1548 makeTypeVarMap( decl, localTypeVars );
1549
1550 auto mutDecl = mutate( decl );
1551
1552 // Move polymorphic return type to parameter list.
1553 if ( isDynRet( mutDecl->type ) ) {
1554 auto ret = strict_dynamic_cast<ast::ObjectDecl *>(
1555 mutDecl->returns.front().get_and_mutate() );
1556 ret->set_type( new ast::PointerType( ret->type ) );
1557 mutDecl->params.insert( mutDecl->params.begin(), ret );
1558 mutDecl->returns.erase( mutDecl->returns.begin() );
1559 ret->init = nullptr;
1560 }
1561
1562 // Add size/align and assertions for type parameters to parameter list.
1563 ast::vector<ast::DeclWithType> inferredParams;
1564 ast::vector<ast::DeclWithType> layoutParams;
1565 for ( ast::ptr<ast::TypeDecl> & typeParam : mutDecl->type_params ) {
1566 auto mutParam = mutate( typeParam.get() );
1567 // Add all size and alignment parameters to parameter list.
1568 if ( mutParam->isComplete() ) {
1569 ast::TypeInstType paramType( mutParam );
1570 std::string paramName = Mangle::mangleType( &paramType );
1571
1572 auto sizeParam = makeObj( typeParam->location, sizeofName( paramName ) );
1573 layoutParams.emplace_back( sizeParam );
1574
1575 auto alignParam = makeObj( typeParam->location, alignofName( paramName ) );
1576 layoutParams.emplace_back( alignParam );
1577 }
1578 // TODO: These should possibly all be gone.
1579 // More all assertions into parameter list.
1580 for ( ast::ptr<ast::DeclWithType> & assert : mutParam->assertions ) {
1581 // Assertion parameters may not be used in body,
1582 // pass along with unused attribute.
1583 assert.get_and_mutate()->attributes.push_back(
1584 new ast::Attribute( "unused" ) );
1585 inferredParams.push_back( assert );
1586 }
1587 mutParam->assertions.clear();
1588 typeParam = mutParam;
1589 }
1590 // TODO: New version of inner loop.
1591 for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
1592 // Assertion parameters may not be used in body,
1593 // pass along with unused attribute.
1594 assert.get_and_mutate()->attributes.push_back(
1595 new ast::Attribute( "unused" ) );
1596 inferredParams.push_back( assert );
1597 }
1598 mutDecl->assertions.clear();
1599
1600 // Add size/align for generic parameter types to parameter list.
1601 std::set<std::string> seenTypes;
1602 ast::vector<ast::DeclWithType> otypeParams;
1603 for ( ast::ptr<ast::DeclWithType> & funcParam : mutDecl->params ) {
1604 ast::Type const * polyType = isPolyType( funcParam->get_type(), localTypeVars );
1605 if ( !polyType || dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
1606 continue;
1607 }
1608 std::string typeName = Mangle::mangleType( polyType );
1609 if ( seenTypes.count( typeName ) ) continue;
1610 seenTypes.insert( typeName );
1611
1612 auto sizeParam = makeObj( funcParam->location, sizeofName( typeName ) );
1613 otypeParams.emplace_back( sizeParam );
1614
1615 auto alignParam = makeObj( funcParam->location, alignofName( typeName ) );
1616 otypeParams.emplace_back( alignParam );
1617
1618 // Zero-length arrays are illegal in C, so empty structs have no
1619 // offset array.
1620 if ( auto * polyStruct =
1621 dynamic_cast<ast::StructInstType const *>( polyType ) ;
1622 polyStruct && !polyStruct->base->members.empty() ) {
1623 auto offsetParam = makePtr( funcParam->location, offsetofName( typeName ) );
1624 otypeParams.emplace_back( offsetParam );
1625 }
1626 }
1627
1628 // Prepend each argument group. From last group to first. addAdapters
1629 // does do the same, it just does it itself and see all other parameters.
1630 spliceBegin( mutDecl->params, inferredParams );
1631 spliceBegin( mutDecl->params, otypeParams );
1632 spliceBegin( mutDecl->params, layoutParams );
1633 addAdapters( mutDecl, localTypeVars );
1634
1635 return mutDecl;
1636}
1637
1638ast::FunctionDecl const * DeclAdapter::postvisit(
1639 ast::FunctionDecl const * decl ) {
1640 ast::FunctionDecl * mutDecl = mutate( decl );
1641 if ( !mutDecl->returns.empty() && mutDecl->stmts
1642 // Intrinsic functions won't be using the _retval so no need to
1643 // generate it.
1644 && mutDecl->linkage != ast::Linkage::Intrinsic
1645 // Remove check for prefix once thunks properly use ctor/dtors.
1646 && !isPrefix( mutDecl->name, "_thunk" )
1647 && !isPrefix( mutDecl->name, "_adapter" ) ) {
1648 assert( 1 == mutDecl->returns.size() );
1649 ast::DeclWithType const * retval = mutDecl->returns.front();
1650 if ( "" == retval->name ) {
1651 retval = ast::mutate_field(
1652 retval, &ast::DeclWithType::name, "_retval" );
1653 mutDecl->returns.front() = retval;
1654 }
1655 auto stmts = mutDecl->stmts.get_and_mutate();
1656 stmts->kids.push_front( new ast::DeclStmt( retval->location, retval ) );
1657 ast::DeclWithType * newRet = ast::deepCopy( retval );
1658 mutDecl->returns.front() = newRet;
1659 }
1660 // Errors should have been caught by this point, remove initializers from
1661 // parameters to allow correct codegen of default arguments.
1662 for ( ast::ptr<ast::DeclWithType> & param : mutDecl->params ) {
1663 if ( auto obj = param.as<ast::ObjectDecl>() ) {
1664 param = ast::mutate_field( obj, &ast::ObjectDecl::init, nullptr );
1665 }
1666 }
1667 // TODO: Can this be updated as we go along?
1668 mutDecl->type = makeFunctionType( mutDecl );
1669 return mutDecl;
1670}
1671
1672void DeclAdapter::addAdapters(
1673 ast::FunctionDecl * mutDecl, TypeVarMap & localTypeVars ) {
1674 ast::vector<ast::FunctionType> functions;
1675 for ( ast::ptr<ast::DeclWithType> & arg : mutDecl->params ) {
1676 ast::Type const * type = arg->get_type();
1677 type = findAndReplaceFunction( type, functions, localTypeVars, needsAdapter );
1678 arg.get_and_mutate()->set_type( type );
1679 }
1680 std::set<std::string> adaptersDone;
1681 for ( ast::ptr<ast::FunctionType> const & func : functions ) {
1682 std::string mangleName = mangleAdapterName( func, localTypeVars );
1683 if ( adaptersDone.find( mangleName ) != adaptersDone.end() ) {
1684 continue;
1685 }
1686 std::string adapterName = makeAdapterName( mangleName );
1687 // The adapter may not actually be used, so make sure it has unused.
1688 mutDecl->params.insert( mutDecl->params.begin(), new ast::ObjectDecl(
1689 mutDecl->location, adapterName,
1690 new ast::PointerType( makeAdapterType( func, localTypeVars ) ),
1691 nullptr, {}, {}, nullptr,
1692 { new ast::Attribute( "unused" ) } ) );
1693 adaptersDone.insert( adaptersDone.begin(), mangleName );
1694 }
1695}
1696
1697// --------------------------------------------------------------------------
1698// TODO: Ideally, there would be no floating nodes at all.
1699/// Corrects the floating nodes created in CallAdapter.
1700struct RewireAdapters final : public ast::WithGuards {
1701 ScopedMap<std::string, ast::ObjectDecl const *> adapters;
1702 void beginScope() { adapters.beginScope(); }
1703 void endScope() { adapters.endScope(); }
1704 void previsit( ast::FunctionDecl const * decl );
1705 ast::VariableExpr const * previsit( ast::VariableExpr const * expr );
1706};
1707
1708void RewireAdapters::previsit( ast::FunctionDecl const * decl ) {
1709 GuardScope( adapters );
1710 for ( ast::ptr<ast::DeclWithType> const & param : decl->params ) {
1711 if ( auto objectParam = param.as<ast::ObjectDecl>() ) {
1712 adapters.insert( objectParam->name, objectParam );
1713 }
1714 }
1715}
1716
1717ast::VariableExpr const * RewireAdapters::previsit(
1718 ast::VariableExpr const * expr ) {
1719 // If the node is not floating, we can skip.
1720 if ( expr->var->isManaged() ) return expr;
1721 auto it = adapters.find( expr->var->name );
1722 assertf( it != adapters.end(), "Could not correct floating node." );
1723 return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
1724
1725}
1726
1727// --------------------------------------------------------------------------
1728// TODO: This is kind of a blind test. I believe all withExprs are handled
1729// in the resolver and we could clear them out after that.
1730struct RemoveWithExprs final {
1731 ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl ) {
1732 if ( decl->withExprs.empty() ) return decl;
1733 auto mutDecl = mutate( decl );
1734 mutDecl->withExprs.clear();
1735 return mutDecl;
1736 }
1737};
1738
1739// --------------------------------------------------------------------------
1740/// Inserts code to access polymorphic layout inforation.
1741/// * Replaces member and size/alignment/offsetof expressions on polymorphic
1742/// generic types with calculated expressions.
1743/// * Replaces member expressions for polymorphic types with calculated
1744/// add-field-offset-and-dereference.
1745/// * Calculates polymorphic offsetof expressions from offset array.
1746/// * Inserts dynamic calculation of polymorphic type layouts where needed.
1747struct PolyGenericCalculator final :
1748 public BoxPass,
1749 public ast::WithConstTypeSubstitution,
1750 public ast::WithDeclsToAdd<>,
1751 public ast::WithGuards,
1752 public ast::WithStmtsToAdd<>,
1753 public ast::WithVisitorRef<PolyGenericCalculator> {
1754 PolyGenericCalculator();
1755
1756 void previsit( ast::ObjectDecl const * decl );
1757 void previsit( ast::FunctionDecl const * decl );
1758 void previsit( ast::TypedefDecl const * decl );
1759 void previsit( ast::TypeDecl const * decl );
1760 ast::Decl const * postvisit( ast::TypeDecl const * decl );
1761 ast::StructDecl const * previsit( ast::StructDecl const * decl );
1762 ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
1763 void previsit( ast::PointerType const * type );
1764 void previsit( ast::FunctionType const * type );
1765 ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
1766 ast::Expr const * postvisit( ast::MemberExpr const * expr );
1767 void previsit( ast::AddressExpr const * expr );
1768 ast::Expr const * postvisit( ast::AddressExpr const * expr );
1769 ast::Expr const * postvisit( ast::SizeofExpr const * expr );
1770 ast::Expr const * postvisit( ast::AlignofExpr const * expr );
1771 ast::Expr const * postvisit( ast::OffsetofExpr const * expr );
1772 ast::Expr const * postvisit( ast::OffsetPackExpr const * expr );
1773
1774 void beginScope();
1775 void endScope();
1776private:
1777 /// Makes a new variable in the current scope with the given name,
1778 /// type and optional initializer.
1779 ast::ObjectDecl * makeVar(
1780 CodeLocation const & location, std::string const & name,
1781 ast::Type const * type, ast::Init const * init = nullptr );
1782 /// Returns true if the type has a dynamic layout;
1783 /// such a layout will be stored in appropriately-named local variables
1784 /// when the function returns.
1785 bool findGeneric( CodeLocation const & location, ast::Type const * );
1786 /// Adds type parameters to the layout call; will generate the
1787 /// appropriate parameters if needed.
1788 void addOTypeParamsToLayoutCall(
1789 ast::UntypedExpr * layoutCall,
1790 const ast::vector<ast::Type> & otypeParams );
1791 /// Change the type of generic aggregate members to char[].
1792 void mutateMembers( ast::AggregateDecl * aggr );
1793 /// Returns the calculated sizeof expression for type, or nullptr for use
1794 /// C sizeof().
1795 ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
1796
1797 /// Enters a new scope for type-variables,
1798 /// adding the type variables from the provided type.
1799 void beginTypeScope( ast::Type const * );
1800 /// Enters a new scope for known layouts and offsets, and queues exit calls.
1801 void beginGenericScope();
1802
1803 /// Set of generic type layouts known in the current scope,
1804 /// indexed by sizeofName.
1805 ScopedSet<std::string> knownLayouts;
1806 /// Set of non-generic types for which the offset array exists in the
1807 /// current scope, indexed by offsetofName.
1808 ScopedSet<std::string> knownOffsets;
1809 /// Namer for VLA (variable length array) buffers.
1810 UniqueName bufNamer;
1811 /// If the argument of an AddressExpr is MemberExpr, it is stored here.
1812 ast::MemberExpr const * addrMember = nullptr;
1813 /// Used to avoid recursing too deep in type declarations.
1814 bool expect_func_type = false;
1815};
1816
1817PolyGenericCalculator::PolyGenericCalculator() :
1818 knownLayouts(), knownOffsets(), bufNamer( "_buf" )
1819{}
1820
1821/// Converts polymorphic type into a suitable monomorphic representation.
1822/// Currently: __attribute__((aligned(8) )) char[size_T];
1823ast::Type * polyToMonoType( CodeLocation const & location,
1824 ast::Type const * declType ) {
1825 auto charType = new ast::BasicType( ast::BasicType::Char );
1826 auto size = new ast::NameExpr( location,
1827 sizeofName( Mangle::mangleType( declType ) ) );
1828 auto aligned = new ast::Attribute( "aligned",
1829 { ast::ConstantExpr::from_int( location, 8 ) } );
1830 auto ret = new ast::ArrayType( charType, size,
1831 ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
1832 ret->attributes.push_back( aligned );
1833 return ret;
1834}
1835
1836void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) {
1837 beginTypeScope( decl->type );
1838}
1839
1840void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
1841 beginGenericScope();
1842 beginTypeScope( decl->type );
1843
1844 // TODO: Going though dec->params does not work for some reason.
1845 for ( ast::ptr<ast::Type> const & funcParam : decl->type->params ) {
1846 // Condition here duplicates that in `DeclAdapter::previsit( FunctionDecl const * )`
1847 ast::Type const * polyType = isPolyType( funcParam, scopeTypeVars );
1848 if ( polyType && !dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
1849 knownLayouts.insert( Mangle::mangleType( polyType ) );
1850 }
1851 }
1852}
1853
1854void PolyGenericCalculator::previsit( ast::TypedefDecl const * decl ) {
1855 assertf( false, "All typedef declarations should be removed." );
1856 beginTypeScope( decl->base );
1857}
1858
1859void PolyGenericCalculator::previsit( ast::TypeDecl const * decl ) {
1860 addToTypeVarMap( decl, scopeTypeVars );
1861}
1862
1863ast::Decl const * PolyGenericCalculator::postvisit(
1864 ast::TypeDecl const * decl ) {
1865 ast::Type const * base = decl->base;
1866 if ( nullptr == base) return decl;
1867
1868 // Add size/align variables for opaque type declarations.
1869 ast::TypeInstType inst( decl->name, decl );
1870 std::string typeName = Mangle::mangleType( &inst );
1871 ast::Type * layoutType = new ast::BasicType(
1872 ast::BasicType::LongUnsignedInt );
1873
1874 ast::ObjectDecl * sizeDecl = new ast::ObjectDecl( decl->location,
1875 sizeofName( typeName ), layoutType,
1876 new ast::SingleInit( decl->location,
1877 new ast::SizeofExpr( decl->location, deepCopy( base ) )
1878 )
1879 );
1880 ast::ObjectDecl * alignDecl = new ast::ObjectDecl( decl->location,
1881 alignofName( typeName ), layoutType,
1882 new ast::SingleInit( decl->location,
1883 new ast::AlignofExpr( decl->location, deepCopy( base ) )
1884 )
1885 );
1886
1887 // Ensure that the initializing sizeof/alignof exprs are properly mutated.
1888 sizeDecl->accept( *visitor );
1889 alignDecl->accept( *visitor );
1890
1891 // Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls
1892 // can occur at global scope.
1893 declsToAddAfter.push_back( alignDecl );
1894 // replace with sizeDecl.
1895 return sizeDecl;
1896}
1897
1898ast::StructDecl const * PolyGenericCalculator::previsit(
1899 ast::StructDecl const * decl ) {
1900 auto mutDecl = mutate( decl );
1901 mutateMembers( mutDecl );
1902 return mutDecl;
1903}
1904
1905ast::UnionDecl const * PolyGenericCalculator::previsit(
1906 ast::UnionDecl const * decl ) {
1907 auto mutDecl = mutate( decl );
1908 mutateMembers( mutDecl );
1909 return mutDecl;
1910}
1911
1912void PolyGenericCalculator::previsit( ast::PointerType const * type ) {
1913 beginTypeScope( type );
1914}
1915
1916void PolyGenericCalculator::previsit( ast::FunctionType const * type ) {
1917 beginTypeScope( type );
1918
1919 GuardValue( expect_func_type );
1920 GuardScope( *this );
1921
1922 // The other functions type we will see in this scope are probably
1923 // function parameters they don't help us with the layout and offsets so
1924 // don't mark them as known in this scope.
1925 expect_func_type = false;
1926
1927 // Make sure that any type information passed into the function is
1928 // accounted for.
1929 for ( ast::ptr<ast::Type> const & funcParam : type->params ) {
1930 // Condition here duplicates that in `DeclAdapter::previsit( FunctionDecl const * )`
1931 ast::Type const * polyType = isPolyType( funcParam, scopeTypeVars );
1932 if ( polyType && !dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
1933 knownLayouts.insert( Mangle::mangleType( polyType ) );
1934 }
1935 }
1936}
1937
1938//void PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1939ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1940 ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
1941 if ( !decl || !findGeneric( decl->location, decl->type ) ) {
1942 return stmt;
1943 }
1944
1945 // Change initialization of a polymorphic value object to allocate via a
1946 // variable-length-array (alloca was previouly used, but it cannot be
1947 // safely used in loops).
1948 ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
1949 bufNamer.newName(),
1950 polyToMonoType( decl->location, decl->type ),
1951 nullptr, {}, ast::Linkage::C
1952 );
1953 stmtsToAddBefore.push_back( new ast::DeclStmt( stmt->location, newBuf ) );
1954
1955 // If the object has a cleanup attribute, the clean-up should be on the
1956 // buffer, not the pointer. [Perhaps this should be lifted?]
1957 auto matchAndMove = [newBuf]( ast::ptr<ast::Attribute> & attr ) {
1958 if ( "cleanup" == attr->name ) {
1959 newBuf->attributes.push_back( attr );
1960 return true;
1961 }
1962 return false;
1963 };
1964
1965 auto mutDecl = mutate( decl );
1966
1967 // Forally, side effects are not safe in this function. But it works.
1968 erase_if( mutDecl->attributes, matchAndMove );
1969
1970 mutDecl->init = new ast::SingleInit( decl->location,
1971 new ast::VariableExpr( decl->location, newBuf ) );
1972
1973 return ast::mutate_field( stmt, &ast::DeclStmt::decl, mutDecl );
1974}
1975
1976/// Checks if memberDecl matches the decl from an aggregate.
1977bool isMember( ast::DeclWithType const * memberDecl, ast::Decl const * decl ) {
1978 // No matter the field, if the name is different it is not the same.
1979 if ( memberDecl->name != decl->name ) {
1980 return false;
1981 }
1982
1983 if ( memberDecl->name.empty() ) {
1984 // Plan-9 Field: Match on unique_id.
1985 return ( memberDecl->uniqueId == decl->uniqueId );
1986 }
1987
1988 ast::DeclWithType const * declWithType =
1989 strict_dynamic_cast<ast::DeclWithType const *>( decl );
1990
1991 if ( memberDecl->mangleName.empty() || declWithType->mangleName.empty() ) {
1992 // Tuple-Element Field: Expect neither had mangled name;
1993 // accept match on simple name (like field_2) only.
1994 assert( memberDecl->mangleName.empty() );
1995 assert( declWithType->mangleName.empty() );
1996 return true;
1997 }
1998
1999 // Ordinary Field: Use full name to accommodate overloading.
2000 return ( memberDecl->mangleName == declWithType->mangleName );
2001}
2002
2003/// Finds the member in the base list that matches the given declaration;
2004/// returns its index, or -1 if not present.
2005long findMember( ast::DeclWithType const * memberDecl,
2006 const ast::vector<ast::Decl> & baseDecls ) {
2007 for ( auto pair : enumerate( baseDecls ) ) {
2008 if ( isMember( memberDecl, pair.val.get() ) ) {
2009 return pair.idx;
2010 }
2011 }
2012 return -1;
2013}
2014
2015/// Returns an index expression into the offset array for a type.
2016ast::Expr * makeOffsetIndex( CodeLocation const & location,
2017 ast::Type const * objectType, long i ) {
2018 std::string name = offsetofName( Mangle::mangleType( objectType ) );
2019 return ast::UntypedExpr::createCall( location, "?[?]", {
2020 new ast::NameExpr( location, name ),
2021 ast::ConstantExpr::from_ulong( location, i ),
2022 } );
2023}
2024
2025ast::Expr const * PolyGenericCalculator::postvisit(
2026 ast::MemberExpr const * expr ) {
2027 // Only mutate member expressions for polymorphic types.
2028 int typeDepth;
2029 ast::Type const * objectType = hasPolyBase(
2030 expr->aggregate->result, scopeTypeVars, &typeDepth
2031 );
2032 if ( !objectType ) return expr;
2033 // Ensure layout for this type is available.
2034 // The boolean result is ignored.
2035 findGeneric( expr->location, objectType );
2036
2037 // Replace member expression with dynamically-computed layout expression.
2038 ast::Expr * newMemberExpr = nullptr;
2039 if ( auto structType = dynamic_cast<ast::StructInstType const *>( objectType ) ) {
2040 long offsetIndex = findMember( expr->member, structType->base->members );
2041 if ( -1 == offsetIndex ) return expr;
2042
2043 // Replace member expression with pointer to struct plus offset.
2044 ast::UntypedExpr * fieldLoc = new ast::UntypedExpr( expr->location,
2045 new ast::NameExpr( expr->location, "?+?" ) );
2046 ast::Expr * aggr = deepCopy( expr->aggregate );
2047 aggr->env = nullptr;
2048 fieldLoc->args.push_back( aggr );
2049 fieldLoc->args.push_back(
2050 makeOffsetIndex( expr->location, objectType, offsetIndex ) );
2051 fieldLoc->result = deepCopy( expr->result );
2052 newMemberExpr = fieldLoc;
2053 // Union members are all at offset zero, so just use the aggregate expr.
2054 } else if ( dynamic_cast<ast::UnionInstType const *>( objectType ) ) {
2055 ast::Expr * aggr = deepCopy( expr->aggregate );
2056 aggr->env = nullptr;
2057 aggr->result = deepCopy( expr->result );
2058 newMemberExpr = aggr;
2059 } else {
2060 return expr;
2061 }
2062 assert( newMemberExpr );
2063
2064 // Must apply the generic substitution to the member type to handle cases
2065 // where the member is a generic parameter subsituted by a known concrete
2066 // type. [ex]
2067 // forall( T ) struct Box { T x; }
2068 // forall( T ) void f() {
2069 // Box( T * ) b; b.x;
2070 // }
2071 // TODO: expr->result should be exactly expr->member->get_type() after
2072 // substitution, so it doesn't seem like it should be necessary to apply
2073 // the substitution manually. For some reason this is not currently the
2074 // case. This requires more investigation.
2075 ast::ptr<ast::Type> memberType = deepCopy( expr->member->get_type() );
2076 ast::TypeSubstitution sub = genericSubstitution( objectType );
2077 sub.apply( memberType );
2078
2079 // Not all members of a polymorphic type are themselves of a polymorphic
2080 // type; in this cas the member expression should be wrapped and
2081 // dereferenced to form an lvalue.
2082 if ( !isPolyType( memberType, scopeTypeVars ) ) {
2083 auto ptrCastExpr = new ast::CastExpr( expr->location, newMemberExpr,
2084 new ast::PointerType( memberType ) );
2085 auto derefExpr = ast::UntypedExpr::createDeref( expr->location,
2086 ptrCastExpr );
2087 newMemberExpr = derefExpr;
2088 }
2089
2090 return newMemberExpr;
2091}
2092
2093void PolyGenericCalculator::previsit( ast::AddressExpr const * expr ) {
2094 GuardValue( addrMember ) = expr->arg.as<ast::MemberExpr>();
2095}
2096
2097ast::Expr const * PolyGenericCalculator::postvisit(
2098 ast::AddressExpr const * expr ) {
2099 // arg has to have been a MemberExpr and has been mutated.
2100 if ( nullptr == addrMember || expr->arg == addrMember ) {
2101 return expr;
2102 }
2103 ast::UntypedExpr const * untyped = expr->arg.as<ast::UntypedExpr>();
2104 if ( !untyped || getFunctionName( untyped ) != "?+?" ) {
2105 return expr;
2106 }
2107 // MemberExpr was converted to pointer + offset; and it is not valid C to
2108 // take the address of an addition, so stript the address-of.
2109 // It also preserves the env value.
2110 return ast::mutate_field( expr->arg.get(), &ast::Expr::env, expr->env );
2111}
2112
2113ast::Expr const * PolyGenericCalculator::postvisit(
2114 ast::SizeofExpr const * expr ) {
2115 ast::Type const * type = expr->type ? expr->type : expr->expr->result;
2116 ast::Expr const * gen = genSizeof( expr->location, type );
2117 return ( gen ) ? gen : expr;
2118}
2119
2120ast::Expr const * PolyGenericCalculator::postvisit(
2121 ast::AlignofExpr const * expr ) {
2122 ast::Type const * type = expr->type ? expr->type : expr->expr->result;
2123 if ( findGeneric( expr->location, type ) ) {
2124 return new ast::NameExpr( expr->location,
2125 alignofName( Mangle::mangleType( type ) ) );
2126 } else {
2127 return expr;
2128 }
2129}
2130
2131ast::Expr const * PolyGenericCalculator::postvisit(
2132 ast::OffsetofExpr const * expr ) {
2133 ast::Type const * type = expr->type;
2134 if ( !findGeneric( expr->location, type ) ) return expr;
2135
2136 // Structures replace offsetof expression with an index into offset array.
2137 if ( auto structType = dynamic_cast<ast::StructInstType const *>( type ) ) {
2138 long offsetIndex = findMember( expr->member, structType->base->members );
2139 if ( -1 == offsetIndex ) return expr;
2140
2141 return makeOffsetIndex( expr->location, type, offsetIndex );
2142 // All union members are at offset zero.
2143 } else if ( dynamic_cast<ast::UnionInstType const *>( type ) ) {
2144 return ast::ConstantExpr::from_ulong( expr->location, 0 );
2145 } else {
2146 return expr;
2147 }
2148}
2149
2150ast::Expr const * PolyGenericCalculator::postvisit(
2151 ast::OffsetPackExpr const * expr ) {
2152 ast::StructInstType const * type = expr->type;
2153
2154 // Pull offset back from generated type information.
2155 if ( findGeneric( expr->location, type ) ) {
2156 return new ast::NameExpr( expr->location,
2157 offsetofName( Mangle::mangleType( type ) ) );
2158 }
2159
2160 std::string offsetName = offsetofName( Mangle::mangleType( type ) );
2161 // Use the already generated offsets for this type.
2162 if ( knownOffsets.contains( offsetName ) ) {
2163 return new ast::NameExpr( expr->location, offsetName );
2164 }
2165
2166 knownOffsets.insert( offsetName );
2167
2168 auto baseMembers = type->base->members;
2169 ast::Type const * offsetType = new ast::BasicType(
2170 ast::BasicType::LongUnsignedInt );
2171
2172 // Build initializer list for offset array.
2173 ast::vector<ast::Init> inits;
2174 for ( ast::ptr<ast::Decl> & member : baseMembers ) {
2175 auto memberDecl = member.as<ast::DeclWithType>();
2176 assertf( memberDecl, "Requesting offset of non-DWT member: %s",
2177 toCString( member ) );
2178 inits.push_back( new ast::SingleInit( expr->location,
2179 new ast::OffsetofExpr( expr->location,
2180 deepCopy( type ),
2181 memberDecl
2182 )
2183 ) );
2184 }
2185
2186 auto offsetArray = makeVar( expr->location, offsetName,
2187 new ast::ArrayType(
2188 offsetType,
2189 ast::ConstantExpr::from_ulong( expr->location, baseMembers.size() ),
2190 ast::FixedLen,
2191 ast::DynamicDim
2192 ),
2193 new ast::ListInit( expr->location, std::move( inits ) )
2194 );
2195
2196 return new ast::VariableExpr( expr->location, offsetArray );
2197}
2198
2199void PolyGenericCalculator::beginScope() {
2200 knownLayouts.beginScope();
2201 knownOffsets.beginScope();
2202}
2203
2204void PolyGenericCalculator::endScope() {
2205 knownOffsets.endScope();
2206 knownLayouts.endScope();
2207}
2208
2209ast::ObjectDecl * PolyGenericCalculator::makeVar(
2210 CodeLocation const & location, std::string const & name,
2211 ast::Type const * type, ast::Init const * init ) {
2212 ast::ObjectDecl * ret = new ast::ObjectDecl( location, name, type, init );
2213 stmtsToAddBefore.push_back( new ast::DeclStmt( location, ret ) );
2214 return ret;
2215}
2216
2217/// Returns true if any of the otype parameters have a dynamic layout; and
2218/// puts all otype parameters in the output list.
2219bool findGenericParams(
2220 ast::vector<ast::Type> & out,
2221 ast::vector<ast::TypeDecl> const & baseParams,
2222 ast::vector<ast::Expr> const & typeParams ) {
2223 bool hasDynamicLayout = false;
2224
2225 for ( auto pair : group_iterate( baseParams, typeParams ) ) {
2226 auto baseParam = std::get<0>( pair );
2227 auto typeParam = std::get<1>( pair );
2228 if ( !baseParam->isComplete() ) continue;
2229 ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
2230 assertf( typeExpr, "All type parameters should be type expressions." );
2231
2232 ast::Type const * type = typeExpr->type.get();
2233 out.push_back( type );
2234 if ( isPolyType( type ) ) hasDynamicLayout = true;
2235 }
2236
2237 return hasDynamicLayout;
2238}
2239
2240bool PolyGenericCalculator::findGeneric(
2241 CodeLocation const & location, ast::Type const * type ) {
2242 type = replaceTypeInst( type, typeSubs );
2243
2244 if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
2245 // Assumes that getting put in the scopeTypeVars includes having the
2246 // layout variables set.
2247 if ( scopeTypeVars.contains( *inst ) ) {
2248 return true;
2249 }
2250 } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
2251 // Check if this type already has a layout generated for it.
2252 std::string typeName = Mangle::mangleType( type );
2253 if ( knownLayouts.contains( typeName ) ) return true;
2254
2255 // Check if any type parameters have dynamic layout;
2256 // If none do, this type is (or will be) monomorphized.
2257 ast::vector<ast::Type> sizedParams;
2258 if ( !findGenericParams( sizedParams,
2259 inst->base->params, inst->params ) ) {
2260 return false;
2261 }
2262
2263 // Insert local variables for layout and generate call to layout
2264 // function.
2265 // Done early so as not to interfere with the later addition of
2266 // parameters to the layout call.
2267 knownLayouts.insert( typeName );
2268 ast::Type const * layoutType = makeSizeAlignType();
2269
2270 int memberCount = inst->base->members.size();
2271 if ( 0 == memberCount ) {
2272 // All empty structures have the same layout (size 1, align 1).
2273 makeVar( location,
2274 sizeofName( typeName ), layoutType,
2275 new ast::SingleInit( location,
2276 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2277 makeVar( location,
2278 alignofName( typeName ), ast::deepCopy( layoutType ),
2279 new ast::SingleInit( location,
2280 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2281 // Since 0-length arrays are forbidden in C, skip the offset array.
2282 } else {
2283 ast::ObjectDecl const * sizeofVar = makeVar( location,
2284 sizeofName( typeName ), deepCopy( layoutType ), nullptr );
2285 ast::ObjectDecl const * alignofVar = makeVar( location,
2286 alignofName( typeName ), deepCopy( layoutType ), nullptr );
2287 ast::ObjectDecl const * offsetofVar = makeVar( location,
2288 offsetofName( typeName ),
2289 new ast::ArrayType(
2290 layoutType,
2291 ast::ConstantExpr::from_int( location, memberCount ),
2292 ast::FixedLen,
2293 ast::DynamicDim
2294 ),
2295 nullptr
2296 );
2297
2298 // Generate call to layout function.
2299 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2300 new ast::NameExpr( location, layoutofName( inst->base ) ),
2301 {
2302 new ast::AddressExpr(
2303 new ast::VariableExpr( location, sizeofVar ) ),
2304 new ast::AddressExpr(
2305 new ast::VariableExpr( location, alignofVar ) ),
2306 new ast::VariableExpr( location, offsetofVar ),
2307 } );
2308
2309 addOTypeParamsToLayoutCall( layoutCall, sizedParams );
2310
2311 stmtsToAddBefore.emplace_back(
2312 new ast::ExprStmt( location, layoutCall ) );
2313 }
2314
2315 return true;
2316 } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
2317 // Check if this type already has a layout generated for it.
2318 std::string typeName = Mangle::mangleType( type );
2319 if ( knownLayouts.contains( typeName ) ) return true;
2320
2321 // Check if any type parameters have dynamic layout;
2322 // If none do, this type is (or will be) monomorphized.
2323 ast::vector<ast::Type> sizedParams;
2324 if ( !findGenericParams( sizedParams,
2325 inst->base->params, inst->params ) ) {
2326 return false;
2327 }
2328
2329 // Insert local variables for layout and generate call to layout
2330 // function.
2331 // Done early so as not to interfere with the later addition of
2332 // parameters to the layout call.
2333 knownLayouts.insert( typeName );
2334 ast::Type const * layoutType = makeSizeAlignType();
2335
2336 ast::ObjectDecl * sizeofVar = makeVar( location,
2337 sizeofName( typeName ), layoutType );
2338 ast::ObjectDecl * alignofVar = makeVar( location,
2339 alignofName( typeName ), ast::deepCopy( layoutType ) );
2340
2341 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2342 new ast::NameExpr( location, layoutofName( inst->base ) ),
2343 {
2344 new ast::AddressExpr(
2345 new ast::VariableExpr( location, sizeofVar ) ),
2346 new ast::AddressExpr(
2347 new ast::VariableExpr( location, alignofVar ) ),
2348 } );
2349
2350 addOTypeParamsToLayoutCall( layoutCall, sizedParams );
2351
2352 stmtsToAddBefore.emplace_back(
2353 new ast::ExprStmt( location, layoutCall ) );
2354
2355 return true;
2356 }
2357 return false;
2358}
2359
2360void PolyGenericCalculator::addOTypeParamsToLayoutCall(
2361 ast::UntypedExpr * layoutCall,
2362 const ast::vector<ast::Type> & otypeParams ) {
2363 CodeLocation const & location = layoutCall->location;
2364 ast::vector<ast::Expr> & args = layoutCall->args;
2365 for ( ast::ptr<ast::Type> const & param : otypeParams ) {
2366 if ( findGeneric( location, param ) ) {
2367 // Push size/align vars for a generic parameter back.
2368 std::string paramName = Mangle::mangleType( param );
2369 args.emplace_back(
2370 new ast::NameExpr( location, sizeofName( paramName ) ) );
2371 args.emplace_back(
2372 new ast::NameExpr( location, alignofName( paramName ) ) );
2373 } else {
2374 args.emplace_back(
2375 new ast::SizeofExpr( location, ast::deepCopy( param ) ) );
2376 args.emplace_back(
2377 new ast::AlignofExpr( location, ast::deepCopy( param ) ) );
2378 }
2379 }
2380}
2381
2382void PolyGenericCalculator::mutateMembers( ast::AggregateDecl * aggr ) {
2383 std::set<std::string> genericParams;
2384 for ( ast::ptr<ast::TypeDecl> const & decl : aggr->params ) {
2385 genericParams.insert( decl->name );
2386 }
2387 for ( ast::ptr<ast::Decl> & decl : aggr->members ) {
2388 auto field = decl.as<ast::ObjectDecl>();
2389 if ( nullptr == field ) continue;
2390
2391 ast::Type const * type = replaceTypeInst( field->type, typeSubs );
2392 auto typeInst = dynamic_cast<ast::TypeInstType const *>( type );
2393 if ( nullptr == typeInst ) continue;
2394
2395 // Do not try to monoporphize generic parameters.
2396 if ( scopeTypeVars.contains( ast::TypeEnvKey( *typeInst ) ) &&
2397 !genericParams.count( typeInst->name ) ) {
2398 // Polymorphic aggregate members should be converted into
2399 // monomorphic members. Using char[size_T] here respects
2400 // the expected sizing rules of an aggregate type.
2401 decl = ast::mutate_field( field, &ast::ObjectDecl::type,
2402 polyToMonoType( field->location, field->type ) );
2403 }
2404 }
2405}
2406
2407ast::Expr const * PolyGenericCalculator::genSizeof(
2408 CodeLocation const & location, ast::Type const * type ) {
2409 if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
2410 // Generate calculated size for possibly generic array.
2411 ast::Expr const * sizeofBase = genSizeof( location, array->base );
2412 if ( nullptr == sizeofBase ) return nullptr;
2413 ast::Expr const * dim = array->dimension;
2414 return makeOp( location, "?*?", sizeofBase, dim );
2415 } else if ( findGeneric( location, type ) ) {
2416 // Generate calculated size for generic type.
2417 return new ast::NameExpr( location, sizeofName(
2418 Mangle::mangleType( type ) ) );
2419 } else {
2420 return nullptr;
2421 }
2422}
2423
2424void PolyGenericCalculator::beginTypeScope( ast::Type const * type ) {
2425 GuardScope( scopeTypeVars );
2426 makeTypeVarMap( type, scopeTypeVars );
2427}
2428
2429void PolyGenericCalculator::beginGenericScope() {
2430 GuardScope( *this );
2431 // We expect the first function type see to be the type relating to this
2432 // scope but any further type is probably some unrelated function pointer
2433 // keep track of whrich is the first.
2434 GuardValue( expect_func_type ) = true;
2435}
2436
2437// --------------------------------------------------------------------------
2438/// No common theme found.
2439/// * Replaces initialization of polymorphic values with alloca.
2440/// * Replaces declaration of dtype/ftype with appropriate void expression.
2441/// * Replaces sizeof expressions of polymorphic types with a variable.
2442/// * Strips fields from generic structure declarations.
2443struct Eraser final :
2444 public BoxPass,
2445 public ast::WithGuards {
2446 void guardTypeVarMap( ast::Type const * type ) {
2447 GuardScope( scopeTypeVars );
2448 makeTypeVarMap( type, scopeTypeVars );
2449 }
2450
2451 ast::ObjectDecl const * previsit( ast::ObjectDecl const * decl );
2452 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
2453 ast::TypedefDecl const * previsit( ast::TypedefDecl const * decl );
2454 ast::StructDecl const * previsit( ast::StructDecl const * decl );
2455 ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
2456 void previsit( ast::TypeDecl const * decl );
2457 void previsit( ast::PointerType const * type );
2458 void previsit( ast::FunctionType const * type );
2459};
2460
2461ast::ObjectDecl const * Eraser::previsit( ast::ObjectDecl const * decl ) {
2462 guardTypeVarMap( decl->type );
2463 return scrubAllTypeVars( decl );
2464}
2465
2466ast::FunctionDecl const * Eraser::previsit( ast::FunctionDecl const * decl ) {
2467 guardTypeVarMap( decl->type );
2468 return scrubAllTypeVars( decl );
2469}
2470
2471ast::TypedefDecl const * Eraser::previsit( ast::TypedefDecl const * decl ) {
2472 guardTypeVarMap( decl->base );
2473 return scrubAllTypeVars( decl );
2474}
2475
2476/// Strips the members from a generic aggregate.
2477template<typename node_t>
2478node_t const * stripGenericMembers( node_t const * decl ) {
2479 if ( decl->params.empty() ) return decl;
2480 auto mutDecl = ast::mutate( decl );
2481 mutDecl->members.clear();
2482 return mutDecl;
2483}
2484
2485ast::StructDecl const * Eraser::previsit( ast::StructDecl const * decl ) {
2486 return stripGenericMembers( decl );
2487}
2488
2489ast::UnionDecl const * Eraser::previsit( ast::UnionDecl const * decl ) {
2490 return stripGenericMembers( decl );
2491}
2492
2493void Eraser::previsit( ast::TypeDecl const * decl ) {
2494 addToTypeVarMap( decl, scopeTypeVars );
2495}
2496
2497void Eraser::previsit( ast::PointerType const * type ) {
2498 guardTypeVarMap( type );
2499}
2500
2501void Eraser::previsit( ast::FunctionType const * type ) {
2502 guardTypeVarMap( type );
2503}
2504
2505} // namespace
2506
2507// --------------------------------------------------------------------------
2508void box( ast::TranslationUnit & translationUnit ) {
2509 ast::Pass<LayoutFunctionBuilder>::run( translationUnit );
2510 ast::Pass<CallAdapter>::run( translationUnit );
2511 ast::Pass<DeclAdapter>::run( translationUnit );
2512 ast::Pass<RewireAdapters>::run( translationUnit );
2513 ast::Pass<RemoveWithExprs>::run( translationUnit );
2514 ast::Pass<PolyGenericCalculator>::run( translationUnit );
2515 ast::Pass<Eraser>::run( translationUnit );
2516}
2517
2518} // namespace GenPoly
2519
2520// Local Variables: //
2521// tab-width: 4 //
2522// mode: c++ //
2523// compile-command: "make install" //
2524// End: //
Note: See TracBrowser for help on using the repository browser.