source: src/GenPoly/Box.cpp @ 35cc6d4

Last change on this file since 35cc6d4 was 35cc6d4, checked in by Michael Brooks <mlbrooks@…>, 3 months ago

Mitigate several unused-declaration warnings in generated code.

See tests/nowarn/unused for the specific cases.

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