source: src/GenPoly/Box.cpp@ eae8b37

Last change on this file since eae8b37 was ed96731, checked in by Andrew Beach <ajbeach@…>, 10 months ago

With{Stmts,Decls}ToAdd how has an -X version like WithSymbolTableX. Although these -X versions might be useful can could possibly be removed in the future. (This is a therapy commit.)

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