Changeset 0f6d2884


Ignore:
Timestamp:
Nov 17, 2023, 1:56:19 PM (13 months ago)
Author:
caparson <caparson@…>
Branches:
master
Children:
16e0dcb, 41606df1
Parents:
3f219eb (diff), b0845f9 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
src
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • src/BasicTypes-gen.cc

    r3f219eb r0f6d2884  
    443443        code << str.substr( 0, start );
    444444
    445         code << "\t\t\t// GENERATED BY " __FILE__ << endl;
    446445        code <<
    447                 "\t\t\t// NOTES ON MANGLING:\n"
    448                 "\t\t\t// * Itanium spec says that Float80 encodes to \"e\" (like LongDouble), but the distinct lengths cause resolution problems.\n"
    449                 "\t\t\t// * Float128 is supposed to encode to \"g\", but I wanted it to mangle equal to LongDouble.\n"
    450                 "\t\t\t// * Mangling for non-standard complex types is by best guess\n"
    451                 "\t\t\t// * _FloatN is supposed to encode as \"DF\"N\"_\"; modified for same reason as above.\n"
    452                 "\t\t\t// * unused mangling identifiers:\n"
    453                 "\t\t\t//   - \"z\" ellipsis\n"
    454                 "\t\t\t//   - \"Dd\" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x)\n"
    455                 "\t\t\t//   - \"De\" IEEE 754r 128-bit decimal floating point\n"
    456                 "\t\t\t//   - \"Df\" IEEE 754r 32-bit decimal floating point\n"
    457                 "\t\t\t//   - \"Dh\" IEEE 754r 16-bit decimal floating point (borrowed for _Float16)\n"
    458                 "\t\t\t//   - \"DF\"N\"_\" ISO/IEC TS 18661 N-bit binary floating point (_FloatN)\n"
    459                 "\t\t\t//   - \"Di\" char32_t\n"
    460                 "\t\t\t//   - \"Ds\" char16_t\n";
    461 
    462         code << "\t\t\tconst std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;
     446                "// GENERATED BY " __FILE__ "\n"
     447                "// NOTES ON MANGLING:\n"
     448                "// * Itanium spec says that Float80 encodes to \"e\" (like LongDouble), but the distinct lengths cause resolution problems.\n"
     449                "// * Float128 is supposed to encode to \"g\", but I wanted it to mangle equal to LongDouble.\n"
     450                "// * Mangling for non-standard complex types is by best guess\n"
     451                "// * _FloatN is supposed to encode as \"DF\"N\"_\"; modified for same reason as above.\n"
     452                "// * unused mangling identifiers:\n"
     453                "//   - \"z\" ellipsis\n"
     454                "//   - \"Dd\" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x)\n"
     455                "//   - \"De\" IEEE 754r 128-bit decimal floating point\n"
     456                "//   - \"Df\" IEEE 754r 32-bit decimal floating point\n"
     457                "//   - \"Dh\" IEEE 754r 16-bit decimal floating point (borrowed for _Float16)\n"
     458                "//   - \"DF\"N\"_\" ISO/IEC TS 18661 N-bit binary floating point (_FloatN)\n"
     459                "//   - \"Di\" char32_t\n"
     460                "//   - \"Ds\" char16_t\n";
     461
     462        code << "const std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;
    463463        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    464                 code << "\t\t\t\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl;
    465         } // for
    466         code << "\t\t\t}; // basicTypes" << endl;
    467         code << "\t\t\t";                                                                       // indentation for end marker
     464                code << "\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl;
     465        } // for
     466        code << "}; // basicTypes" << endl;
    468467
    469468        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", ManglerCommon );
  • src/SymTab/FixFunction.cc

    r3f219eb r0f6d2884  
    2626
    2727namespace {
    28         struct FixFunction final : public ast::WithShortCircuiting {
    29                 bool isVoid = false;
    3028
    31                 void previsit( const ast::FunctionDecl * ) { visit_children = false; }
     29struct FixFunction final : public ast::WithShortCircuiting {
     30        bool isVoid = false;
    3231
    33                 const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
    34                         // Cannot handle cases with asserions.
    35                         assert( func->assertions.empty() );
    36                         return new ast::ObjectDecl{
    37                                 func->location, func->name, new ast::PointerType( func->type ), nullptr,
    38                                 func->storage, func->linkage, nullptr, copy( func->attributes ) };
    39                 }
     32        void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    4033
    41                 void previsit( const ast::ArrayType * ) { visit_children = false; }
     34        const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
     35                // Cannot handle cases with asserions.
     36                assert( func->assertions.empty() );
     37                return new ast::ObjectDecl{
     38                        func->location, func->name, new ast::PointerType( func->type ), nullptr,
     39                        func->storage, func->linkage, nullptr, copy( func->attributes ) };
     40        }
    4241
    43                 const ast::Type * postvisit( const ast::ArrayType * array ) {
    44                         return new ast::PointerType{
    45                                 array->base, array->dimension, array->isVarLen, array->isStatic,
    46                                 array->qualifiers };
    47                 }
     42        void previsit( const ast::ArrayType * ) { visit_children = false; }
    4843
    49                 void previsit( const ast::FunctionType * ) { visit_children = false; }
     44        const ast::Type * postvisit( const ast::ArrayType * array ) {
     45                return new ast::PointerType{
     46                        array->base, array->dimension, array->isVarLen, array->isStatic,
     47                        array->qualifiers };
     48        }
    5049
    51                 const ast::Type * postvisit( const ast::FunctionType * type ) {
    52                         return new ast::PointerType( type );
    53                 }
     50        void previsit( const ast::FunctionType * ) { visit_children = false; }
    5451
    55                 void previsit( const ast::VoidType * ) { isVoid = true; }
     52        const ast::Type * postvisit( const ast::FunctionType * type ) {
     53                return new ast::PointerType( type );
     54        }
    5655
    57                 void previsit( const ast::BasicType * ) { visit_children = false; }
    58                 void previsit( const ast::PointerType * ) { visit_children = false; }
    59                 void previsit( const ast::StructInstType * ) { visit_children = false; }
    60                 void previsit( const ast::UnionInstType * ) { visit_children = false; }
    61                 void previsit( const ast::EnumInstType * ) { visit_children = false; }
    62                 void previsit( const ast::TraitInstType * ) { visit_children = false; }
    63                 void previsit( const ast::TypeInstType * ) { visit_children = false; }
    64                 void previsit( const ast::TupleType * ) { visit_children = false; }
    65                 void previsit( const ast::VarArgsType * ) { visit_children = false; }
    66                 void previsit( const ast::ZeroType * ) { visit_children = false; }
    67                 void previsit( const ast::OneType * ) { visit_children = false; }
    68         };
     56        void previsit( const ast::VoidType * ) { isVoid = true; }
     57
     58        void previsit( const ast::BasicType * ) { visit_children = false; }
     59        void previsit( const ast::PointerType * ) { visit_children = false; }
     60        void previsit( const ast::StructInstType * ) { visit_children = false; }
     61        void previsit( const ast::UnionInstType * ) { visit_children = false; }
     62        void previsit( const ast::EnumInstType * ) { visit_children = false; }
     63        void previsit( const ast::TraitInstType * ) { visit_children = false; }
     64        void previsit( const ast::TypeInstType * ) { visit_children = false; }
     65        void previsit( const ast::TupleType * ) { visit_children = false; }
     66        void previsit( const ast::VarArgsType * ) { visit_children = false; }
     67        void previsit( const ast::ZeroType * ) { visit_children = false; }
     68        void previsit( const ast::OneType * ) { visit_children = false; }
     69};
     70
    6971} // anonymous namespace
    7072
  • src/SymTab/FixFunction.h

    r3f219eb r0f6d2884  
    2222
    2323namespace SymTab {
    24         /// Returns declaration with function and array types replaced by equivalent pointer types.
    25         /// Sets isVoid to true if type is void
    26         const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid );
    27         const ast::Type * fixFunction( const ast::Type * type, bool & isVoid );
     24
     25/// Returns declaration with function and array types replaced by equivalent pointer types.
     26/// Sets isVoid to true if type is void.
     27const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid );
     28const ast::Type * fixFunction( const ast::Type * type, bool & isVoid );
     29
    2830} // namespace SymTab
    2931
  • src/SymTab/Mangler.cc

    r3f219eb r0f6d2884  
    2828
    2929namespace Mangle {
    30         namespace {
    31                 /// Mangles names to a unique C identifier
    32                 struct Mangler : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler>, public ast::WithGuards {
    33                         Mangler( Mangle::Mode mode );
    34                         Mangler( const Mangler & ) = delete;
    35 
    36                         void previsit( const ast::Node * ) { visit_children = false; }
    37 
    38                         void postvisit( const ast::ObjectDecl * declaration );
    39                         void postvisit( const ast::FunctionDecl * declaration );
    40                         void postvisit( const ast::TypeDecl * declaration );
    41 
    42                         void postvisit( const ast::VoidType * voidType );
    43                         void postvisit( const ast::BasicType * basicType );
    44                         void postvisit( const ast::PointerType * pointerType );
    45                         void postvisit( const ast::ArrayType * arrayType );
    46                         void postvisit( const ast::ReferenceType * refType );
    47                         void postvisit( const ast::FunctionType * functionType );
    48                         void postvisit( const ast::StructInstType * aggregateUseType );
    49                         void postvisit( const ast::UnionInstType * aggregateUseType );
    50                         void postvisit( const ast::EnumInstType * aggregateUseType );
    51                         void postvisit( const ast::TypeInstType * aggregateUseType );
    52                         void postvisit( const ast::TraitInstType * inst );
    53                         void postvisit( const ast::TupleType * tupleType );
    54                         void postvisit( const ast::VarArgsType * varArgsType );
    55                         void postvisit( const ast::ZeroType * zeroType );
    56                         void postvisit( const ast::OneType * oneType );
    57                         void postvisit( const ast::QualifiedType * qualType );
    58 
    59                         /// The result is the current constructed mangled name.
    60                         std::string result() const { return mangleName; }
    61                   private:
    62                         std::string mangleName;         ///< Mangled name being constructed
    63                         typedef std::map< std::string, std::pair< int, int > > VarMapType;
    64                         VarMapType varNums;             ///< Map of type variables to indices
    65                         int nextVarNum;                 ///< Next type variable index
    66                         bool isTopLevel;                ///< Is the Mangler at the top level
    67                         bool mangleOverridable;         ///< Specially mangle overridable built-in methods
    68                         bool typeMode;                  ///< Produce a unique mangled name for a type
    69                         bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
    70                         bool inFunctionType = false;    ///< Include type qualifiers if false.
    71                         bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type
    72 
    73                   private:
    74                         Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    75                                 int nextVarNum, const VarMapType& varNums );
    76                         friend class ast::Pass<Mangler>;
    77 
    78                   private:
    79                         void mangleDecl( const ast::DeclWithType *declaration );
    80                         void mangleRef( const ast::BaseInstType *refType, const std::string & prefix );
    81 
    82                         void printQualifiers( const ast::Type *type );
    83                 }; // Mangler
    84         } // namespace
    85 
    86         std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
    87                 return ast::Pass<Mangler>::read( decl, mode );
    88         }
    89 
    90         namespace {
    91                 Mangler::Mangler( Mangle::Mode mode )
    92                         : nextVarNum( 0 ), isTopLevel( true ),
    93                         mangleOverridable  ( ! mode.no_overrideable   ),
    94                         typeMode           (   mode.type              ),
    95                         mangleGenericParams( ! mode.no_generic_params ) {}
    96 
    97                 Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    98                         int nextVarNum, const VarMapType& varNums )
    99                         : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
    100                         mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    101                         mangleGenericParams( mangleGenericParams ) {}
    102 
    103                 void Mangler::mangleDecl( const ast::DeclWithType * decl ) {
    104                         bool wasTopLevel = isTopLevel;
    105                         if ( isTopLevel ) {
    106                                 varNums.clear();
    107                                 nextVarNum = 0;
    108                                 isTopLevel = false;
    109                         } // if
    110                         mangleName += Encoding::manglePrefix;
    111                         const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( decl->name );
    112                         if ( opInfo ) {
    113                                 mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
    114                         } else {
    115                                 mangleName += std::to_string( decl->name.size() ) + decl->name;
    116                         } // if
    117                         decl->get_type()->accept( *visitor );
    118                         if ( mangleOverridable && decl->linkage.is_overrideable ) {
    119                                 // want to be able to override autogenerated and intrinsic routines,
    120                                 // so they need a different name mangling
    121                                 if ( decl->linkage == ast::Linkage::AutoGen ) {
    122                                         mangleName += Encoding::autogen;
    123                                 } else if ( decl->linkage == ast::Linkage::Intrinsic ) {
    124                                         mangleName += Encoding::intrinsic;
    125                                 } else {
    126                                         // if we add another kind of overridable function, this has to change
    127                                         assert( false && "unknown overrideable linkage" );
    128                                 } // if
     30
     31namespace {
     32
     33/// Mangles names to a unique C identifier.
     34struct Mangler : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler>, public ast::WithGuards {
     35        Mangler( Mangle::Mode mode );
     36        Mangler( const Mangler & ) = delete;
     37
     38        void previsit( const ast::Node * ) { visit_children = false; }
     39
     40        void postvisit( const ast::ObjectDecl * declaration );
     41        void postvisit( const ast::FunctionDecl * declaration );
     42        void postvisit( const ast::TypeDecl * declaration );
     43
     44        void postvisit( const ast::VoidType * voidType );
     45        void postvisit( const ast::BasicType * basicType );
     46        void postvisit( const ast::PointerType * pointerType );
     47        void postvisit( const ast::ArrayType * arrayType );
     48        void postvisit( const ast::ReferenceType * refType );
     49        void postvisit( const ast::FunctionType * functionType );
     50        void postvisit( const ast::StructInstType * aggregateUseType );
     51        void postvisit( const ast::UnionInstType * aggregateUseType );
     52        void postvisit( const ast::EnumInstType * aggregateUseType );
     53        void postvisit( const ast::TypeInstType * aggregateUseType );
     54        void postvisit( const ast::TraitInstType * inst );
     55        void postvisit( const ast::TupleType * tupleType );
     56        void postvisit( const ast::VarArgsType * varArgsType );
     57        void postvisit( const ast::ZeroType * zeroType );
     58        void postvisit( const ast::OneType * oneType );
     59        void postvisit( const ast::QualifiedType * qualType );
     60
     61        /// The result is the current constructed mangled name.
     62        std::string result() const { return mangleName; }
     63private:
     64        std::string mangleName;         ///< Mangled name being constructed
     65        typedef std::map< std::string, std::pair< int, int > > VarMapType;
     66        VarMapType varNums;             ///< Map of type variables to indices
     67        int nextVarNum;                 ///< Next type variable index
     68        bool isTopLevel;                ///< Is the Mangler at the top level
     69        bool mangleOverridable;         ///< Specially mangle overridable built-in methods
     70        bool typeMode;                  ///< Produce a unique mangled name for a type
     71        bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
     72        bool inFunctionType = false;    ///< Include type qualifiers if false.
     73        bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type
     74
     75private:
     76        Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
     77                int nextVarNum, const VarMapType& varNums );
     78        friend class ast::Pass<Mangler>;
     79
     80private:
     81        void mangleDecl( const ast::DeclWithType *declaration );
     82        void mangleRef( const ast::BaseInstType *refType, const std::string & prefix );
     83
     84        void printQualifiers( const ast::Type *type );
     85}; // Mangler
     86
     87Mangler::Mangler( Mangle::Mode mode )
     88        : nextVarNum( 0 ), isTopLevel( true ),
     89        mangleOverridable  ( ! mode.no_overrideable   ),
     90        typeMode           (   mode.type              ),
     91        mangleGenericParams( ! mode.no_generic_params ) {}
     92
     93Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
     94        int nextVarNum, const VarMapType& varNums )
     95        : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
     96        mangleOverridable( mangleOverridable ), typeMode( typeMode ),
     97        mangleGenericParams( mangleGenericParams ) {}
     98
     99void Mangler::mangleDecl( const ast::DeclWithType * decl ) {
     100        bool wasTopLevel = isTopLevel;
     101        if ( isTopLevel ) {
     102                varNums.clear();
     103                nextVarNum = 0;
     104                isTopLevel = false;
     105        }
     106        mangleName += Encoding::manglePrefix;
     107        if ( auto opInfo = CodeGen::operatorLookup( decl->name ) ) {
     108                mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
     109        } else {
     110                mangleName += std::to_string( decl->name.size() ) + decl->name;
     111        }
     112        decl->get_type()->accept( *visitor );
     113        if ( mangleOverridable && decl->linkage.is_overrideable ) {
     114                // want to be able to override autogenerated and intrinsic routines,
     115                // so they need a different name mangling
     116                if ( decl->linkage == ast::Linkage::AutoGen ) {
     117                        mangleName += Encoding::autogen;
     118                } else if ( decl->linkage == ast::Linkage::Intrinsic ) {
     119                        mangleName += Encoding::intrinsic;
     120                } else {
     121                        // if we add another kind of overridable function, this has to change
     122                        assert( false && "unknown overrideable linkage" );
     123                }
     124        }
     125        isTopLevel = wasTopLevel;
     126}
     127
     128void Mangler::postvisit( const ast::ObjectDecl * decl ) {
     129        mangleDecl( decl );
     130}
     131
     132void Mangler::postvisit( const ast::FunctionDecl * decl ) {
     133        mangleDecl( decl );
     134}
     135
     136void Mangler::postvisit( const ast::VoidType * voidType ) {
     137        printQualifiers( voidType );
     138        mangleName += Encoding::void_t;
     139}
     140
     141void Mangler::postvisit( const ast::BasicType * basicType ) {
     142        printQualifiers( basicType );
     143        assertf( basicType->kind < ast::BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
     144        mangleName += Encoding::basicTypes[ basicType->kind ];
     145}
     146
     147void Mangler::postvisit( const ast::PointerType * pointerType ) {
     148        printQualifiers( pointerType );
     149        // Mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers.
     150        if ( !pointerType->base.as<ast::FunctionType>() ) mangleName += Encoding::pointer;
     151        maybe_accept( pointerType->base.get(), *visitor );
     152}
     153
     154void Mangler::postvisit( const ast::ArrayType * arrayType ) {
     155        // TODO: encode dimension
     156        printQualifiers( arrayType );
     157        mangleName += Encoding::array + "0";
     158        arrayType->base->accept( *visitor );
     159}
     160
     161void Mangler::postvisit( const ast::ReferenceType * refType ) {
     162        // Don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
     163        // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
     164        // by pretending every reference type is a function parameter.
     165        GuardValue( inFunctionType ) = true;
     166        printQualifiers( refType );
     167        refType->base->accept( *visitor );
     168}
     169
     170void Mangler::postvisit( const ast::FunctionType * functionType ) {
     171        printQualifiers( functionType );
     172        mangleName += Encoding::function;
     173        // Turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
     174        // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
     175        // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different.
     176        GuardValue( inFunctionType ) = true;
     177        if (functionType->returns.empty()) mangleName += Encoding::void_t;
     178        else accept_each( functionType->returns, *visitor );
     179        mangleName += "_";
     180        accept_each( functionType->params, *visitor );
     181        mangleName += "_";
     182}
     183
     184void Mangler::mangleRef(
     185                const ast::BaseInstType * refType, const std::string & prefix ) {
     186        printQualifiers( refType );
     187
     188        mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
     189
     190        if ( mangleGenericParams && ! refType->params.empty() ) {
     191                mangleName += "_";
     192                for ( const ast::Expr * param : refType->params ) {
     193                        auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
     194                        assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
     195                        paramType->type->accept( *visitor );
     196                }
     197                mangleName += "_";
     198        }
     199}
     200
     201void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) {
     202        mangleRef( aggregateUseType, Encoding::struct_t );
     203}
     204
     205void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) {
     206        mangleRef( aggregateUseType, Encoding::union_t );
     207}
     208
     209void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) {
     210        mangleRef( aggregateUseType, Encoding::enum_t );
     211}
     212
     213void Mangler::postvisit( const ast::TypeInstType * typeInst ) {
     214        VarMapType::iterator varNum = varNums.find( typeInst->name );
     215        if ( varNum == varNums.end() ) {
     216                mangleRef( typeInst, Encoding::type );
     217        } else {
     218                printQualifiers( typeInst );
     219                // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.
     220                //   forall(dtype T) void f(T);
     221                //   forall(dtype S) void f(S);
     222                // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
     223                // are first found and prefixing with the appropriate encoding for the type class.
     224                assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
     225                mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
     226        }
     227}
     228
     229void Mangler::postvisit( const ast::TraitInstType * inst ) {
     230        printQualifiers( inst );
     231        mangleName += std::to_string( inst->name.size() ) + inst->name;
     232}
     233
     234void Mangler::postvisit( const ast::TupleType * tupleType ) {
     235        printQualifiers( tupleType );
     236        mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
     237        accept_each( tupleType->types, *visitor );
     238}
     239
     240void Mangler::postvisit( const ast::VarArgsType * varArgsType ) {
     241        printQualifiers( varArgsType );
     242        static const std::string vargs = "__builtin_va_list";
     243        mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
     244}
     245
     246void Mangler::postvisit( const ast::ZeroType * ) {
     247        mangleName += Encoding::zero;
     248}
     249
     250void Mangler::postvisit( const ast::OneType * ) {
     251        mangleName += Encoding::one;
     252}
     253
     254void Mangler::postvisit( const ast::QualifiedType * qualType ) {
     255        bool inqual = inQualifiedType;
     256        if ( !inqual ) {
     257                // N marks the start of a qualified type.
     258                inQualifiedType = true;
     259                mangleName += Encoding::qualifiedTypeStart;
     260        }
     261        qualType->parent->accept( *visitor );
     262        qualType->child->accept( *visitor );
     263        if ( !inqual ) {
     264                // E marks the end of a qualified type.
     265                inQualifiedType = false;
     266                mangleName += Encoding::qualifiedTypeEnd;
     267        }
     268}
     269
     270void Mangler::postvisit( const ast::TypeDecl * decl ) {
     271        // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
     272        // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
     273        // Note: The current scheme may already work correctly for this case, I have not thought about this deeply
     274        // and the case has not yet come up in practice. Alternatively, if not then this code can be removed
     275        // aside from the assert false.
     276        assertf(false, "Mangler should not visit typedecl: %s", toCString(decl));
     277        assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
     278        mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
     279}
     280
     281// For debugging:
     282__attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
     283        for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
     284                os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
     285        }
     286}
     287
     288void Mangler::printQualifiers( const ast::Type * type ) {
     289        // Skip if not including qualifiers:
     290        if ( typeMode ) return;
     291        auto funcType = dynamic_cast<const ast::FunctionType *>( type );
     292        if ( funcType && !funcType->forall.empty() ) {
     293                std::list< std::string > assertionNames;
     294                int dcount = 0, fcount = 0, vcount = 0, acount = 0;
     295                mangleName += Encoding::forall;
     296                for ( auto & decl : funcType->forall ) {
     297                        switch ( decl->kind ) {
     298                        case ast::TypeDecl::Dtype:
     299                                dcount++;
     300                                break;
     301                        case ast::TypeDecl::Ftype:
     302                                fcount++;
     303                                break;
     304                        case ast::TypeDecl::Ttype:
     305                                vcount++;
     306                                break;
     307                        default:
     308                                assertf( false, "unimplemented kind for type variable %s", Encoding::typeVariables[decl->kind].c_str() );
    129309                        }
    130                         isTopLevel = wasTopLevel;
    131                 }
    132 
    133                 void Mangler::postvisit( const ast::ObjectDecl * decl ) {
    134                         mangleDecl( decl );
    135                 }
    136 
    137                 void Mangler::postvisit( const ast::FunctionDecl * decl ) {
    138                         mangleDecl( decl );
    139                 }
    140 
    141                 void Mangler::postvisit( const ast::VoidType * voidType ) {
    142                         printQualifiers( voidType );
    143                         mangleName += Encoding::void_t;
    144                 }
    145 
    146                 void Mangler::postvisit( const ast::BasicType * basicType ) {
    147                         printQualifiers( basicType );
    148                         assertf( basicType->kind < ast::BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
    149                         mangleName += Encoding::basicTypes[ basicType->kind ];
    150                 }
    151 
    152                 void Mangler::postvisit( const ast::PointerType * pointerType ) {
    153                         printQualifiers( pointerType );
    154                         // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
    155                         if ( ! pointerType->base.as<ast::FunctionType>() ) mangleName += Encoding::pointer;
    156                         maybe_accept( pointerType->base.get(), *visitor );
    157                 }
    158 
    159                 void Mangler::postvisit( const ast::ArrayType * arrayType ) {
    160                         // TODO: encode dimension
    161                         printQualifiers( arrayType );
    162                         mangleName += Encoding::array + "0";
    163                         arrayType->base->accept( *visitor );
    164                 }
    165 
    166                 void Mangler::postvisit( const ast::ReferenceType * refType ) {
    167                         // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
    168                         // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
    169                         // by pretending every reference type is a function parameter.
    170                         GuardValue( inFunctionType );
    171                         inFunctionType = true;
    172                         printQualifiers( refType );
    173                         refType->base->accept( *visitor );
    174                 }
    175 
    176                 void Mangler::postvisit( const ast::FunctionType * functionType ) {
    177                         printQualifiers( functionType );
    178                         mangleName += Encoding::function;
    179                         // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
    180                         // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
    181                         // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different
    182                         GuardValue( inFunctionType );
    183                         inFunctionType = true;
    184                         if (functionType->returns.empty()) mangleName += Encoding::void_t;
    185                         else accept_each( functionType->returns, *visitor );
    186                         mangleName += "_";
    187                         accept_each( functionType->params, *visitor );
    188                         mangleName += "_";
    189                 }
    190 
    191                 void Mangler::mangleRef(
    192                                 const ast::BaseInstType * refType, const std::string & prefix ) {
    193                         printQualifiers( refType );
    194 
    195                         mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
    196 
    197                         if ( mangleGenericParams && ! refType->params.empty() ) {
    198                                 mangleName += "_";
    199                                 for ( const ast::Expr * param : refType->params ) {
    200                                         auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
    201                                         assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
    202                                         paramType->type->accept( *visitor );
    203                                 }
    204                                 mangleName += "_";
    205                         }
    206                 }
    207 
    208                 void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) {
    209                         mangleRef( aggregateUseType, Encoding::struct_t );
    210                 }
    211 
    212                 void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) {
    213                         mangleRef( aggregateUseType, Encoding::union_t );
    214                 }
    215 
    216                 void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) {
    217                         mangleRef( aggregateUseType, Encoding::enum_t );
    218                 }
    219 
    220                 void Mangler::postvisit( const ast::TypeInstType * typeInst ) {
    221                         VarMapType::iterator varNum = varNums.find( typeInst->name );
    222                         if ( varNum == varNums.end() ) {
    223                                 mangleRef( typeInst, Encoding::type );
    224                         } else {
    225                                 printQualifiers( typeInst );
    226                                 // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.
    227                                 //   forall(dtype T) void f(T);
    228                                 //   forall(dtype S) void f(S);
    229                                 // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
    230                                 // are first found and prefixing with the appropriate encoding for the type class.
    231                                 assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    232                                 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
    233                         } // if
    234                 }
    235 
    236                 void Mangler::postvisit( const ast::TraitInstType * inst ) {
    237                         printQualifiers( inst );
    238                         mangleName += std::to_string( inst->name.size() ) + inst->name;
    239                 }
    240 
    241                 void Mangler::postvisit( const ast::TupleType * tupleType ) {
    242                         printQualifiers( tupleType );
    243                         mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
    244                         accept_each( tupleType->types, *visitor );
    245                 }
    246 
    247                 void Mangler::postvisit( const ast::VarArgsType * varArgsType ) {
    248                         printQualifiers( varArgsType );
    249                         static const std::string vargs = "__builtin_va_list";
    250                         mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
    251                 }
    252 
    253                 void Mangler::postvisit( const ast::ZeroType * ) {
    254                         mangleName += Encoding::zero;
    255                 }
    256 
    257                 void Mangler::postvisit( const ast::OneType * ) {
    258                         mangleName += Encoding::one;
    259                 }
    260 
    261                 void Mangler::postvisit( const ast::QualifiedType * qualType ) {
    262                         bool inqual = inQualifiedType;
    263                         if ( !inqual ) {
    264                                 // N marks the start of a qualified type
    265                                 inQualifiedType = true;
    266                                 mangleName += Encoding::qualifiedTypeStart;
    267                         }
    268                         qualType->parent->accept( *visitor );
    269                         qualType->child->accept( *visitor );
    270                         if ( !inqual ) {
    271                                 // E marks the end of a qualified type
    272                                 inQualifiedType = false;
    273                                 mangleName += Encoding::qualifiedTypeEnd;
    274                         }
    275                 }
    276 
    277                 void Mangler::postvisit( const ast::TypeDecl * decl ) {
    278                         // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
    279                         // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
    280                         // Note: The current scheme may already work correctly for this case, I have not thought about this deeply
    281                         // and the case has not yet come up in practice. Alternatively, if not then this code can be removed
    282                         // aside from the assert false.
    283                         assertf(false, "Mangler should not visit typedecl: %s", toCString(decl));
    284                         assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    285                         mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
    286                 }
    287 
    288                 // For debugging:
    289                 __attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
    290                         for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
    291                                 os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
    292                         } // for
    293                 }
    294 
    295                 void Mangler::printQualifiers( const ast::Type * type ) {
    296                         // skip if not including qualifiers
    297                         if ( typeMode ) return;
    298                         auto funcType = dynamic_cast<const ast::FunctionType *>( type );
    299                         if ( funcType && !funcType->forall.empty() ) {
    300                                 std::list< std::string > assertionNames;
    301                                 int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    302                                 mangleName += Encoding::forall;
    303                                 for ( auto & decl : funcType->forall ) {
    304                                         switch ( decl->kind ) {
    305                                         case ast::TypeDecl::Dtype:
    306                                                 dcount++;
    307                                                 break;
    308                                         case ast::TypeDecl::Ftype:
    309                                                 fcount++;
    310                                                 break;
    311                                         case ast::TypeDecl::Ttype:
    312                                                 vcount++;
    313                                                 break;
    314                                         default:
    315                                                 assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[decl->kind].c_str() );
    316                                         } // switch
    317                                         varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
    318                                 } // for
    319                                 for ( auto & assert : funcType->assertions ) {
    320                                         assertionNames.push_back( ast::Pass<Mangler>::read(
    321                                                 assert->var.get(),
    322                                                 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
    323                                         acount++;
    324                                 } // for
    325                                 mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
    326                                 for ( const auto & a : assertionNames ) mangleName += a;
    327                                 mangleName += "_";
    328                         } // if
    329                         if ( ! inFunctionType ) {
    330                                 // these qualifiers do not distinguish the outermost type of a function parameter
    331                                 if ( type->is_const() ) {
    332                                         mangleName += Encoding::qualifiers.at( ast::CV::Const );
    333                                 } // if
    334                                 if ( type->is_volatile() ) {
    335                                         mangleName += Encoding::qualifiers.at( ast::CV::Volatile );
    336                                 } // if
    337                                 // Removed due to restrict not affecting function compatibility in GCC
    338                                 // if ( type->get_isRestrict() ) {
    339                                 //      mangleName += "E";
    340                                 // } // if
    341                                 if ( type->is_atomic() ) {
    342                                         mangleName += Encoding::qualifiers.at( ast::CV::Atomic );
    343                                 } // if
    344                         }
    345                         if ( type->is_mutex() ) {
    346                                 mangleName += Encoding::qualifiers.at( ast::CV::Mutex );
    347                         } // if
    348                         if ( inFunctionType ) {
    349                                 // turn off inFunctionType so that types can be differentiated for nested qualifiers
    350                                 GuardValue( inFunctionType );
    351                                 inFunctionType = false;
    352                         }
    353                 }
    354         }       // namespace
     310                        varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
     311                }
     312                for ( auto & assert : funcType->assertions ) {
     313                        assertionNames.push_back( ast::Pass<Mangler>::read(
     314                                assert->var.get(),
     315                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
     316                        acount++;
     317                }
     318                mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
     319                for ( const auto & a : assertionNames ) mangleName += a;
     320                mangleName += "_";
     321        }
     322        if ( !inFunctionType ) {
     323                // These qualifiers do not distinguish the outermost type of a function parameter.
     324                if ( type->is_const() ) {
     325                        mangleName += Encoding::qualifiers.at( ast::CV::Const );
     326                }
     327                if ( type->is_volatile() ) {
     328                        mangleName += Encoding::qualifiers.at( ast::CV::Volatile );
     329                }
     330                if ( type->is_atomic() ) {
     331                        mangleName += Encoding::qualifiers.at( ast::CV::Atomic );
     332                }
     333        }
     334        if ( type->is_mutex() ) {
     335                mangleName += Encoding::qualifiers.at( ast::CV::Mutex );
     336        }
     337        if ( inFunctionType ) {
     338                // Turn off inFunctionType so that types can be differentiated for nested qualifiers.
     339                GuardValue( inFunctionType ) = false;
     340        }
     341}
     342
     343}       // namespace
     344
     345std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
     346        return ast::Pass<Mangler>::read( decl, mode );
     347}
     348
    355349} // namespace Mangle
    356350
  • src/SymTab/Mangler.h

    r3f219eb r0f6d2884  
    3434}
    3535
    36 namespace SymTab {
    37         namespace Mangler {
    38                 namespace Encoding {
    39                         extern const std::string manglePrefix;
    40                         extern const std::string basicTypes[];
    41                         extern const std::map<int, std::string> qualifiers;
     36namespace Mangle {
    4237
    43                         extern const std::string void_t;
    44                         extern const std::string zero;
    45                         extern const std::string one;
     38/// Bitflags for mangle Mode:
     39enum {
     40        NoOverrideable  = 1 << 0,
     41        Type            = 1 << 1,
     42        NoGenericParams = 1 << 2
     43};
    4644
    47                         extern const std::string function;
    48                         extern const std::string tuple;
    49                         extern const std::string pointer;
    50                         extern const std::string array;
    51                         extern const std::string qualifiedTypeStart;
    52                         extern const std::string qualifiedTypeEnd;
    53 
    54                         extern const std::string forall;
    55                         extern const std::string typeVariables[];
    56 
    57                         extern const std::string struct_t;
    58                         extern const std::string union_t;
    59                         extern const std::string enum_t;
    60                         extern const std::string type;
    61 
    62                         extern const std::string autogen;
    63                         extern const std::string intrinsic;
     45/// Bitflag type for mangle Mode:
     46struct mangle_flags {
     47        union {
     48                unsigned int val;
     49                struct {
     50                        bool no_overrideable   : 1;
     51                        bool type              : 1;
     52                        bool no_generic_params : 1;
    6453                };
    65         } // Mangler
    66 } // SymTab
    67 
    68 namespace Mangle {
    69         /// Bitflags for mangle modes
    70         enum {
    71                 NoOverrideable  = 1 << 0,
    72                 Type            = 1 << 1,
    73                 NoGenericParams = 1 << 2
    7454        };
    7555
    76         /// Bitflag type for mangler modes
    77         struct mangle_flags {
    78                 union {
    79                         unsigned int val;
    80                         struct {
    81                                 bool no_overrideable   : 1;
    82                                 bool type              : 1;
    83                                 bool no_generic_params : 1;
    84                         };
    85                 };
     56        constexpr mangle_flags( unsigned int val ) : val(val) {}
     57};
    8658
    87                 constexpr mangle_flags( unsigned int val ) : val(val) {}
    88         };
     59using Mode = bitfield<mangle_flags>;
    8960
    90         using Mode = bitfield<mangle_flags>;
     61/// Mangle declaration name.
     62std::string mangle( const ast::Node * decl, Mode mode = {} );
    9163
    92         /// Mangle declaration name.
    93         std::string mangle( const ast::Node * decl, Mode mode = {} );
     64/// Most common mangle configuration for types.
     65static inline std::string mangleType( const ast::Node * type ) {
     66        return mangle( type, { NoOverrideable | Type } );
     67}
    9468
    95         /// Most common mangle configuration for types.
    96         static inline std::string mangleType( const ast::Node * type ) {
    97                 return mangle( type, { NoOverrideable | Type } );
    98         }
     69/// The substrings used in name mangling and demangling.
     70namespace Encoding {
     71        extern const std::string manglePrefix;
     72        extern const std::string basicTypes[];
     73        extern const std::map<int, std::string> qualifiers;
    9974
    100         namespace Encoding {
    101                 using namespace SymTab::Mangler::Encoding;
    102         };
     75        extern const std::string void_t;
     76        extern const std::string zero;
     77        extern const std::string one;
     78
     79        extern const std::string function;
     80        extern const std::string tuple;
     81        extern const std::string pointer;
     82        extern const std::string array;
     83        extern const std::string qualifiedTypeStart;
     84        extern const std::string qualifiedTypeEnd;
     85
     86        extern const std::string forall;
     87        extern const std::string typeVariables[];
     88
     89        extern const std::string struct_t;
     90        extern const std::string union_t;
     91        extern const std::string enum_t;
     92        extern const std::string type;
     93
     94        extern const std::string autogen;
     95        extern const std::string intrinsic;
     96}
     97
    10398}
    10499
  • src/SymTab/ManglerCommon.cc

    r3f219eb r0f6d2884  
    1919#include "AST/Type.hpp"
    2020
    21 namespace SymTab {
    22         namespace Mangler {
    23                 namespace Encoding {
    24                         const std::string manglePrefix = "_X";
     21namespace Mangle {
    2522
    26                         // GENERATED START, DO NOT EDIT
    27                         // GENERATED BY BasicTypes-gen.cc
    28                         // NOTES ON MANGLING:
    29                         // * Itanium spec says that Float80 encodes to "e" (like LongDouble), but the distinct lengths cause resolution problems.
    30                         // * Float128 is supposed to encode to "g", but I wanted it to mangle equal to LongDouble.
    31                         // * Mangling for non-standard complex types is by best guess
    32                         // * _FloatN is supposed to encode as "DF"N"_"; modified for same reason as above.
    33                         // * unused mangling identifiers:
    34                         //   - "z" ellipsis
    35                         //   - "Dd" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x)
    36                         //   - "De" IEEE 754r 128-bit decimal floating point
    37                         //   - "Df" IEEE 754r 32-bit decimal floating point
    38                         //   - "Dh" IEEE 754r 16-bit decimal floating point (borrowed for _Float16)
    39                         //   - "DF"N"_" ISO/IEC TS 18661 N-bit binary floating point (_FloatN)
    40                         //   - "Di" char32_t
    41                         //   - "Ds" char16_t
    42                         const std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {
    43                                 "b",        // _Bool
    44                                 "c",        // char
    45                                 "a",        // signed char
    46                                 "h",        // unsigned char
    47                                 "s",        // signed short int
    48                                 "t",        // unsigned short int
    49                                 "i",        // signed int
    50                                 "j",        // unsigned int
    51                                 "l",        // signed long int
    52                                 "m",        // unsigned long int
    53                                 "x",        // signed long long int
    54                                 "y",        // unsigned long long int
    55                                 "n",        // __int128
    56                                 "o",        // unsigned __int128
    57                                 "DF16_",    // _Float16
    58                                 "CDF16_",   // _Float16 _Complex
    59                                 "DF32_",    // _Float32
    60                                 "CDF32_",   // _Float32 _Complex
    61                                 "f",        // float
    62                                 "Cf",       // float _Complex
    63                                 "DF32x_",   // _Float32x
    64                                 "CDF32x_",  // _Float32x _Complex
    65                                 "DF64_",    // _Float64
    66                                 "CDF64_",   // _Float64 _Complex
    67                                 "d",        // double
    68                                 "Cd",       // double _Complex
    69                                 "DF64x_",   // _Float64x
    70                                 "CDF64x_",  // _Float64x _Complex
    71                                 "Dq",       // __float80
    72                                 "DF128_",   // _Float128
    73                                 "CDF128_",  // _Float128 _Complex
    74                                 "g",        // __float128
    75                                 "e",        // long double
    76                                 "Ce",       // long double _Complex
    77                                 "DF128x_",  // _Float128x
    78                                 "CDF128x_", // _Float128x _Complex
    79                         }; // basicTypes
    80                         // GENERATED END
    81                         static_assert(
    82                                 sizeof(basicTypes)/sizeof(basicTypes[0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES,
    83                                 "Each basic type kind should have a corresponding mangler letter"
    84                         );
     23namespace Encoding {
    8524
    86                         const std::map<int, std::string> qualifiers = {
    87                                 { ast::CV::Const, "K" },
    88                                 { ast::CV::Volatile, "V" },
    89                                 { ast::CV::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA
    90                                 { ast::CV::Mutex, "X" },
    91                         };
     25const std::string manglePrefix = "_X";
    9226
    93                         const std::string void_t = "v";
    94                         const std::string zero = "Z";
    95                         const std::string one = "O";
     27// GENERATED START, DO NOT EDIT
     28// GENERATED BY BasicTypes-gen.cc
     29// NOTES ON MANGLING:
     30// * Itanium spec says that Float80 encodes to "e" (like LongDouble), but the distinct lengths cause resolution problems.
     31// * Float128 is supposed to encode to "g", but I wanted it to mangle equal to LongDouble.
     32// * Mangling for non-standard complex types is by best guess
     33// * _FloatN is supposed to encode as "DF"N"_"; modified for same reason as above.
     34// * unused mangling identifiers:
     35//   - "z" ellipsis
     36//   - "Dd" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x)
     37//   - "De" IEEE 754r 128-bit decimal floating point
     38//   - "Df" IEEE 754r 32-bit decimal floating point
     39//   - "Dh" IEEE 754r 16-bit decimal floating point (borrowed for _Float16)
     40//   - "DF"N"_" ISO/IEC TS 18661 N-bit binary floating point (_FloatN)
     41//   - "Di" char32_t
     42//   - "Ds" char16_t
     43const std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {
     44        "b",        // _Bool
     45        "c",        // char
     46        "a",        // signed char
     47        "h",        // unsigned char
     48        "s",        // signed short int
     49        "t",        // unsigned short int
     50        "i",        // signed int
     51        "j",        // unsigned int
     52        "l",        // signed long int
     53        "m",        // unsigned long int
     54        "x",        // signed long long int
     55        "y",        // unsigned long long int
     56        "n",        // __int128
     57        "o",        // unsigned __int128
     58        "DF16_",    // _Float16
     59        "CDF16_",   // _Float16 _Complex
     60        "DF32_",    // _Float32
     61        "CDF32_",   // _Float32 _Complex
     62        "f",        // float
     63        "Cf",       // float _Complex
     64        "DF32x_",   // _Float32x
     65        "CDF32x_",  // _Float32x _Complex
     66        "DF64_",    // _Float64
     67        "CDF64_",   // _Float64 _Complex
     68        "d",        // double
     69        "Cd",       // double _Complex
     70        "DF64x_",   // _Float64x
     71        "CDF64x_",  // _Float64x _Complex
     72        "Dq",       // __float80
     73        "DF128_",   // _Float128
     74        "CDF128_",  // _Float128 _Complex
     75        "g",        // __float128
     76        "e",        // long double
     77        "Ce",       // long double _Complex
     78        "DF128x_",  // _Float128x
     79        "CDF128x_", // _Float128x _Complex
     80}; // basicTypes
     81// GENERATED END
     82static_assert(
     83        sizeof(basicTypes) / sizeof(basicTypes[0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES,
     84        "Each basic type kind should have a corresponding mangler letter"
     85);
    9686
    97                         const std::string function = "F";
    98                         const std::string tuple = "T";
    99                         const std::string pointer = "P";
    100                         const std::string array = "A";
    101                         const std::string qualifiedTypeStart = "N";
    102                         const std::string qualifiedTypeEnd = "E";
     87const std::map<int, std::string> qualifiers = {
     88        { ast::CV::Const, "K" },
     89        { ast::CV::Volatile, "V" },
     90        { ast::CV::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA
     91        { ast::CV::Mutex, "X" },
     92};
    10393
    104                         const std::string forall = "Q";
    105                         const std::string typeVariables[] = {
    106                                 "BD", // dtype
    107                                 "BDS", // dtype + sized
    108                                 "BO", // otype
    109                                 "BF", // ftype
    110                                 "BT", // ttype
    111                                 "BAL", // array length type
    112                         };
    113                         static_assert(
    114                                 sizeof(typeVariables) / sizeof(typeVariables[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
    115                                 "Each type variable kind should have a corresponding mangler prefix"
    116                         );
     94const std::string void_t = "v";
     95const std::string zero = "Z";
     96const std::string one = "O";
    11797
    118                         const std::string struct_t = "S";
    119                         const std::string union_t = "U";
    120                         const std::string enum_t = "M";
    121                         const std::string type = "Y";
     98const std::string function = "F";
     99const std::string tuple = "T";
     100const std::string pointer = "P";
     101const std::string array = "A";
     102const std::string qualifiedTypeStart = "N";
     103const std::string qualifiedTypeEnd = "E";
    122104
    123                         const std::string autogen = "autogen__";
    124                         const std::string intrinsic = "intrinsic__";
    125                 } // namespace Encoding
    126         } // namespace Mangler
    127 } // namespace SymTab
     105const std::string forall = "Q";
     106const std::string typeVariables[] = {
     107        "BD", // dtype
     108        "BDS", // dtype + sized
     109        "BO", // otype
     110        "BF", // ftype
     111        "BT", // ttype
     112        "BAL", // array length type
     113};
     114static_assert(
     115        sizeof(typeVariables) / sizeof(typeVariables[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
     116        "Each type variable kind should have a corresponding mangler prefix"
     117);
     118
     119const std::string struct_t = "S";
     120const std::string union_t = "U";
     121const std::string enum_t = "M";
     122const std::string type = "Y";
     123
     124const std::string autogen = "autogen__";
     125const std::string intrinsic = "intrinsic__";
     126
     127} // namespace Encoding
     128
     129} // namespace Mangle
  • src/Tuples/TupleAssignment.cc

    r3f219eb r0f6d2884  
    4646
    4747namespace {
    48         /// true if `expr` is of tuple type
    49         bool isTuple( const ast::Expr * expr ) {
    50                 if ( ! expr ) return false;
    51                 assert( expr->result );
    52                 return dynamic_cast< const ast::TupleType * >( expr->result->stripReferences() );
     48
     49/// Checks if `expr` is of tuple type.
     50bool isTuple( const ast::Expr * expr ) {
     51        if ( !expr ) return false;
     52        assert( expr->result );
     53        return dynamic_cast< const ast::TupleType * >( expr->result->stripReferences() );
     54}
     55
     56/// Checks if `expr` is of tuple type or a cast to one.
     57bool refToTuple( const ast::Expr * expr ) {
     58        assert( expr->result );
     59        // Check for function returning tuple of reference types.
     60        if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) {
     61                return refToTuple( castExpr->arg );
     62        } else {
     63                return isTuple( expr );
    5364        }
    54 
    55         /// true if `expr` is of tuple type or a reference to one
    56         bool refToTuple( const ast::Expr * expr ) {
    57                 assert( expr->result );
    58                 // check for function returning tuple of reference types
    59                 if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) {
    60                         return refToTuple( castExpr->arg );
    61                 } else {
    62                         return isTuple( expr );
    63                 }
    64         }
    65 
    66         /// Dispatcher for tuple (multiple and mass) assignment operations
    67         class TupleAssignSpotter final {
    68                 /// Actually finds tuple assignment operations, by subclass
    69                 struct Matcher {
    70                         ResolvExpr::CandidateList lhs, rhs;
    71                         TupleAssignSpotter & spotter;
    72                         CodeLocation location;
    73                         ResolvExpr::Cost baseCost;
    74                         std::vector< ast::ptr< ast::ObjectDecl > > tmpDecls;
    75                         ast::TypeEnvironment env;
    76                         ast::OpenVarSet open;
    77                         ast::AssertionSet need;
    78 
    79                         void combineState( const ResolvExpr::Candidate & cand ) {
    80                                 env.simpleCombine( cand.env );
    81                                 ast::mergeOpenVars( open, cand.open );
    82                                 need.insert( cand.need.begin(), cand.need.end() );
    83                         }
    84 
    85                         Matcher(
    86                                 TupleAssignSpotter & s, const CodeLocation & loc,
    87                                 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
    88                         : lhs( l ), rhs( r ), spotter( s ), location( loc ),
    89                           baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ), tmpDecls(),
    90                           env(), open(), need() {
    91                                 for ( auto & cand : lhs ) combineState( *cand );
    92                                 for ( auto & cand : rhs ) combineState( *cand );
    93                         }
    94                         virtual ~Matcher() = default;
    95 
    96                         virtual std::vector< ast::ptr< ast::Expr > > match() = 0;
    97 
    98                         /// removes environments from subexpressions within statement expressions, which could
    99                         /// throw off later passes like those in Box which rely on PolyMutator, and adds the
    100                         /// bindings to the env
    101                         struct EnvRemover {
    102                                 /// environment to hoist ExprStmt environments to
    103                                 ast::TypeEnvironment & tenv;
    104 
    105                                 EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {}
    106 
    107                                 const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) {
    108                                         if ( stmt->expr->env ) {
    109                                                 tenv.add( *stmt->expr->env );
    110                                                 ast::ExprStmt * mut = mutate( stmt );
    111                                                 mut->expr.get_and_mutate()->env = nullptr;
    112                                                 return mut;
    113                                         }
    114                                         return stmt;
     65}
     66
     67/// Dispatcher for tuple (multiple and mass) assignment operations.
     68class TupleAssignSpotter final {
     69        /// Actually finds tuple assignment operations, by subclass.
     70        struct Matcher {
     71                ResolvExpr::CandidateList lhs, rhs;
     72                TupleAssignSpotter & spotter;
     73                CodeLocation location;
     74                ResolvExpr::Cost baseCost;
     75                std::vector< ast::ptr< ast::ObjectDecl > > tmpDecls;
     76                ast::TypeEnvironment env;
     77                ast::OpenVarSet open;
     78                ast::AssertionSet need;
     79
     80                void combineState( const ResolvExpr::Candidate & cand ) {
     81                        env.simpleCombine( cand.env );
     82                        ast::mergeOpenVars( open, cand.open );
     83                        need.insert( cand.need.begin(), cand.need.end() );
     84                }
     85
     86                Matcher(
     87                        TupleAssignSpotter & s, const CodeLocation & loc,
     88                        const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     89                : lhs( l ), rhs( r ), spotter( s ), location( loc ),
     90                  baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ), tmpDecls(),
     91                  env(), open(), need() {
     92                        for ( auto & cand : lhs ) combineState( *cand );
     93                        for ( auto & cand : rhs ) combineState( *cand );
     94                }
     95                virtual ~Matcher() = default;
     96
     97                virtual std::vector< ast::ptr< ast::Expr > > match() = 0;
     98
     99                /// Removes environments from subexpressions within statement expressions, which could
     100                /// throw off later passes like those in Box which rely on PolyMutator, and adds the
     101                /// bindings to the env.
     102                struct EnvRemover {
     103                        /// Environment to hoist ExprStmt environments to.
     104                        ast::TypeEnvironment & tenv;
     105
     106                        EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {}
     107
     108                        const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) {
     109                                if ( stmt->expr->env ) {
     110                                        tenv.add( *stmt->expr->env );
     111                                        ast::ExprStmt * mut = mutate( stmt );
     112                                        mut->expr.get_and_mutate()->env = nullptr;
     113                                        return mut;
    115114                                }
    116                         };
    117 
    118                         ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) {
    119                                 assert( expr->result && ! expr->result->isVoid() );
    120 
    121                                 ast::ObjectDecl * ret = new ast::ObjectDecl{
    122                                         location, namer.newName(), expr->result, new ast::SingleInit{ location, expr },
    123                                         ast::Storage::Classes{}, ast::Linkage::Cforall };
    124 
    125                                 // if expression type is a reference, just need an initializer, otherwise construct
    126                                 if ( ! expr->result.as< ast::ReferenceType >() ) {
    127                                         // resolve ctor/dtor for the new object
    128                                         ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
    129                                                         InitTweak::genCtorInit( location, ret ), spotter.crntFinder.context );
    130                                         // remove environments from subexpressions of stmtExpr
    131                                         ast::Pass< EnvRemover > rm{ env };
    132                                         ret->init = ctorInit->accept( rm );
     115                                return stmt;
     116                        }
     117                };
     118
     119                ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) {
     120                        assert( expr->result && !expr->result->isVoid() );
     121
     122                        ast::ObjectDecl * ret = new ast::ObjectDecl(
     123                                location, namer.newName(), expr->result, new ast::SingleInit( location, expr ),
     124                                ast::Storage::Classes{}, ast::Linkage::Cforall );
     125
     126                        // If expression type is a reference, just need an initializer, otherwise construct.
     127                        if ( ! expr->result.as< ast::ReferenceType >() ) {
     128                                // Resolve ctor/dtor for the new object.
     129                                ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
     130                                                InitTweak::genCtorInit( location, ret ), spotter.crntFinder.context );
     131                                // Remove environments from subexpressions of stmtExpr.
     132                                ast::Pass< EnvRemover > rm( env );
     133                                ret->init = ctorInit->accept( rm );
     134                        }
     135
     136                        PRINT( std::cerr << "new object: " << ret << std::endl; )
     137                        return ret;
     138                }
     139
     140                ast::UntypedExpr * createFunc(
     141                        const std::string & fname, const ast::ObjectDecl * left,
     142                        const ast::ObjectDecl * right
     143                ) {
     144                        assert( left );
     145                        std::vector< ast::ptr< ast::Expr > > args;
     146                        args.emplace_back( new ast::VariableExpr( location, left ) );
     147                        if ( right ) { args.emplace_back( new ast::VariableExpr( location, right ) ); }
     148
     149                        if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
     150                                args.front() = new ast::AddressExpr( location, args.front() );
     151                                if ( right ) { args.back() = new ast::AddressExpr( location, args.back() ); }
     152                                return new ast::UntypedExpr(
     153                                        location, new ast::NameExpr( location, "?=?" ), std::move( args ) );
     154                        } else {
     155                                return new ast::UntypedExpr(
     156                                        location, new ast::NameExpr( location, fname ), std::move( args ) );
     157                        }
     158                }
     159        };
     160
     161        /// Finds mass-assignment operations.
     162        struct MassAssignMatcher final : public Matcher {
     163                MassAssignMatcher(
     164                        TupleAssignSpotter & s, const CodeLocation & loc,
     165                        const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     166                : Matcher( s, loc, l, r ) {}
     167
     168                std::vector< ast::ptr< ast::Expr > > match() override {
     169                        static UniqueName lhsNamer( "__massassign_L" );
     170                        static UniqueName rhsNamer( "__massassign_R" );
     171                        // Empty tuple case falls into this matcher.
     172                        assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
     173
     174                        ast::ptr< ast::ObjectDecl > rtmp =
     175                                1 == rhs.size() ? newObject( rhsNamer, rhs.front()->expr ) : nullptr;
     176
     177                        std::vector< ast::ptr< ast::Expr > > out;
     178                        for ( ResolvExpr::CandidateRef & lhsCand : lhs ) {
     179                                // Create a temporary object for each value in
     180                                // the LHS and create a call involving the RHS.
     181                                ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr );
     182                                out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) );
     183                                tmpDecls.emplace_back( std::move( ltmp ) );
     184                        }
     185                        if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) );
     186
     187                        return out;
     188                }
     189        };
     190
     191        /// Finds multiple-assignment operations.
     192        struct MultipleAssignMatcher final : public Matcher {
     193                MultipleAssignMatcher(
     194                        TupleAssignSpotter & s, const CodeLocation & loc,
     195                        const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     196                : Matcher( s, loc, l, r ) {}
     197
     198                std::vector< ast::ptr< ast::Expr > > match() override {
     199                        static UniqueName lhsNamer( "__multassign_L" );
     200                        static UniqueName rhsNamer( "__multassign_R" );
     201
     202                        if ( lhs.size() != rhs.size() ) return {};
     203
     204                        // Produce a new temporary object for each value in
     205                        // the LHS and RHS and pairwise create the calls.
     206                        std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp;
     207
     208                        std::vector< ast::ptr< ast::Expr > > out;
     209                        for ( unsigned i = 0; i < lhs.size(); ++i ) {
     210                                ResolvExpr::CandidateRef & lhsCand = lhs[i];
     211                                ResolvExpr::CandidateRef & rhsCand = rhs[i];
     212
     213                                // Convert RHS to LHS type minus one reference --
     214                                // important for case where LHS is && and RHS is lvalue.
     215                                auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >();
     216                                rhsCand->expr = new ast::CastExpr( rhsCand->expr, lhsType->base );
     217                                ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr );
     218                                ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr );
     219                                out.emplace_back( createFunc( spotter.fname, lobj, robj ) );
     220                                ltmp.emplace_back( std::move( lobj ) );
     221                                rtmp.emplace_back( std::move( robj ) );
     222
     223                                // Resolve the cast expression so that rhsCand return type is bound
     224                                // by the cast type as needed, and transfer the resulting environment.
     225                                ResolvExpr::CandidateFinder finder( spotter.crntFinder.context, env );
     226                                finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
     227                                assert( 1 == finder.candidates.size() );
     228                                env = std::move( finder.candidates.front()->env );
     229                        }
     230
     231                        splice( tmpDecls, ltmp );
     232                        splice( tmpDecls, rtmp );
     233
     234                        return out;
     235                }
     236        };
     237
     238        ResolvExpr::CandidateFinder & crntFinder;
     239        std::string fname;
     240        std::unique_ptr< Matcher > matcher;
     241
     242public:
     243        TupleAssignSpotter( ResolvExpr::CandidateFinder & f )
     244        : crntFinder( f ), fname(), matcher() {}
     245
     246        // Find left- and right-hand-sides for mass or multiple assignment.
     247        void spot(
     248                const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args
     249        ) {
     250                if ( auto op = expr->func.as< ast::NameExpr >() ) {
     251                        // Skip non-assignment functions.
     252                        if ( !CodeGen::isCtorDtorAssign( op->name ) ) return;
     253                        fname = op->name;
     254
     255                        // Handled by CandidateFinder if applicable (both odd cases).
     256                        if ( args.empty() || ( 1 == args.size() && CodeGen::isAssignment( fname ) ) ) {
     257                                return;
     258                        }
     259
     260                        // Look over all possible left-hand-side.
     261                        for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) {
     262                                // Skip non-tuple LHS.
     263                                if ( !refToTuple( lhsCand->expr ) ) continue;
     264
     265                                // Explode is aware of casts - ensure every LHS
     266                                // is sent into explode with a reference cast.
     267                                if ( !lhsCand->expr.as< ast::CastExpr >() ) {
     268                                        lhsCand->expr = new ast::CastExpr(
     269                                                lhsCand->expr, new ast::ReferenceType( lhsCand->expr->result ) );
    133270                                }
    134271
    135                                 PRINT( std::cerr << "new object: " << ret << std::endl; )
    136                                 return ret;
    137                         }
    138 
    139                         ast::UntypedExpr * createFunc(
    140                                 const std::string & fname, const ast::ObjectDecl * left,
    141                                 const ast::ObjectDecl * right
    142                         ) {
    143                                 assert( left );
    144                                 std::vector< ast::ptr< ast::Expr > > args;
    145                                 args.emplace_back( new ast::VariableExpr{ location, left } );
    146                                 if ( right ) { args.emplace_back( new ast::VariableExpr{ location, right } ); }
    147 
    148                                 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
    149                                         args.front() = new ast::AddressExpr{ location, args.front() };
    150                                         if ( right ) { args.back() = new ast::AddressExpr{ location, args.back() }; }
    151                                         return new ast::UntypedExpr{
    152                                                 location, new ast::NameExpr{ location, "?=?" }, std::move(args) };
    153                                 } else {
    154                                         return new ast::UntypedExpr{
    155                                                 location, new ast::NameExpr{ location, fname }, std::move(args) };
    156                                 }
    157                         }
    158                 };
    159 
    160                 /// Finds mass-assignment operations
    161                 struct MassAssignMatcher final : public Matcher {
    162                         MassAssignMatcher(
    163                                 TupleAssignSpotter & s, const CodeLocation & loc,
    164                                 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
    165                         : Matcher( s, loc, l, r ) {}
    166 
    167                         std::vector< ast::ptr< ast::Expr > > match() override {
    168                                 static UniqueName lhsNamer( "__massassign_L" );
    169                                 static UniqueName rhsNamer( "__massassign_R" );
    170                                 // empty tuple case falls into this matcher
    171                                 assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
    172 
    173                                 ast::ptr< ast::ObjectDecl > rtmp =
    174                                         rhs.size() == 1 ? newObject( rhsNamer, rhs.front()->expr ) : nullptr;
    175 
    176                                 std::vector< ast::ptr< ast::Expr > > out;
    177                                 for ( ResolvExpr::CandidateRef & lhsCand : lhs ) {
    178                                         // create a temporary object for each value in the LHS and create a call
    179                                         // involving the RHS
    180                                         ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr );
    181                                         out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) );
    182                                         tmpDecls.emplace_back( std::move( ltmp ) );
    183                                 }
    184                                 if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) );
    185 
    186                                 return out;
    187                         }
    188                 };
    189 
    190                 /// Finds multiple-assignment operations
    191                 struct MultipleAssignMatcher final : public Matcher {
    192                         MultipleAssignMatcher(
    193                                 TupleAssignSpotter & s, const CodeLocation & loc,
    194                                 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
    195                         : Matcher( s, loc, l, r ) {}
    196 
    197                         std::vector< ast::ptr< ast::Expr > > match() override {
    198                                 static UniqueName lhsNamer( "__multassign_L" );
    199                                 static UniqueName rhsNamer( "__multassign_R" );
    200 
    201                                 if ( lhs.size() != rhs.size() ) return {};
    202 
    203                                 // produce a new temporary object for each value in the LHS and RHS and pairwise
    204                                 // create the calls
    205                                 std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp;
    206 
    207                                 std::vector< ast::ptr< ast::Expr > > out;
    208                                 for ( unsigned i = 0; i < lhs.size(); ++i ) {
    209                                         ResolvExpr::CandidateRef & lhsCand = lhs[i];
    210                                         ResolvExpr::CandidateRef & rhsCand = rhs[i];
    211 
    212                                         // convert RHS to LHS type minus one reference -- important for case where LHS
    213                                         // is && and RHS is lvalue
    214                                         auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >();
    215                                         rhsCand->expr = new ast::CastExpr{ rhsCand->expr, lhsType->base };
    216                                         ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr );
    217                                         ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr );
    218                                         out.emplace_back( createFunc( spotter.fname, lobj, robj ) );
    219                                         ltmp.emplace_back( std::move( lobj ) );
    220                                         rtmp.emplace_back( std::move( robj ) );
    221 
    222                                         // resolve the cast expression so that rhsCand return type is bound by the cast
    223                                         // type as needed, and transfer the resulting environment
    224                                         ResolvExpr::CandidateFinder finder( spotter.crntFinder.context, env );
    225                                         finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
    226                                         assert( finder.candidates.size() == 1 );
    227                                         env = std::move( finder.candidates.front()->env );
    228                                 }
    229 
    230                                 splice( tmpDecls, ltmp );
    231                                 splice( tmpDecls, rtmp );
    232 
    233                                 return out;
    234                         }
    235                 };
    236 
    237                 ResolvExpr::CandidateFinder & crntFinder;
    238                 std::string fname;
    239                 std::unique_ptr< Matcher > matcher;
    240 
    241         public:
    242                 TupleAssignSpotter( ResolvExpr::CandidateFinder & f )
    243                 : crntFinder( f ), fname(), matcher() {}
    244 
    245                 // find left- and right-hand-sides for mass or multiple assignment
    246                 void spot(
    247                         const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args
    248                 ) {
    249                         if ( auto op = expr->func.as< ast::NameExpr >() ) {
    250                                 // skip non-assignment functions
    251                                 if ( ! CodeGen::isCtorDtorAssign( op->name ) ) return;
    252                                 fname = op->name;
    253 
    254                                 // handled by CandidateFinder if applicable (both odd cases)
    255                                 if ( args.empty() || ( args.size() == 1 && CodeGen::isAssignment( fname ) ) ) {
    256                                         return;
    257                                 }
    258 
    259                                 // look over all possible left-hand-side
    260                                 for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) {
    261                                         // skip non-tuple LHS
    262                                         if ( ! refToTuple( lhsCand->expr ) ) continue;
    263 
    264                                         // explode is aware of casts - ensure every LHS is sent into explode with a
    265                                         // reference cast
    266                                         if ( ! lhsCand->expr.as< ast::CastExpr >() ) {
    267                                                 lhsCand->expr = new ast::CastExpr{
    268                                                         lhsCand->expr, new ast::ReferenceType{ lhsCand->expr->result } };
    269                                         }
    270 
    271                                         // explode the LHS so that each field of a tuple-valued expr is assigned
    272                                         ResolvExpr::CandidateList lhs;
    273                                         explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true );
    274                                         for ( ResolvExpr::CandidateRef & cand : lhs ) {
    275                                                 // each LHS value must be a reference - some come in with a cast, if not
    276                                                 // just cast to reference here
    277                                                 if ( ! cand->expr->result.as< ast::ReferenceType >() ) {
    278                                                         cand->expr = new ast::CastExpr{
    279                                                                 cand->expr, new ast::ReferenceType{ cand->expr->result } };
    280                                                 }
    281                                         }
    282 
    283                                         if ( args.size() == 1 ) {
    284                                                 // mass default-initialization/destruction
    285                                                 ResolvExpr::CandidateList rhs{};
    286                                                 matcher.reset( new MassAssignMatcher{ *this, expr->location, lhs, rhs } );
    287                                                 match();
    288                                         } else if ( args.size() == 2 ) {
    289                                                 for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) {
    290                                                         ResolvExpr::CandidateList rhs;
    291                                                         if ( isTuple( rhsCand->expr ) ) {
    292                                                                 // multiple assignment
    293                                                                 explode( *rhsCand, crntFinder.context.symtab, back_inserter(rhs), true );
    294                                                                 matcher.reset(
    295                                                                         new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
    296                                                         } else {
    297                                                                 // mass assignment
    298                                                                 rhs.emplace_back( rhsCand );
    299                                                                 matcher.reset(
    300                                                                         new MassAssignMatcher{ *this, expr->location, lhs, rhs } );
    301                                                         }
    302                                                         match();
    303                                                 }
    304                                         } else {
    305                                                 // expand all possible RHS possibilities
    306                                                 std::vector< ResolvExpr::CandidateList > rhsCands;
    307                                                 combos(
    308                                                         std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) );
    309                                                 for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) {
    310                                                         // multiple assignment
    311                                                         ResolvExpr::CandidateList rhs;
    312                                                         explode( rhsCand, crntFinder.context.symtab, back_inserter(rhs), true );
    313                                                         matcher.reset(
    314                                                                 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
    315                                                         match();
    316                                                 }
     272                                // Explode the LHS so that each field of a tuple-valued expr is assigned.
     273                                ResolvExpr::CandidateList lhs;
     274                                explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true );
     275                                for ( ResolvExpr::CandidateRef & cand : lhs ) {
     276                                        // Each LHS value must be a reference - some come in
     277                                        // with a cast, if not just cast to reference here.
     278                                        if ( !cand->expr->result.as< ast::ReferenceType >() ) {
     279                                                cand->expr = new ast::CastExpr(
     280                                                        cand->expr, new ast::ReferenceType( cand->expr->result ) );
    317281                                        }
    318282                                }
    319                         }
    320                 }
    321 
    322                 void match() {
    323                         assert( matcher );
    324 
    325                         std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match();
    326 
    327                         if ( ! ( matcher->lhs.empty() && matcher->rhs.empty() ) ) {
    328                                 // if both LHS and RHS are empty than this is the empty tuple case, wherein it's
    329                                 // okay for newAssigns to be empty. Otherwise, return early so that no new
    330                                 // candidates are generated
    331                                 if ( newAssigns.empty() ) return;
    332                         }
    333 
    334                         ResolvExpr::CandidateList crnt;
    335                         // now resolve new assignments
    336                         for ( const ast::Expr * expr : newAssigns ) {
    337                                 PRINT(
    338                                         std::cerr << "== resolving tuple assign ==" << std::endl;
    339                                         std::cerr << expr << std::endl;
    340                                 )
    341 
    342                                 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env );
    343                                 finder.allowVoid = true;
    344 
    345                                 try {
    346                                         finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() );
    347                                 } catch (...) {
    348                                         // no match is not failure, just that this tuple assignment is invalid
    349                                         return;
     283
     284                                if ( 1 == args.size() ) {
     285                                        // Mass default-initialization/destruction.
     286                                        ResolvExpr::CandidateList rhs{};
     287                                        matcher.reset( new MassAssignMatcher( *this, expr->location, lhs, rhs ) );
     288                                        match();
     289                                } else if ( 2 == args.size() ) {
     290                                        for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) {
     291                                                ResolvExpr::CandidateList rhs;
     292                                                if ( isTuple( rhsCand->expr ) ) {
     293                                                        // Multiple assignment:
     294                                                        explode( *rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true );
     295                                                        matcher.reset(
     296                                                                new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) );
     297                                                } else {
     298                                                        // Mass assignment:
     299                                                        rhs.emplace_back( rhsCand );
     300                                                        matcher.reset(
     301                                                                new MassAssignMatcher( *this, expr->location, lhs, rhs ) );
     302                                                }
     303                                                match();
     304                                        }
     305                                } else {
     306                                        // Expand all possible RHS possibilities.
     307                                        std::vector< ResolvExpr::CandidateList > rhsCands;
     308                                        combos(
     309                                                std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) );
     310                                        for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) {
     311                                                // Multiple assignment:
     312                                                ResolvExpr::CandidateList rhs;
     313                                                explode( rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true );
     314                                                matcher.reset(
     315                                                        new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) );
     316                                                match();
     317                                        }
    350318                                }
    351 
    352                                 ResolvExpr::CandidateList & cands = finder.candidates;
    353                                 assert( cands.size() == 1 );
    354                                 assert( cands.front()->expr );
    355                                 crnt.emplace_back( std::move( cands.front() ) );
    356                         }
    357 
    358                         // extract expressions from the assignment candidates to produce a list of assignments
    359                         // that together form a sigle candidate
    360                         std::vector< ast::ptr< ast::Expr > > solved;
    361                         for ( ResolvExpr::CandidateRef & cand : crnt ) {
    362                                 solved.emplace_back( cand->expr );
    363                                 matcher->combineState( *cand );
    364                         }
    365 
    366                         crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >(
    367                                 new ast::TupleAssignExpr{
    368                                         matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) },
    369                                 std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ),
    370                                 ResolvExpr::sumCost( crnt ) + matcher->baseCost ) );
    371                 }
    372         };
     319                        }
     320                }
     321        }
     322
     323        void match() {
     324                assert( matcher );
     325
     326                std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match();
     327
     328                if ( !( matcher->lhs.empty() && matcher->rhs.empty() ) ) {
     329                        // If both LHS and RHS are empty than this is the empty tuple
     330                        // case, wherein it's okay for newAssigns to be empty. Otherwise,
     331                        // return early so that no new candidates are generated.
     332                        if ( newAssigns.empty() ) return;
     333                }
     334
     335                ResolvExpr::CandidateList crnt;
     336                // Now resolve new assignments.
     337                for ( const ast::Expr * expr : newAssigns ) {
     338                        PRINT(
     339                                std::cerr << "== resolving tuple assign ==" << std::endl;
     340                                std::cerr << expr << std::endl;
     341                        )
     342
     343                        ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env );
     344                        finder.allowVoid = true;
     345
     346                        try {
     347                                finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() );
     348                        } catch (...) {
     349                                // No match is not failure, just that this tuple assignment is invalid.
     350                                return;
     351                        }
     352
     353                        ResolvExpr::CandidateList & cands = finder.candidates;
     354                        assert( 1 == cands.size() );
     355                        assert( cands.front()->expr );
     356                        crnt.emplace_back( std::move( cands.front() ) );
     357                }
     358
     359                // extract expressions from the assignment candidates to produce a list of assignments
     360                // that together form a sigle candidate
     361                std::vector< ast::ptr< ast::Expr > > solved;
     362                for ( ResolvExpr::CandidateRef & cand : crnt ) {
     363                        solved.emplace_back( cand->expr );
     364                        matcher->combineState( *cand );
     365                }
     366
     367                crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >(
     368                        new ast::TupleAssignExpr(
     369                                matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) ),
     370                        std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ),
     371                        ResolvExpr::sumCost( crnt ) + matcher->baseCost ) );
     372        }
     373};
     374
    373375} // anonymous namespace
    374376
     
    377379        std::vector< ResolvExpr::CandidateFinder > & args
    378380) {
    379         TupleAssignSpotter spotter{ finder };
     381        TupleAssignSpotter spotter( finder );
    380382        spotter.spot( assign, args );
    381383}
  • src/Tuples/Tuples.cc

    r3f219eb r0f6d2884  
    2525namespace {
    2626
    27         /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives
    28         /// a very crude approximation, wherein any function call expression means the code may be
    29         /// impure.
    30     struct ImpurityDetector : public ast::WithShortCircuiting {
    31                 bool result = false;
     27/// Determines if impurity (read: side-effects) may exist in a piece of code.
     28/// Currently gives a very crude approximation, wherein almost any function
     29/// call expression means the code may be impure.
     30struct ImpurityDetector : public ast::WithShortCircuiting {
     31        bool result = false;
    3232
    33                 void previsit( ast::ApplicationExpr const * appExpr ) {
    34                         if ( ast::DeclWithType const * function = ast::getFunction( appExpr ) ) {
    35                                 if ( function->linkage == ast::Linkage::Intrinsic
    36                                                 && ( function->name == "*?" || function->name == "?[?]" ) ) {
    37                                         return;
    38                                 }
     33        void previsit( ast::ApplicationExpr const * appExpr ) {
     34                if ( ast::DeclWithType const * function = ast::getFunction( appExpr ) ) {
     35                        if ( function->linkage == ast::Linkage::Intrinsic
     36                                        && ( function->name == "*?" || function->name == "?[?]" ) ) {
     37                                return;
    3938                        }
    40                         result = true; visit_children = false;
    4139                }
    42                 void previsit( ast::UntypedExpr const * ) {
    43                         result = true; visit_children = false;
    44                 }
    45         };
     40                result = true; visit_children = false;
     41        }
     42        void previsit( ast::UntypedExpr const * ) {
     43                result = true; visit_children = false;
     44        }
     45};
    4646
    47         struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
    48                 using ImpurityDetector::previsit;
    49                 void previsit( ast::UniqueExpr const * ) {
    50                         visit_children = false;
    51                 }
    52         };
     47struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
     48        using ImpurityDetector::previsit;
     49        void previsit( ast::UniqueExpr const * ) {
     50                visit_children = false;
     51        }
     52};
     53
    5354} // namespace
    5455
  • src/Tuples/Tuples.h

    r3f219eb r0f6d2884  
    2424
    2525namespace Tuples {
    26         // TupleAssignment.cc
    27         void handleTupleAssignment(
    28                 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
    29                 std::vector< ResolvExpr::CandidateFinder > & args );
    3026
    31         // TupleExpansion.cc
    32         /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
    33         void expandMemberTuples( ast::TranslationUnit & translationUnit );
     27// TupleAssignment.cc
     28void handleTupleAssignment(
     29        ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     30        std::vector< ResolvExpr::CandidateFinder > & args );
    3431
    35         /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
    36         void expandTuples( ast::TranslationUnit & translaionUnit );
     32// TupleExpansion.cc
     33/// Expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate.
     34void expandMemberTuples( ast::TranslationUnit & translationUnit );
    3735
    38         /// replaces UniqueExprs with a temporary variable and one call
    39         void expandUniqueExpr( ast::TranslationUnit & translationUnit );
     36/// Replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
     37void expandTuples( ast::TranslationUnit & translaionUnit );
    4038
    41         /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
    42         const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
     39/// Replaces UniqueExprs with a temporary variable and one call.
     40void expandUniqueExpr( ast::TranslationUnit & translationUnit );
    4341
    44         /// returns a TypeInstType if `type` is a ttype, nullptr otherwise
    45         const ast::TypeInstType * isTtype( const ast::Type * type );
     42/// Returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types.
     43const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
    4644
    47         /// returns true if the expression may contain side-effects.
    48         bool maybeImpure( const ast::Expr * expr );
     45/// Returns a TypeInstType if `type` is a ttype, nullptr otherwise
     46const ast::TypeInstType * isTtype( const ast::Type * type );
    4947
    50         /// Returns true if the expression may contain side-effect,
    51         /// ignoring the presence of unique expressions.
    52         bool maybeImpureIgnoreUnique( const ast::Expr * expr );
     48/// Returns true if the expression may contain side-effects.
     49bool maybeImpure( const ast::Expr * expr );
     50
     51/// Returns true if the expression may contain side-effect,
     52/// ignoring the presence of unique expressions.
     53bool maybeImpureIgnoreUnique( const ast::Expr * expr );
     54
    5355} // namespace Tuples
    5456
Note: See TracChangeset for help on using the changeset viewer.