Changes in / [0f6d2884:3f219eb]


Ignore:
Location:
src
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • src/BasicTypes-gen.cc

    r0f6d2884 r3f219eb  
    443443        code << str.substr( 0, start );
    444444
     445        code << "\t\t\t// GENERATED BY " __FILE__ << endl;
    445446        code <<
    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;
     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;
    463463        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    464                 code << "\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl;
    465         } // for
    466         code << "}; // basicTypes" << endl;
     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
    467468
    468469        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", ManglerCommon );
  • src/SymTab/FixFunction.cc

    r0f6d2884 r3f219eb  
    2626
    2727namespace {
     28        struct FixFunction final : public ast::WithShortCircuiting {
     29                bool isVoid = false;
    2830
    29 struct FixFunction final : public ast::WithShortCircuiting {
    30         bool isVoid = false;
     31                void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    3132
    32         void previsit( const ast::FunctionDecl * ) { visit_children = false; }
     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                }
    3340
    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         }
     41                void previsit( const ast::ArrayType * ) { visit_children = false; }
    4142
    42         void previsit( const ast::ArrayType * ) { visit_children = false; }
     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                }
    4348
    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         }
     49                void previsit( const ast::FunctionType * ) { visit_children = false; }
    4950
    50         void previsit( const ast::FunctionType * ) { visit_children = false; }
     51                const ast::Type * postvisit( const ast::FunctionType * type ) {
     52                        return new ast::PointerType( type );
     53                }
    5154
    52         const ast::Type * postvisit( const ast::FunctionType * type ) {
    53                 return new ast::PointerType( type );
    54         }
     55                void previsit( const ast::VoidType * ) { isVoid = true; }
    5556
    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 
     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        };
    7169} // anonymous namespace
    7270
  • src/SymTab/FixFunction.h

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

    r0f6d2884 r3f219eb  
    2828
    2929namespace Mangle {
    30 
    31 namespace {
    32 
    33 /// Mangles names to a unique C identifier.
    34 struct 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; }
    63 private:
    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 
    75 private:
    76         Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    77                 int nextVarNum, const VarMapType& varNums );
    78         friend class ast::Pass<Mangler>;
    79 
    80 private:
    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 
    87 Mangler::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 
    93 Mangler::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 
    99 void Mangler::mangleDecl( const ast::DeclWithType * decl ) {
    100         bool wasTopLevel = isTopLevel;
    101         if ( isTopLevel ) {
    102                 varNums.clear();
    103                 nextVarNum = 0;
    104                 isTopLevel = false;
     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 );
    10588        }
    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 
    128 void Mangler::postvisit( const ast::ObjectDecl * decl ) {
    129         mangleDecl( decl );
    130 }
    131 
    132 void Mangler::postvisit( const ast::FunctionDecl * decl ) {
    133         mangleDecl( decl );
    134 }
    135 
    136 void Mangler::postvisit( const ast::VoidType * voidType ) {
    137         printQualifiers( voidType );
    138         mangleName += Encoding::void_t;
    139 }
    140 
    141 void 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 
    147 void 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 
    154 void 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 
    161 void 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 
    170 void 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 
    184 void 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 
    201 void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) {
    202         mangleRef( aggregateUseType, Encoding::struct_t );
    203 }
    204 
    205 void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) {
    206         mangleRef( aggregateUseType, Encoding::union_t );
    207 }
    208 
    209 void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) {
    210         mangleRef( aggregateUseType, Encoding::enum_t );
    211 }
    212 
    213 void 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 
    229 void Mangler::postvisit( const ast::TraitInstType * inst ) {
    230         printQualifiers( inst );
    231         mangleName += std::to_string( inst->name.size() ) + inst->name;
    232 }
    233 
    234 void 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 
    240 void 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 
    246 void Mangler::postvisit( const ast::ZeroType * ) {
    247         mangleName += Encoding::zero;
    248 }
    249 
    250 void Mangler::postvisit( const ast::OneType * ) {
    251         mangleName += Encoding::one;
    252 }
    253 
    254 void 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 
    270 void 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 
    288 void 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() );
    309                         }
    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 
    345 std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
    346         return ast::Pass<Mangler>::read( decl, mode );
    347 }
    348 
     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
     129                        }
     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
    349355} // namespace Mangle
    350356
  • src/SymTab/Mangler.h

    r0f6d2884 r3f219eb  
    3434}
    3535
     36namespace 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;
     42
     43                        extern const std::string void_t;
     44                        extern const std::string zero;
     45                        extern const std::string one;
     46
     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;
     64                };
     65        } // Mangler
     66} // SymTab
     67
    3668namespace Mangle {
    37 
    38 /// Bitflags for mangle Mode:
    39 enum {
    40         NoOverrideable  = 1 << 0,
    41         Type            = 1 << 1,
    42         NoGenericParams = 1 << 2
    43 };
    44 
    45 /// Bitflag type for mangle Mode:
    46 struct 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;
    53                 };
     69        /// Bitflags for mangle modes
     70        enum {
     71                NoOverrideable  = 1 << 0,
     72                Type            = 1 << 1,
     73                NoGenericParams = 1 << 2
    5474        };
    5575
    56         constexpr mangle_flags( unsigned int val ) : val(val) {}
    57 };
     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                };
    5886
    59 using Mode = bitfield<mangle_flags>;
     87                constexpr mangle_flags( unsigned int val ) : val(val) {}
     88        };
    6089
    61 /// Mangle declaration name.
    62 std::string mangle( const ast::Node * decl, Mode mode = {} );
     90        using Mode = bitfield<mangle_flags>;
    6391
    64 /// Most common mangle configuration for types.
    65 static inline std::string mangleType( const ast::Node * type ) {
    66         return mangle( type, { NoOverrideable | Type } );
    67 }
     92        /// Mangle declaration name.
     93        std::string mangle( const ast::Node * decl, Mode mode = {} );
    6894
    69 /// The substrings used in name mangling and demangling.
    70 namespace Encoding {
    71         extern const std::string manglePrefix;
    72         extern const std::string basicTypes[];
    73         extern const std::map<int, std::string> qualifiers;
     95        /// Most common mangle configuration for types.
     96        static inline std::string mangleType( const ast::Node * type ) {
     97                return mangle( type, { NoOverrideable | Type } );
     98        }
    7499
    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 
     100        namespace Encoding {
     101                using namespace SymTab::Mangler::Encoding;
     102        };
    98103}
    99104
  • src/SymTab/ManglerCommon.cc

    r0f6d2884 r3f219eb  
    1919#include "AST/Type.hpp"
    2020
    21 namespace Mangle {
     21namespace SymTab {
     22        namespace Mangler {
     23                namespace Encoding {
     24                        const std::string manglePrefix = "_X";
    2225
    23 namespace Encoding {
     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                        );
    2485
    25 const std::string manglePrefix = "_X";
     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                        };
    2692
    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
    43 const 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
    82 static_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 );
     93                        const std::string void_t = "v";
     94                        const std::string zero = "Z";
     95                        const std::string one = "O";
    8696
    87 const 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 };
     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";
    93103
    94 const std::string void_t = "v";
    95 const std::string zero = "Z";
    96 const std::string one = "O";
     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                        );
    97117
    98 const std::string function = "F";
    99 const std::string tuple = "T";
    100 const std::string pointer = "P";
    101 const std::string array = "A";
    102 const std::string qualifiedTypeStart = "N";
    103 const std::string qualifiedTypeEnd = "E";
     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";
    104122
    105 const std::string forall = "Q";
    106 const 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 };
    114 static_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 
    119 const std::string struct_t = "S";
    120 const std::string union_t = "U";
    121 const std::string enum_t = "M";
    122 const std::string type = "Y";
    123 
    124 const std::string autogen = "autogen__";
    125 const std::string intrinsic = "intrinsic__";
    126 
    127 } // namespace Encoding
    128 
    129 } // namespace Mangle
     123                        const std::string autogen = "autogen__";
     124                        const std::string intrinsic = "intrinsic__";
     125                } // namespace Encoding
     126        } // namespace Mangler
     127} // namespace SymTab
  • src/Tuples/TupleAssignment.cc

    r0f6d2884 r3f219eb  
    4646
    4747namespace {
    48 
    49 /// Checks if `expr` is of tuple type.
    50 bool 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.
    57 bool 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 );
     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() );
    6453        }
    65 }
    66 
    67 /// Dispatcher for tuple (multiple and mass) assignment operations.
    68 class 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() );
     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 );
    8463                }
    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 );
     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;
     115                                }
     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 );
     133                                }
     134
     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                                                }
     317                                        }
     318                                }
     319                        }
    94320                }
    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;
    114                                 }
    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                         }
     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;
     350                                }
     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 ) );
    158371                }
    159372        };
    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 
    242 public:
    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 ) );
    270                                 }
    271 
    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 ) );
    281                                         }
    282                                 }
    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                                         }
    318                                 }
    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 
    375373} // anonymous namespace
    376374
     
    379377        std::vector< ResolvExpr::CandidateFinder > & args
    380378) {
    381         TupleAssignSpotter spotter( finder );
     379        TupleAssignSpotter spotter{ finder };
    382380        spotter.spot( assign, args );
    383381}
  • src/Tuples/Tuples.cc

    r0f6d2884 r3f219eb  
    2525namespace {
    2626
    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.
    30 struct ImpurityDetector : public ast::WithShortCircuiting {
    31         bool result = false;
     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;
    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;
     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                                }
    3839                        }
     40                        result = true; visit_children = false;
    3941                }
    40                 result = true; visit_children = false;
    41         }
    42         void previsit( ast::UntypedExpr const * ) {
    43                 result = true; visit_children = false;
    44         }
    45 };
     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 };
    53 
     47        struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
     48                using ImpurityDetector::previsit;
     49                void previsit( ast::UniqueExpr const * ) {
     50                        visit_children = false;
     51                }
     52        };
    5453} // namespace
    5554
  • src/Tuples/Tuples.h

    r0f6d2884 r3f219eb  
    2424
    2525namespace Tuples {
     26        // TupleAssignment.cc
     27        void handleTupleAssignment(
     28                ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     29                std::vector< ResolvExpr::CandidateFinder > & args );
    2630
    27 // TupleAssignment.cc
    28 void handleTupleAssignment(
    29         ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
    30         std::vector< ResolvExpr::CandidateFinder > & args );
     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 );
    3134
    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.
    34 void expandMemberTuples( ast::TranslationUnit & translationUnit );
     35        /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
     36        void expandTuples( ast::TranslationUnit & translaionUnit );
    3537
    36 /// Replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
    37 void expandTuples( ast::TranslationUnit & translaionUnit );
     38        /// replaces UniqueExprs with a temporary variable and one call
     39        void expandUniqueExpr( ast::TranslationUnit & translationUnit );
    3840
    39 /// Replaces UniqueExprs with a temporary variable and one call.
    40 void expandUniqueExpr( ast::TranslationUnit & translationUnit );
     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 );
    4143
    42 /// Returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types.
    43 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
     44        /// returns a TypeInstType if `type` is a ttype, nullptr otherwise
     45        const ast::TypeInstType * isTtype( const ast::Type * type );
    4446
    45 /// Returns a TypeInstType if `type` is a ttype, nullptr otherwise
    46 const ast::TypeInstType * isTtype( const ast::Type * type );
     47        /// returns true if the expression may contain side-effects.
     48        bool maybeImpure( const ast::Expr * expr );
    4749
    48 /// Returns true if the expression may contain side-effects.
    49 bool maybeImpure( const ast::Expr * expr );
    50 
    51 /// Returns true if the expression may contain side-effect,
    52 /// ignoring the presence of unique expressions.
    53 bool maybeImpureIgnoreUnique( const ast::Expr * expr );
    54 
     50        /// Returns true if the expression may contain side-effect,
     51        /// ignoring the presence of unique expressions.
     52        bool maybeImpureIgnoreUnique( const ast::Expr * expr );
    5553} // namespace Tuples
    5654
Note: See TracChangeset for help on using the changeset viewer.