source: src/GenPoly/Box.cpp @ b6f2e7ab

Last change on this file since b6f2e7ab was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 5 weeks ago

Removed SizeofExpr::expr and AlignofExpr::expr, expressions that would be stored there are wrapped in TypeofType? and stored in the type field. Some special cases to hide the typeof in code generation were added. In addition, initializer length is calculated in more cases so that the full type of more arrays is known sooner. Other than that, most of the code changes were just stripping out the conditional code and checks no longer needed. Some tests had to be updated, because the typeof is not hidden in dumps and the resolver replaces known typeof expressions with the type. The extension case caused some concern but it appears that just hides warnings in the expression which no longer exists.

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