source: src/GenPoly/Box.cpp @ a933489b

Last change on this file since a933489b was 82a5ea2, checked in by Andrew Beach <ajbeach@…>, 2 months ago

Added checks for (and a test to check the checks) assertions we will not be able to adapt. Using an adapted version of Mike's error message.

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