source: src/GenPoly/Box.cc @ a50fdfb

ADTast-experimental
Last change on this file since a50fdfb was 9feb34b, checked in by Andrew Beach <ajbeach@…>, 19 months ago

Moved toString and toCString to a new header. Updated includes. cassert was somehow getting instances of toString before but that stopped working so I embedded the new smaller include.

  • Property mode set to 100644
File size: 86.5 KB
RevLine 
[51587aa]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//
[ae63a18]7// Box.cc --
[51587aa]8//
9// Author           : Richard C. Bilson
10// Created On       : Mon May 18 07:44:20 2015
[d18540f]11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Dec 19 16:36:00 2022
13// Update Count     : 348
[51587aa]14//
[51b7345]15
[e563edf]16#include "Box.h"
17
[08fc48f]18#include <algorithm>                     // for mismatch
[e3e16bc]19#include <cassert>                       // for assert, strict_dynamic_cast
[08fc48f]20#include <iostream>                      // for operator<<, stringstream
21#include <list>                          // for list, list<>::iterator, _Lis...
22#include <map>                           // for _Rb_tree_const_iterator, map
23#include <memory>                        // for auto_ptr
24#include <set>                           // for set
25#include <string>                        // for string, allocator, basic_string
26#include <utility>                       // for pair
[51b7345]27
[bff227f]28#include "CodeGen/OperatorTable.h"
[a0c7dc36]29#include "Common/PassVisitor.h"          // for PassVisitor
[08fc48f]30#include "Common/ScopedMap.h"            // for ScopedMap, ScopedMap<>::iter...
31#include "Common/SemanticError.h"        // for SemanticError
32#include "Common/UniqueName.h"           // for UniqueName
[9feb34b]33#include "Common/ToString.hpp"           // for toCString
[08fc48f]34#include "FindFunction.h"                // for findFunction, findAndReplace...
35#include "GenPoly/ErasableScopedMap.h"   // for ErasableScopedMap<>::const_i...
36#include "GenPoly/GenPoly.h"             // for TyVarMap, isPolyType, mangle...
37#include "InitTweak/InitTweak.h"         // for getFunctionName, isAssignment
38#include "Lvalue.h"                      // for generalizedLvalue
[e563edf]39#include "ResolvExpr/Unify.h"            // for typesCompatible
[08fc48f]40#include "ScopedSet.h"                   // for ScopedSet, ScopedSet<>::iter...
41#include "ScrubTyVars.h"                 // for ScrubTyVars
42#include "SymTab/Indexer.h"              // for Indexer
43#include "SymTab/Mangler.h"              // for Mangler
[07de76b]44#include "SynTree/LinkageSpec.h"         // for C, Spec, Cforall, Intrinsic
[08fc48f]45#include "SynTree/Attribute.h"           // for Attribute
46#include "SynTree/Constant.h"            // for Constant
47#include "SynTree/Declaration.h"         // for DeclarationWithType, ObjectDecl
48#include "SynTree/Expression.h"          // for ApplicationExpr, UntypedExpr
49#include "SynTree/Initializer.h"         // for SingleInit, Initializer, Lis...
[ba3706f]50#include "SynTree/Label.h"               // for Label
[08fc48f]51#include "SynTree/Mutator.h"             // for maybeMutate, Mutator, mutateAll
52#include "SynTree/Statement.h"           // for ExprStmt, DeclStmt, ReturnStmt
53#include "SynTree/SynTree.h"             // for UniqueId
54#include "SynTree/Type.h"                // for Type, FunctionType, PointerType
55#include "SynTree/TypeSubstitution.h"    // for TypeSubstitution, operator<<
[51b7345]56
57namespace GenPoly {
[01aeade]58        namespace {
[4da152a]59                FunctionType *makeAdapterType( FunctionType const *adaptee, const TyVarMap &tyVars );
[e56cfdb0]60
[fc72845d]61                class BoxPass {
62                protected:
63                        BoxPass() : scopeTyVars( TypeDecl::Data{} ) {}
64                        TyVarMap scopeTyVars;
65                };
66
[8c91088]67                /// Adds layout-generation functions to polymorphic types.
[b4bfa0a]68                class LayoutFunctionBuilder final : public WithDeclsToAdd, public WithVisitorRef<LayoutFunctionBuilder>, public WithShortCircuiting {
[9d7b3ea]69                public:
[b4bfa0a]70                        void previsit( StructDecl *structDecl );
71                        void previsit( UnionDecl *unionDecl );
[9d7b3ea]72                };
[70a06f6]73
[49db841]74                /// Updates the call sites of polymorphic functions.
[8c91088]75                /// Replaces polymorphic return types with out-parameters,
76                /// replaces calls to polymorphic functions with adapter calls,
77                /// and adds appropriate type variables to the function call.
[49db841]78                class CallAdapter final : public BoxPass, public WithConstTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<CallAdapter>, public WithShortCircuiting {
[01aeade]79                  public:
[49db841]80                        CallAdapter();
[62e5546]81
[5e3f1e1]82                        void premutate( Declaration * declaration );
[201182a]83                        void premutate( FunctionDecl * functionDecl );
84                        void premutate( TypeDecl * typeDecl );
85                        void premutate( CommaExpr * commaExpr );
86                        Expression * postmutate( ApplicationExpr * appExpr );
87                        Expression * postmutate( UntypedExpr *expr );
88                        void premutate( AddressExpr * addrExpr );
89                        Expression * postmutate( AddressExpr * addrExpr );
90                        void premutate( ReturnStmt * returnStmt );
91                        void premutate( PointerType * pointerType );
92                        void premutate( FunctionType * functionType );
[62e5546]93
[201182a]94                        void beginScope();
95                        void endScope();
[01aeade]96                  private:
[5c52b06]97                        /// Pass the extra type parameters from polymorphic generic arguments or return types into a function application
[9f70a67b]98                        /// Will insert 0, 2 or 3 more arguments.
[474a170]99                        std::list< Expression *>::iterator passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes );
[05d47278]100                        /// passes extra type parameters into a polymorphic function application
[a805100]101                        /// Returns an iterator to the first argument after the added
102                        /// arguments, which are added at the beginning.
103                        std::list< Expression *>::iterator passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars );
[48ca586]104                        /// wraps a function application with a new temporary for the out-parameter return value
[a805100]105                        /// The new out-parameter is the new first parameter.
106                        Expression *addRetParam( ApplicationExpr *appExpr, Type *retType );
[48ca586]107                        /// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value
[a805100]108                        Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType );
[7ed7b4a]109                        /// Converts a function call into a call of the adapter with the
110                        /// original function as the first argument (all other arguments
111                        /// are pushed back). May adjust return value.
[a805100]112                        Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function );
[7ed7b4a]113                        /// Modifies the `arg`, replacing it with a boxed expression
114                        /// that matches `formal` under the current TyVarMap.
115                        void boxParam( Expression *&arg, Type *formal, const TyVarMap &exprTyVars );
116                        /// Box an argument of `appExpr` for each parameter in `function`
117                        /// starting at `arg`.
118                        /// `exprTyVars` is the function's type variables.
119                        void boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars );
120                        /// Boxes each assertion and inserts them into `appExpr` at
121                        /// `arg`. `exprTyVars` is the function's type variables.
122                        void addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars );
[1194734]123                        /// Stores assignment operators from assertion list in local map of assignment operations
[01aeade]124                        void passAdapters( ApplicationExpr *appExpr, FunctionType *functionType, const TyVarMap &exprTyVars );
[7ed7b4a]125                        /// Creates an adapter definition from `adaptee` to `realType`, using
126                        /// `mangleName` as the base name for the adapter. `tyVars` is the map of
127                        /// type variables for the function type of the adapted expression.
[4da152a]128                        FunctionDecl *makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars );
[05d47278]129                        /// Replaces intrinsic operator functions with their arithmetic desugaring
[01aeade]130                        Expression *handleIntrinsics( ApplicationExpr *appExpr );
[05d47278]131                        /// Inserts a new temporary variable into the current scope with an auto-generated name
[01aeade]132                        ObjectDecl *makeTemporary( Type *type );
[c29d9ce]133
[89173242]134                        ScopedMap< std::string, DeclarationWithType* > adapters;     ///< Set of adapter functions in the current scope
[70a06f6]135
[cce9429]136                        std::map< ApplicationExpr *, Expression * > retVals;
137
[01aeade]138                        DeclarationWithType *retval;
139                        UniqueName tempNamer;
140                };
141
[49db841]142                /// Updates declarations (and types) that require adapters.
[89173242]143                /// * Moves polymorphic returns in function types to pointer-type parameters
144                /// * adds type size and assertion parameters to parameter lists
[49db841]145                struct DeclAdapter final : public BoxPass, public WithGuards {
[a31b384]146                        void handleAggDecl();
147
148                        DeclarationWithType * postmutate( FunctionDecl *functionDecl );
149                        void premutate( StructDecl *structDecl );
150                        void premutate( UnionDecl *unionDecl );
151                        void premutate( TraitDecl *unionDecl );
152                        void premutate( TypeDecl *typeDecl );
153                        void premutate( PointerType *pointerType );
154                        void premutate( FunctionType *funcType );
[70a06f6]155
[01aeade]156                  private:
157                        void addAdapters( FunctionType *functionType );
[ae63a18]158
[01aeade]159                        std::map< UniqueId, std::string > adapterName;
160                };
161
[8c91088]162                /// * Replaces member and size/align/offsetof expressions on polymorphic generic types with calculated expressions.
[8a34677]163                /// * Replaces member expressions for polymorphic types with calculated add-field-offset-and-dereference
164                /// * Calculates polymorphic offsetof expressions from offset array
165                /// * Inserts dynamic calculation of polymorphic type layouts where needed
[02fdb8e]166                class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithConstTypeSubstitution {
[8a34677]167                public:
[a0ad7dc]168                        PolyGenericCalculator();
169
[a0c7dc36]170                        void premutate( ObjectDecl *objectDecl );
171                        void premutate( FunctionDecl *functionDecl );
172                        void premutate( TypedefDecl *objectDecl );
173                        void premutate( TypeDecl *objectDecl );
174                        Declaration * postmutate( TypeDecl *TraitDecl );
175                        void premutate( PointerType *pointerType );
176                        void premutate( FunctionType *funcType );
177                        void premutate( DeclStmt *declStmt );
178                        Expression *postmutate( MemberExpr *memberExpr );
[02c816fc]179                        void premutate( AddressExpr *addrExpr );
180                        Expression *postmutate( AddressExpr *addrExpr );
[a0c7dc36]181                        Expression *postmutate( SizeofExpr *sizeofExpr );
182                        Expression *postmutate( AlignofExpr *alignofExpr );
183                        Expression *postmutate( OffsetofExpr *offsetofExpr );
184                        Expression *postmutate( OffsetPackExpr *offsetPackExpr );
[8dceeb7]185                        void premutate( StructDecl * );
186                        void premutate( UnionDecl * );
[a0c7dc36]187
188                        void beginScope();
189                        void endScope();
[8a34677]190
191                private:
192                        /// Makes a new variable in the current scope with the given name, type & optional initializer
193                        ObjectDecl *makeVar( const std::string &name, Type *type, Initializer *init = 0 );
194                        /// returns true if the type has a dynamic layout; such a layout will be stored in appropriately-named local variables when the function returns
[4da152a]195                        bool findGeneric( Type const *ty );
[8a34677]196                        /// adds type parameters to the layout call; will generate the appropriate parameters if needed
197                        void addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams );
[8dceeb7]198                        /// change the type of generic aggregate members to char[]
199                        void mutateMembers( AggregateDecl * aggrDecl );
[e16294d]200                        /// returns the calculated sizeof expression for ty, or nullptr for use C sizeof()
201                        Expression* genSizeof( Type* ty );
[aa19ccf]202
203                        /// Enters a new scope for type-variables, adding the type variables from ty
204                        void beginTypeScope( Type *ty );
[a0c7dc36]205                        /// Enters a new scope for knowLayouts and knownOffsets and queues exit calls
206                        void beginGenericScope();
[70a06f6]207
[8a34677]208                        ScopedSet< std::string > knownLayouts;          ///< Set of generic type layouts known in the current scope, indexed by sizeofName
209                        ScopedSet< std::string > knownOffsets;          ///< Set of non-generic types for which the offset array exists in the current scope, indexed by offsetofName
[a0ad7dc]210                        UniqueName bufNamer;                           ///< Namer for VLA buffers
[02c816fc]211                        Expression * addrMember = nullptr;             ///< AddressExpr argument is MemberExpr?
[18070ee]212                        bool expect_func_type = false;                 ///< used to avoid recursing too deep in type decls
[05d47278]213                };
[b4cd03b7]214
[49db841]215                /// Erases unneeded/unwanted polymorphic information.
[8c91088]216                /// Replaces initialization of polymorphic values with alloca,
217                /// declaration of dtype/ftype with appropriate void expression,
218                /// sizeof expressions of polymorphic types with the proper variable,
219                /// and strips fields from generic struct declarations.
[49db841]220                struct Eraser final {
[fc72845d]221                        void premutate( ObjectDecl * objectDecl );
222                        void premutate( FunctionDecl * functionDecl );
223                        void premutate( TypedefDecl * typedefDecl );
224                        void premutate( StructDecl * structDecl );
225                        void premutate( UnionDecl * unionDecl );
[01aeade]226                };
227        } // anonymous namespace
228
229        void box( std::list< Declaration *>& translationUnit ) {
[b4bfa0a]230                PassVisitor<LayoutFunctionBuilder> layoutBuilder;
[49db841]231                PassVisitor<CallAdapter> callAdapter;
232                PassVisitor<DeclAdapter> declAdapter;
[a0c7dc36]233                PassVisitor<PolyGenericCalculator> polyCalculator;
[49db841]234                PassVisitor<Eraser> eraser;
[70a06f6]235
[b4bfa0a]236                acceptAll( translationUnit, layoutBuilder );
[49db841]237                mutateAll( translationUnit, callAdapter );
238                mutateAll( translationUnit, declAdapter );
[a0c7dc36]239                mutateAll( translationUnit, polyCalculator );
[49db841]240                mutateAll( translationUnit, eraser );
[6c3744e]241        }
242
[49db841]243////////////////////////////////// LayoutFunctionBuilder ////////////////////////////////////////
[9d7b3ea]244
245        /// Get a list of type declarations that will affect a layout function
246        std::list< TypeDecl* > takeOtypeOnly( std::list< TypeDecl* > &decls ) {
247                std::list< TypeDecl * > otypeDecls;
248
[0b1ca47]249                for ( TypeDecl * const decl : decls ) {
250                        if ( decl->isComplete() ) {
251                                otypeDecls.push_back( decl );
[9d7b3ea]252                        }
253                }
[70a06f6]254
[9d7b3ea]255                return otypeDecls;
256        }
257
258        /// Adds parameters for otype layout to a function type
259        void addOtypeParams( FunctionType *layoutFnType, std::list< TypeDecl* > &otypeParams ) {
260                BasicType sizeAlignType( Type::Qualifiers(), BasicType::LongUnsignedInt );
[70a06f6]261
[0b1ca47]262                for ( TypeDecl * const param : otypeParams ) {
263                        TypeInstType paramType( Type::Qualifiers(), param->get_name(), param );
[adc6781]264                        std::string paramName = mangleType( &paramType );
[68fe077a]265                        layoutFnType->get_parameters().push_back( new ObjectDecl( sizeofName( paramName ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignType.clone(), 0 ) );
266                        layoutFnType->get_parameters().push_back( new ObjectDecl( alignofName( paramName ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignType.clone(), 0 ) );
[9d7b3ea]267                }
268        }
269
270        /// Builds a layout function declaration
[e3bf4cf]271        FunctionDecl *buildLayoutFunctionDecl( AggregateDecl *typeDecl, bool isInFunction, FunctionType *layoutFnType ) {
[9d7b3ea]272                // Routines at global scope marked "static" to prevent multiple definitions is separate translation units
273                // because each unit generates copies of the default routines for each aggregate.
[a7c90d4]274                FunctionDecl *layoutDecl = new FunctionDecl( layoutofName( typeDecl ),
[e3bf4cf]275                                                                                                         isInFunction ? Type::StorageClasses() : Type::StorageClasses( Type::Static ),
[ba3706f]276                                                                                                         LinkageSpec::AutoGen, layoutFnType, new CompoundStmt(),
[ddfd945]277                                                                                                         std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) );
[9d7b3ea]278                layoutDecl->fixUniqueId();
279                return layoutDecl;
280        }
281
282        /// Makes a binary operation
283        Expression *makeOp( const std::string &name, Expression *lhs, Expression *rhs ) {
284                UntypedExpr *expr = new UntypedExpr( new NameExpr( name ) );
[0690350]285                expr->args.push_back( lhs );
286                expr->args.push_back( rhs );
[9d7b3ea]287                return expr;
288        }
289
290        /// Returns the dereference of a local pointer variable
291        Expression *derefVar( ObjectDecl *var ) {
[0690350]292                return UntypedExpr::createDeref( new VariableExpr( var ) );
[9d7b3ea]293        }
294
295        /// makes an if-statement with a single-expression if-block and no then block
296        Statement *makeCond( Expression *cond, Expression *ifPart ) {
[ba3706f]297                return new IfStmt( cond, new ExprStmt( ifPart ), 0 );
[9d7b3ea]298        }
299
300        /// makes a statement that assigns rhs to lhs if lhs < rhs
301        Statement *makeAssignMax( Expression *lhs, Expression *rhs ) {
302                return makeCond( makeOp( "?<?", lhs, rhs ), makeOp( "?=?", lhs->clone(), rhs->clone() ) );
303        }
304
305        /// makes a statement that aligns lhs to rhs (rhs should be an integer power of two)
306        Statement *makeAlignTo( Expression *lhs, Expression *rhs ) {
307                // check that the lhs is zeroed out to the level of rhs
[d56e5bc]308                Expression *ifCond = makeOp( "?&?", lhs, makeOp( "?-?", rhs, new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
[9d7b3ea]309                // if not aligned, increment to alignment
310                Expression *ifExpr = makeOp( "?+=?", lhs->clone(), makeOp( "?-?", rhs->clone(), ifCond->clone() ) );
311                return makeCond( ifCond, ifExpr );
312        }
[70a06f6]313
[9d7b3ea]314        /// adds an expression to a compound statement
315        void addExpr( CompoundStmt *stmts, Expression *expr ) {
[ba3706f]316                stmts->get_kids().push_back( new ExprStmt( expr ) );
[9d7b3ea]317        }
318
319        /// adds a statement to a compound statement
320        void addStmt( CompoundStmt *stmts, Statement *stmt ) {
321                stmts->get_kids().push_back( stmt );
322        }
[70a06f6]323
[b4bfa0a]324        void LayoutFunctionBuilder::previsit( StructDecl *structDecl ) {
[9d7b3ea]325                // do not generate layout function for "empty" tag structs
[b4bfa0a]326                visit_children = false;
327                if ( structDecl->get_members().empty() ) return;
[9d7b3ea]328
329                // get parameters that can change layout, exiting early if none
330                std::list< TypeDecl* > otypeParams = takeOtypeOnly( structDecl->get_parameters() );
[b4bfa0a]331                if ( otypeParams.empty() ) return;
[9d7b3ea]332
333                // build layout function signature
334                FunctionType *layoutFnType = new FunctionType( Type::Qualifiers(), false );
335                BasicType *sizeAlignType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
336                PointerType *sizeAlignOutType = new PointerType( Type::Qualifiers(), sizeAlignType );
[70a06f6]337
[68fe077a]338                ObjectDecl *sizeParam = new ObjectDecl( sizeofName( structDecl->get_name() ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignOutType, 0 );
[9d7b3ea]339                layoutFnType->get_parameters().push_back( sizeParam );
[68fe077a]340                ObjectDecl *alignParam = new ObjectDecl( alignofName( structDecl->get_name() ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignOutType->clone(), 0 );
[9d7b3ea]341                layoutFnType->get_parameters().push_back( alignParam );
[68fe077a]342                ObjectDecl *offsetParam = new ObjectDecl( offsetofName( structDecl->get_name() ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignOutType->clone(), 0 );
[9d7b3ea]343                layoutFnType->get_parameters().push_back( offsetParam );
344                addOtypeParams( layoutFnType, otypeParams );
345
346                // build function decl
[e3bf4cf]347                FunctionDecl *layoutDecl = buildLayoutFunctionDecl( structDecl, isInFunction(), layoutFnType );
[9d7b3ea]348
349                // calculate struct layout in function body
350
[5a3ac84]351                // initialize size and alignment to 0 and 1 (will have at least one member to re-edit size)
[d56e5bc]352                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 0 ) ) ) );
353                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
[637c139]354                for ( auto index_member : enumerate( structDecl->members ) ) {
355                        DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( index_member.val );
[9d7b3ea]356                        assert( dwt );
[bd91e2a]357                        Type *memberType = dwt->get_type();
[9d7b3ea]358
[637c139]359                        if ( 0 < index_member.idx ) {
[9d7b3ea]360                                // make sure all members after the first (automatically aligned at 0) are properly padded for alignment
[bd91e2a]361                                addStmt( layoutDecl->get_statements(), makeAlignTo( derefVar( sizeParam ), new AlignofExpr( memberType->clone() ) ) );
[9d7b3ea]362                        }
[70a06f6]363
[9d7b3ea]364                        // place current size in the current offset index
[637c139]365                        addExpr( layoutDecl->get_statements(), makeOp( "?=?", makeOp( "?[?]", new VariableExpr( offsetParam ), new ConstantExpr( Constant::from_ulong( index_member.idx ) ) ),
[9d7b3ea]366                                                                              derefVar( sizeParam ) ) );
367
368                        // add member size to current size
[bd91e2a]369                        addExpr( layoutDecl->get_statements(), makeOp( "?+=?", derefVar( sizeParam ), new SizeofExpr( memberType->clone() ) ) );
[70a06f6]370
[9d7b3ea]371                        // take max of member alignment and global alignment
[bd91e2a]372                        addStmt( layoutDecl->get_statements(), makeAssignMax( derefVar( alignParam ), new AlignofExpr( memberType->clone() ) ) );
[9d7b3ea]373                }
374                // make sure the type is end-padded to a multiple of its alignment
375                addStmt( layoutDecl->get_statements(), makeAlignTo( derefVar( sizeParam ), derefVar( alignParam ) ) );
376
[b4bfa0a]377                declsToAddAfter.push_back( layoutDecl );
[9d7b3ea]378        }
[70a06f6]379
[b4bfa0a]380        void LayoutFunctionBuilder::previsit( UnionDecl *unionDecl ) {
[9d7b3ea]381                // do not generate layout function for "empty" tag unions
[b4bfa0a]382                visit_children = false;
383                if ( unionDecl->get_members().empty() ) return;
[70a06f6]384
[9d7b3ea]385                // get parameters that can change layout, exiting early if none
386                std::list< TypeDecl* > otypeParams = takeOtypeOnly( unionDecl->get_parameters() );
[b4bfa0a]387                if ( otypeParams.empty() ) return;
[9d7b3ea]388
389                // build layout function signature
390                FunctionType *layoutFnType = new FunctionType( Type::Qualifiers(), false );
391                BasicType *sizeAlignType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
392                PointerType *sizeAlignOutType = new PointerType( Type::Qualifiers(), sizeAlignType );
[70a06f6]393
[68fe077a]394                ObjectDecl *sizeParam = new ObjectDecl( sizeofName( unionDecl->get_name() ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignOutType, 0 );
[9d7b3ea]395                layoutFnType->get_parameters().push_back( sizeParam );
[68fe077a]396                ObjectDecl *alignParam = new ObjectDecl( alignofName( unionDecl->get_name() ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignOutType->clone(), 0 );
[9d7b3ea]397                layoutFnType->get_parameters().push_back( alignParam );
398                addOtypeParams( layoutFnType, otypeParams );
399
400                // build function decl
[e3bf4cf]401                FunctionDecl *layoutDecl = buildLayoutFunctionDecl( unionDecl, isInFunction(), layoutFnType );
[9d7b3ea]402
403                // calculate union layout in function body
[d56e5bc]404                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
405                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
[0b1ca47]406                for ( Declaration * const member : unionDecl->members ) {
407                        DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( member );
[9d7b3ea]408                        assert( dwt );
[bd91e2a]409                        Type *memberType = dwt->get_type();
[70a06f6]410
[9d7b3ea]411                        // take max member size and global size
[bd91e2a]412                        addStmt( layoutDecl->get_statements(), makeAssignMax( derefVar( sizeParam ), new SizeofExpr( memberType->clone() ) ) );
[70a06f6]413
[9d7b3ea]414                        // take max of member alignment and global alignment
[bd91e2a]415                        addStmt( layoutDecl->get_statements(), makeAssignMax( derefVar( alignParam ), new AlignofExpr( memberType->clone() ) ) );
[9d7b3ea]416                }
417                // make sure the type is end-padded to a multiple of its alignment
418                addStmt( layoutDecl->get_statements(), makeAlignTo( derefVar( sizeParam ), derefVar( alignParam ) ) );
419
[b4bfa0a]420                declsToAddAfter.push_back( layoutDecl );
[9d7b3ea]421        }
[70a06f6]422
[49db841]423////////////////////////////////////////////// CallAdapter //////////////////////////////////////
[01aeade]424
425        namespace {
[4da152a]426                std::string makePolyMonoSuffix( FunctionType const * function, const TyVarMap &tyVars ) {
[ed1065c]427                        // NOTE: this function previously used isPolyObj, which failed to produce
428                        // the correct thing in some situations. It's not clear to me why this wasn't working.
429
[ae63a18]430                        // if the return type or a parameter type involved polymorphic types, then the adapter will need
431                        // to take those polymorphic types as pointers. Therefore, there can be two different functions
[bdf1954]432                        // with the same mangled name, so we need to further mangle the names.
[8d9d974]433                        std::stringstream name;
[4da152a]434                        for ( DeclarationWithType const * const ret : function->returnVals ) {
[8d9d974]435                                name << ( isPolyType( ret->get_type(), tyVars ) ? 'P' : 'M' );
[bdf1954]436                        }
[8d9d974]437                        name << '_';
[4da152a]438                        for ( DeclarationWithType const * const arg : function->parameters ) {
[8d9d974]439                                name << ( isPolyType( arg->get_type(), tyVars ) ? 'P' : 'M' );
440                        }
[bdf1954]441                        return name.str();
442                }
443
[4da152a]444                std::string mangleAdapterName( FunctionType const * function, const TyVarMap &tyVars ) {
[bdf1954]445                        return SymTab::Mangler::mangle( function ) + makePolyMonoSuffix( function, tyVars );
446                }
447
[01aeade]448                std::string makeAdapterName( const std::string &mangleName ) {
449                        return "_adapter" + mangleName;
450                }
[6c3744e]451
[f6aa89c]452                /// Replaces a polymorphic type with its concrete equivalant under the current environment (returns itself if concrete).
453                /// If `doClone` is set to false, will not clone interior types
454                Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone = true );
455
[49db841]456                CallAdapter::CallAdapter() : tempNamer( "_temp" ) {}
[01aeade]457
[5e3f1e1]458                void CallAdapter::premutate( Declaration * ) {
459                        // Prevent type declaration information from leaking out.
460                        GuardScope( scopeTyVars );
461                }
462
[49db841]463                void CallAdapter::premutate( FunctionDecl *functionDecl ) {
[e56cfdb0]464                        if ( functionDecl->get_statements() ) {         // empty routine body ?
[2a7b3ca]465                                // std::cerr << "mutating function: " << functionDecl->get_mangleName() << std::endl;
[201182a]466                                GuardScope( scopeTyVars );
467                                GuardValue( retval );
[e56cfdb0]468
469                                // process polymorphic return value
[cce9429]470                                retval = nullptr;
[201182a]471                                FunctionType *functionType = functionDecl->type;
472                                if ( isDynRet( functionType ) && functionDecl->linkage != LinkageSpec::C ) {
473                                        retval = functionType->returnVals.front();
[ae63a18]474
[01aeade]475                                        // give names to unnamed return values
[201182a]476                                        if ( retval->name == "" ) {
477                                                retval->name = "_retparm";
478                                                retval->linkage = LinkageSpec::C;
[01aeade]479                                        } // if
480                                } // if
[ae63a18]481
[201182a]482                                makeTyVarMap( functionType, scopeTyVars );
[e56cfdb0]483
[4da152a]484                                std::list< FunctionType const *> functions;
[0b1ca47]485                                for ( TypeDecl * const tyVar : functionType->forall ) {
486                                        for ( DeclarationWithType * const assert : tyVar->assertions ) {
487                                                findFunction( assert->get_type(), functions, scopeTyVars, needsAdapter );
[e56cfdb0]488                                        } // for
489                                } // for
[9f70a67b]490                                for ( DeclarationWithType * const arg : functionType->parameters ) {
[0b1ca47]491                                        findFunction( arg->get_type(), functions, scopeTyVars, needsAdapter );
[e56cfdb0]492                                } // for
[b4cd03b7]493
[4da152a]494                                for ( FunctionType const * const funType : functions ) {
[0b1ca47]495                                        std::string mangleName = mangleAdapterName( funType, scopeTyVars );
[e9b5043]496                                        if ( !adapters.contains( mangleName ) ) {
[e56cfdb0]497                                                std::string adapterName = makeAdapterName( mangleName );
[0b1ca47]498                                                adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), nullptr ) ) );
[e56cfdb0]499                                        } // if
500                                } // for
[2a7b3ca]501                                // std::cerr << "end function: " << functionDecl->get_mangleName() << std::endl;
[01aeade]502                        } // if
503                }
[6c3744e]504
[49db841]505                void CallAdapter::premutate( TypeDecl *typeDecl ) {
[2c57025]506                        addToTyVarMap( typeDecl, scopeTyVars );
[01aeade]507                }
[6c3744e]508
[49db841]509                void CallAdapter::premutate( CommaExpr *commaExpr ) {
[cce9429]510                        // Attempting to find application expressions that were mutated by the copy constructor passes
511                        // to use an explicit return variable, so that the variable can be reused as a parameter to the
512                        // call rather than creating a new temp variable. Previously this step was an optimization, but
513                        // with the introduction of tuples and UniqueExprs, it is necessary to ensure that they use the same variable.
514                        // Essentially, looking for pattern: (x=f(...), x)
515                        // To compound the issue, the right side can be *x, etc. because of lvalue-returning functions
516                        if ( UntypedExpr * assign = dynamic_cast< UntypedExpr * >( commaExpr->get_arg1() ) ) {
[bff227f]517                                if ( CodeGen::isAssignment( InitTweak::getFunctionName( assign ) ) ) {
[cce9429]518                                        assert( assign->get_args().size() == 2 );
519                                        if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( assign->get_args().back() ) ) {
520                                                // first argument is assignable, so it must be an lvalue, so it should be legal to take its address.
521                                                retVals[appExpr] = assign->get_args().front();
522                                        }
523                                }
524                        }
[01aeade]525                }
[6c3744e]526
[49db841]527                std::list< Expression *>::iterator CallAdapter::passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes ) {
[4b8f918]528                        Type *polyType = isPolyType( parmType, exprTyVars );
529                        if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) {
530                                std::string typeName = mangleType( polyType );
[474a170]531                                if ( seenTypes.count( typeName ) ) return arg;
[5c52b06]532
533                                arg = appExpr->get_args().insert( arg, new SizeofExpr( argBaseType->clone() ) );
534                                arg++;
535                                arg = appExpr->get_args().insert( arg, new AlignofExpr( argBaseType->clone() ) );
536                                arg++;
[4b8f918]537                                if ( dynamic_cast< StructInstType* >( polyType ) ) {
[5c52b06]538                                        if ( StructInstType *argBaseStructType = dynamic_cast< StructInstType* >( argBaseType ) ) {
[89173242]539                                                // zero-length arrays are forbidden by C, so don't pass offset for empty struct
540                                                if ( ! argBaseStructType->get_baseStruct()->get_members().empty() ) {
[d75038c]541                                                        arg = appExpr->get_args().insert( arg, new OffsetPackExpr( argBaseStructType->clone() ) );
[89173242]542                                                        arg++;
543                                                }
[5c52b06]544                                        } else {
[a16764a6]545                                                SemanticError( argBaseType, "Cannot pass non-struct type for generic struct: " );
[5c52b06]546                                        }
547                                }
548
[adc6781]549                                seenTypes.insert( typeName );
[5c52b06]550                        }
[474a170]551                        return arg;
[5c52b06]552                }
553
[49db841]554                std::list< Expression *>::iterator CallAdapter::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars ) {
[a805100]555                        assert( env );
556                        std::list< Expression *>::iterator arg = appExpr->args.begin();
[7754cde]557                        // pass size/align for type variables
[9f70a67b]558                        // NOTE: This is iterating over a map. This means the sorting
559                        // order of the keys changes behaviour, as the iteration order
[5a4b403]560                        // is visible outside the loop. - The order matches the orignal
561                        // order because the vars have been renamed with numbers that,
562                        // even when converted to strings, sort in the original order.
563                        // (At least, that is the best explination I have.)
[331ee52c]564                        for ( std::pair<const std::string, TypeDecl::Data> const & tyParam : exprTyVars ) {
[9f70a67b]565                                if ( !tyParam.second.isComplete ) continue;
566                                Type *concrete = env->lookup( tyParam.first );
567                                // If there is an unbound type variable, it should have detected already.
568                                assertf( concrete, "Unbound type variable: %s in: %s",
569                                        toCString( tyParam.first ), toCString( *env ) );
570
571                                arg = appExpr->get_args().insert( arg, new SizeofExpr( concrete->clone() ) );
572                                arg++;
573                                arg = appExpr->get_args().insert( arg, new AlignofExpr( concrete->clone() ) );
574                                arg++;
[01aeade]575                        } // for
[7754cde]576
577                        // add size/align for generic types to parameter list
[a805100]578                        if ( ! appExpr->get_function()->result ) return arg;
[906e24d]579                        FunctionType *funcType = getFunctionType( appExpr->get_function()->get_result() );
[7754cde]580                        assert( funcType );
[ae63a18]581
[9f70a67b]582                        // Iterator over the original function arguments.
583                        std::list< Expression* >::const_iterator fnArg;
584                        // Names for generic types we've seen.
585                        std::set< std::string > seenTypes;
[7754cde]586
[5c52b06]587                        // a polymorphic return type may need to be added to the argument list
588                        if ( polyRetType ) {
[f6aa89c]589                                Type *concRetType = replaceWithConcrete( polyRetType, env );
[474a170]590                                arg = passArgTypeVars( appExpr, polyRetType, concRetType, arg, exprTyVars, seenTypes );
[9f70a67b]591                                // Skip the return parameter in the argument list.
592                                fnArg = arg + 1;
593                        } else {
594                                fnArg = arg;
[5c52b06]595                        }
[70a06f6]596
[5c52b06]597                        // add type information args for presently unseen types in parameter list
[9f70a67b]598                        std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin();
[5c52b06]599                        for ( ; fnParm != funcType->get_parameters().end() && fnArg != appExpr->get_args().end(); ++fnParm, ++fnArg ) {
[5802a4f]600                                Type * argType = (*fnArg)->get_result();
[9f70a67b]601                                if ( ! argType ) continue;
[474a170]602                                arg = passArgTypeVars( appExpr, (*fnParm)->get_type(), argType, arg, exprTyVars, seenTypes );
[7754cde]603                        }
[a805100]604                        return arg;
[01aeade]605                }
[6c3744e]606
[49db841]607                ObjectDecl *CallAdapter::makeTemporary( Type *type ) {
[68fe077a]608                        ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), Type::StorageClasses(), LinkageSpec::C, 0, type, 0 );
[ba3706f]609                        stmtsToAddBefore.push_back( new DeclStmt( newObj ) );
[01aeade]610                        return newObj;
611                }
[6c3744e]612
[49db841]613                Expression *CallAdapter::addRetParam( ApplicationExpr *appExpr, Type *retType ) {
[cf16f94]614                        // Create temporary to hold return value of polymorphic function and produce that temporary as a result
[cce9429]615                        // using a comma expression.
[d9fa60a]616                        assert( retType );
[cce9429]617
618                        Expression * paramExpr = nullptr;
619                        // try to use existing return value parameter if it exists, otherwise create a new temporary
620                        if ( retVals.count( appExpr ) ) {
621                                paramExpr = retVals[appExpr]->clone();
622                        } else {
623                                ObjectDecl *newObj = makeTemporary( retType->clone() );
624                                paramExpr = new VariableExpr( newObj );
625                        }
626                        Expression * retExpr = paramExpr->clone();
[5c52b06]627
628                        // If the type of the temporary is not polymorphic, box temporary by taking its address;
629                        // otherwise the temporary is already boxed and can be used directly.
[cce9429]630                        if ( ! isPolyType( paramExpr->get_result(), scopeTyVars, env ) ) {
[cf16f94]631                                paramExpr = new AddressExpr( paramExpr );
[01aeade]632                        } // if
[a805100]633                        // Add argument to function call.
634                        appExpr->args.push_front( paramExpr );
[cf16f94]635                        // Build a comma expression to call the function and emulate a normal return.
[cce9429]636                        CommaExpr *commaExpr = new CommaExpr( appExpr, retExpr );
[029e330]637                        commaExpr->env = appExpr->env;
638                        appExpr->env = nullptr;
[cf16f94]639                        return commaExpr;
[01aeade]640                }
[6c3744e]641
[f6aa89c]642                /// Replaces all the type parameters of a generic type with their concrete equivalents under the current environment
643                void replaceParametersWithConcrete( std::list< Expression* >& params, TypeSubstitution const * env ) {
[994028dc]644                        for ( Expression * const param : params ) {
645                                TypeExpr *paramType = dynamic_cast< TypeExpr* >( param );
[8bf784a]646                                assertf(paramType, "Aggregate parameters should be type expressions");
[f6aa89c]647                                paramType->set_type( replaceWithConcrete( paramType->get_type(), env, false ) );
[48ca586]648                        }
649                }
[b4cd03b7]650
[f6aa89c]651                // See forward definition.
652                Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone ) {
[7ed7b4a]653                        assert( env );
[48ca586]654                        if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
655                                Type *concrete = env->lookup( typeInst->get_name() );
656                                if ( concrete == 0 ) {
[7b2c0a99]657                                        return typeInst;
[48ca586]658                                } // if
659                                return concrete;
660                        } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
661                                if ( doClone ) {
662                                        structType = structType->clone();
663                                }
[f6aa89c]664                                replaceParametersWithConcrete( structType->get_parameters(), env );
[48ca586]665                                return structType;
666                        } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
667                                if ( doClone ) {
668                                        unionType = unionType->clone();
669                                }
[f6aa89c]670                                replaceParametersWithConcrete( unionType->get_parameters(), env );
[48ca586]671                                return unionType;
672                        }
673                        return type;
674                }
675
[49db841]676                Expression *CallAdapter::addDynRetParam( ApplicationExpr *appExpr, Type *dynType ) {
[f6aa89c]677                        Type *concrete = replaceWithConcrete( dynType, env );
[70a06f6]678                        // add out-parameter for return value
[a805100]679                        return addRetParam( appExpr, concrete );
[01aeade]680                }
[6c3744e]681
[49db841]682                Expression *CallAdapter::applyAdapter( ApplicationExpr *appExpr, FunctionType *function ) {
[01aeade]683                        Expression *ret = appExpr;
[a805100]684                        if ( isDynRet( function, scopeTyVars ) ) {
685                                ret = addRetParam( appExpr, function->returnVals.front()->get_type() );
[01aeade]686                        } // if
[a805100]687                        std::string mangleName = mangleAdapterName( function, scopeTyVars );
[01aeade]688                        std::string adapterName = makeAdapterName( mangleName );
[b1a6d6b]689
[b4cd03b7]690                        // cast adaptee to void (*)(), since it may have any type inside a polymorphic function
691                        Type * adapteeType = new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
[029e330]692                        appExpr->get_args().push_front( new CastExpr( appExpr->function, adapteeType ) );
[906e24d]693                        appExpr->set_function( new NameExpr( adapterName ) ); // xxx - result is never set on NameExpr
[ae63a18]694
[01aeade]695                        return ret;
696                }
[6c3744e]697
[4573e3c]698                // find instances of polymorphic type parameters
699                struct PolyFinder {
700                        const TyVarMap * tyVars = nullptr;
701                        bool found = false;
702
703                        void previsit( TypeInstType * t ) {
704                                if ( isPolyType( t, *tyVars ) ) {
705                                        found = true;
706                                }
707                        }
708                };
709
710                // true if there is an instance of a polymorphic type parameter in t
711                bool hasPolymorphism( Type * t, const TyVarMap &tyVars ) {
712                        PassVisitor<PolyFinder> finder;
713                        finder.pass.tyVars = &tyVars;
714                        maybeAccept( t, finder );
715                        return finder.pass.found;
716                }
717
[b4cd03b7]718                /// cast parameters to polymorphic functions so that types are replaced with
719                /// void * if they are type parameters in the formal type.
720                /// this gets rid of warnings from gcc.
[01aeade]721                void addCast( Expression *&actual, Type *formal, const TyVarMap &tyVars ) {
[4573e3c]722                        // type contains polymorphism, but isn't exactly a polytype, in which case it
723                        // has some real actual type (e.g. unsigned int) and casting to void * is wrong
724                        if ( hasPolymorphism( formal, tyVars ) && ! isPolyType( formal, tyVars ) ) {
[ea5daeb]725                                Type * newType = formal->clone();
[b4cd03b7]726                                newType = ScrubTyVars::scrub( newType, tyVars );
[01aeade]727                                actual = new CastExpr( actual, newType );
728                        } // if
729                }
[6c3744e]730
[49db841]731                void CallAdapter::boxParam( Expression *&arg, Type *param, const TyVarMap &exprTyVars ) {
[b3212de]732                        assertf( arg->result, "arg does not have result: %s", toString( arg ).c_str() );
733                        addCast( arg, param, exprTyVars );
734                        if ( ! needsBoxing( param, arg->result, exprTyVars, env ) ) return;
735
736                        if ( arg->get_lvalue() ) {
737                                // argument expression may be CFA lvalue, but not C lvalue -- apply generalizedLvalue transformations.
738                                // if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( arg ) ) {
739                                //      if ( dynamic_cast<ArrayType *>( varExpr->var->get_type() ) ){
740                                //              // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
741                                //              return;
742                                //      }
743                                // }
[7ed7b4a]744                                arg = generalizedLvalue( new AddressExpr( arg ) );
[b3212de]745                                if ( ! ResolvExpr::typesCompatible( param, arg->get_result(), SymTab::Indexer() ) ) {
746                                        // silence warnings by casting boxed parameters when the actual type does not match up with the formal type.
747                                        arg = new CastExpr( arg, param->clone() );
748                                }
749                        } else {
750                                // use type computed in unification to declare boxed variables
751                                Type * newType = param->clone();
752                                if ( env ) env->apply( newType );
[7ed7b4a]753                                ObjectDecl *newObj = makeTemporary( newType );
754                                // TODO: is this right??? (Why wouldn't it be?)
755                                newObj->get_type()->get_qualifiers() = Type::Qualifiers();
756                                // TODO: why doesn't this just use initialization syntax?
757                                // (Possibly to ensure code is run at the right time.)
758                                UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) );
[b3212de]759                                assign->get_args().push_back( new VariableExpr( newObj ) );
760                                assign->get_args().push_back( arg );
761                                stmtsToAddBefore.push_back( new ExprStmt( assign ) );
762                                arg = new AddressExpr( new VariableExpr( newObj ) );
763                        } // if
764                }
765
[49db841]766                void CallAdapter::boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars ) {
[994028dc]767                        for ( DeclarationWithType * param : function->parameters ) {
768                                assertf( arg != appExpr->args.end(), "boxParams: missing argument for param %s to %s in %s", toString( param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() );
[7ed7b4a]769                                boxParam( *arg, param->get_type(), exprTyVars );
[994028dc]770                                ++arg;
[01aeade]771                        } // for
772                }
[6c3744e]773
[49db841]774                void CallAdapter::addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars ) {
[994028dc]775                        for ( TypeDecl * const tyVar : functionType->forall ) {
776                                for ( DeclarationWithType * const assert : tyVar->assertions ) {
777                                        InferredParams::const_iterator inferParam = appExpr->inferParams.find( assert->get_uniqueId() );
778                                        assertf( inferParam != appExpr->inferParams.end(), "addInferredParams missing inferred parameter: %s in: %s", toString( assert ).c_str(), toString( appExpr ).c_str() );
[01aeade]779                                        Expression *newExpr = inferParam->second.expr->clone();
[7ed7b4a]780                                        boxParam( newExpr, assert->get_type(), tyVars );
[9f70a67b]781                                        arg = appExpr->get_args().insert( arg, newExpr );
782                                        ++arg;
[01aeade]783                                } // for
784                        } // for
785                }
[6c3744e]786
[01aeade]787                void makeRetParm( FunctionType *funcType ) {
[4573e3c]788                        DeclarationWithType *retParm = funcType->returnVals.front();
[6c3744e]789
[01aeade]790                        // make a new parameter that is a pointer to the type of the old return value
791                        retParm->set_type( new PointerType( Type::Qualifiers(), retParm->get_type() ) );
792                        funcType->get_parameters().push_front( retParm );
[6c3744e]793
[01aeade]794                        // we don't need the return value any more
795                        funcType->get_returnVals().clear();
796                }
[6c3744e]797
[4da152a]798                FunctionType *makeAdapterType( FunctionType const *adaptee, const TyVarMap &tyVars ) {
[01aeade]799                        // actually make the adapter type
800                        FunctionType *adapter = adaptee->clone();
[3bb195cb]801                        if ( isDynRet( adapter, tyVars ) ) {
[01aeade]802                                makeRetParm( adapter );
803                        } // if
[68fe077a]804                        adapter->get_parameters().push_front( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) ), 0 ) );
[01aeade]805                        return adapter;
806                }
[6c3744e]807
[4da152a]808                Expression *makeAdapterArg(
809                                DeclarationWithType *param,
810                                DeclarationWithType const *arg,
811                                DeclarationWithType const *realParam,
812                                const TyVarMap &tyVars ) {
[01aeade]813                        assert( param );
814                        assert( arg );
[b3212de]815                        if ( isPolyType( realParam->get_type(), tyVars )
816                                        && ! isPolyType( arg->get_type() ) ) {
817                                UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
818                                deref->args.push_back( new CastExpr( new VariableExpr( param ), new PointerType( Type::Qualifiers(), arg->get_type()->clone() ) ) );
819                                deref->result = arg->get_type()->clone();
820                                return deref;
[01aeade]821                        } // if
822                        return new VariableExpr( param );
823                }
[6c3744e]824
[4da152a]825                void addAdapterParams(
826                                ApplicationExpr *adapteeApp,
827                                std::list< DeclarationWithType *>::const_iterator arg,
828                                std::list< DeclarationWithType *>::const_iterator param,
829                                std::list< DeclarationWithType *>::const_iterator paramEnd,
830                                std::list< DeclarationWithType *>::const_iterator realParam,
831                                const TyVarMap &tyVars ) {
[01aeade]832                        UniqueName paramNamer( "_p" );
833                        for ( ; param != paramEnd; ++param, ++arg, ++realParam ) {
834                                if ( (*param)->get_name() == "" ) {
835                                        (*param)->set_name( paramNamer.newName() );
836                                        (*param)->set_linkage( LinkageSpec::C );
837                                } // if
838                                adapteeApp->get_args().push_back( makeAdapterArg( *param, *arg, *realParam, tyVars ) );
839                        } // for
840                }
[6c3744e]841
[49db841]842                FunctionDecl *CallAdapter::makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {
[01aeade]843                        FunctionType *adapterType = makeAdapterType( adaptee, tyVars );
844                        adapterType = ScrubTyVars::scrub( adapterType, tyVars );
845                        DeclarationWithType *adapteeDecl = adapterType->get_parameters().front();
846                        adapteeDecl->set_name( "_adaptee" );
[1f370451]847                        // do not carry over attributes to real type parameters/return values
848                        for ( DeclarationWithType * dwt : realType->parameters ) {
849                                deleteAll( dwt->get_type()->attributes );
850                                dwt->get_type()->attributes.clear();
851                        }
852                        for ( DeclarationWithType * dwt : realType->returnVals ) {
853                                deleteAll( dwt->get_type()->attributes );
854                                dwt->get_type()->attributes.clear();
855                        }
[01aeade]856                        ApplicationExpr *adapteeApp = new ApplicationExpr( new CastExpr( new VariableExpr( adapteeDecl ), new PointerType( Type::Qualifiers(), realType ) ) );
857                        Statement *bodyStmt;
[ae63a18]858
[271a5d3]859                        for ( auto tys : group_iterate( realType->forall, adapterType->forall, adaptee->forall ) ) {
860                                TypeDecl * tyArg = std::get<0>( tys );
861                                TypeDecl * tyParam = std::get<1>( tys );
862                                TypeDecl * realTyParam = std::get<2>( tys );
863                                for ( auto asserts : group_iterate( tyArg->assertions, tyParam->assertions, realTyParam->assertions ) ) {
864                                        DeclarationWithType * assertArg = std::get<0>( asserts );
865                                        DeclarationWithType * assertParam = std::get<1>( asserts );
866                                        DeclarationWithType * realAssertParam = std::get<2>( asserts );
867                                        adapteeApp->args.push_back( makeAdapterArg( assertParam, assertArg, realAssertParam, tyVars ) );
[01aeade]868                                } // for
869                        } // for
[ae63a18]870
[4da152a]871                        std::list< DeclarationWithType *>::const_iterator arg = realType->parameters.begin();
872                        std::list< DeclarationWithType *>::const_iterator param = adapterType->parameters.begin();
873                        std::list< DeclarationWithType *>::const_iterator realParam = adaptee->parameters.begin();
[cc3528f]874                        param++;                // skip adaptee parameter in the adapter type
[01aeade]875                        if ( realType->get_returnVals().empty() ) {
[cc3528f]876                                // void return
[01aeade]877                                addAdapterParams( adapteeApp, arg, param, adapterType->get_parameters().end(), realParam, tyVars );
[ba3706f]878                                bodyStmt = new ExprStmt( adapteeApp );
[4da152a]879                        } else if ( isDynType( adaptee->returnVals.front()->get_type(), tyVars ) ) {
[cc3528f]880                                // return type T
[01aeade]881                                if ( (*param)->get_name() == "" ) {
882                                        (*param)->set_name( "_ret" );
883                                        (*param)->set_linkage( LinkageSpec::C );
884                                } // if
885                                UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) );
[c10ee66]886                                UntypedExpr *deref = UntypedExpr::createDeref( new CastExpr( new VariableExpr( *param++ ), new PointerType( Type::Qualifiers(), realType->get_returnVals().front()->get_type()->clone() ) ) );
[01aeade]887                                assign->get_args().push_back( deref );
888                                addAdapterParams( adapteeApp, arg, param, adapterType->get_parameters().end(), realParam, tyVars );
889                                assign->get_args().push_back( adapteeApp );
[ba3706f]890                                bodyStmt = new ExprStmt( assign );
[01aeade]891                        } else {
892                                // adapter for a function that returns a monomorphic value
893                                addAdapterParams( adapteeApp, arg, param, adapterType->get_parameters().end(), realParam, tyVars );
[ba3706f]894                                bodyStmt = new ReturnStmt( adapteeApp );
[01aeade]895                        } // if
[ba3706f]896                        CompoundStmt *adapterBody = new CompoundStmt();
[01aeade]897                        adapterBody->get_kids().push_back( bodyStmt );
898                        std::string adapterName = makeAdapterName( mangleName );
[68fe077a]899                        return new FunctionDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, adapterType, adapterBody );
[01aeade]900                }
[6c3744e]901
[49db841]902                void CallAdapter::passAdapters( ApplicationExpr * appExpr, FunctionType * functionType, const TyVarMap & exprTyVars ) {
[e497c1d]903                        // collect a list of function types passed as parameters or implicit parameters (assertions)
[4da152a]904                        std::list<FunctionType const *> functions;
[0b1ca47]905                        for ( TypeDecl * const tyVar : functionType->get_forall() ) {
906                                for ( DeclarationWithType * const assert : tyVar->get_assertions() ) {
907                                        findFunction( assert->get_type(), functions, exprTyVars, needsAdapter );
[01aeade]908                                } // for
909                        } // for
[0b1ca47]910                        for ( DeclarationWithType * const arg : functionType->get_parameters() ) {
911                                findFunction( arg->get_type(), functions, exprTyVars, needsAdapter );
[01aeade]912                        } // for
[e497c1d]913
[e56cfdb0]914                        // parameter function types for which an appropriate adapter has been generated.  we cannot use the types
915                        // after applying substitutions, since two different parameter types may be unified to the same type
[01aeade]916                        std::set< std::string > adaptersDone;
[e497c1d]917
[4da152a]918                        for ( FunctionType const * const funType : functions ) {
[9845cb6]919                                std::string mangleName = SymTab::Mangler::mangle( funType );
[e497c1d]920
[e56cfdb0]921                                // only attempt to create an adapter or pass one as a parameter if we haven't already done so for this
922                                // pre-substitution parameter function type.
[9f70a67b]923                                // The second part of the insert result is "is the value new".
[9845cb6]924                                if ( !adaptersDone.insert( mangleName ).second ) continue;
925
926                                // Apply substitution to type variables to figure out what the adapter's type should look like.
927                                assert( env );
928                                FunctionType *realType = funType->clone();
929                                env->apply( realType );
930                                mangleName = SymTab::Mangler::mangle( realType );
931                                mangleName += makePolyMonoSuffix( funType, exprTyVars );
932
933                                typedef ScopedMap< std::string, DeclarationWithType* >::iterator AdapterIter;
934                                AdapterIter adapter = adapters.find( mangleName );
935                                if ( adapter == adapters.end() ) {
936                                        // Adapter has not been created yet in the current scope, so define it.
937                                        FunctionDecl *newAdapter = makeAdapter( funType, realType, mangleName, exprTyVars );
938                                        std::pair< AdapterIter, bool > answer = adapters.insert( mangleName, newAdapter );
939                                        adapter = answer.first;
940                                        stmtsToAddBefore.push_back( new DeclStmt( newAdapter ) );
[01aeade]941                                } // if
[9845cb6]942                                assert( adapter != adapters.end() );
943
944                                // Add the appropriate adapter as a parameter.
945                                appExpr->args.push_front( new VariableExpr( adapter->second ) );
[01aeade]946                        } // for
[e56cfdb0]947                } // passAdapters
[6c3744e]948
[78dd0da]949                Expression *makeIncrDecrExpr( ApplicationExpr *appExpr, Type *polyType, bool isIncr ) {
[4da152a]950                        NameExpr *opExpr = new NameExpr( ( isIncr ) ? "?+=?" : "?-=?" );
[01aeade]951                        UntypedExpr *addAssign = new UntypedExpr( opExpr );
952                        if ( AddressExpr *address = dynamic_cast< AddressExpr *>( appExpr->get_args().front() ) ) {
953                                addAssign->get_args().push_back( address->get_arg() );
954                        } else {
955                                addAssign->get_args().push_back( appExpr->get_args().front() );
[6c3744e]956                        } // if
[adc6781]957                        addAssign->get_args().push_back( new NameExpr( sizeofName( mangleType( polyType ) ) ) );
[906e24d]958                        addAssign->set_result( appExpr->get_result()->clone() );
[01aeade]959                        if ( appExpr->get_env() ) {
960                                addAssign->set_env( appExpr->get_env() );
[6c3744e]961                                appExpr->set_env( 0 );
962                        } // if
[01aeade]963                        appExpr->get_args().clear();
964                        delete appExpr;
965                        return addAssign;
966                }
967
[49db841]968                Expression *CallAdapter::handleIntrinsics( ApplicationExpr *appExpr ) {
[20cba76]969                        if ( VariableExpr *varExpr = dynamic_cast< VariableExpr *>( appExpr->function ) ) {
970                                if ( varExpr->var->linkage == LinkageSpec::Intrinsic ) {
971                                        if ( varExpr->var->name == "?[?]" ) {
[d29fa5f]972                                                assert( appExpr->result );
[01aeade]973                                                assert( appExpr->get_args().size() == 2 );
[20cba76]974                                                Type *baseType1 = isPolyPtr( appExpr->args.front()->result, scopeTyVars, env );
975                                                Type *baseType2 = isPolyPtr( appExpr->args.back()->result, scopeTyVars, env );
[ae63a18]976                                                assert( ! baseType1 || ! baseType2 ); // the arguments cannot both be polymorphic pointers
[01aeade]977                                                UntypedExpr *ret = 0;
[ae63a18]978                                                if ( baseType1 || baseType2 ) { // one of the arguments is a polymorphic pointer
[01aeade]979                                                        ret = new UntypedExpr( new NameExpr( "?+?" ) );
980                                                } // if
[ffad73a]981                                                if ( baseType1 ) {
[01aeade]982                                                        UntypedExpr *multiply = new UntypedExpr( new NameExpr( "?*?" ) );
983                                                        multiply->get_args().push_back( appExpr->get_args().back() );
[adc6781]984                                                        multiply->get_args().push_back( new SizeofExpr( baseType1->clone() ) );
[01aeade]985                                                        ret->get_args().push_back( appExpr->get_args().front() );
986                                                        ret->get_args().push_back( multiply );
[ffad73a]987                                                } else if ( baseType2 ) {
[01aeade]988                                                        UntypedExpr *multiply = new UntypedExpr( new NameExpr( "?*?" ) );
989                                                        multiply->get_args().push_back( appExpr->get_args().front() );
[adc6781]990                                                        multiply->get_args().push_back( new SizeofExpr( baseType2->clone() ) );
[01aeade]991                                                        ret->get_args().push_back( multiply );
992                                                        ret->get_args().push_back( appExpr->get_args().back() );
993                                                } // if
[ffad73a]994                                                if ( baseType1 || baseType2 ) {
[83794e1]995                                                        delete ret->get_result();
996                                                        ret->set_result( appExpr->get_result()->clone() );
[01aeade]997                                                        if ( appExpr->get_env() ) {
998                                                                ret->set_env( appExpr->get_env() );
999                                                                appExpr->set_env( 0 );
1000                                                        } // if
1001                                                        appExpr->get_args().clear();
1002                                                        delete appExpr;
1003                                                        return ret;
1004                                                } // if
1005                                        } else if ( varExpr->get_var()->get_name() == "*?" ) {
[d29fa5f]1006                                                assert( appExpr->result );
[01aeade]1007                                                assert( ! appExpr->get_args().empty() );
[83794e1]1008                                                if ( isPolyType( appExpr->get_result(), scopeTyVars, env ) ) {
[0a81c3f]1009                                                        // remove dereference from polymorphic types since they are boxed.
[01aeade]1010                                                        Expression *ret = appExpr->get_args().front();
[83794e1]1011                                                        // fix expr type to remove pointer
[906e24d]1012                                                        delete ret->get_result();
[83794e1]1013                                                        ret->set_result( appExpr->get_result()->clone() );
[01aeade]1014                                                        if ( appExpr->get_env() ) {
1015                                                                ret->set_env( appExpr->get_env() );
1016                                                                appExpr->set_env( 0 );
1017                                                        } // if
1018                                                        appExpr->get_args().clear();
1019                                                        delete appExpr;
1020                                                        return ret;
1021                                                } // if
1022                                        } else if ( varExpr->get_var()->get_name() == "?++" || varExpr->get_var()->get_name() == "?--" ) {
[d29fa5f]1023                                                assert( appExpr->result );
[01aeade]1024                                                assert( appExpr->get_args().size() == 1 );
[906e24d]1025                                                if ( Type *baseType = isPolyPtr( appExpr->get_result(), scopeTyVars, env ) ) {
1026                                                        Type *tempType = appExpr->get_result()->clone();
[01aeade]1027                                                        if ( env ) {
1028                                                                env->apply( tempType );
1029                                                        } // if
1030                                                        ObjectDecl *newObj = makeTemporary( tempType );
1031                                                        VariableExpr *tempExpr = new VariableExpr( newObj );
1032                                                        UntypedExpr *assignExpr = new UntypedExpr( new NameExpr( "?=?" ) );
1033                                                        assignExpr->get_args().push_back( tempExpr->clone() );
1034                                                        if ( AddressExpr *address = dynamic_cast< AddressExpr *>( appExpr->get_args().front() ) ) {
1035                                                                assignExpr->get_args().push_back( address->get_arg()->clone() );
1036                                                        } else {
1037                                                                assignExpr->get_args().push_back( appExpr->get_args().front()->clone() );
1038                                                        } // if
[ffad73a]1039                                                        CommaExpr *firstComma = new CommaExpr( assignExpr, makeIncrDecrExpr( appExpr, baseType, varExpr->get_var()->get_name() == "?++" ) );
[01aeade]1040                                                        return new CommaExpr( firstComma, tempExpr );
1041                                                } // if
1042                                        } else if ( varExpr->get_var()->get_name() == "++?" || varExpr->get_var()->get_name() == "--?" ) {
[d29fa5f]1043                                                assert( appExpr->result );
[01aeade]1044                                                assert( appExpr->get_args().size() == 1 );
[906e24d]1045                                                if ( Type *baseType = isPolyPtr( appExpr->get_result(), scopeTyVars, env ) ) {
[ffad73a]1046                                                        return makeIncrDecrExpr( appExpr, baseType, varExpr->get_var()->get_name() == "++?" );
[01aeade]1047                                                } // if
1048                                        } else if ( varExpr->get_var()->get_name() == "?+?" || varExpr->get_var()->get_name() == "?-?" ) {
[d29fa5f]1049                                                assert( appExpr->result );
[01aeade]1050                                                assert( appExpr->get_args().size() == 2 );
[906e24d]1051                                                Type *baseType1 = isPolyPtr( appExpr->get_args().front()->get_result(), scopeTyVars, env );
1052                                                Type *baseType2 = isPolyPtr( appExpr->get_args().back()->get_result(), scopeTyVars, env );
[ffad73a]1053                                                if ( baseType1 && baseType2 ) {
[01aeade]1054                                                        UntypedExpr *divide = new UntypedExpr( new NameExpr( "?/?" ) );
1055                                                        divide->get_args().push_back( appExpr );
[adc6781]1056                                                        divide->get_args().push_back( new SizeofExpr( baseType1->clone() ) );
[906e24d]1057                                                        divide->set_result( appExpr->get_result()->clone() );
[01aeade]1058                                                        if ( appExpr->get_env() ) {
1059                                                                divide->set_env( appExpr->get_env() );
1060                                                                appExpr->set_env( 0 );
1061                                                        } // if
1062                                                        return divide;
[ffad73a]1063                                                } else if ( baseType1 ) {
[01aeade]1064                                                        UntypedExpr *multiply = new UntypedExpr( new NameExpr( "?*?" ) );
1065                                                        multiply->get_args().push_back( appExpr->get_args().back() );
[adc6781]1066                                                        multiply->get_args().push_back( new SizeofExpr( baseType1->clone() ) );
[01aeade]1067                                                        appExpr->get_args().back() = multiply;
[ffad73a]1068                                                } else if ( baseType2 ) {
[01aeade]1069                                                        UntypedExpr *multiply = new UntypedExpr( new NameExpr( "?*?" ) );
1070                                                        multiply->get_args().push_back( appExpr->get_args().front() );
[adc6781]1071                                                        multiply->get_args().push_back( new SizeofExpr( baseType2->clone() ) );
[01aeade]1072                                                        appExpr->get_args().front() = multiply;
1073                                                } // if
1074                                        } else if ( varExpr->get_var()->get_name() == "?+=?" || varExpr->get_var()->get_name() == "?-=?" ) {
[d29fa5f]1075                                                assert( appExpr->result );
[01aeade]1076                                                assert( appExpr->get_args().size() == 2 );
[906e24d]1077                                                Type *baseType = isPolyPtr( appExpr->get_result(), scopeTyVars, env );
[ffad73a]1078                                                if ( baseType ) {
[01aeade]1079                                                        UntypedExpr *multiply = new UntypedExpr( new NameExpr( "?*?" ) );
1080                                                        multiply->get_args().push_back( appExpr->get_args().back() );
[adc6781]1081                                                        multiply->get_args().push_back( new SizeofExpr( baseType->clone() ) );
[01aeade]1082                                                        appExpr->get_args().back() = multiply;
1083                                                } // if
1084                                        } // if
1085                                        return appExpr;
1086                                } // if
[6c3744e]1087                        } // if
[01aeade]1088                        return 0;
1089                }
[6c3744e]1090
[49db841]1091                Expression *CallAdapter::postmutate( ApplicationExpr *appExpr ) {
[2a7b3ca]1092                        // std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl;
[271a5d3]1093                        // for ( auto tyVar : scopeTyVars ) {
1094                        //      std::cerr << tyVar.first << " ";
[e56cfdb0]1095                        // }
1096                        // std::cerr << "\n";
[ae63a18]1097
[201182a]1098                        assert( appExpr->function->result );
1099                        FunctionType * function = getFunctionType( appExpr->function->result );
1100                        assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() );
[ae63a18]1101
[01aeade]1102                        if ( Expression *newExpr = handleIntrinsics( appExpr ) ) {
1103                                return newExpr;
1104                        } // if
[ae63a18]1105
[01aeade]1106                        Expression *ret = appExpr;
[9f70a67b]1107                        // Save iterator to the first original parameter (works with lists).
[01aeade]1108                        std::list< Expression *>::iterator paramBegin = appExpr->get_args().begin();
[ae63a18]1109
[2c57025]1110                        TyVarMap exprTyVars( TypeDecl::Data{} );
[5802a4f]1111                        makeTyVarMap( function, exprTyVars ); // xxx - should this take into account the variables already bound in scopeTyVars (i.e. remove them from exprTyVars?)
[3bb195cb]1112                        ReferenceToType *dynRetType = isDynRet( function, exprTyVars );
[5c52b06]1113
[2a7b3ca]1114                        // std::cerr << function << std::endl;
1115                        // std::cerr << "scopeTyVars: ";
1116                        // printTyVarMap( std::cerr, scopeTyVars );
1117                        // std::cerr << "exprTyVars: ";
1118                        // printTyVarMap( std::cerr, exprTyVars );
1119                        // std::cerr << "env: " << *env << std::endl;
1120                        // std::cerr << needsAdapter( function, scopeTyVars ) << ! needsAdapter( function, exprTyVars) << std::endl;
1121
[b940dc71]1122                        // NOTE: addDynRetParam needs to know the actual (generated) return type so it can make a temp variable, so pass the result type from the appExpr
1123                        // passTypeVars needs to know the program-text return type (i.e. the distinction between _conc_T30 and T3(int))
1124                        // concRetType may not be a good name in one or both of these places. A more appropriate name change is welcome.
[3bb195cb]1125                        if ( dynRetType ) {
[2a7b3ca]1126                                // std::cerr << "dynRetType: " << dynRetType << std::endl;
[b940dc71]1127                                Type *concRetType = appExpr->get_result()->isVoid() ? nullptr : appExpr->get_result();
[a805100]1128                                ret = addDynRetParam( appExpr, concRetType ); // xxx - used to use dynRetType instead of concRetType
[5802a4f]1129                        } else if ( needsAdapter( function, scopeTyVars ) && ! needsAdapter( function, exprTyVars) ) { // xxx - exprTyVars is used above...?
1130                                // xxx - the ! needsAdapter check may be incorrect. It seems there is some situation where an adapter is applied where it shouldn't be, and this fixes it for some cases. More investigation is needed.
1131
[e56cfdb0]1132                                // std::cerr << "needs adapter: ";
[2e3a379]1133                                // printTyVarMap( std::cerr, scopeTyVars );
1134                                // std::cerr << *env << std::endl;
[01aeade]1135                                // change the application so it calls the adapter rather than the passed function
[a805100]1136                                ret = applyAdapter( appExpr, function );
[01aeade]1137                        } // if
[ae63a18]1138
[f6aa89c]1139                        Type *concRetType = replaceWithConcrete( dynRetType, env );
[a805100]1140                        std::list< Expression *>::iterator arg =
1141                                passTypeVars( appExpr, concRetType, exprTyVars ); // xxx - used to use dynRetType instead of concRetType; this changed so that the correct type paramaters are passed for return types (it should be the concrete type's parameters, not the formal type's)
[7ed7b4a]1142                        addInferredParams( appExpr, arg, function, exprTyVars );
[51b7345]1143
[a805100]1144                        // This needs to point at the original first argument.
1145                        boxParams( appExpr, paramBegin, function, exprTyVars );
[ae63a18]1146
[01aeade]1147                        passAdapters( appExpr, function, exprTyVars );
[6c3744e]1148
[01aeade]1149                        return ret;
1150                }
[6c3744e]1151
[4da152a]1152                bool isPolyDeref( UntypedExpr const * expr, TyVarMap const & scopeTyVars, TypeSubstitution const * env ) {
[201182a]1153                        if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
[4da152a]1154                                if ( auto name = dynamic_cast<NameExpr const *>( expr->function ) ) {
[2097cd4]1155                                        if ( name->name == "*?" ) {
[b3212de]1156                                                return true;
[01aeade]1157                                        } // if
1158                                } // if
1159                        } // if
[b3212de]1160                        return false;
1161                }
1162
[49db841]1163                Expression * CallAdapter::postmutate( UntypedExpr *expr ) {
[b3212de]1164                        if ( isPolyDeref( expr, scopeTyVars, env ) ) {
1165                                Expression *ret = expr->args.front();
1166                                expr->args.clear();
1167                                delete expr;
1168                                return ret;
1169                        }
[201182a]1170                        return expr;
[01aeade]1171                }
[6c3744e]1172
[49db841]1173                void CallAdapter::premutate( AddressExpr * ) { visit_children = false; }
[9f70a67b]1174
[49db841]1175                Expression * CallAdapter::postmutate( AddressExpr * addrExpr ) {
[2097cd4]1176                        assert( addrExpr->arg->result && ! addrExpr->arg->result->isVoid() );
[cf16f94]1177
1178                        bool needs = false;
[2097cd4]1179                        if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->arg ) ) {
[b3212de]1180                                if ( isPolyDeref( expr, scopeTyVars, env ) ) {
1181                                        if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->args.front() ) ) {
1182                                                assert( appExpr->function->result );
1183                                                FunctionType *function = getFunctionType( appExpr->function->result );
1184                                                assert( function );
1185                                                needs = needsAdapter( function, scopeTyVars );
[cf16f94]1186                                        } // if
1187                                } // if
1188                        } // if
[fea7ca7]1189                        // isPolyType check needs to happen before mutating addrExpr arg, so pull it forward
1190                        // out of the if condition.
[2097cd4]1191                        addrExpr->arg = addrExpr->arg->acceptMutator( *visitor );
[d335627]1192                        // ... but must happen after mutate, since argument might change (e.g. intrinsic *?, ?[?]) - re-evaluate above comment
[2097cd4]1193                        bool polytype = isPolyType( addrExpr->arg->result, scopeTyVars, env );
[fea7ca7]1194                        if ( polytype || needs ) {
[2097cd4]1195                                Expression *ret = addrExpr->arg;
1196                                delete ret->result;
1197                                ret->result = addrExpr->result->clone();
1198                                addrExpr->arg = nullptr;
[01aeade]1199                                delete addrExpr;
1200                                return ret;
1201                        } else {
1202                                return addrExpr;
1203                        } // if
1204                }
[6c3744e]1205
[49db841]1206                void CallAdapter::premutate( ReturnStmt *returnStmt ) {
[201182a]1207                        if ( retval && returnStmt->expr ) {
1208                                assert( returnStmt->expr->result && ! returnStmt->expr->result->isVoid() );
1209                                delete returnStmt->expr;
1210                                returnStmt->expr = nullptr;
[01aeade]1211                        } // if
1212                }
[6c3744e]1213
[49db841]1214                void CallAdapter::premutate( PointerType *pointerType ) {
[201182a]1215                        GuardScope( scopeTyVars );
[01aeade]1216                        makeTyVarMap( pointerType, scopeTyVars );
1217                }
[6c3744e]1218
[49db841]1219                void CallAdapter::premutate( FunctionType *functionType ) {
[201182a]1220                        GuardScope( scopeTyVars );
[01aeade]1221                        makeTyVarMap( functionType, scopeTyVars );
1222                }
[51b7345]1223
[49db841]1224                void CallAdapter::beginScope() {
[6635c74]1225                        adapters.beginScope();
[01aeade]1226                }
[b1a6d6b]1227
[49db841]1228                void CallAdapter::endScope() {
[6635c74]1229                        adapters.endScope();
[01aeade]1230                }
[51b7345]1231
[49db841]1232////////////////////////////////////////// DeclAdapter //////////////////////////////////////////
[51b7345]1233
[49db841]1234                void DeclAdapter::addAdapters( FunctionType *functionType ) {
[4da152a]1235                        std::list< FunctionType const *> functions;
[994028dc]1236                        for ( DeclarationWithType * const arg : functionType->parameters ) {
[0b1ca47]1237                                Type *orig = arg->get_type();
[01aeade]1238                                findAndReplaceFunction( orig, functions, scopeTyVars, needsAdapter );
[0b1ca47]1239                                arg->set_type( orig );
[01aeade]1240                        }
1241                        std::set< std::string > adaptersDone;
[4da152a]1242                        for ( FunctionType const * const funType : functions ) {
[0b1ca47]1243                                std::string mangleName = mangleAdapterName( funType, scopeTyVars );
[01aeade]1244                                if ( adaptersDone.find( mangleName ) == adaptersDone.end() ) {
1245                                        std::string adapterName = makeAdapterName( mangleName );
[83794e1]1246                                        // adapter may not be used in body, pass along with unused attribute.
[9f70a67b]1247                                        functionType->parameters.push_front(
1248                                                new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), 0, { new Attribute( "unused" ) } ) );
[01aeade]1249                                        adaptersDone.insert( adaptersDone.begin(), mangleName );
1250                                }
1251                        }
1252                }
[6c3744e]1253
[49db841]1254                DeclarationWithType * DeclAdapter::postmutate( FunctionDecl *functionDecl ) {
[2097cd4]1255                        FunctionType * ftype = functionDecl->type;
1256                        if ( ! ftype->returnVals.empty() && functionDecl->statements ) {
[3322180]1257                                // intrinsic functions won't be using the _retval so no need to generate it.
1258                                if ( functionDecl->linkage != LinkageSpec::Intrinsic && !isPrefix( functionDecl->name, "_thunk" ) && ! isPrefix( functionDecl->name, "_adapter" ) ) { // xxx - remove check for prefix once thunks properly use ctor/dtors
[2097cd4]1259                                        assert( ftype->returnVals.size() == 1 );
1260                                        DeclarationWithType * retval = ftype->returnVals.front();
1261                                        if ( retval->name == "" ) {
1262                                                retval->name = "_retval";
[cce9429]1263                                        }
[2097cd4]1264                                        functionDecl->statements->kids.push_front( new DeclStmt( retval ) );
[cce9429]1265                                        DeclarationWithType * newRet = retval->clone(); // for ownership purposes
[2097cd4]1266                                        ftype->returnVals.front() = newRet;
[cce9429]1267                                }
1268                        }
[064cb18]1269                        // errors should have been caught by this point, remove initializers from parameters to allow correct codegen of default arguments
[2097cd4]1270                        for ( Declaration * param : functionDecl->type->parameters ) {
[064cb18]1271                                if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( param ) ) {
[2097cd4]1272                                        delete obj->init;
1273                                        obj->init = nullptr;
[064cb18]1274                                }
1275                        }
[cce9429]1276                        return functionDecl;
[01aeade]1277                }
[6c3744e]1278
[49db841]1279                void DeclAdapter::premutate( StructDecl * ) {
[dd0c97b]1280                        // prevent tyVars from leaking into containing scope
[a31b384]1281                        GuardScope( scopeTyVars );
[dd0c97b]1282                }
1283
[49db841]1284                void DeclAdapter::premutate( UnionDecl * ) {
[a31b384]1285                        // prevent tyVars from leaking into containing scope
1286                        GuardScope( scopeTyVars );
[dd0c97b]1287                }
1288
[49db841]1289                void DeclAdapter::premutate( TraitDecl * ) {
[a31b384]1290                        // prevent tyVars from leaking into containing scope
1291                        GuardScope( scopeTyVars );
[9b18044]1292                }
1293
[49db841]1294                void DeclAdapter::premutate( TypeDecl *typeDecl ) {
[2c57025]1295                        addToTyVarMap( typeDecl, scopeTyVars );
[01aeade]1296                }
[6c3744e]1297
[49db841]1298                void DeclAdapter::premutate( PointerType *pointerType ) {
[a31b384]1299                        GuardScope( scopeTyVars );
[01aeade]1300                        makeTyVarMap( pointerType, scopeTyVars );
1301                }
[6c3744e]1302
[49db841]1303                void DeclAdapter::premutate( FunctionType *funcType ) {
[a31b384]1304                        GuardScope( scopeTyVars );
[01aeade]1305                        makeTyVarMap( funcType, scopeTyVars );
[7754cde]1306
1307                        // move polymorphic return type to parameter list
[3bb195cb]1308                        if ( isDynRet( funcType ) ) {
[e3e16bc]1309                                ObjectDecl *ret = strict_dynamic_cast< ObjectDecl* >( funcType->get_returnVals().front() );
[01aeade]1310                                ret->set_type( new PointerType( Type::Qualifiers(), ret->get_type() ) );
1311                                funcType->get_parameters().push_front( ret );
1312                                funcType->get_returnVals().pop_front();
[d9fa60a]1313                                ret->set_init( nullptr ); // xxx - memory leak?
[01aeade]1314                        }
[7754cde]1315
1316                        // add size/align and assertions for type parameters to parameter list
[01aeade]1317                        std::list< DeclarationWithType *>::iterator last = funcType->get_parameters().begin();
1318                        std::list< DeclarationWithType *> inferredParams;
[83794e1]1319                        // size/align/offset parameters may not be used in body, pass along with unused attribute.
1320                        ObjectDecl newObj( "", Type::StorageClasses(), LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), 0,
1321                                           { new Attribute( "unused" ) } );
[68fe077a]1322                        ObjectDecl newPtr( "", Type::StorageClasses(), LinkageSpec::C, 0,
[05d47278]1323                                           new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 );
[0b1ca47]1324                        for ( TypeDecl * const tyParam : funcType->get_forall() ) {
[db0b3ce]1325                                ObjectDecl *sizeParm, *alignParm;
1326                                // add all size and alignment parameters to parameter list
[0b1ca47]1327                                if ( tyParam->isComplete() ) {
1328                                        TypeInstType parmType( Type::Qualifiers(), tyParam->get_name(), tyParam );
[adc6781]1329                                        std::string parmName = mangleType( &parmType );
[ae63a18]1330
[78dd0da]1331                                        sizeParm = newObj.clone();
[adc6781]1332                                        sizeParm->set_name( sizeofName( parmName ) );
[db0b3ce]1333                                        last = funcType->get_parameters().insert( last, sizeParm );
1334                                        ++last;
[78dd0da]1335
1336                                        alignParm = newObj.clone();
[adc6781]1337                                        alignParm->set_name( alignofName( parmName ) );
[db0b3ce]1338                                        last = funcType->get_parameters().insert( last, alignParm );
[01aeade]1339                                        ++last;
1340                                }
[e56cfdb0]1341                                // move all assertions into parameter list
[0b1ca47]1342                                for ( DeclarationWithType * const assert : tyParam->get_assertions() ) {
[83794e1]1343                                        // assertion parameters may not be used in body, pass along with unused attribute.
[0b1ca47]1344                                        assert->get_attributes().push_back( new Attribute( "unused" ) );
1345                                        inferredParams.push_back( assert );
[01aeade]1346                                }
[0b1ca47]1347                                tyParam->get_assertions().clear();
[01aeade]1348                        }
[7754cde]1349
[5c52b06]1350                        // add size/align for generic parameter types to parameter list
[b18b0b5]1351                        std::set< std::string > seenTypes; // sizeofName for generic types we've seen
[0b1ca47]1352                        for ( DeclarationWithType * const fnParam : funcType->get_parameters() ) {
1353                                Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars );
[4b8f918]1354                                if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) {
1355                                        std::string typeName = mangleType( polyType );
[adc6781]1356                                        if ( seenTypes.count( typeName ) ) continue;
[ae63a18]1357
[05d47278]1358                                        ObjectDecl *sizeParm, *alignParm, *offsetParm;
[7754cde]1359                                        sizeParm = newObj.clone();
[adc6781]1360                                        sizeParm->set_name( sizeofName( typeName ) );
[7754cde]1361                                        last = funcType->get_parameters().insert( last, sizeParm );
1362                                        ++last;
1363
1364                                        alignParm = newObj.clone();
[adc6781]1365                                        alignParm->set_name( alignofName( typeName ) );
[7754cde]1366                                        last = funcType->get_parameters().insert( last, alignParm );
1367                                        ++last;
1368
[4b8f918]1369                                        if ( StructInstType *polyBaseStruct = dynamic_cast< StructInstType* >( polyType ) ) {
[89173242]1370                                                // NOTE zero-length arrays are illegal in C, so empty structs have no offset array
1371                                                if ( ! polyBaseStruct->get_baseStruct()->get_members().empty() ) {
1372                                                        offsetParm = newPtr.clone();
[adc6781]1373                                                        offsetParm->set_name( offsetofName( typeName ) );
[89173242]1374                                                        last = funcType->get_parameters().insert( last, offsetParm );
1375                                                        ++last;
1376                                                }
[05d47278]1377                                        }
[adc6781]1378                                        seenTypes.insert( typeName );
[7754cde]1379                                }
1380                        }
1381
1382                        // splice assertion parameters into parameter list
[01aeade]1383                        funcType->get_parameters().splice( last, inferredParams );
1384                        addAdapters( funcType );
1385                }
[51b7345]1386
[49db841]1387////////////////////////////////////////// PolyGenericCalculator ////////////////////////////////
[51b7345]1388
[a0ad7dc]1389                PolyGenericCalculator::PolyGenericCalculator()
[201182a]1390                        : knownLayouts(), knownOffsets(), bufNamer( "_buf" ) {}
[a0ad7dc]1391
[aa19ccf]1392                void PolyGenericCalculator::beginTypeScope( Type *ty ) {
[a0c7dc36]1393                        GuardScope( scopeTyVars );
[aa19ccf]1394                        makeTyVarMap( ty, scopeTyVars );
1395                }
1396
[a0c7dc36]1397                void PolyGenericCalculator::beginGenericScope() {
1398                        GuardScope( *this );
[18070ee]1399                        // We expect the first function type see to be the type relating to this scope
1400                        // but any further type is probably some unrelated function pointer
1401                        // keep track of which is the first
1402                        GuardValue( expect_func_type );
1403                        expect_func_type = true;
[01aeade]1404                }
[6c3744e]1405
[a0c7dc36]1406                void PolyGenericCalculator::premutate( ObjectDecl *objectDecl ) {
1407                        beginTypeScope( objectDecl->get_type() );
[01aeade]1408                }
[6c3744e]1409
[a0c7dc36]1410                void PolyGenericCalculator::premutate( FunctionDecl *functionDecl ) {
1411                        beginGenericScope();
[1ba88a0]1412
[a0c7dc36]1413                        beginTypeScope( functionDecl->get_functionType() );
[01aeade]1414                }
[6c3744e]1415
[a0c7dc36]1416                void PolyGenericCalculator::premutate( TypedefDecl *typedefDecl ) {
[8dceeb7]1417                        assert(false);
[a0c7dc36]1418                        beginTypeScope( typedefDecl->get_base() );
[01aeade]1419                }
[6c3744e]1420
[a0c7dc36]1421                void PolyGenericCalculator::premutate( TypeDecl * typeDecl ) {
[2c57025]1422                        addToTyVarMap( typeDecl, scopeTyVars );
[01aeade]1423                }
[51b7345]1424
[a0c7dc36]1425                Declaration * PolyGenericCalculator::postmutate( TypeDecl *typeDecl ) {
1426                        if ( Type * base = typeDecl->base ) {
1427                                // add size/align variables for opaque type declarations
1428                                TypeInstType inst( Type::Qualifiers(), typeDecl->name, typeDecl );
1429                                std::string typeName = mangleType( &inst );
1430                                Type *layoutType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
[ae63a18]1431
[a0c7dc36]1432                                ObjectDecl * sizeDecl = ObjectDecl::newObject( sizeofName( typeName ), layoutType, new SingleInit( new SizeofExpr( base->clone() ) ) );
1433                                ObjectDecl * alignDecl = ObjectDecl::newObject( alignofName( typeName ), layoutType->clone(), new SingleInit( new AlignofExpr( base->clone() ) ) );
[ae63a18]1434
[a0c7dc36]1435                                // ensure that the initializing sizeof/alignof exprs are properly mutated
1436                                sizeDecl->acceptMutator( *visitor );
1437                                alignDecl->acceptMutator( *visitor );
1438
1439                                // can't use makeVar, because it inserts into stmtsToAdd and TypeDecls can occur at global scope
1440                                declsToAddAfter.push_back( alignDecl );
1441                                // replace with sizeDecl
1442                                return sizeDecl;
1443                        }
1444                        return typeDecl;
1445                }
1446
1447                void PolyGenericCalculator::premutate( PointerType *pointerType ) {
1448                        beginTypeScope( pointerType );
[01aeade]1449                }
[6c3744e]1450
[a0c7dc36]1451                void PolyGenericCalculator::premutate( FunctionType *funcType ) {
[aa19ccf]1452                        beginTypeScope( funcType );
[ae63a18]1453
[18070ee]1454                        GuardValue( expect_func_type );
1455
1456                        if(!expect_func_type) {
1457                                // If this is the first function type we see
1458                                // Then it's the type of the declaration and we care about it
[b3212de]1459                                GuardScope( *this );
[18070ee]1460                        }
1461
1462                        // The other functions type we will see in this scope are probably functions parameters
1463                        // they don't help us with the layout and offsets so don't mark them as known in this scope
1464                        expect_func_type = false;
1465
[8a34677]1466                        // make sure that any type information passed into the function is accounted for
[0b1ca47]1467                        for ( DeclarationWithType * const fnParam : funcType->get_parameters() ) {
[49db841]1468                                // condition here duplicates that in DeclAdapter::mutate( FunctionType* )
[0b1ca47]1469                                Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars );
[4b8f918]1470                                if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) {
1471                                        knownLayouts.insert( mangleType( polyType ) );
[8a34677]1472                                }
1473                        }
[6c3744e]1474                }
[51b7345]1475
[8dceeb7]1476                /// converts polymorphic type T into a suitable monomorphic representation, currently: __attribute__((aligned(8)) char[size_T]
[4da152a]1477                Type * polyToMonoType( Type const * declType ) {
[8dceeb7]1478                        Type * charType = new BasicType( Type::Qualifiers(), BasicType::Kind::Char);
1479                        Expression * size = new NameExpr( sizeofName( mangleType(declType) ) );
1480                        Attribute * aligned = new Attribute( "aligned", std::list<Expression*>{ new ConstantExpr( Constant::from_int(8) ) } );
1481                        return new ArrayType( Type::Qualifiers(), charType, size,
1482                                true, false, std::list<Attribute *>{ aligned } );
1483                }
1484
1485                void PolyGenericCalculator::mutateMembers( AggregateDecl * aggrDecl ) {
1486                        std::set< std::string > genericParams;
1487                        for ( TypeDecl * td : aggrDecl->parameters ) {
1488                                genericParams.insert( td->name );
1489                        }
1490                        for ( Declaration * decl : aggrDecl->members ) {
1491                                if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( decl ) ) {
1492                                        Type * ty = replaceTypeInst( field->type, env );
1493                                        if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( ty ) ) {
1494                                                // do not try to monomorphize generic parameters
[e9b5043]1495                                                if ( scopeTyVars.contains( typeInst->get_name() ) && ! genericParams.count( typeInst->name ) ) {
[8dceeb7]1496                                                        // polymorphic aggregate members should be converted into monomorphic members.
1497                                                        // Using char[size_T] here respects the expected sizing rules of an aggregate type.
1498                                                        Type * newType = polyToMonoType( field->type );
1499                                                        delete field->type;
1500                                                        field->type = newType;
1501                                                }
1502                                        }
1503                                }
1504                        }
1505                }
1506
1507                void PolyGenericCalculator::premutate( StructDecl * structDecl ) {
1508                        mutateMembers( structDecl );
1509                }
1510
1511                void PolyGenericCalculator::premutate( UnionDecl * unionDecl ) {
1512                        mutateMembers( unionDecl );
1513                }
1514
[a0c7dc36]1515                void PolyGenericCalculator::premutate( DeclStmt *declStmt ) {
[01aeade]1516                        if ( ObjectDecl *objectDecl = dynamic_cast< ObjectDecl *>( declStmt->get_decl() ) ) {
[8a34677]1517                                if ( findGeneric( objectDecl->get_type() ) ) {
[a0ad7dc]1518                                        // change initialization of a polymorphic value object to allocate via a VLA
1519                                        // (alloca was previously used, but can't be safely used in loops)
[8dceeb7]1520                                        ObjectDecl *newBuf = ObjectDecl::newObject( bufNamer.newName(), polyToMonoType( objectDecl->type ), nullptr );
[ba3706f]1521                                        stmtsToAddBefore.push_back( new DeclStmt( newBuf ) );
[e01559c]1522
[6312b1c]1523                                        // if the object has a cleanup attribute, the cleanup should be on the buffer, not the pointer
1524                                        auto matchAndMove = [newBuf](Attribute * attr){
1525                                                if(attr->name == "cleanup") {
1526                                                        newBuf->attributes.push_back(attr);
1527                                                        return true;
1528                                                }
1529                                                return false;
1530                                        };
1531
1532                                        objectDecl->attributes.remove_if(matchAndMove);
1533
[e01559c]1534                                        delete objectDecl->get_init();
[cccc534]1535                                        objectDecl->set_init( new SingleInit( new VariableExpr( newBuf ) ) );
[01aeade]1536                                }
1537                        }
1538                }
[05d47278]1539
[2a4b088]1540                /// Finds the member in the base list that matches the given declaration; returns its index, or -1 if not present
1541                long findMember( DeclarationWithType *memberDecl, std::list< Declaration* > &baseDecls ) {
[0b1ca47]1542                        for ( auto pair : enumerate( baseDecls ) ) {
1543                                Declaration * decl = pair.val;
1544                                size_t i = pair.idx;
1545                                if ( memberDecl->get_name() != decl->get_name() )
[801978b]1546                                        continue;
1547
1548                                if ( memberDecl->get_name().empty() ) {
1549                                        // plan-9 field: match on unique_id
[0b1ca47]1550                                        if ( memberDecl->get_uniqueId() == decl->get_uniqueId() )
[801978b]1551                                                return i;
1552                                        else
1553                                                continue;
1554                                }
1555
[0b1ca47]1556                                DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( decl );
[801978b]1557
1558                                if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) {
1559                                        // tuple-element field: expect neither had mangled name; accept match on simple name (like field_2) only
1560                                        assert( memberDecl->get_mangleName().empty() && declWithType->get_mangleName().empty() );
1561                                        return i;
1562                                }
[2a4b088]1563
[801978b]1564                                // ordinary field: use full name to accommodate overloading
1565                                if ( memberDecl->get_mangleName() == declWithType->get_mangleName() )
1566                                        return i;
1567                                else
1568                                        continue;
[2a4b088]1569                        }
1570                        return -1;
1571                }
1572
1573                /// Returns an index expression into the offset array for a type
[4da152a]1574                Expression *makeOffsetIndex( Type const *objectType, long i ) {
[d56e5bc]1575                        ConstantExpr *fieldIndex = new ConstantExpr( Constant::from_ulong( i ) );
[2a4b088]1576                        UntypedExpr *fieldOffset = new UntypedExpr( new NameExpr( "?[?]" ) );
[adc6781]1577                        fieldOffset->get_args().push_back( new NameExpr( offsetofName( mangleType( objectType ) ) ) );
[2a4b088]1578                        fieldOffset->get_args().push_back( fieldIndex );
1579                        return fieldOffset;
1580                }
1581
[a0c7dc36]1582                Expression *PolyGenericCalculator::postmutate( MemberExpr *memberExpr ) {
[05d47278]1583                        // only mutate member expressions for polymorphic types
[8488c715]1584                        int tyDepth;
[20cba76]1585                        Type *objectType = hasPolyBase( memberExpr->aggregate->result, scopeTyVars, &tyDepth );
[05d47278]1586                        if ( ! objectType ) return memberExpr;
[8a34677]1587                        findGeneric( objectType ); // ensure layout for this type is available
[05d47278]1588
[ea5daeb]1589                        // replace member expression with dynamically-computed layout expression
[20cba76]1590                        Expression *newMemberExpr = nullptr;
[05d47278]1591                        if ( StructInstType *structType = dynamic_cast< StructInstType* >( objectType ) ) {
[2a4b088]1592                                // look up offset index
[20cba76]1593                                long i = findMember( memberExpr->member, structType->baseStruct->members );
[2a4b088]1594                                if ( i == -1 ) return memberExpr;
[05d47278]1595
[2a4b088]1596                                // replace member expression with pointer to base plus offset
1597                                UntypedExpr *fieldLoc = new UntypedExpr( new NameExpr( "?+?" ) );
[20cba76]1598                                Expression * aggr = memberExpr->aggregate->clone();
1599                                delete aggr->env; // xxx - there's a problem with keeping the env for some reason, so for now just get rid of it
1600                                aggr->env = nullptr;
[5802a4f]1601                                fieldLoc->get_args().push_back( aggr );
[2a4b088]1602                                fieldLoc->get_args().push_back( makeOffsetIndex( objectType, i ) );
[20cba76]1603                                fieldLoc->set_result( memberExpr->result->clone() );
[4318107]1604                                newMemberExpr = fieldLoc;
[98735ef]1605                        } else if ( dynamic_cast< UnionInstType* >( objectType ) ) {
[c10ee66]1606                                // union members are all at offset zero, so just use the aggregate expr
[20cba76]1607                                Expression * aggr = memberExpr->aggregate->clone();
1608                                delete aggr->env; // xxx - there's a problem with keeping the env for some reason, so for now just get rid of it
1609                                aggr->env= nullptr;
[c10ee66]1610                                newMemberExpr = aggr;
[20cba76]1611                                newMemberExpr->result = memberExpr->result->clone();
[2a4b088]1612                        } else return memberExpr;
[4318107]1613                        assert( newMemberExpr );
1614
[661214c]1615                        // Must apply the generic substitution to the member type to handle cases where the member is a generic parameter substituted by a known concrete type, e.g.
1616                        //   forall(otype T) struct Box { T x; }
1617                        //   forall(otype T) f() {
1618                        //     Box(T *) b; b.x;
1619                        //   }
1620                        // TODO: memberExpr->result should be exactly memberExpr->member->get_type() after substitution, so it doesn't seem like it should be necessary to apply the substitution manually. For some reason this is not currently the case. This requires more investigation.
1621                        Type *memberType = memberExpr->member->get_type()->clone();
1622                        TypeSubstitution sub = objectType->genericSubstitution();
1623                        sub.apply( memberType );
[4067aa8]1624                        if ( ! isPolyType( memberType, scopeTyVars ) ) {
1625                                // Not all members of a polymorphic type are themselves of polymorphic type; in this case the member expression should be wrapped and dereferenced to form an lvalue
1626                                CastExpr *ptrCastExpr = new CastExpr( newMemberExpr, new PointerType( Type::Qualifiers(), memberType->clone() ) );
[c10ee66]1627                                UntypedExpr *derefExpr = UntypedExpr::createDeref( ptrCastExpr );
[4318107]1628                                newMemberExpr = derefExpr;
1629                        }
1630
[661214c]1631                        delete memberType;
[4318107]1632                        delete memberExpr;
1633                        return newMemberExpr;
[2a4b088]1634                }
[05d47278]1635
[02c816fc]1636                void PolyGenericCalculator::premutate( AddressExpr * addrExpr ) {
1637                        GuardValue( addrMember );
1638                        // is the argument a MemberExpr before mutating?
1639                        addrMember = dynamic_cast< MemberExpr * >( addrExpr->arg );
1640                }
1641
1642                Expression * PolyGenericCalculator::postmutate( AddressExpr * addrExpr ) {
1643                        if ( addrMember && addrMember != addrExpr->arg ) {
1644                                // arg was a MemberExpr and has been mutated
1645                                if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * >( addrExpr->arg ) ) {
1646                                        if ( InitTweak::getFunctionName( untyped ) == "?+?" ) {
1647                                                // MemberExpr was converted to pointer+offset, and it is not valid C to take the address of an addition, so strip the address-of
1648                                                // TODO: should  addrExpr->arg->result be changed to addrExpr->result?
1649                                                Expression * ret = addrExpr->arg;
1650                                                addrExpr->arg = nullptr;
1651                                                std::swap( addrExpr->env, ret->env );
1652                                                delete addrExpr;
1653                                                return ret;
1654                                        }
1655                                }
1656                        }
1657                        return addrExpr;
1658                }
1659
[8a34677]1660                ObjectDecl *PolyGenericCalculator::makeVar( const std::string &name, Type *type, Initializer *init ) {
[20cba76]1661                        ObjectDecl *newObj = new ObjectDecl( name, Type::StorageClasses(), LinkageSpec::C, nullptr, type, init );
[ba3706f]1662                        stmtsToAddBefore.push_back( new DeclStmt( newObj ) );
[8a34677]1663                        return newObj;
1664                }
1665
1666                void PolyGenericCalculator::addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams ) {
[0b1ca47]1667                        for ( Type * const param : otypeParams ) {
1668                                if ( findGeneric( param ) ) {
[8a34677]1669                                        // push size/align vars for a generic parameter back
[0b1ca47]1670                                        std::string paramName = mangleType( param );
[adc6781]1671                                        layoutCall->get_args().push_back( new NameExpr( sizeofName( paramName ) ) );
1672                                        layoutCall->get_args().push_back( new NameExpr( alignofName( paramName ) ) );
[8a34677]1673                                } else {
[0b1ca47]1674                                        layoutCall->get_args().push_back( new SizeofExpr( param->clone() ) );
1675                                        layoutCall->get_args().push_back( new AlignofExpr( param->clone() ) );
[8a34677]1676                                }
1677                        }
1678                }
1679
1680                /// returns true if any of the otype parameters have a dynamic layout and puts all otype parameters in the output list
[4da152a]1681                bool findGenericParams( std::list< TypeDecl* > const &baseParams, std::list< Expression* > const &typeParams, std::list< Type* > &out ) {
[8a34677]1682                        bool hasDynamicLayout = false;
1683
[271a5d3]1684                        for ( auto paramPair : group_iterate( baseParams, typeParams ) ) {
1685                                TypeDecl * baseParam = std::get<0>( paramPair );
1686                                Expression * typeParam = std::get<1>( paramPair );
[8a34677]1687                                // skip non-otype parameters
[271a5d3]1688                                if ( ! baseParam->isComplete() ) continue;
1689                                TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( typeParam );
[8a34677]1690                                assert( typeExpr && "all otype parameters should be type expressions" );
1691
1692                                Type *type = typeExpr->get_type();
1693                                out.push_back( type );
1694                                if ( isPolyType( type ) ) hasDynamicLayout = true;
1695                        }
1696
1697                        return hasDynamicLayout;
1698                }
1699
[4da152a]1700                bool PolyGenericCalculator::findGeneric( Type const *ty ) {
[c2ad3c9]1701                        ty = replaceTypeInst( ty, env );
[9799ec8]1702
[4da152a]1703                        if ( auto typeInst = dynamic_cast< TypeInstType const * >( ty ) ) {
[e9b5043]1704                                if ( scopeTyVars.contains( typeInst->get_name() ) ) {
[8a34677]1705                                        // NOTE assumes here that getting put in the scopeTyVars included having the layout variables set
1706                                        return true;
1707                                }
1708                                return false;
[4da152a]1709                        } else if ( auto structTy = dynamic_cast< StructInstType const * >( ty ) ) {
[8a34677]1710                                // check if this type already has a layout generated for it
[adc6781]1711                                std::string typeName = mangleType( ty );
[e9b5043]1712                                if ( knownLayouts.contains( typeName ) ) return true;
[8a34677]1713
1714                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
1715                                std::list< Type* > otypeParams;
[4da152a]1716                                if ( ! findGenericParams( *structTy->get_baseParameters(), structTy->parameters, otypeParams ) ) return false;
[8a34677]1717
1718                                // insert local variables for layout and generate call to layout function
[adc6781]1719                                knownLayouts.insert( typeName );  // done early so as not to interfere with the later addition of parameters to the layout call
[8a34677]1720                                Type *layoutType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
1721
1722                                int n_members = structTy->get_baseStruct()->get_members().size();
1723                                if ( n_members == 0 ) {
1724                                        // all empty structs have the same layout - size 1, align 1
[cc3528f]1725                                        makeVar( sizeofName( typeName ), layoutType, new SingleInit( new ConstantExpr( Constant::from_ulong( (unsigned long)1 ) ) ) );
1726                                        makeVar( alignofName( typeName ), layoutType->clone(), new SingleInit( new ConstantExpr( Constant::from_ulong( (unsigned long)1 ) ) ) );
[8a34677]1727                                        // NOTE zero-length arrays are forbidden in C, so empty structs have no offsetof array
1728                                } else {
[adc6781]1729                                        ObjectDecl *sizeVar = makeVar( sizeofName( typeName ), layoutType );
1730                                        ObjectDecl *alignVar = makeVar( alignofName( typeName ), layoutType->clone() );
[cb4c607]1731                                        ObjectDecl *offsetVar = makeVar( offsetofName( typeName ), new ArrayType( Type::Qualifiers(), layoutType->clone(), new ConstantExpr( Constant::from_int( n_members ) ), false, false ) );
[8a34677]1732
1733                                        // generate call to layout function
[adc6781]1734                                        UntypedExpr *layoutCall = new UntypedExpr( new NameExpr( layoutofName( structTy->get_baseStruct() ) ) );
[8a34677]1735                                        layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( sizeVar ) ) );
1736                                        layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( alignVar ) ) );
1737                                        layoutCall->get_args().push_back( new VariableExpr( offsetVar ) );
1738                                        addOtypeParamsToLayoutCall( layoutCall, otypeParams );
1739
[ba3706f]1740                                        stmtsToAddBefore.push_back( new ExprStmt( layoutCall ) );
[8a34677]1741                                }
1742
[18070ee]1743                                // std::cout << "TRUE 2" << std::endl;
1744
[8a34677]1745                                return true;
[4da152a]1746                        } else if ( auto unionTy = dynamic_cast< UnionInstType const * >( ty ) ) {
[8a34677]1747                                // check if this type already has a layout generated for it
[adc6781]1748                                std::string typeName = mangleType( ty );
[e9b5043]1749                                if ( knownLayouts.contains( typeName ) ) return true;
[8a34677]1750
1751                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
1752                                std::list< Type* > otypeParams;
[4da152a]1753                                if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy->parameters, otypeParams ) ) return false;
[8a34677]1754
1755                                // insert local variables for layout and generate call to layout function
[adc6781]1756                                knownLayouts.insert( typeName );  // done early so as not to interfere with the later addition of parameters to the layout call
[8a34677]1757                                Type *layoutType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
1758
[adc6781]1759                                ObjectDecl *sizeVar = makeVar( sizeofName( typeName ), layoutType );
1760                                ObjectDecl *alignVar = makeVar( alignofName( typeName ), layoutType->clone() );
[8a34677]1761
1762                                // generate call to layout function
[adc6781]1763                                UntypedExpr *layoutCall = new UntypedExpr( new NameExpr( layoutofName( unionTy->get_baseUnion() ) ) );
[8a34677]1764                                layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( sizeVar ) ) );
1765                                layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( alignVar ) ) );
1766                                addOtypeParamsToLayoutCall( layoutCall, otypeParams );
1767
[ba3706f]1768                                stmtsToAddBefore.push_back( new ExprStmt( layoutCall ) );
[8a34677]1769
1770                                return true;
1771                        }
1772
1773                        return false;
1774                }
1775
[e16294d]1776                Expression * PolyGenericCalculator::genSizeof( Type* ty ) {
1777                        if ( ArrayType * aty = dynamic_cast<ArrayType *>(ty) ) {
1778                                // generate calculated size for possibly generic array
1779                                Expression * sizeofBase = genSizeof( aty->get_base() );
1780                                if ( ! sizeofBase ) return nullptr;
1781                                Expression * dim = aty->get_dimension();
1782                                aty->set_dimension( nullptr );
1783                                return makeOp( "?*?", sizeofBase, dim );
1784                        } else if ( findGeneric( ty ) ) {
1785                                // generate calculated size for generic type
1786                                return new NameExpr( sizeofName( mangleType( ty ) ) );
1787                        } else return nullptr;
1788                }
1789
[a0c7dc36]1790                Expression *PolyGenericCalculator::postmutate( SizeofExpr *sizeofExpr ) {
[029e330]1791                        Type *ty = sizeofExpr->get_isType() ?
[e16294d]1792                                sizeofExpr->get_type() : sizeofExpr->get_expr()->get_result();
[029e330]1793
[e16294d]1794                        Expression * gen = genSizeof( ty );
1795                        if ( gen ) {
[8a34677]1796                                delete sizeofExpr;
[e16294d]1797                                return gen;
1798                        } else return sizeofExpr;
[8a34677]1799                }
1800
[a0c7dc36]1801                Expression *PolyGenericCalculator::postmutate( AlignofExpr *alignofExpr ) {
[2edd80ae]1802                        Type *ty = alignofExpr->get_isType() ? alignofExpr->get_type() : alignofExpr->get_expr()->get_result();
[8a34677]1803                        if ( findGeneric( ty ) ) {
[adc6781]1804                                Expression *ret = new NameExpr( alignofName( mangleType( ty ) ) );
[8a34677]1805                                delete alignofExpr;
1806                                return ret;
1807                        }
1808                        return alignofExpr;
1809                }
1810
[a0c7dc36]1811                Expression *PolyGenericCalculator::postmutate( OffsetofExpr *offsetofExpr ) {
[2a4b088]1812                        // only mutate expressions for polymorphic structs/unions
[8a34677]1813                        Type *ty = offsetofExpr->get_type();
1814                        if ( ! findGeneric( ty ) ) return offsetofExpr;
[2a4b088]1815
1816                        if ( StructInstType *structType = dynamic_cast< StructInstType* >( ty ) ) {
1817                                // replace offsetof expression by index into offset array
1818                                long i = findMember( offsetofExpr->get_member(), structType->get_baseStruct()->get_members() );
1819                                if ( i == -1 ) return offsetofExpr;
1820
1821                                Expression *offsetInd = makeOffsetIndex( ty, i );
1822                                delete offsetofExpr;
1823                                return offsetInd;
[5c52b06]1824                        } else if ( dynamic_cast< UnionInstType* >( ty ) ) {
[2a4b088]1825                                // all union members are at offset zero
1826                                delete offsetofExpr;
[d56e5bc]1827                                return new ConstantExpr( Constant::from_ulong( 0 ) );
[2a4b088]1828                        } else return offsetofExpr;
[05d47278]1829                }
1830
[a0c7dc36]1831                Expression *PolyGenericCalculator::postmutate( OffsetPackExpr *offsetPackExpr ) {
[8a34677]1832                        StructInstType *ty = offsetPackExpr->get_type();
1833
1834                        Expression *ret = 0;
1835                        if ( findGeneric( ty ) ) {
1836                                // pull offset back from generated type information
[adc6781]1837                                ret = new NameExpr( offsetofName( mangleType( ty ) ) );
[8a34677]1838                        } else {
[adc6781]1839                                std::string offsetName = offsetofName( mangleType( ty ) );
[e9b5043]1840                                if ( knownOffsets.contains( offsetName ) ) {
[8a34677]1841                                        // use the already-generated offsets for this type
1842                                        ret = new NameExpr( offsetName );
1843                                } else {
1844                                        knownOffsets.insert( offsetName );
1845
1846                                        std::list< Declaration* > &baseMembers = ty->get_baseStruct()->get_members();
1847                                        Type *offsetType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
1848
1849                                        // build initializer list for offset array
1850                                        std::list< Initializer* > inits;
[271a5d3]1851                                        for ( Declaration * const member : baseMembers ) {
1852                                                DeclarationWithType *memberDecl = dynamic_cast< DeclarationWithType* >( member );
1853                                                assertf( memberDecl, "Requesting offset of Non-DWT member: %s", toString( member ).c_str() );
1854                                                inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
[8a34677]1855                                        }
1856
1857                                        // build the offset array and replace the pack with a reference to it
[cb4c607]1858                                        ObjectDecl *offsetArray = makeVar( offsetName, new ArrayType( Type::Qualifiers(), offsetType, new ConstantExpr( Constant::from_ulong( baseMembers.size() ) ), false, false ),
[8a34677]1859                                                        new ListInit( inits ) );
1860                                        ret = new VariableExpr( offsetArray );
1861                                }
1862                        }
1863
1864                        delete offsetPackExpr;
1865                        return ret;
1866                }
1867
[a0c7dc36]1868                void PolyGenericCalculator::beginScope() {
[8a34677]1869                        knownLayouts.beginScope();
1870                        knownOffsets.beginScope();
1871                }
1872
[a0c7dc36]1873                void PolyGenericCalculator::endScope() {
[8a34677]1874                        knownLayouts.endScope();
[adc6781]1875                        knownOffsets.endScope();
[8a34677]1876                }
1877
[49db841]1878////////////////////////////////////////// Eraser ///////////////////////////////////////////////
[05d47278]1879
[49db841]1880                void Eraser::premutate( ObjectDecl * objectDecl ) {
[d18540f]1881                        ScrubTyVars::scrubAll( objectDecl );
[05d47278]1882                }
1883
[49db841]1884                void Eraser::premutate( FunctionDecl * functionDecl ) {
[d18540f]1885                        ScrubTyVars::scrubAll( functionDecl );
[05d47278]1886                }
1887
[49db841]1888                void Eraser::premutate( TypedefDecl * typedefDecl ) {
[d18540f]1889                        ScrubTyVars::scrubAll( typedefDecl );
[05d47278]1890                }
1891
[fea3faa]1892                /// Strips the members from a generic aggregate
[d18540f]1893                static void stripGenericMembers( AggregateDecl * decl ) {
[fc72845d]1894                        if ( ! decl->parameters.empty() ) decl->members.clear();
[fea3faa]1895                }
1896
[49db841]1897                void Eraser::premutate( StructDecl * structDecl ) {
[fea3faa]1898                        stripGenericMembers( structDecl );
1899                }
[acd7c5dd]1900
[49db841]1901                void Eraser::premutate( UnionDecl * unionDecl ) {
[fea3faa]1902                        stripGenericMembers( unionDecl );
1903                }
[01aeade]1904        } // anonymous namespace
[51b7345]1905} // namespace GenPoly
[01aeade]1906
[51587aa]1907// Local Variables: //
1908// tab-width: 4 //
1909// mode: c++ //
1910// compile-command: "make install" //
1911// End: //
Note: See TracBrowser for help on using the repository browser.