source: src/GenPoly/Box.cpp@ aa14aafe

Last change on this file since aa14aafe was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 13 months ago

Removed SizeofExpr::expr and AlignofExpr::expr, expressions that would be stored there are wrapped in TypeofType and stored in the type field. Some special cases to hide the typeof in code generation were added. In addition, initializer length is calculated in more cases so that the full type of more arrays is known sooner. Other than that, most of the code changes were just stripping out the conditional code and checks no longer needed. Some tests had to be updated, because the typeof is not hidden in dumps and the resolver replaces known typeof expressions with the type. The extension case caused some concern but it appears that just hides warnings in the expression which no longer exists.

  • 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
1643static ast::Type * polyToMonoTypeRec( CodeLocation const & loc,
1644 ast::Type const * ty ) {
1645 ast::Type * ret;
1646 if ( auto aTy = dynamic_cast<ast::ArrayType const *>( ty ) ) {
1647 // recursive case
1648 auto monoBase = polyToMonoTypeRec( loc, aTy->base );
1649 ret = new ast::ArrayType( monoBase, aTy->dimension,
1650 aTy->isVarLen, aTy->isStatic, aTy->qualifiers );
1651 } else {
1652 // base case
1653 auto charType = new ast::BasicType( ast::BasicKind::Char );
1654 auto size = new ast::NameExpr( loc,
1655 sizeofName( Mangle::mangleType( ty ) ) );
1656 ret = new ast::ArrayType( charType, size,
1657 ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
1658 }
1659 return ret;
1660}
1661
1662/// Converts polymorphic type into a suitable monomorphic representation.
1663/// Simple cases: T -> __attribute__(( aligned(8) )) char[sizeof_T];
1664/// Array cases: T[eOut][eIn] -> __attribute__(( aligned(8) )) char[eOut][eIn][sizeof_T];
1665ast::Type * polyToMonoType( CodeLocation const & loc, ast::Type const * ty ) {
1666 auto ret = polyToMonoTypeRec( loc, ty );
1667 ret->attributes.emplace_back( new ast::Attribute( "aligned",
1668 { ast::ConstantExpr::from_int( loc, 8 ) } ) );
1669 return ret;
1670}
1671
1672void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
1673 GuardScope( *this );
1674 beginTypeScope( decl->type );
1675}
1676
1677void PolyGenericCalculator::previsit( ast::TypedefDecl const * decl ) {
1678 assertf( false, "All typedef declarations should be removed." );
1679 beginTypeScope( decl->base );
1680}
1681
1682void PolyGenericCalculator::previsit( ast::TypeDecl const * decl ) {
1683 addToTypeVarMap( decl, scopeTypeVars );
1684}
1685
1686ast::Decl const * PolyGenericCalculator::postvisit(
1687 ast::TypeDecl const * decl ) {
1688 ast::Type const * base = decl->base;
1689 if ( nullptr == base ) return decl;
1690
1691 // Add size/align variables for opaque type declarations.
1692 ast::TypeInstType inst( decl->name, decl );
1693 std::string typeName = Mangle::mangleType( &inst );
1694
1695 ast::ObjectDecl * sizeDecl = new ast::ObjectDecl( decl->location,
1696 sizeofName( typeName ), makeLayoutCType(),
1697 new ast::SingleInit( decl->location,
1698 new ast::SizeofExpr( decl->location, deepCopy( base ) )
1699 )
1700 );
1701 ast::ObjectDecl * alignDecl = new ast::ObjectDecl( decl->location,
1702 alignofName( typeName ), makeLayoutCType(),
1703 new ast::SingleInit( decl->location,
1704 new ast::AlignofExpr( decl->location, deepCopy( base ) )
1705 )
1706 );
1707
1708 // Ensure that the initializing sizeof/alignof exprs are properly mutated.
1709 sizeDecl->accept( *visitor );
1710 alignDecl->accept( *visitor );
1711
1712 // A little trick to replace this with two declarations.
1713 // Adding after makes sure that there is no conflict with adding stmts.
1714 declsToAddAfter.push_back( alignDecl );
1715 return sizeDecl;
1716}
1717
1718ast::StructDecl const * PolyGenericCalculator::previsit(
1719 ast::StructDecl const * decl ) {
1720 auto mutDecl = mutate( decl );
1721 mutateMembers( mutDecl );
1722 return mutDecl;
1723}
1724
1725ast::UnionDecl const * PolyGenericCalculator::previsit(
1726 ast::UnionDecl const * decl ) {
1727 auto mutDecl = mutate( decl );
1728 mutateMembers( mutDecl );
1729 return mutDecl;
1730}
1731
1732ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1733 ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
1734 if ( !decl || !findGeneric( decl->location, decl->type ) ) {
1735 return stmt;
1736 }
1737
1738 // Change initialization of a polymorphic value object to allocate via a
1739 // variable-length-array (alloca cannot be safely used in loops).
1740 ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
1741 bufNamer.newName(),
1742 polyToMonoType( decl->location, decl->type ),
1743 nullptr, {}, ast::Linkage::C
1744 );
1745 stmtsToAddBefore.push_back( new ast::DeclStmt( stmt->location, newBuf ) );
1746
1747 // If the object has a cleanup attribute, the clean-up should be on the
1748 // buffer, not the pointer. [Perhaps this should be lifted?]
1749 auto matchAndMove = [newBuf]( ast::ptr<ast::Attribute> & attr ) {
1750 if ( "cleanup" == attr->name ) {
1751 newBuf->attributes.push_back( attr );
1752 return true;
1753 }
1754 return false;
1755 };
1756
1757 auto mutDecl = mutate( decl );
1758
1759 // Forally, side effects are not safe in this function. But it works.
1760 erase_if( mutDecl->attributes, matchAndMove );
1761
1762 // Change the decl's type.
1763 // Upon finishing the box pass, it shall be void*.
1764 // At this middle-of-box-pass point, that type is T.
1765
1766 // example 1
1767 // before box: T t ;
1768 // before here: char _bufxx [_sizeof_Y1T]; T t = _bufxx;
1769 // after here: char _bufxx [_sizeof_Y1T]; T t = _bufxx; (no change here - non array case)
1770 // after box: char _bufxx [_sizeof_Y1T]; void *t = _bufxx;
1771
1772 // example 2
1773 // before box: T t[42] ;
1774 // before here: char _bufxx[42][_sizeof_Y1T]; T t[42] = _bufxx;
1775 // after here: char _bufxx[42][_sizeof_Y1T]; T t = _bufxx;
1776 // after box: char _bufxx[42][_sizeof_Y1T]; void *t = _bufxx;
1777
1778 // Strip all "array of" wrappers
1779 while ( auto arrayType = dynamic_cast<ast::ArrayType const *>( mutDecl->type.get() ) ) {
1780 mutDecl->type = arrayType->base;
1781 }
1782
1783 mutDecl->init = new ast::SingleInit( decl->location,
1784 new ast::VariableExpr( decl->location, newBuf ) );
1785
1786 return ast::mutate_field( stmt, &ast::DeclStmt::decl, mutDecl );
1787}
1788
1789/// Checks if memberDecl matches the decl from an aggregate.
1790bool isMember( ast::DeclWithType const * memberDecl, ast::Decl const * decl ) {
1791 // No matter the field, if the name is different it is not the same.
1792 if ( memberDecl->name != decl->name ) {
1793 return false;
1794 }
1795
1796 if ( memberDecl->name.empty() ) {
1797 // Plan-9 Field: Match on unique_id.
1798 return ( memberDecl->uniqueId == decl->uniqueId );
1799 }
1800
1801 ast::DeclWithType const * declWithType =
1802 strict_dynamic_cast<ast::DeclWithType const *>( decl );
1803
1804 if ( memberDecl->mangleName.empty() || declWithType->mangleName.empty() ) {
1805 // Tuple-Element Field: Expect neither had mangled name;
1806 // accept match on simple name (like field_2) only.
1807 assert( memberDecl->mangleName.empty() );
1808 assert( declWithType->mangleName.empty() );
1809 return true;
1810 }
1811
1812 // Ordinary Field: Use full name to accommodate overloading.
1813 return ( memberDecl->mangleName == declWithType->mangleName );
1814}
1815
1816/// Finds the member in the base list that matches the given declaration;
1817/// returns its index, or -1 if not present.
1818long findMember( ast::DeclWithType const * memberDecl,
1819 const ast::vector<ast::Decl> & baseDecls ) {
1820 for ( auto const & [index, value] : enumerate( baseDecls ) ) {
1821 if ( isMember( memberDecl, value.get() ) ) {
1822 return index;
1823 }
1824 }
1825 return -1;
1826}
1827
1828/// Returns an index expression into the offset array for a type.
1829ast::Expr * makeOffsetIndex( CodeLocation const & location,
1830 ast::Type const * objectType, long i ) {
1831 std::string name = offsetofName( Mangle::mangleType( objectType ) );
1832 return ast::UntypedExpr::createCall( location, "?[?]", {
1833 new ast::NameExpr( location, name ),
1834 ast::ConstantExpr::from_ulong( location, i ),
1835 } );
1836}
1837
1838ast::Expr const * PolyGenericCalculator::postvisit(
1839 ast::MemberExpr const * expr ) {
1840 // Only mutate member expressions for polymorphic types.
1841 ast::Type const * objectType = hasPolyBase(
1842 expr->aggregate->result, scopeTypeVars
1843 );
1844 if ( !objectType ) return expr;
1845 // Ensure layout for this type is available.
1846 // The boolean result is ignored.
1847 findGeneric( expr->location, objectType );
1848
1849 // Replace member expression with dynamically-computed layout expression.
1850 ast::Expr * newMemberExpr = nullptr;
1851 if ( auto structType = dynamic_cast<ast::StructInstType const *>( objectType ) ) {
1852 long offsetIndex = findMember( expr->member, structType->base->members );
1853 if ( -1 == offsetIndex ) return expr;
1854
1855 // Replace member expression with pointer to struct plus offset.
1856 ast::UntypedExpr * fieldLoc = new ast::UntypedExpr( expr->location,
1857 new ast::NameExpr( expr->location, "?+?" ) );
1858 ast::Expr * aggr = deepCopy( expr->aggregate );
1859 aggr->env = nullptr;
1860 fieldLoc->args.push_back( aggr );
1861 fieldLoc->args.push_back(
1862 makeOffsetIndex( expr->location, objectType, offsetIndex ) );
1863 fieldLoc->result = deepCopy( expr->result );
1864 newMemberExpr = fieldLoc;
1865 // Union members are all at offset zero, so just use the aggregate expr.
1866 } else if ( dynamic_cast<ast::UnionInstType const *>( objectType ) ) {
1867 ast::Expr * aggr = deepCopy( expr->aggregate );
1868 aggr->env = nullptr;
1869 aggr->result = deepCopy( expr->result );
1870 newMemberExpr = aggr;
1871 } else {
1872 return expr;
1873 }
1874 assert( newMemberExpr );
1875
1876 // Must apply the generic substitution to the member type to handle cases
1877 // where the member is a generic parameter subsituted by a known concrete
1878 // type. [ex]
1879 // forall( T ) struct Box { T x; }
1880 // forall( T ) void f() {
1881 // Box( T * ) b; b.x;
1882 // }
1883 // TODO: expr->result should be exactly expr->member->get_type() after
1884 // substitution, so it doesn't seem like it should be necessary to apply
1885 // the substitution manually. For some reason this is not currently the
1886 // case. This requires more investigation.
1887 ast::ptr<ast::Type> memberType = deepCopy( expr->member->get_type() );
1888 ast::TypeSubstitution sub = genericSubstitution( objectType );
1889 sub.apply( memberType );
1890
1891 // Not all members of a polymorphic type are themselves of a polymorphic
1892 // type; in this case the member expression should be wrapped and
1893 // dereferenced to form an lvalue.
1894 if ( !isPolyType( memberType, scopeTypeVars ) ) {
1895 auto ptrCastExpr = new ast::CastExpr( expr->location, newMemberExpr,
1896 new ast::PointerType( memberType ) );
1897 auto derefExpr = ast::UntypedExpr::createDeref( expr->location,
1898 ptrCastExpr );
1899 newMemberExpr = derefExpr;
1900 }
1901
1902 return newMemberExpr;
1903}
1904
1905void PolyGenericCalculator::previsit( ast::AddressExpr const * expr ) {
1906 GuardValue( addrMember ) = expr->arg.as<ast::MemberExpr>();
1907}
1908
1909ast::Expr const * PolyGenericCalculator::postvisit(
1910 ast::AddressExpr const * expr ) {
1911 // arg has to have been a MemberExpr and has been mutated.
1912 if ( nullptr == addrMember || expr->arg == addrMember ) {
1913 return expr;
1914 }
1915 ast::UntypedExpr const * untyped = expr->arg.as<ast::UntypedExpr>();
1916 if ( !untyped || getFunctionName( untyped ) != "?+?" ) {
1917 return expr;
1918 }
1919 // MemberExpr was converted to pointer + offset; and it is not valid C to
1920 // take the address of an addition, so strip away the address-of.
1921 // It also preserves the env value.
1922 return ast::mutate_field( expr->arg.get(), &ast::Expr::env, expr->env );
1923}
1924
1925ast::Expr const * PolyGenericCalculator::postvisit(
1926 ast::SizeofExpr const * expr ) {
1927 ast::Expr const * gen = genSizeof( expr->location, expr->type );
1928 return ( gen ) ? gen : expr;
1929}
1930
1931ast::Expr const * PolyGenericCalculator::postvisit(
1932 ast::AlignofExpr const * expr ) {
1933 ast::Expr const * gen = genAlignof( expr->location, expr->type );
1934 return ( gen ) ? gen : expr;
1935}
1936
1937ast::Expr const * PolyGenericCalculator::postvisit(
1938 ast::OffsetofExpr const * expr ) {
1939 ast::Type const * type = expr->type;
1940 if ( !findGeneric( expr->location, type ) ) return expr;
1941
1942 // Structures replace offsetof expression with an index into offset array.
1943 if ( auto structType = dynamic_cast<ast::StructInstType const *>( type ) ) {
1944 long offsetIndex = findMember( expr->member, structType->base->members );
1945 if ( -1 == offsetIndex ) return expr;
1946
1947 return makeOffsetIndex( expr->location, type, offsetIndex );
1948 // All union members are at offset zero.
1949 } else if ( dynamic_cast<ast::UnionInstType const *>( type ) ) {
1950 return ast::ConstantExpr::from_ulong( expr->location, 0 );
1951 } else {
1952 return expr;
1953 }
1954}
1955
1956ast::Expr const * PolyGenericCalculator::postvisit(
1957 ast::OffsetPackExpr const * expr ) {
1958 ast::StructInstType const * type = expr->type;
1959
1960 // Pull offset back from generated type information.
1961 if ( findGeneric( expr->location, type ) ) {
1962 return new ast::NameExpr( expr->location,
1963 offsetofName( Mangle::mangleType( type ) ) );
1964 }
1965
1966 std::string offsetName = offsetofName( Mangle::mangleType( type ) );
1967 // Use the already generated offsets for this type.
1968 if ( knownOffsets.contains( offsetName ) ) {
1969 return new ast::NameExpr( expr->location, offsetName );
1970 }
1971
1972 knownOffsets.insert( offsetName );
1973
1974 // Build initializer list for offset array.
1975 ast::vector<ast::Init> inits;
1976 for ( ast::ptr<ast::Decl> const & member : type->base->members ) {
1977 auto memberDecl = member.as<ast::DeclWithType>();
1978 assertf( memberDecl, "Requesting offset of non-DWT member: %s",
1979 toCString( member ) );
1980 inits.push_back( new ast::SingleInit( expr->location,
1981 new ast::OffsetofExpr( expr->location,
1982 deepCopy( type ),
1983 memberDecl
1984 )
1985 ) );
1986 }
1987
1988 auto offsetArray = makeVar( expr->location, offsetName,
1989 new ast::ArrayType(
1990 makeLayoutType(),
1991 ast::ConstantExpr::from_ulong( expr->location, inits.size() ),
1992 ast::FixedLen,
1993 ast::DynamicDim
1994 ),
1995 new ast::ListInit( expr->location, std::move( inits ) )
1996 );
1997
1998 return new ast::VariableExpr( expr->location, offsetArray );
1999}
2000
2001void PolyGenericCalculator::beginScope() {
2002 knownLayouts.beginScope();
2003 knownOffsets.beginScope();
2004}
2005
2006void PolyGenericCalculator::endScope() {
2007 knownOffsets.endScope();
2008 knownLayouts.endScope();
2009}
2010
2011ast::ObjectDecl * PolyGenericCalculator::makeVar(
2012 CodeLocation const & location, std::string const & name,
2013 ast::Type const * type, ast::Init const * init ) {
2014 ast::ObjectDecl * ret = new ast::ObjectDecl( location, name, type, init );
2015 stmtsToAddBefore.push_back( new ast::DeclStmt( location, ret ) );
2016 return ret;
2017}
2018
2019/// Returns true if any of the otype parameters have a dynamic layout; and
2020/// puts all otype parameters in the output list.
2021bool findGenericParams(
2022 ast::vector<ast::Type> & out,
2023 ast::vector<ast::TypeDecl> const & baseParams,
2024 ast::vector<ast::Expr> const & typeParams ) {
2025 bool hasDynamicLayout = false;
2026
2027 for ( auto const & [baseParam, typeParam] : group_iterate(
2028 baseParams, typeParams ) ) {
2029 if ( !baseParam->isComplete() ) continue;
2030 ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
2031 assertf( typeExpr, "All type parameters should be type expressions." );
2032
2033 ast::Type const * type = typeExpr->type.get();
2034 out.push_back( type );
2035 if ( isPolyType( type ) ) hasDynamicLayout = true;
2036 }
2037
2038 return hasDynamicLayout;
2039}
2040
2041bool PolyGenericCalculator::findGeneric(
2042 CodeLocation const & location, ast::Type const * type ) {
2043 type = replaceTypeInst( type, typeSubs );
2044
2045 if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
2046 // Assumes that getting put in the scopeTypeVars includes having the
2047 // layout variables set.
2048 if ( scopeTypeVars.contains( *inst ) ) {
2049 return true;
2050 }
2051 } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
2052 // Check if this type already has a layout generated for it.
2053 std::string typeName = Mangle::mangleType( type );
2054 if ( knownLayouts.contains( typeName ) ) return true;
2055
2056 // Check if any type parameters have dynamic layout;
2057 // If none do, this type is (or will be) monomorphized.
2058 ast::vector<ast::Type> sizedParams;
2059 if ( !findGenericParams( sizedParams,
2060 inst->base->params, inst->params ) ) {
2061 return false;
2062 }
2063
2064 // Insert local variables for layout and generate call to layout
2065 // function.
2066 // Done early so as not to interfere with the later addition of
2067 // parameters to the layout call.
2068 knownLayouts.insert( typeName );
2069
2070 int memberCount = inst->base->members.size();
2071 if ( 0 == memberCount ) {
2072 // All empty structures have the same layout (size 1, align 1).
2073 makeVar( location,
2074 sizeofName( typeName ), makeLayoutType(),
2075 new ast::SingleInit( location,
2076 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2077 makeVar( location,
2078 alignofName( typeName ), makeLayoutType(),
2079 new ast::SingleInit( location,
2080 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2081 // Since 0-length arrays are forbidden in C, skip the offset array.
2082 } else {
2083 ast::ObjectDecl const * sizeofVar = makeVar( location,
2084 sizeofName( typeName ), makeLayoutType(), nullptr );
2085 ast::ObjectDecl const * alignofVar = makeVar( location,
2086 alignofName( typeName ), makeLayoutType(), nullptr );
2087 ast::ObjectDecl const * offsetofVar = makeVar( location,
2088 offsetofName( typeName ),
2089 new ast::ArrayType(
2090 makeLayoutType(),
2091 ast::ConstantExpr::from_int( location, memberCount ),
2092 ast::FixedLen,
2093 ast::DynamicDim
2094 ),
2095 nullptr
2096 );
2097
2098 // Generate call to layout function.
2099 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2100 new ast::NameExpr( location, layoutofName( inst->base ) ),
2101 {
2102 new ast::AddressExpr(
2103 new ast::VariableExpr( location, sizeofVar ) ),
2104 new ast::AddressExpr(
2105 new ast::VariableExpr( location, alignofVar ) ),
2106 new ast::VariableExpr( location, offsetofVar ),
2107 } );
2108
2109 addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2110
2111 stmtsToAddBefore.emplace_back(
2112 new ast::ExprStmt( location, layoutCall ) );
2113 }
2114
2115 return true;
2116 } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
2117 // Check if this type already has a layout generated for it.
2118 std::string typeName = Mangle::mangleType( type );
2119 if ( knownLayouts.contains( typeName ) ) return true;
2120
2121 // Check if any type parameters have dynamic layout;
2122 // If none do, this type is (or will be) monomorphized.
2123 ast::vector<ast::Type> sizedParams;
2124 if ( !findGenericParams( sizedParams,
2125 inst->base->params, inst->params ) ) {
2126 return false;
2127 }
2128
2129 // Insert local variables for layout and generate call to layout
2130 // function.
2131 // Done early so as not to interfere with the later addition of
2132 // parameters to the layout call.
2133 knownLayouts.insert( typeName );
2134
2135 ast::ObjectDecl * sizeofVar = makeVar( location,
2136 sizeofName( typeName ), makeLayoutType() );
2137 ast::ObjectDecl * alignofVar = makeVar( location,
2138 alignofName( typeName ), makeLayoutType() );
2139
2140 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2141 new ast::NameExpr( location, layoutofName( inst->base ) ),
2142 {
2143 new ast::AddressExpr(
2144 new ast::VariableExpr( location, sizeofVar ) ),
2145 new ast::AddressExpr(
2146 new ast::VariableExpr( location, alignofVar ) ),
2147 } );
2148
2149 addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2150
2151 stmtsToAddBefore.emplace_back(
2152 new ast::ExprStmt( location, layoutCall ) );
2153
2154 return true;
2155
2156 } else if ( auto inst = dynamic_cast<ast::ArrayType const *>( type ) ) {
2157 return findGeneric( location, inst->base );
2158 }
2159 return false;
2160}
2161
2162void PolyGenericCalculator::addSTypeParamsToLayoutCall(
2163 ast::UntypedExpr * layoutCall,
2164 const ast::vector<ast::Type> & otypeParams ) {
2165 CodeLocation const & location = layoutCall->location;
2166 ast::vector<ast::Expr> & args = layoutCall->args;
2167 for ( ast::ptr<ast::Type> const & param : otypeParams ) {
2168 if ( findGeneric( location, param ) ) {
2169 // Push size/align vars for a generic parameter back.
2170 std::string paramName = Mangle::mangleType( param );
2171 args.emplace_back(
2172 new ast::NameExpr( location, sizeofName( paramName ) ) );
2173 args.emplace_back(
2174 new ast::NameExpr( location, alignofName( paramName ) ) );
2175 } else {
2176 args.emplace_back(
2177 new ast::SizeofExpr( location, ast::deepCopy( param ) ) );
2178 args.emplace_back(
2179 new ast::AlignofExpr( location, ast::deepCopy( param ) ) );
2180 }
2181 }
2182}
2183
2184void PolyGenericCalculator::mutateMembers( ast::AggregateDecl * aggr ) {
2185 std::set<std::string> genericParams;
2186 for ( ast::ptr<ast::TypeDecl> const & decl : aggr->params ) {
2187 genericParams.insert( decl->name );
2188 }
2189 for ( ast::ptr<ast::Decl> & decl : aggr->members ) {
2190 auto field = decl.as<ast::ObjectDecl>();
2191 if ( nullptr == field ) continue;
2192
2193 ast::Type const * type = replaceTypeInst( field->type, typeSubs );
2194 auto typeInst = dynamic_cast<ast::TypeInstType const *>( type );
2195 if ( nullptr == typeInst ) continue;
2196
2197 // Do not try to monoporphize generic parameters.
2198 if ( scopeTypeVars.contains( ast::TypeEnvKey( *typeInst ) ) &&
2199 !genericParams.count( typeInst->name ) ) {
2200 // Polymorphic aggregate members should be converted into
2201 // monomorphic members. Using char[size_T] here respects
2202 // the expected sizing rules of an aggregate type.
2203 decl = ast::mutate_field( field, &ast::ObjectDecl::type,
2204 polyToMonoType( field->location, field->type ) );
2205 }
2206 }
2207}
2208
2209ast::Expr const * PolyGenericCalculator::genSizeof(
2210 CodeLocation const & location, ast::Type const * type ) {
2211 if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
2212 // Generate calculated size for possibly generic array.
2213 ast::Expr const * sizeofBase = genSizeof( location, array->base );
2214 if ( nullptr == sizeofBase ) return nullptr;
2215 ast::Expr const * dim = array->dimension;
2216 return makeOp( location, "?*?", sizeofBase, dim );
2217 } else if ( findGeneric( location, type ) ) {
2218 // Generate reference to _sizeof parameter
2219 return new ast::NameExpr( location, sizeofName(
2220 Mangle::mangleType( type ) ) );
2221 } else {
2222 return nullptr;
2223 }
2224}
2225
2226ast::Expr const * PolyGenericCalculator::genAlignof(
2227 CodeLocation const & location, ast::Type const * type ) {
2228 if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
2229 // alignof array is alignof element
2230 return genAlignof( location, array->base );
2231 } else if ( findGeneric( location, type ) ) {
2232 // Generate reference to _alignof parameter
2233 return new ast::NameExpr( location, alignofName(
2234 Mangle::mangleType( type ) ) );
2235 } else {
2236 return nullptr;
2237 }
2238}
2239
2240void PolyGenericCalculator::beginTypeScope( ast::Type const * type ) {
2241 GuardScope( scopeTypeVars );
2242 makeTypeVarMap( type, scopeTypeVars );
2243}
2244
2245// --------------------------------------------------------------------------
2246/// Removes unneeded or incorrect type information.
2247/// * Replaces initialization of polymorphic values with alloca.
2248/// * Replaces declaration of dtype/ftype with appropriate void expression.
2249/// * Replaces sizeof expressions of polymorphic types with a variable.
2250/// * Strips fields from generic structure declarations.
2251struct Eraser final :
2252 public ast::WithGuards {
2253 void guardTypeVarMap( ast::Type const * type ) {
2254 GuardScope( scopeTypeVars );
2255 makeTypeVarMap( type, scopeTypeVars );
2256 }
2257
2258 ast::ObjectDecl const * previsit( ast::ObjectDecl const * decl );
2259 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
2260 ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
2261 ast::TypedefDecl const * previsit( ast::TypedefDecl const * decl );
2262 ast::StructDecl const * previsit( ast::StructDecl const * decl );
2263 ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
2264 void previsit( ast::TypeDecl const * decl );
2265 void previsit( ast::PointerType const * type );
2266 void previsit( ast::FunctionType const * type );
2267public:
2268 TypeVarMap scopeTypeVars;
2269};
2270
2271ast::ObjectDecl const * Eraser::previsit( ast::ObjectDecl const * decl ) {
2272 guardTypeVarMap( decl->type );
2273 return scrubAllTypeVars( decl );
2274}
2275
2276ast::FunctionDecl const * Eraser::previsit( ast::FunctionDecl const * decl ) {
2277 guardTypeVarMap( decl->type );
2278 return scrubAllTypeVars( decl );
2279}
2280
2281ast::FunctionDecl const * Eraser::postvisit( ast::FunctionDecl const * decl ) {
2282 if ( decl->type_params.empty() ) return decl;
2283 auto mutDecl = mutate( decl );
2284 mutDecl->type_params.clear();
2285 return mutDecl;
2286}
2287
2288ast::TypedefDecl const * Eraser::previsit( ast::TypedefDecl const * decl ) {
2289 guardTypeVarMap( decl->base );
2290 return scrubAllTypeVars( decl );
2291}
2292
2293/// Strips the members from a generic aggregate.
2294template<typename node_t>
2295node_t const * stripGenericMembers( node_t const * decl ) {
2296 if ( decl->params.empty() ) return decl;
2297 auto mutDecl = ast::mutate( decl );
2298 mutDecl->members.clear();
2299 return mutDecl;
2300}
2301
2302ast::StructDecl const * Eraser::previsit( ast::StructDecl const * decl ) {
2303 return stripGenericMembers( decl );
2304}
2305
2306ast::UnionDecl const * Eraser::previsit( ast::UnionDecl const * decl ) {
2307 return stripGenericMembers( decl );
2308}
2309
2310void Eraser::previsit( ast::TypeDecl const * decl ) {
2311 addToTypeVarMap( decl, scopeTypeVars );
2312}
2313
2314void Eraser::previsit( ast::PointerType const * type ) {
2315 guardTypeVarMap( type );
2316}
2317
2318void Eraser::previsit( ast::FunctionType const * type ) {
2319 guardTypeVarMap( type );
2320}
2321
2322} // namespace
2323
2324// --------------------------------------------------------------------------
2325void box( ast::TranslationUnit & translationUnit ) {
2326 ast::Pass<LayoutFunctionBuilder>::run( translationUnit );
2327 ast::Pass<CallAdapter>::run( translationUnit );
2328 ast::Pass<DeclAdapter>::run( translationUnit );
2329 ast::Pass<RewireAdapters>::run( translationUnit );
2330 ast::Pass<PolyGenericCalculator>::run( translationUnit );
2331 ast::Pass<Eraser>::run( translationUnit );
2332}
2333
2334} // namespace GenPoly
2335
2336// Local Variables: //
2337// tab-width: 4 //
2338// mode: c++ //
2339// compile-command: "make install" //
2340// End: //
Note: See TracBrowser for help on using the repository browser.