source: src/GenPoly/BoxNew.cpp @ 045cda3

Last change on this file since 045cda3 was 045cda3, checked in by Andrew Beach <ajbeach@…>, 9 months ago

First clean-up pass on box pass. Some of it is stuff that could have been done in the initial commit but there was just so much of it. The rest is mostly simple restructuring that makes the translation less direct.

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