source: src/GenPoly/Box.cpp@ 1f6623c

Last change on this file since 1f6623c was 58eb9250, checked in by Michael Brooks <mlbrooks@…>, 9 months ago

Partly fix #269 and try to fix nightly build. Switch to correct type for polymorphic sizeof(-) on 32-bit.

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