source: src/GenPoly/BoxNew.cpp@ 0bf0b978

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

Layout function builds its entire parameter list before creating the declaration now.

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