source: src/GenPoly/BoxNew.cpp @ d3652df

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

Took the new EraseWith? pass out of the box pass. It might be able to go even earlier or folded into an existing pass. C code generation now will not generate WithStmt? nodes.

  • Property mode set to 100644
File size: 90.0 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        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
1525        ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
1526private:
1527        void addAdapters( ast::FunctionDecl * decl, TypeVarMap & localTypeVars );
1528};
1529
1530// size/align/offset parameters may not be used, so add the unused attribute.
1531ast::ObjectDecl * makeObj(
1532                CodeLocation const & location, std::string const & name ) {
1533        return new ast::ObjectDecl( location, name,
1534                makeSizeAlignType(),
1535                nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr,
1536                { new ast::Attribute( "unused" ) } );
1537}
1538
1539ast::ObjectDecl * makePtr(
1540                CodeLocation const & location, std::string const & name ) {
1541        return new ast::ObjectDecl( location, name,
1542                new ast::PointerType( makeSizeAlignType() ),
1543                nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr );
1544}
1545
1546ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
1547        TypeVarMap localTypeVars = { ast::TypeData() };
1548        makeTypeVarMap( decl, localTypeVars );
1549
1550        auto mutDecl = mutate( decl );
1551
1552        // Move polymorphic return type to parameter list.
1553        if ( isDynRet( mutDecl->type ) ) {
1554                auto ret = strict_dynamic_cast<ast::ObjectDecl *>(
1555                        mutDecl->returns.front().get_and_mutate() );
1556                ret->set_type( new ast::PointerType( ret->type ) );
1557                mutDecl->params.insert( mutDecl->params.begin(), ret );
1558                mutDecl->returns.erase( mutDecl->returns.begin() );
1559                ret->init = nullptr;
1560        }
1561
1562        // Add size/align and assertions for type parameters to parameter list.
1563        ast::vector<ast::DeclWithType> inferredParams;
1564        ast::vector<ast::DeclWithType> layoutParams;
1565        for ( ast::ptr<ast::TypeDecl> & typeParam : mutDecl->type_params ) {
1566                auto mutParam = mutate( typeParam.get() );
1567                // Add all size and alignment parameters to parameter list.
1568                if ( mutParam->isComplete() ) {
1569                        ast::TypeInstType paramType( mutParam );
1570                        std::string paramName = Mangle::mangleType( &paramType );
1571
1572                        auto sizeParam = makeObj( typeParam->location, sizeofName( paramName ) );
1573                        layoutParams.emplace_back( sizeParam );
1574
1575                        auto alignParam = makeObj( typeParam->location, alignofName( paramName ) );
1576                        layoutParams.emplace_back( alignParam );
1577                }
1578                // TODO: These should possibly all be gone.
1579                // More all assertions into parameter list.
1580                for ( ast::ptr<ast::DeclWithType> & assert : mutParam->assertions ) {
1581                        // Assertion parameters may not be used in body,
1582                        // pass along with unused attribute.
1583                        assert.get_and_mutate()->attributes.push_back(
1584                                new ast::Attribute( "unused" ) );
1585                        inferredParams.push_back( assert );
1586                }
1587                mutParam->assertions.clear();
1588                typeParam = mutParam;
1589        }
1590        // TODO: New version of inner loop.
1591        for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
1592                // Assertion parameters may not be used in body,
1593                // pass along with unused attribute.
1594                assert.get_and_mutate()->attributes.push_back(
1595                        new ast::Attribute( "unused" ) );
1596                inferredParams.push_back( assert );
1597        }
1598        mutDecl->assertions.clear();
1599
1600        // Add size/align for generic parameter types to parameter list.
1601        std::set<std::string> seenTypes;
1602        ast::vector<ast::DeclWithType> otypeParams;
1603        for ( ast::ptr<ast::DeclWithType> & funcParam : mutDecl->params ) {
1604                ast::Type const * polyType = isPolyType( funcParam->get_type(), localTypeVars );
1605                if ( !polyType || dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
1606                        continue;
1607                }
1608                std::string typeName = Mangle::mangleType( polyType );
1609                if ( seenTypes.count( typeName ) ) continue;
1610                seenTypes.insert( typeName );
1611
1612                auto sizeParam = makeObj( funcParam->location, sizeofName( typeName ) );
1613                otypeParams.emplace_back( sizeParam );
1614
1615                auto alignParam = makeObj( funcParam->location, alignofName( typeName ) );
1616                otypeParams.emplace_back( alignParam );
1617
1618                // Zero-length arrays are illegal in C, so empty structs have no
1619                // offset array.
1620                if ( auto * polyStruct =
1621                                dynamic_cast<ast::StructInstType const *>( polyType ) ;
1622                                polyStruct && !polyStruct->base->members.empty() ) {
1623                        auto offsetParam = makePtr( funcParam->location, offsetofName( typeName ) );
1624                        otypeParams.emplace_back( offsetParam );
1625                }
1626        }
1627
1628        // Prepend each argument group. From last group to first. addAdapters
1629        // does do the same, it just does it itself and see all other parameters.
1630        spliceBegin( mutDecl->params, inferredParams );
1631        spliceBegin( mutDecl->params, otypeParams );
1632        spliceBegin( mutDecl->params, layoutParams );
1633        addAdapters( mutDecl, localTypeVars );
1634
1635        return mutDecl;
1636}
1637
1638ast::FunctionDecl const * DeclAdapter::postvisit(
1639                ast::FunctionDecl const * decl ) {
1640        ast::FunctionDecl * mutDecl = mutate( decl );
1641        if ( !mutDecl->returns.empty() && mutDecl->stmts
1642                        // Intrinsic functions won't be using the _retval so no need to
1643                        // generate it.
1644                        && mutDecl->linkage != ast::Linkage::Intrinsic
1645                        // Remove check for prefix once thunks properly use ctor/dtors.
1646                        && !isPrefix( mutDecl->name, "_thunk" )
1647                        && !isPrefix( mutDecl->name, "_adapter" ) ) {
1648                assert( 1 == mutDecl->returns.size() );
1649                ast::DeclWithType const * retval = mutDecl->returns.front();
1650                if ( "" == retval->name ) {
1651                        retval = ast::mutate_field(
1652                                retval, &ast::DeclWithType::name, "_retval" );
1653                        mutDecl->returns.front() = retval;
1654                }
1655                auto stmts = mutDecl->stmts.get_and_mutate();
1656                stmts->kids.push_front( new ast::DeclStmt( retval->location, retval ) );
1657                ast::DeclWithType * newRet = ast::deepCopy( retval );
1658                mutDecl->returns.front() = newRet;
1659        }
1660        // Errors should have been caught by this point, remove initializers from
1661        // parameters to allow correct codegen of default arguments.
1662        for ( ast::ptr<ast::DeclWithType> & param : mutDecl->params ) {
1663                if ( auto obj = param.as<ast::ObjectDecl>() ) {
1664                        param = ast::mutate_field( obj, &ast::ObjectDecl::init, nullptr );
1665                }
1666        }
1667        // TODO: Can this be updated as we go along?
1668        mutDecl->type = makeFunctionType( mutDecl );
1669        return mutDecl;
1670}
1671
1672void DeclAdapter::addAdapters(
1673                ast::FunctionDecl * mutDecl, TypeVarMap & localTypeVars ) {
1674        ast::vector<ast::FunctionType> functions;
1675        for ( ast::ptr<ast::DeclWithType> & arg : mutDecl->params ) {
1676                ast::Type const * type = arg->get_type();
1677                type = findAndReplaceFunction( type, functions, localTypeVars, needsAdapter );
1678                arg.get_and_mutate()->set_type( type );
1679        }
1680        std::set<std::string> adaptersDone;
1681        for ( ast::ptr<ast::FunctionType> const & func : functions ) {
1682                std::string mangleName = mangleAdapterName( func, localTypeVars );
1683                if ( adaptersDone.find( mangleName ) != adaptersDone.end() ) {
1684                        continue;
1685                }
1686                std::string adapterName = makeAdapterName( mangleName );
1687                // The adapter may not actually be used, so make sure it has unused.
1688                mutDecl->params.insert( mutDecl->params.begin(), new ast::ObjectDecl(
1689                        mutDecl->location, adapterName,
1690                        new ast::PointerType( makeAdapterType( func, localTypeVars ) ),
1691                        nullptr, {}, {}, nullptr,
1692                        { new ast::Attribute( "unused" ) } ) );
1693                adaptersDone.insert( adaptersDone.begin(), mangleName );
1694        }
1695}
1696
1697// --------------------------------------------------------------------------
1698// TODO: Ideally, there would be no floating nodes at all.
1699/// Corrects the floating nodes created in CallAdapter.
1700struct RewireAdapters final : public ast::WithGuards {
1701        ScopedMap<std::string, ast::ObjectDecl const *> adapters;
1702        void beginScope() { adapters.beginScope(); }
1703        void endScope() { adapters.endScope(); }
1704        void previsit( ast::FunctionDecl const * decl );
1705        ast::VariableExpr const * previsit( ast::VariableExpr const * expr );
1706};
1707
1708void RewireAdapters::previsit( ast::FunctionDecl const * decl ) {
1709        GuardScope( adapters );
1710        for ( ast::ptr<ast::DeclWithType> const & param : decl->params ) {
1711                if ( auto objectParam = param.as<ast::ObjectDecl>() ) {
1712                        adapters.insert( objectParam->name, objectParam );
1713                }
1714        }
1715}
1716
1717ast::VariableExpr const * RewireAdapters::previsit(
1718                ast::VariableExpr const * expr ) {
1719        // If the node is not floating, we can skip.
1720        if ( expr->var->isManaged() ) return expr;
1721        auto it = adapters.find( expr->var->name );
1722        assertf( it != adapters.end(), "Could not correct floating node." );
1723        return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
1724
1725}
1726
1727// --------------------------------------------------------------------------
1728/// Inserts code to access polymorphic layout inforation.
1729/// * Replaces member and size/alignment/offsetof expressions on polymorphic
1730///   generic types with calculated expressions.
1731/// * Replaces member expressions for polymorphic types with calculated
1732///   add-field-offset-and-dereference.
1733/// * Calculates polymorphic offsetof expressions from offset array.
1734/// * Inserts dynamic calculation of polymorphic type layouts where needed.
1735struct PolyGenericCalculator final :
1736                public BoxPass,
1737                public ast::WithConstTypeSubstitution,
1738                public ast::WithDeclsToAdd<>,
1739                public ast::WithGuards,
1740                public ast::WithStmtsToAdd<>,
1741                public ast::WithVisitorRef<PolyGenericCalculator> {
1742        PolyGenericCalculator();
1743
1744        void previsit( ast::ObjectDecl const * decl );
1745        void previsit( ast::FunctionDecl const * decl );
1746        void previsit( ast::TypedefDecl const * decl );
1747        void previsit( ast::TypeDecl const * decl );
1748        ast::Decl const * postvisit( ast::TypeDecl const * decl );
1749        ast::StructDecl const * previsit( ast::StructDecl const * decl );
1750        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
1751        void previsit( ast::PointerType const * type );
1752        void previsit( ast::FunctionType const * type );
1753        ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
1754        ast::Expr const * postvisit( ast::MemberExpr const * expr );
1755        void previsit( ast::AddressExpr const * expr );
1756        ast::Expr const * postvisit( ast::AddressExpr const * expr );
1757        ast::Expr const * postvisit( ast::SizeofExpr const * expr );
1758        ast::Expr const * postvisit( ast::AlignofExpr const * expr );
1759        ast::Expr const * postvisit( ast::OffsetofExpr const * expr );
1760        ast::Expr const * postvisit( ast::OffsetPackExpr const * expr );
1761
1762        void beginScope();
1763        void endScope();
1764private:
1765        /// Makes a new variable in the current scope with the given name,
1766        /// type and optional initializer.
1767        ast::ObjectDecl * makeVar(
1768                        CodeLocation const & location, std::string const & name,
1769                        ast::Type const * type, ast::Init const * init = nullptr );
1770        /// Returns true if the type has a dynamic layout;
1771        /// such a layout will be stored in appropriately-named local variables
1772        /// when the function returns.
1773        bool findGeneric( CodeLocation const & location, ast::Type const * );
1774        /// Adds type parameters to the layout call; will generate the
1775        /// appropriate parameters if needed.
1776        void addOTypeParamsToLayoutCall(
1777                ast::UntypedExpr * layoutCall,
1778                const ast::vector<ast::Type> & otypeParams );
1779        /// Change the type of generic aggregate members to char[].
1780        void mutateMembers( ast::AggregateDecl * aggr );
1781        /// Returns the calculated sizeof expression for type, or nullptr for use
1782        /// C sizeof().
1783        ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
1784
1785        /// Enters a new scope for type-variables,
1786        /// adding the type variables from the provided type.
1787        void beginTypeScope( ast::Type const * );
1788        /// Enters a new scope for known layouts and offsets, and queues exit calls.
1789        void beginGenericScope();
1790
1791        /// Set of generic type layouts known in the current scope,
1792        /// indexed by sizeofName.
1793        ScopedSet<std::string> knownLayouts;
1794        /// Set of non-generic types for which the offset array exists in the
1795        /// current scope, indexed by offsetofName.
1796        ScopedSet<std::string> knownOffsets;
1797        /// Namer for VLA (variable length array) buffers.
1798        UniqueName bufNamer;
1799        /// If the argument of an AddressExpr is MemberExpr, it is stored here.
1800        ast::MemberExpr const * addrMember = nullptr;
1801        /// Used to avoid recursing too deep in type declarations.
1802        bool expect_func_type = false;
1803};
1804
1805PolyGenericCalculator::PolyGenericCalculator() :
1806        knownLayouts(), knownOffsets(), bufNamer( "_buf" )
1807{}
1808
1809/// Converts polymorphic type into a suitable monomorphic representation.
1810/// Currently: __attribute__((aligned(8) )) char[size_T];
1811ast::Type * polyToMonoType( CodeLocation const & location,
1812                ast::Type const * declType ) {
1813        auto charType = new ast::BasicType( ast::BasicType::Char );
1814        auto size = new ast::NameExpr( location,
1815                sizeofName( Mangle::mangleType( declType ) ) );
1816        auto aligned = new ast::Attribute( "aligned",
1817                { ast::ConstantExpr::from_int( location, 8 ) } );
1818        auto ret = new ast::ArrayType( charType, size,
1819                ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
1820        ret->attributes.push_back( aligned );
1821        return ret;
1822}
1823
1824void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) {
1825        beginTypeScope( decl->type );
1826}
1827
1828void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
1829        beginGenericScope();
1830        beginTypeScope( decl->type );
1831
1832        // TODO: Going though dec->params does not work for some reason.
1833        for ( ast::ptr<ast::Type> const & funcParam : decl->type->params ) {
1834                // Condition here duplicates that in `DeclAdapter::previsit( FunctionDecl const * )`
1835                ast::Type const * polyType = isPolyType( funcParam, scopeTypeVars );
1836                if ( polyType && !dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
1837                        knownLayouts.insert( Mangle::mangleType( polyType ) );
1838                }
1839        }
1840}
1841
1842void PolyGenericCalculator::previsit( ast::TypedefDecl const * decl ) {
1843        assertf( false, "All typedef declarations should be removed." );
1844        beginTypeScope( decl->base );
1845}
1846
1847void PolyGenericCalculator::previsit( ast::TypeDecl const * decl ) {
1848        addToTypeVarMap( decl, scopeTypeVars );
1849}
1850
1851ast::Decl const * PolyGenericCalculator::postvisit(
1852                ast::TypeDecl const * decl ) {
1853        ast::Type const * base = decl->base;
1854        if ( nullptr == base) return decl;
1855
1856        // Add size/align variables for opaque type declarations.
1857        ast::TypeInstType inst( decl->name, decl );
1858        std::string typeName = Mangle::mangleType( &inst );
1859        ast::Type * layoutType = new ast::BasicType(
1860                ast::BasicType::LongUnsignedInt );
1861
1862        ast::ObjectDecl * sizeDecl = new ast::ObjectDecl( decl->location,
1863                sizeofName( typeName ), layoutType,
1864                new ast::SingleInit( decl->location,
1865                        new ast::SizeofExpr( decl->location, deepCopy( base ) )
1866                )
1867        );
1868        ast::ObjectDecl * alignDecl = new ast::ObjectDecl( decl->location,
1869                alignofName( typeName ), layoutType,
1870                new ast::SingleInit( decl->location,
1871                        new ast::AlignofExpr( decl->location, deepCopy( base ) )
1872                )
1873        );
1874
1875        // Ensure that the initializing sizeof/alignof exprs are properly mutated.
1876        sizeDecl->accept( *visitor );
1877        alignDecl->accept( *visitor );
1878
1879        // Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls
1880        // can occur at global scope.
1881        declsToAddAfter.push_back( alignDecl );
1882        // replace with sizeDecl.
1883        return sizeDecl;
1884}
1885
1886ast::StructDecl const * PolyGenericCalculator::previsit(
1887                ast::StructDecl const * decl ) {
1888        auto mutDecl = mutate( decl );
1889        mutateMembers( mutDecl );
1890        return mutDecl;
1891}
1892
1893ast::UnionDecl const * PolyGenericCalculator::previsit(
1894                ast::UnionDecl const * decl ) {
1895        auto mutDecl = mutate( decl );
1896        mutateMembers( mutDecl );
1897        return mutDecl;
1898}
1899
1900void PolyGenericCalculator::previsit( ast::PointerType const * type ) {
1901        beginTypeScope( type );
1902}
1903
1904void PolyGenericCalculator::previsit( ast::FunctionType const * type ) {
1905        beginTypeScope( type );
1906
1907        GuardValue( expect_func_type );
1908        GuardScope( *this );
1909
1910        // The other functions type we will see in this scope are probably
1911        // function parameters they don't help us with the layout and offsets so
1912        // don't mark them as known in this scope.
1913        expect_func_type = false;
1914
1915        // Make sure that any type information passed into the function is
1916        // accounted for.
1917        for ( ast::ptr<ast::Type> const & funcParam : type->params ) {
1918                // Condition here duplicates that in `DeclAdapter::previsit( FunctionDecl const * )`
1919                ast::Type const * polyType = isPolyType( funcParam, scopeTypeVars );
1920                if ( polyType && !dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
1921                        knownLayouts.insert( Mangle::mangleType( polyType ) );
1922                }
1923        }
1924}
1925
1926//void PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1927ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1928        ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
1929        if ( !decl || !findGeneric( decl->location, decl->type ) ) {
1930                return stmt;
1931        }
1932
1933        // Change initialization of a polymorphic value object to allocate via a
1934        // variable-length-array (alloca was previouly used, but it cannot be
1935        // safely used in loops).
1936        ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
1937                bufNamer.newName(),
1938                polyToMonoType( decl->location, decl->type ),
1939                nullptr, {}, ast::Linkage::C
1940        );
1941        stmtsToAddBefore.push_back( new ast::DeclStmt( stmt->location, newBuf ) );
1942
1943        // If the object has a cleanup attribute, the clean-up should be on the
1944        // buffer, not the pointer. [Perhaps this should be lifted?]
1945        auto matchAndMove = [newBuf]( ast::ptr<ast::Attribute> & attr ) {
1946                if ( "cleanup" == attr->name ) {
1947                        newBuf->attributes.push_back( attr );
1948                        return true;
1949                }
1950                return false;
1951        };
1952
1953        auto mutDecl = mutate( decl );
1954
1955        // Forally, side effects are not safe in this function. But it works.
1956        erase_if( mutDecl->attributes, matchAndMove );
1957
1958        mutDecl->init = new ast::SingleInit( decl->location,
1959                new ast::VariableExpr( decl->location, newBuf ) );
1960
1961        return ast::mutate_field( stmt, &ast::DeclStmt::decl, mutDecl );
1962}
1963
1964/// Checks if memberDecl matches the decl from an aggregate.
1965bool isMember( ast::DeclWithType const * memberDecl, ast::Decl const * decl ) {
1966        // No matter the field, if the name is different it is not the same.
1967        if ( memberDecl->name != decl->name ) {
1968                return false;
1969        }
1970
1971        if ( memberDecl->name.empty() ) {
1972                // Plan-9 Field: Match on unique_id.
1973                return ( memberDecl->uniqueId == decl->uniqueId );
1974        }
1975
1976        ast::DeclWithType const * declWithType =
1977                strict_dynamic_cast<ast::DeclWithType const *>( decl );
1978
1979        if ( memberDecl->mangleName.empty() || declWithType->mangleName.empty() ) {
1980                // Tuple-Element Field: Expect neither had mangled name;
1981                // accept match on simple name (like field_2) only.
1982                assert( memberDecl->mangleName.empty() );
1983                assert( declWithType->mangleName.empty() );
1984                return true;
1985        }
1986
1987        // Ordinary Field: Use full name to accommodate overloading.
1988        return ( memberDecl->mangleName == declWithType->mangleName );
1989}
1990
1991/// Finds the member in the base list that matches the given declaration;
1992/// returns its index, or -1 if not present.
1993long findMember( ast::DeclWithType const * memberDecl,
1994                const ast::vector<ast::Decl> & baseDecls ) {
1995        for ( auto pair : enumerate( baseDecls ) ) {
1996                if ( isMember( memberDecl, pair.val.get() ) ) {
1997                        return pair.idx;
1998                }
1999        }
2000        return -1;
2001}
2002
2003/// Returns an index expression into the offset array for a type.
2004ast::Expr * makeOffsetIndex( CodeLocation const & location,
2005                ast::Type const * objectType, long i ) {
2006        std::string name = offsetofName( Mangle::mangleType( objectType ) );
2007        return ast::UntypedExpr::createCall( location, "?[?]", {
2008                new ast::NameExpr( location, name ),
2009                ast::ConstantExpr::from_ulong( location, i ),
2010        } );
2011}
2012
2013ast::Expr const * PolyGenericCalculator::postvisit(
2014                ast::MemberExpr const * expr ) {
2015        // Only mutate member expressions for polymorphic types.
2016        int typeDepth;
2017        ast::Type const * objectType = hasPolyBase(
2018                expr->aggregate->result, scopeTypeVars, &typeDepth
2019        );
2020        if ( !objectType ) return expr;
2021        // Ensure layout for this type is available.
2022        // The boolean result is ignored.
2023        findGeneric( expr->location, objectType );
2024
2025        // Replace member expression with dynamically-computed layout expression.
2026        ast::Expr * newMemberExpr = nullptr;
2027        if ( auto structType = dynamic_cast<ast::StructInstType const *>( objectType ) ) {
2028                long offsetIndex = findMember( expr->member, structType->base->members );
2029                if ( -1 == offsetIndex ) return expr;
2030
2031                // Replace member expression with pointer to struct plus offset.
2032                ast::UntypedExpr * fieldLoc = new ast::UntypedExpr( expr->location,
2033                                new ast::NameExpr( expr->location, "?+?" ) );
2034                ast::Expr * aggr = deepCopy( expr->aggregate );
2035                aggr->env = nullptr;
2036                fieldLoc->args.push_back( aggr );
2037                fieldLoc->args.push_back(
2038                        makeOffsetIndex( expr->location, objectType, offsetIndex ) );
2039                fieldLoc->result = deepCopy( expr->result );
2040                newMemberExpr = fieldLoc;
2041        // Union members are all at offset zero, so just use the aggregate expr.
2042        } else if ( dynamic_cast<ast::UnionInstType const *>( objectType ) ) {
2043                ast::Expr * aggr = deepCopy( expr->aggregate );
2044                aggr->env = nullptr;
2045                aggr->result = deepCopy( expr->result );
2046                newMemberExpr = aggr;
2047        } else {
2048                return expr;
2049        }
2050        assert( newMemberExpr );
2051
2052        // Must apply the generic substitution to the member type to handle cases
2053        // where the member is a generic parameter subsituted by a known concrete
2054        // type. [ex]
2055        //      forall( T ) struct Box { T x; }
2056        //      forall( T ) void f() {
2057        //              Box( T * ) b; b.x;
2058        //      }
2059        // TODO: expr->result should be exactly expr->member->get_type() after
2060        // substitution, so it doesn't seem like it should be necessary to apply
2061        // the substitution manually. For some reason this is not currently the
2062        // case. This requires more investigation.
2063        ast::ptr<ast::Type> memberType = deepCopy( expr->member->get_type() );
2064        ast::TypeSubstitution sub = genericSubstitution( objectType );
2065        sub.apply( memberType );
2066
2067        // Not all members of a polymorphic type are themselves of a polymorphic
2068        // type; in this cas the member expression should be wrapped and
2069        // dereferenced to form an lvalue.
2070        if ( !isPolyType( memberType, scopeTypeVars ) ) {
2071                auto ptrCastExpr = new ast::CastExpr( expr->location, newMemberExpr,
2072                        new ast::PointerType( memberType ) );
2073                auto derefExpr = ast::UntypedExpr::createDeref( expr->location,
2074                        ptrCastExpr );
2075                newMemberExpr = derefExpr;
2076        }
2077
2078        return newMemberExpr;
2079}
2080
2081void PolyGenericCalculator::previsit( ast::AddressExpr const * expr ) {
2082        GuardValue( addrMember ) = expr->arg.as<ast::MemberExpr>();
2083}
2084
2085ast::Expr const * PolyGenericCalculator::postvisit(
2086                ast::AddressExpr const * expr ) {
2087        // arg has to have been a MemberExpr and has been mutated.
2088        if ( nullptr == addrMember || expr->arg == addrMember ) {
2089                return expr;
2090        }
2091        ast::UntypedExpr const * untyped = expr->arg.as<ast::UntypedExpr>();
2092        if ( !untyped || getFunctionName( untyped ) != "?+?" ) {
2093                return expr;
2094        }
2095        // MemberExpr was converted to pointer + offset; and it is not valid C to
2096        // take the address of an addition, so stript the address-of.
2097        // It also preserves the env value.
2098        return ast::mutate_field( expr->arg.get(), &ast::Expr::env, expr->env );
2099}
2100
2101ast::Expr const * PolyGenericCalculator::postvisit(
2102                ast::SizeofExpr const * expr ) {
2103        ast::Type const * type = expr->type ? expr->type : expr->expr->result;
2104        ast::Expr const * gen = genSizeof( expr->location, type );
2105        return ( gen ) ? gen : expr;
2106}
2107
2108ast::Expr const * PolyGenericCalculator::postvisit(
2109                ast::AlignofExpr const * expr ) {
2110        ast::Type const * type = expr->type ? expr->type : expr->expr->result;
2111        if ( findGeneric( expr->location, type ) ) {
2112                return new ast::NameExpr( expr->location,
2113                        alignofName( Mangle::mangleType( type ) ) );
2114        } else {
2115                return expr;
2116        }
2117}
2118
2119ast::Expr const * PolyGenericCalculator::postvisit(
2120                ast::OffsetofExpr const * expr ) {
2121        ast::Type const * type = expr->type;
2122        if ( !findGeneric( expr->location, type ) ) return expr;
2123
2124        // Structures replace offsetof expression with an index into offset array.
2125        if ( auto structType = dynamic_cast<ast::StructInstType const *>( type ) ) {
2126                long offsetIndex = findMember( expr->member, structType->base->members );
2127                if ( -1 == offsetIndex ) return expr;
2128
2129                return makeOffsetIndex( expr->location, type, offsetIndex );
2130        // All union members are at offset zero.
2131        } else if ( dynamic_cast<ast::UnionInstType const *>( type ) ) {
2132                return ast::ConstantExpr::from_ulong( expr->location, 0 );
2133        } else {
2134                return expr;
2135        }
2136}
2137
2138ast::Expr const * PolyGenericCalculator::postvisit(
2139                ast::OffsetPackExpr const * expr ) {
2140        ast::StructInstType const * type = expr->type;
2141
2142        // Pull offset back from generated type information.
2143        if ( findGeneric( expr->location, type ) ) {
2144                return new ast::NameExpr( expr->location,
2145                        offsetofName( Mangle::mangleType( type ) ) );
2146        }
2147
2148        std::string offsetName = offsetofName( Mangle::mangleType( type ) );
2149        // Use the already generated offsets for this type.
2150        if ( knownOffsets.contains( offsetName ) ) {
2151                return new ast::NameExpr( expr->location, offsetName );
2152        }
2153
2154        knownOffsets.insert( offsetName );
2155
2156        auto baseMembers = type->base->members;
2157        ast::Type const * offsetType = new ast::BasicType(
2158                ast::BasicType::LongUnsignedInt );
2159
2160        // Build initializer list for offset array.
2161        ast::vector<ast::Init> inits;
2162        for ( ast::ptr<ast::Decl> & member : baseMembers ) {
2163                auto memberDecl = member.as<ast::DeclWithType>();
2164                assertf( memberDecl, "Requesting offset of non-DWT member: %s",
2165                        toCString( member ) );
2166                inits.push_back( new ast::SingleInit( expr->location,
2167                        new ast::OffsetofExpr( expr->location,
2168                                deepCopy( type ),
2169                                memberDecl
2170                        )
2171                ) );
2172        }
2173
2174        auto offsetArray = makeVar( expr->location, offsetName,
2175                new ast::ArrayType(
2176                        offsetType,
2177                        ast::ConstantExpr::from_ulong( expr->location, baseMembers.size() ),
2178                        ast::FixedLen,
2179                        ast::DynamicDim
2180                ),
2181                new ast::ListInit( expr->location, std::move( inits ) )
2182        );
2183
2184        return new ast::VariableExpr( expr->location, offsetArray );
2185}
2186
2187void PolyGenericCalculator::beginScope() {
2188        knownLayouts.beginScope();
2189        knownOffsets.beginScope();
2190}
2191
2192void PolyGenericCalculator::endScope() {
2193        knownOffsets.endScope();
2194        knownLayouts.endScope();
2195}
2196
2197ast::ObjectDecl * PolyGenericCalculator::makeVar(
2198                CodeLocation const & location, std::string const & name,
2199                ast::Type const * type, ast::Init const * init ) {
2200        ast::ObjectDecl * ret = new ast::ObjectDecl( location, name, type, init );
2201        stmtsToAddBefore.push_back( new ast::DeclStmt( location, ret ) );
2202        return ret;
2203}
2204
2205/// Returns true if any of the otype parameters have a dynamic layout; and
2206/// puts all otype parameters in the output list.
2207bool findGenericParams(
2208                ast::vector<ast::Type> & out,
2209                ast::vector<ast::TypeDecl> const & baseParams,
2210                ast::vector<ast::Expr> const & typeParams ) {
2211        bool hasDynamicLayout = false;
2212
2213        for ( auto pair : group_iterate( baseParams, typeParams ) ) {
2214                auto baseParam = std::get<0>( pair );
2215                auto typeParam = std::get<1>( pair );
2216                if ( !baseParam->isComplete() ) continue;
2217                ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
2218                assertf( typeExpr, "All type parameters should be type expressions." );
2219
2220                ast::Type const * type = typeExpr->type.get();
2221                out.push_back( type );
2222                if ( isPolyType( type ) ) hasDynamicLayout = true;
2223        }
2224
2225        return hasDynamicLayout;
2226}
2227
2228bool PolyGenericCalculator::findGeneric(
2229                CodeLocation const & location, ast::Type const * type ) {
2230        type = replaceTypeInst( type, typeSubs );
2231
2232        if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
2233                // Assumes that getting put in the scopeTypeVars includes having the
2234                // layout variables set.
2235                if ( scopeTypeVars.contains( *inst ) ) {
2236                        return true;
2237                }
2238        } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
2239                // Check if this type already has a layout generated for it.
2240                std::string typeName = Mangle::mangleType( type );
2241                if ( knownLayouts.contains( typeName ) ) return true;
2242
2243                // Check if any type parameters have dynamic layout;
2244                // If none do, this type is (or will be) monomorphized.
2245                ast::vector<ast::Type> sizedParams;
2246                if ( !findGenericParams( sizedParams,
2247                                inst->base->params, inst->params ) ) {
2248                        return false;
2249                }
2250
2251                // Insert local variables for layout and generate call to layout
2252                // function.
2253                // Done early so as not to interfere with the later addition of
2254                // parameters to the layout call.
2255                knownLayouts.insert( typeName );
2256                ast::Type const * layoutType = makeSizeAlignType();
2257
2258                int memberCount = inst->base->members.size();
2259                if ( 0 == memberCount ) {
2260                        // All empty structures have the same layout (size 1, align 1).
2261                        makeVar( location,
2262                                sizeofName( typeName ), layoutType,
2263                                new ast::SingleInit( location,
2264                                                ast::ConstantExpr::from_ulong( location, 1 ) ) );
2265                        makeVar( location,
2266                                alignofName( typeName ), ast::deepCopy( layoutType ),
2267                                new ast::SingleInit( location,
2268                                                ast::ConstantExpr::from_ulong( location, 1 ) ) );
2269                        // Since 0-length arrays are forbidden in C, skip the offset array.
2270                } else {
2271                        ast::ObjectDecl const * sizeofVar = makeVar( location,
2272                                sizeofName( typeName ), deepCopy( layoutType ), nullptr );
2273                        ast::ObjectDecl const * alignofVar = makeVar( location,
2274                                alignofName( typeName ), deepCopy( layoutType ), nullptr );
2275                        ast::ObjectDecl const * offsetofVar = makeVar( location,
2276                                offsetofName( typeName ),
2277                                new ast::ArrayType(
2278                                        layoutType,
2279                                        ast::ConstantExpr::from_int( location, memberCount ),
2280                                        ast::FixedLen,
2281                                        ast::DynamicDim
2282                                ),
2283                                nullptr
2284                        );
2285
2286                        // Generate call to layout function.
2287                        ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2288                                new ast::NameExpr( location, layoutofName( inst->base ) ),
2289                                {
2290                                        new ast::AddressExpr(
2291                                                new ast::VariableExpr( location, sizeofVar ) ),
2292                                        new ast::AddressExpr(
2293                                                new ast::VariableExpr( location, alignofVar ) ),
2294                                        new ast::VariableExpr( location, offsetofVar ),
2295                                } );
2296
2297                        addOTypeParamsToLayoutCall( layoutCall, sizedParams );
2298
2299                        stmtsToAddBefore.emplace_back(
2300                                new ast::ExprStmt( location, layoutCall ) );
2301                }
2302
2303                return true;
2304        } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
2305                // Check if this type already has a layout generated for it.
2306                std::string typeName = Mangle::mangleType( type );
2307                if ( knownLayouts.contains( typeName ) ) return true;
2308
2309                // Check if any type parameters have dynamic layout;
2310                // If none do, this type is (or will be) monomorphized.
2311                ast::vector<ast::Type> sizedParams;
2312                if ( !findGenericParams( sizedParams,
2313                                inst->base->params, inst->params ) ) {
2314                        return false;
2315                }
2316
2317                // Insert local variables for layout and generate call to layout
2318                // function.
2319                // Done early so as not to interfere with the later addition of
2320                // parameters to the layout call.
2321                knownLayouts.insert( typeName );
2322                ast::Type const * layoutType = makeSizeAlignType();
2323
2324                ast::ObjectDecl * sizeofVar = makeVar( location,
2325                        sizeofName( typeName ), layoutType );
2326                ast::ObjectDecl * alignofVar = makeVar( location,
2327                        alignofName( typeName ), ast::deepCopy( layoutType ) );
2328
2329                ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2330                        new ast::NameExpr( location, layoutofName( inst->base ) ),
2331                        {
2332                                new ast::AddressExpr(
2333                                        new ast::VariableExpr( location, sizeofVar ) ),
2334                                new ast::AddressExpr(
2335                                        new ast::VariableExpr( location, alignofVar ) ),
2336                        } );
2337
2338                addOTypeParamsToLayoutCall( layoutCall, sizedParams );
2339
2340                stmtsToAddBefore.emplace_back(
2341                        new ast::ExprStmt( location, layoutCall ) );
2342
2343                return true;
2344        }
2345        return false;
2346}
2347
2348void PolyGenericCalculator::addOTypeParamsToLayoutCall(
2349                ast::UntypedExpr * layoutCall,
2350                const ast::vector<ast::Type> & otypeParams ) {
2351        CodeLocation const & location = layoutCall->location;
2352        ast::vector<ast::Expr> & args = layoutCall->args;
2353        for ( ast::ptr<ast::Type> const & param : otypeParams ) {
2354                if ( findGeneric( location, param ) ) {
2355                        // Push size/align vars for a generic parameter back.
2356                        std::string paramName = Mangle::mangleType( param );
2357                        args.emplace_back(
2358                                new ast::NameExpr( location, sizeofName( paramName ) ) );
2359                        args.emplace_back(
2360                                new ast::NameExpr( location, alignofName( paramName ) ) );
2361                } else {
2362                        args.emplace_back(
2363                                new ast::SizeofExpr( location, ast::deepCopy( param ) ) );
2364                        args.emplace_back(
2365                                new ast::AlignofExpr( location, ast::deepCopy( param ) ) );
2366                }
2367        }
2368}
2369
2370void PolyGenericCalculator::mutateMembers( ast::AggregateDecl * aggr ) {
2371        std::set<std::string> genericParams;
2372        for ( ast::ptr<ast::TypeDecl> const & decl : aggr->params ) {
2373                genericParams.insert( decl->name );
2374        }
2375        for ( ast::ptr<ast::Decl> & decl : aggr->members ) {
2376                auto field = decl.as<ast::ObjectDecl>();
2377                if ( nullptr == field ) continue;
2378
2379                ast::Type const * type = replaceTypeInst( field->type, typeSubs );
2380                auto typeInst = dynamic_cast<ast::TypeInstType const *>( type );
2381                if ( nullptr == typeInst ) continue;
2382
2383                // Do not try to monoporphize generic parameters.
2384                if ( scopeTypeVars.contains( ast::TypeEnvKey( *typeInst ) ) &&
2385                                !genericParams.count( typeInst->name ) ) {
2386                        // Polymorphic aggregate members should be converted into
2387                        // monomorphic members. Using char[size_T] here respects
2388                        // the expected sizing rules of an aggregate type.
2389                        decl = ast::mutate_field( field, &ast::ObjectDecl::type,
2390                                polyToMonoType( field->location, field->type ) );
2391                }
2392        }
2393}
2394
2395ast::Expr const * PolyGenericCalculator::genSizeof(
2396                CodeLocation const & location, ast::Type const * type ) {
2397        if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
2398                // Generate calculated size for possibly generic array.
2399                ast::Expr const * sizeofBase = genSizeof( location, array->base );
2400                if ( nullptr == sizeofBase ) return nullptr;
2401                ast::Expr const * dim = array->dimension;
2402                return makeOp( location, "?*?", sizeofBase, dim );
2403        } else if ( findGeneric( location, type ) ) {
2404                // Generate calculated size for generic type.
2405                return new ast::NameExpr( location, sizeofName(
2406                                Mangle::mangleType( type ) ) );
2407        } else {
2408                return nullptr;
2409        }
2410}
2411
2412void PolyGenericCalculator::beginTypeScope( ast::Type const * type ) {
2413        GuardScope( scopeTypeVars );
2414        makeTypeVarMap( type, scopeTypeVars );
2415}
2416
2417void PolyGenericCalculator::beginGenericScope() {
2418        GuardScope( *this );
2419        // We expect the first function type see to be the type relating to this
2420        // scope but any further type is probably some unrelated function pointer
2421        // keep track of whrich is the first.
2422        GuardValue( expect_func_type ) = true;
2423}
2424
2425// --------------------------------------------------------------------------
2426/// No common theme found.
2427/// * Replaces initialization of polymorphic values with alloca.
2428/// * Replaces declaration of dtype/ftype with appropriate void expression.
2429/// * Replaces sizeof expressions of polymorphic types with a variable.
2430/// * Strips fields from generic structure declarations.
2431struct Eraser final :
2432                public BoxPass,
2433                public ast::WithGuards {
2434        void guardTypeVarMap( ast::Type const * type ) {
2435                GuardScope( scopeTypeVars );
2436                makeTypeVarMap( type, scopeTypeVars );
2437        }
2438
2439        ast::ObjectDecl const * previsit( ast::ObjectDecl const * decl );
2440        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
2441        ast::TypedefDecl const * previsit( ast::TypedefDecl const * decl );
2442        ast::StructDecl const * previsit( ast::StructDecl const * decl );
2443        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
2444        void previsit( ast::TypeDecl const * decl );
2445        void previsit( ast::PointerType const * type );
2446        void previsit( ast::FunctionType const * type );
2447};
2448
2449ast::ObjectDecl const * Eraser::previsit( ast::ObjectDecl const * decl ) {
2450        guardTypeVarMap( decl->type );
2451        return scrubAllTypeVars( decl );
2452}
2453
2454ast::FunctionDecl const * Eraser::previsit( ast::FunctionDecl const * decl ) {
2455        guardTypeVarMap( decl->type );
2456        return scrubAllTypeVars( decl );
2457}
2458
2459ast::TypedefDecl const * Eraser::previsit( ast::TypedefDecl const * decl ) {
2460        guardTypeVarMap( decl->base );
2461        return scrubAllTypeVars( decl );
2462}
2463
2464/// Strips the members from a generic aggregate.
2465template<typename node_t>
2466node_t const * stripGenericMembers( node_t const * decl ) {
2467        if ( decl->params.empty() ) return decl;
2468        auto mutDecl = ast::mutate( decl );
2469        mutDecl->members.clear();
2470        return mutDecl;
2471}
2472
2473ast::StructDecl const * Eraser::previsit( ast::StructDecl const * decl ) {
2474        return stripGenericMembers( decl );
2475}
2476
2477ast::UnionDecl const * Eraser::previsit( ast::UnionDecl const * decl ) {
2478        return stripGenericMembers( decl );
2479}
2480
2481void Eraser::previsit( ast::TypeDecl const * decl ) {
2482        addToTypeVarMap( decl, scopeTypeVars );
2483}
2484
2485void Eraser::previsit( ast::PointerType const * type ) {
2486        guardTypeVarMap( type );
2487}
2488
2489void Eraser::previsit( ast::FunctionType const * type ) {
2490        guardTypeVarMap( type );
2491}
2492
2493} // namespace
2494
2495// --------------------------------------------------------------------------
2496void box( ast::TranslationUnit & translationUnit ) {
2497        ast::Pass<LayoutFunctionBuilder>::run( translationUnit );
2498        ast::Pass<CallAdapter>::run( translationUnit );
2499        ast::Pass<DeclAdapter>::run( translationUnit );
2500        ast::Pass<RewireAdapters>::run( translationUnit );
2501        ast::Pass<PolyGenericCalculator>::run( translationUnit );
2502        ast::Pass<Eraser>::run( translationUnit );
2503}
2504
2505} // namespace GenPoly
2506
2507// Local Variables: //
2508// tab-width: 4 //
2509// mode: c++ //
2510// compile-command: "make install" //
2511// End: //
Note: See TracBrowser for help on using the repository browser.