Changeset 0f6d2884
- Timestamp:
- Nov 17, 2023, 1:56:19 PM (13 months ago)
- Branches:
- master
- Children:
- 16e0dcb, 41606df1
- Parents:
- 3f219eb (diff), b0845f9 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- src
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
src/BasicTypes-gen.cc
r3f219eb r0f6d2884 443 443 code << str.substr( 0, start ); 444 444 445 code << "\t\t\t// GENERATED BY " __FILE__ << endl;446 445 code << 447 "\t\t\t// NOTES ON MANGLING:\n" 448 "\t\t\t// * Itanium spec says that Float80 encodes to \"e\" (like LongDouble), but the distinct lengths cause resolution problems.\n" 449 "\t\t\t// * Float128 is supposed to encode to \"g\", but I wanted it to mangle equal to LongDouble.\n" 450 "\t\t\t// * Mangling for non-standard complex types is by best guess\n" 451 "\t\t\t// * _FloatN is supposed to encode as \"DF\"N\"_\"; modified for same reason as above.\n" 452 "\t\t\t// * unused mangling identifiers:\n" 453 "\t\t\t// - \"z\" ellipsis\n" 454 "\t\t\t// - \"Dd\" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x)\n" 455 "\t\t\t// - \"De\" IEEE 754r 128-bit decimal floating point\n" 456 "\t\t\t// - \"Df\" IEEE 754r 32-bit decimal floating point\n" 457 "\t\t\t// - \"Dh\" IEEE 754r 16-bit decimal floating point (borrowed for _Float16)\n" 458 "\t\t\t// - \"DF\"N\"_\" ISO/IEC TS 18661 N-bit binary floating point (_FloatN)\n" 459 "\t\t\t// - \"Di\" char32_t\n" 460 "\t\t\t// - \"Ds\" char16_t\n"; 461 462 code << "\t\t\tconst std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl; 446 "// GENERATED BY " __FILE__ "\n" 447 "// NOTES ON MANGLING:\n" 448 "// * Itanium spec says that Float80 encodes to \"e\" (like LongDouble), but the distinct lengths cause resolution problems.\n" 449 "// * Float128 is supposed to encode to \"g\", but I wanted it to mangle equal to LongDouble.\n" 450 "// * Mangling for non-standard complex types is by best guess\n" 451 "// * _FloatN is supposed to encode as \"DF\"N\"_\"; modified for same reason as above.\n" 452 "// * unused mangling identifiers:\n" 453 "// - \"z\" ellipsis\n" 454 "// - \"Dd\" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x)\n" 455 "// - \"De\" IEEE 754r 128-bit decimal floating point\n" 456 "// - \"Df\" IEEE 754r 32-bit decimal floating point\n" 457 "// - \"Dh\" IEEE 754r 16-bit decimal floating point (borrowed for _Float16)\n" 458 "// - \"DF\"N\"_\" ISO/IEC TS 18661 N-bit binary floating point (_FloatN)\n" 459 "// - \"Di\" char32_t\n" 460 "// - \"Ds\" char16_t\n"; 461 462 code << "const std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl; 463 463 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 464 code << "\t\t\t\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl; 465 } // for 466 code << "\t\t\t}; // basicTypes" << endl; 467 code << "\t\t\t"; // indentation for end marker 464 code << "\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl; 465 } // for 466 code << "}; // basicTypes" << endl; 468 467 469 468 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", ManglerCommon ); -
src/SymTab/FixFunction.cc
r3f219eb r0f6d2884 26 26 27 27 namespace { 28 struct FixFunction final : public ast::WithShortCircuiting {29 bool isVoid = false;30 28 31 void previsit( const ast::FunctionDecl * ) { visit_children = false; } 29 struct FixFunction final : public ast::WithShortCircuiting { 30 bool isVoid = false; 32 31 33 const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) { 34 // Cannot handle cases with asserions. 35 assert( func->assertions.empty() ); 36 return new ast::ObjectDecl{ 37 func->location, func->name, new ast::PointerType( func->type ), nullptr, 38 func->storage, func->linkage, nullptr, copy( func->attributes ) }; 39 } 32 void previsit( const ast::FunctionDecl * ) { visit_children = false; } 40 33 41 void previsit( const ast::ArrayType * ) { visit_children = false; } 34 const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) { 35 // Cannot handle cases with asserions. 36 assert( func->assertions.empty() ); 37 return new ast::ObjectDecl{ 38 func->location, func->name, new ast::PointerType( func->type ), nullptr, 39 func->storage, func->linkage, nullptr, copy( func->attributes ) }; 40 } 42 41 43 const ast::Type * postvisit( const ast::ArrayType * array ) { 44 return new ast::PointerType{ 45 array->base, array->dimension, array->isVarLen, array->isStatic, 46 array->qualifiers }; 47 } 42 void previsit( const ast::ArrayType * ) { visit_children = false; } 48 43 49 void previsit( const ast::FunctionType * ) { visit_children = false; } 44 const ast::Type * postvisit( const ast::ArrayType * array ) { 45 return new ast::PointerType{ 46 array->base, array->dimension, array->isVarLen, array->isStatic, 47 array->qualifiers }; 48 } 50 49 51 const ast::Type * postvisit( const ast::FunctionType * type ) { 52 return new ast::PointerType( type ); 53 } 50 void previsit( const ast::FunctionType * ) { visit_children = false; } 54 51 55 void previsit( const ast::VoidType * ) { isVoid = true; } 52 const ast::Type * postvisit( const ast::FunctionType * type ) { 53 return new ast::PointerType( type ); 54 } 56 55 57 void previsit( const ast::BasicType * ) { visit_children = false; } 58 void previsit( const ast::PointerType * ) { visit_children = false; } 59 void previsit( const ast::StructInstType * ) { visit_children = false; } 60 void previsit( const ast::UnionInstType * ) { visit_children = false; } 61 void previsit( const ast::EnumInstType * ) { visit_children = false; } 62 void previsit( const ast::TraitInstType * ) { visit_children = false; } 63 void previsit( const ast::TypeInstType * ) { visit_children = false; } 64 void previsit( const ast::TupleType * ) { visit_children = false; } 65 void previsit( const ast::VarArgsType * ) { visit_children = false; } 66 void previsit( const ast::ZeroType * ) { visit_children = false; } 67 void previsit( const ast::OneType * ) { visit_children = false; } 68 }; 56 void previsit( const ast::VoidType * ) { isVoid = true; } 57 58 void previsit( const ast::BasicType * ) { visit_children = false; } 59 void previsit( const ast::PointerType * ) { visit_children = false; } 60 void previsit( const ast::StructInstType * ) { visit_children = false; } 61 void previsit( const ast::UnionInstType * ) { visit_children = false; } 62 void previsit( const ast::EnumInstType * ) { visit_children = false; } 63 void previsit( const ast::TraitInstType * ) { visit_children = false; } 64 void previsit( const ast::TypeInstType * ) { visit_children = false; } 65 void previsit( const ast::TupleType * ) { visit_children = false; } 66 void previsit( const ast::VarArgsType * ) { visit_children = false; } 67 void previsit( const ast::ZeroType * ) { visit_children = false; } 68 void previsit( const ast::OneType * ) { visit_children = false; } 69 }; 70 69 71 } // anonymous namespace 70 72 -
src/SymTab/FixFunction.h
r3f219eb r0f6d2884 22 22 23 23 namespace SymTab { 24 /// Returns declaration with function and array types replaced by equivalent pointer types. 25 /// Sets isVoid to true if type is void 26 const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ); 27 const ast::Type * fixFunction( const ast::Type * type, bool & isVoid ); 24 25 /// Returns declaration with function and array types replaced by equivalent pointer types. 26 /// Sets isVoid to true if type is void. 27 const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ); 28 const ast::Type * fixFunction( const ast::Type * type, bool & isVoid ); 29 28 30 } // namespace SymTab 29 31 -
src/SymTab/Mangler.cc
r3f219eb r0f6d2884 28 28 29 29 namespace Mangle { 30 namespace { 31 /// Mangles names to a unique C identifier 32 struct Mangler : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler>, public ast::WithGuards { 33 Mangler( Mangle::Mode mode ); 34 Mangler( const Mangler & ) = delete; 35 36 void previsit( const ast::Node * ) { visit_children = false; } 37 38 void postvisit( const ast::ObjectDecl * declaration ); 39 void postvisit( const ast::FunctionDecl * declaration ); 40 void postvisit( const ast::TypeDecl * declaration ); 41 42 void postvisit( const ast::VoidType * voidType ); 43 void postvisit( const ast::BasicType * basicType ); 44 void postvisit( const ast::PointerType * pointerType ); 45 void postvisit( const ast::ArrayType * arrayType ); 46 void postvisit( const ast::ReferenceType * refType ); 47 void postvisit( const ast::FunctionType * functionType ); 48 void postvisit( const ast::StructInstType * aggregateUseType ); 49 void postvisit( const ast::UnionInstType * aggregateUseType ); 50 void postvisit( const ast::EnumInstType * aggregateUseType ); 51 void postvisit( const ast::TypeInstType * aggregateUseType ); 52 void postvisit( const ast::TraitInstType * inst ); 53 void postvisit( const ast::TupleType * tupleType ); 54 void postvisit( const ast::VarArgsType * varArgsType ); 55 void postvisit( const ast::ZeroType * zeroType ); 56 void postvisit( const ast::OneType * oneType ); 57 void postvisit( const ast::QualifiedType * qualType ); 58 59 /// The result is the current constructed mangled name. 60 std::string result() const { return mangleName; } 61 private: 62 std::string mangleName; ///< Mangled name being constructed 63 typedef std::map< std::string, std::pair< int, int > > VarMapType; 64 VarMapType varNums; ///< Map of type variables to indices 65 int nextVarNum; ///< Next type variable index 66 bool isTopLevel; ///< Is the Mangler at the top level 67 bool mangleOverridable; ///< Specially mangle overridable built-in methods 68 bool typeMode; ///< Produce a unique mangled name for a type 69 bool mangleGenericParams; ///< Include generic parameters in name mangling if true 70 bool inFunctionType = false; ///< Include type qualifiers if false. 71 bool inQualifiedType = false; ///< Add start/end delimiters around qualified type 72 73 private: 74 Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 75 int nextVarNum, const VarMapType& varNums ); 76 friend class ast::Pass<Mangler>; 77 78 private: 79 void mangleDecl( const ast::DeclWithType *declaration ); 80 void mangleRef( const ast::BaseInstType *refType, const std::string & prefix ); 81 82 void printQualifiers( const ast::Type *type ); 83 }; // Mangler 84 } // namespace 85 86 std::string mangle( const ast::Node * decl, Mangle::Mode mode ) { 87 return ast::Pass<Mangler>::read( decl, mode ); 88 } 89 90 namespace { 91 Mangler::Mangler( Mangle::Mode mode ) 92 : nextVarNum( 0 ), isTopLevel( true ), 93 mangleOverridable ( ! mode.no_overrideable ), 94 typeMode ( mode.type ), 95 mangleGenericParams( ! mode.no_generic_params ) {} 96 97 Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 98 int nextVarNum, const VarMapType& varNums ) 99 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ), 100 mangleOverridable( mangleOverridable ), typeMode( typeMode ), 101 mangleGenericParams( mangleGenericParams ) {} 102 103 void Mangler::mangleDecl( const ast::DeclWithType * decl ) { 104 bool wasTopLevel = isTopLevel; 105 if ( isTopLevel ) { 106 varNums.clear(); 107 nextVarNum = 0; 108 isTopLevel = false; 109 } // if 110 mangleName += Encoding::manglePrefix; 111 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( decl->name ); 112 if ( opInfo ) { 113 mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName; 114 } else { 115 mangleName += std::to_string( decl->name.size() ) + decl->name; 116 } // if 117 decl->get_type()->accept( *visitor ); 118 if ( mangleOverridable && decl->linkage.is_overrideable ) { 119 // want to be able to override autogenerated and intrinsic routines, 120 // so they need a different name mangling 121 if ( decl->linkage == ast::Linkage::AutoGen ) { 122 mangleName += Encoding::autogen; 123 } else if ( decl->linkage == ast::Linkage::Intrinsic ) { 124 mangleName += Encoding::intrinsic; 125 } else { 126 // if we add another kind of overridable function, this has to change 127 assert( false && "unknown overrideable linkage" ); 128 } // if 30 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; 105 } 106 mangleName += Encoding::manglePrefix; 107 if ( auto opInfo = CodeGen::operatorLookup( decl->name ) ) { 108 mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName; 109 } else { 110 mangleName += std::to_string( decl->name.size() ) + decl->name; 111 } 112 decl->get_type()->accept( *visitor ); 113 if ( mangleOverridable && decl->linkage.is_overrideable ) { 114 // want to be able to override autogenerated and intrinsic routines, 115 // so they need a different name mangling 116 if ( decl->linkage == ast::Linkage::AutoGen ) { 117 mangleName += Encoding::autogen; 118 } else if ( decl->linkage == ast::Linkage::Intrinsic ) { 119 mangleName += Encoding::intrinsic; 120 } else { 121 // if we add another kind of overridable function, this has to change 122 assert( false && "unknown overrideable linkage" ); 123 } 124 } 125 isTopLevel = wasTopLevel; 126 } 127 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() ); 129 309 } 130 isTopLevel = wasTopLevel; 131 } 132 133 void Mangler::postvisit( const ast::ObjectDecl * decl ) { 134 mangleDecl( decl ); 135 } 136 137 void Mangler::postvisit( const ast::FunctionDecl * decl ) { 138 mangleDecl( decl ); 139 } 140 141 void Mangler::postvisit( const ast::VoidType * voidType ) { 142 printQualifiers( voidType ); 143 mangleName += Encoding::void_t; 144 } 145 146 void Mangler::postvisit( const ast::BasicType * basicType ) { 147 printQualifiers( basicType ); 148 assertf( basicType->kind < ast::BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind ); 149 mangleName += Encoding::basicTypes[ basicType->kind ]; 150 } 151 152 void Mangler::postvisit( const ast::PointerType * pointerType ) { 153 printQualifiers( pointerType ); 154 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers 155 if ( ! pointerType->base.as<ast::FunctionType>() ) mangleName += Encoding::pointer; 156 maybe_accept( pointerType->base.get(), *visitor ); 157 } 158 159 void Mangler::postvisit( const ast::ArrayType * arrayType ) { 160 // TODO: encode dimension 161 printQualifiers( arrayType ); 162 mangleName += Encoding::array + "0"; 163 arrayType->base->accept( *visitor ); 164 } 165 166 void Mangler::postvisit( const ast::ReferenceType * refType ) { 167 // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload. 168 // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.), 169 // by pretending every reference type is a function parameter. 170 GuardValue( inFunctionType ); 171 inFunctionType = true; 172 printQualifiers( refType ); 173 refType->base->accept( *visitor ); 174 } 175 176 void Mangler::postvisit( const ast::FunctionType * functionType ) { 177 printQualifiers( functionType ); 178 mangleName += Encoding::function; 179 // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters, 180 // since qualifiers on outermost parameter type do not differentiate function types, e.g., 181 // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different 182 GuardValue( inFunctionType ); 183 inFunctionType = true; 184 if (functionType->returns.empty()) mangleName += Encoding::void_t; 185 else accept_each( functionType->returns, *visitor ); 186 mangleName += "_"; 187 accept_each( functionType->params, *visitor ); 188 mangleName += "_"; 189 } 190 191 void Mangler::mangleRef( 192 const ast::BaseInstType * refType, const std::string & prefix ) { 193 printQualifiers( refType ); 194 195 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name; 196 197 if ( mangleGenericParams && ! refType->params.empty() ) { 198 mangleName += "_"; 199 for ( const ast::Expr * param : refType->params ) { 200 auto paramType = dynamic_cast< const ast::TypeExpr * >( param ); 201 assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param)); 202 paramType->type->accept( *visitor ); 203 } 204 mangleName += "_"; 205 } 206 } 207 208 void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) { 209 mangleRef( aggregateUseType, Encoding::struct_t ); 210 } 211 212 void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) { 213 mangleRef( aggregateUseType, Encoding::union_t ); 214 } 215 216 void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) { 217 mangleRef( aggregateUseType, Encoding::enum_t ); 218 } 219 220 void Mangler::postvisit( const ast::TypeInstType * typeInst ) { 221 VarMapType::iterator varNum = varNums.find( typeInst->name ); 222 if ( varNum == varNums.end() ) { 223 mangleRef( typeInst, Encoding::type ); 224 } else { 225 printQualifiers( typeInst ); 226 // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g. 227 // forall(dtype T) void f(T); 228 // forall(dtype S) void f(S); 229 // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they 230 // are first found and prefixing with the appropriate encoding for the type class. 231 assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second ); 232 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first ); 233 } // if 234 } 235 236 void Mangler::postvisit( const ast::TraitInstType * inst ) { 237 printQualifiers( inst ); 238 mangleName += std::to_string( inst->name.size() ) + inst->name; 239 } 240 241 void Mangler::postvisit( const ast::TupleType * tupleType ) { 242 printQualifiers( tupleType ); 243 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() ); 244 accept_each( tupleType->types, *visitor ); 245 } 246 247 void Mangler::postvisit( const ast::VarArgsType * varArgsType ) { 248 printQualifiers( varArgsType ); 249 static const std::string vargs = "__builtin_va_list"; 250 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs; 251 } 252 253 void Mangler::postvisit( const ast::ZeroType * ) { 254 mangleName += Encoding::zero; 255 } 256 257 void Mangler::postvisit( const ast::OneType * ) { 258 mangleName += Encoding::one; 259 } 260 261 void Mangler::postvisit( const ast::QualifiedType * qualType ) { 262 bool inqual = inQualifiedType; 263 if ( !inqual ) { 264 // N marks the start of a qualified type 265 inQualifiedType = true; 266 mangleName += Encoding::qualifiedTypeStart; 267 } 268 qualType->parent->accept( *visitor ); 269 qualType->child->accept( *visitor ); 270 if ( !inqual ) { 271 // E marks the end of a qualified type 272 inQualifiedType = false; 273 mangleName += Encoding::qualifiedTypeEnd; 274 } 275 } 276 277 void Mangler::postvisit( const ast::TypeDecl * decl ) { 278 // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be 279 // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa. 280 // Note: The current scheme may already work correctly for this case, I have not thought about this deeply 281 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed 282 // aside from the assert false. 283 assertf(false, "Mangler should not visit typedecl: %s", toCString(decl)); 284 assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind ); 285 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name; 286 } 287 288 // For debugging: 289 __attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) { 290 for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) { 291 os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl; 292 } // for 293 } 294 295 void Mangler::printQualifiers( const ast::Type * type ) { 296 // skip if not including qualifiers 297 if ( typeMode ) return; 298 auto funcType = dynamic_cast<const ast::FunctionType *>( type ); 299 if ( funcType && !funcType->forall.empty() ) { 300 std::list< std::string > assertionNames; 301 int dcount = 0, fcount = 0, vcount = 0, acount = 0; 302 mangleName += Encoding::forall; 303 for ( auto & decl : funcType->forall ) { 304 switch ( decl->kind ) { 305 case ast::TypeDecl::Dtype: 306 dcount++; 307 break; 308 case ast::TypeDecl::Ftype: 309 fcount++; 310 break; 311 case ast::TypeDecl::Ttype: 312 vcount++; 313 break; 314 default: 315 assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[decl->kind].c_str() ); 316 } // switch 317 varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind ); 318 } // for 319 for ( auto & assert : funcType->assertions ) { 320 assertionNames.push_back( ast::Pass<Mangler>::read( 321 assert->var.get(), 322 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) ); 323 acount++; 324 } // for 325 mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_"; 326 for ( const auto & a : assertionNames ) mangleName += a; 327 mangleName += "_"; 328 } // if 329 if ( ! inFunctionType ) { 330 // these qualifiers do not distinguish the outermost type of a function parameter 331 if ( type->is_const() ) { 332 mangleName += Encoding::qualifiers.at( ast::CV::Const ); 333 } // if 334 if ( type->is_volatile() ) { 335 mangleName += Encoding::qualifiers.at( ast::CV::Volatile ); 336 } // if 337 // Removed due to restrict not affecting function compatibility in GCC 338 // if ( type->get_isRestrict() ) { 339 // mangleName += "E"; 340 // } // if 341 if ( type->is_atomic() ) { 342 mangleName += Encoding::qualifiers.at( ast::CV::Atomic ); 343 } // if 344 } 345 if ( type->is_mutex() ) { 346 mangleName += Encoding::qualifiers.at( ast::CV::Mutex ); 347 } // if 348 if ( inFunctionType ) { 349 // turn off inFunctionType so that types can be differentiated for nested qualifiers 350 GuardValue( inFunctionType ); 351 inFunctionType = false; 352 } 353 } 354 } // namespace 310 varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind ); 311 } 312 for ( auto & assert : funcType->assertions ) { 313 assertionNames.push_back( ast::Pass<Mangler>::read( 314 assert->var.get(), 315 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) ); 316 acount++; 317 } 318 mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_"; 319 for ( const auto & a : assertionNames ) mangleName += a; 320 mangleName += "_"; 321 } 322 if ( !inFunctionType ) { 323 // These qualifiers do not distinguish the outermost type of a function parameter. 324 if ( type->is_const() ) { 325 mangleName += Encoding::qualifiers.at( ast::CV::Const ); 326 } 327 if ( type->is_volatile() ) { 328 mangleName += Encoding::qualifiers.at( ast::CV::Volatile ); 329 } 330 if ( type->is_atomic() ) { 331 mangleName += Encoding::qualifiers.at( ast::CV::Atomic ); 332 } 333 } 334 if ( type->is_mutex() ) { 335 mangleName += Encoding::qualifiers.at( ast::CV::Mutex ); 336 } 337 if ( inFunctionType ) { 338 // Turn off inFunctionType so that types can be differentiated for nested qualifiers. 339 GuardValue( inFunctionType ) = false; 340 } 341 } 342 343 } // namespace 344 345 std::string mangle( const ast::Node * decl, Mangle::Mode mode ) { 346 return ast::Pass<Mangler>::read( decl, mode ); 347 } 348 355 349 } // namespace Mangle 356 350 -
src/SymTab/Mangler.h
r3f219eb r0f6d2884 34 34 } 35 35 36 namespace SymTab { 37 namespace Mangler { 38 namespace Encoding { 39 extern const std::string manglePrefix; 40 extern const std::string basicTypes[]; 41 extern const std::map<int, std::string> qualifiers; 36 namespace Mangle { 42 37 43 extern const std::string void_t; 44 extern const std::string zero; 45 extern const std::string one; 38 /// Bitflags for mangle Mode: 39 enum { 40 NoOverrideable = 1 << 0, 41 Type = 1 << 1, 42 NoGenericParams = 1 << 2 43 }; 46 44 47 extern const std::string function; 48 extern const std::string tuple; 49 extern const std::string pointer; 50 extern const std::string array; 51 extern const std::string qualifiedTypeStart; 52 extern const std::string qualifiedTypeEnd; 53 54 extern const std::string forall; 55 extern const std::string typeVariables[]; 56 57 extern const std::string struct_t; 58 extern const std::string union_t; 59 extern const std::string enum_t; 60 extern const std::string type; 61 62 extern const std::string autogen; 63 extern const std::string intrinsic; 45 /// Bitflag type for mangle Mode: 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; 64 53 }; 65 } // Mangler66 } // SymTab67 68 namespace Mangle {69 /// Bitflags for mangle modes70 enum {71 NoOverrideable = 1 << 0,72 Type = 1 << 1,73 NoGenericParams = 1 << 274 54 }; 75 55 76 /// Bitflag type for mangler modes 77 struct mangle_flags { 78 union { 79 unsigned int val; 80 struct { 81 bool no_overrideable : 1; 82 bool type : 1; 83 bool no_generic_params : 1; 84 }; 85 }; 56 constexpr mangle_flags( unsigned int val ) : val(val) {} 57 }; 86 58 87 constexpr mangle_flags( unsigned int val ) : val(val) {} 88 }; 59 using Mode = bitfield<mangle_flags>; 89 60 90 using Mode = bitfield<mangle_flags>; 61 /// Mangle declaration name. 62 std::string mangle( const ast::Node * decl, Mode mode = {} ); 91 63 92 /// Mangle declaration name. 93 std::string mangle( const ast::Node * decl, Mode mode = {} ); 64 /// Most common mangle configuration for types. 65 static inline std::string mangleType( const ast::Node * type ) { 66 return mangle( type, { NoOverrideable | Type } ); 67 } 94 68 95 /// Most common mangle configuration for types. 96 static inline std::string mangleType( const ast::Node * type ) { 97 return mangle( type, { NoOverrideable | Type } ); 98 } 69 /// The substrings used in name mangling and demangling. 70 namespace Encoding { 71 extern const std::string manglePrefix; 72 extern const std::string basicTypes[]; 73 extern const std::map<int, std::string> qualifiers; 99 74 100 namespace Encoding { 101 using namespace SymTab::Mangler::Encoding; 102 }; 75 extern const std::string void_t; 76 extern const std::string zero; 77 extern const std::string one; 78 79 extern const std::string function; 80 extern const std::string tuple; 81 extern const std::string pointer; 82 extern const std::string array; 83 extern const std::string qualifiedTypeStart; 84 extern const std::string qualifiedTypeEnd; 85 86 extern const std::string forall; 87 extern const std::string typeVariables[]; 88 89 extern const std::string struct_t; 90 extern const std::string union_t; 91 extern const std::string enum_t; 92 extern const std::string type; 93 94 extern const std::string autogen; 95 extern const std::string intrinsic; 96 } 97 103 98 } 104 99 -
src/SymTab/ManglerCommon.cc
r3f219eb r0f6d2884 19 19 #include "AST/Type.hpp" 20 20 21 namespace SymTab { 22 namespace Mangler { 23 namespace Encoding { 24 const std::string manglePrefix = "_X"; 21 namespace Mangle { 25 22 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 ); 23 namespace Encoding { 85 24 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 }; 25 const std::string manglePrefix = "_X"; 92 26 93 const std::string void_t = "v"; 94 const std::string zero = "Z"; 95 const std::string one = "O"; 27 // GENERATED START, DO NOT EDIT 28 // GENERATED BY BasicTypes-gen.cc 29 // NOTES ON MANGLING: 30 // * Itanium spec says that Float80 encodes to "e" (like LongDouble), but the distinct lengths cause resolution problems. 31 // * Float128 is supposed to encode to "g", but I wanted it to mangle equal to LongDouble. 32 // * Mangling for non-standard complex types is by best guess 33 // * _FloatN is supposed to encode as "DF"N"_"; modified for same reason as above. 34 // * unused mangling identifiers: 35 // - "z" ellipsis 36 // - "Dd" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x) 37 // - "De" IEEE 754r 128-bit decimal floating point 38 // - "Df" IEEE 754r 32-bit decimal floating point 39 // - "Dh" IEEE 754r 16-bit decimal floating point (borrowed for _Float16) 40 // - "DF"N"_" ISO/IEC TS 18661 N-bit binary floating point (_FloatN) 41 // - "Di" char32_t 42 // - "Ds" char16_t 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 ); 96 86 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";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 }; 103 93 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 ); 94 const std::string void_t = "v"; 95 const std::string zero = "Z"; 96 const std::string one = "O"; 117 97 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"; 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"; 122 104 123 const std::string autogen = "autogen__"; 124 const std::string intrinsic = "intrinsic__"; 125 } // namespace Encoding 126 } // namespace Mangler 127 } // namespace SymTab 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 -
src/Tuples/TupleAssignment.cc
r3f219eb r0f6d2884 46 46 47 47 namespace { 48 /// true if `expr` is of tuple type 49 bool isTuple( const ast::Expr * expr ) { 50 if ( ! expr ) return false; 51 assert( expr->result ); 52 return dynamic_cast< const ast::TupleType * >( expr->result->stripReferences() ); 48 49 /// Checks if `expr` is of tuple type. 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 ); 53 64 } 54 55 /// true if `expr` is of tuple type or a reference to one 56 bool refToTuple( const ast::Expr * expr ) { 57 assert( expr->result ); 58 // check for function returning tuple of reference types 59 if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) { 60 return refToTuple( castExpr->arg ); 61 } else { 62 return isTuple( expr ); 63 } 64 } 65 66 /// Dispatcher for tuple (multiple and mass) assignment operations 67 class TupleAssignSpotter final { 68 /// Actually finds tuple assignment operations, by subclass 69 struct Matcher { 70 ResolvExpr::CandidateList lhs, rhs; 71 TupleAssignSpotter & spotter; 72 CodeLocation location; 73 ResolvExpr::Cost baseCost; 74 std::vector< ast::ptr< ast::ObjectDecl > > tmpDecls; 75 ast::TypeEnvironment env; 76 ast::OpenVarSet open; 77 ast::AssertionSet need; 78 79 void combineState( const ResolvExpr::Candidate & cand ) { 80 env.simpleCombine( cand.env ); 81 ast::mergeOpenVars( open, cand.open ); 82 need.insert( cand.need.begin(), cand.need.end() ); 83 } 84 85 Matcher( 86 TupleAssignSpotter & s, const CodeLocation & loc, 87 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 88 : lhs( l ), rhs( r ), spotter( s ), location( loc ), 89 baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ), tmpDecls(), 90 env(), open(), need() { 91 for ( auto & cand : lhs ) combineState( *cand ); 92 for ( auto & cand : rhs ) combineState( *cand ); 93 } 94 virtual ~Matcher() = default; 95 96 virtual std::vector< ast::ptr< ast::Expr > > match() = 0; 97 98 /// removes environments from subexpressions within statement expressions, which could 99 /// throw off later passes like those in Box which rely on PolyMutator, and adds the 100 /// bindings to the env 101 struct EnvRemover { 102 /// environment to hoist ExprStmt environments to 103 ast::TypeEnvironment & tenv; 104 105 EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {} 106 107 const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) { 108 if ( stmt->expr->env ) { 109 tenv.add( *stmt->expr->env ); 110 ast::ExprStmt * mut = mutate( stmt ); 111 mut->expr.get_and_mutate()->env = nullptr; 112 return mut; 113 } 114 return stmt; 65 } 66 67 /// Dispatcher for tuple (multiple and mass) assignment operations. 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() ); 84 } 85 86 Matcher( 87 TupleAssignSpotter & s, const CodeLocation & loc, 88 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 89 : lhs( l ), rhs( r ), spotter( s ), location( loc ), 90 baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ), tmpDecls(), 91 env(), open(), need() { 92 for ( auto & cand : lhs ) combineState( *cand ); 93 for ( auto & cand : rhs ) combineState( *cand ); 94 } 95 virtual ~Matcher() = default; 96 97 virtual std::vector< ast::ptr< ast::Expr > > match() = 0; 98 99 /// Removes environments from subexpressions within statement expressions, which could 100 /// throw off later passes like those in Box which rely on PolyMutator, and adds the 101 /// bindings to the env. 102 struct EnvRemover { 103 /// Environment to hoist ExprStmt environments to. 104 ast::TypeEnvironment & tenv; 105 106 EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {} 107 108 const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) { 109 if ( stmt->expr->env ) { 110 tenv.add( *stmt->expr->env ); 111 ast::ExprStmt * mut = mutate( stmt ); 112 mut->expr.get_and_mutate()->env = nullptr; 113 return mut; 115 114 } 116 }; 117 118 ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) { 119 assert( expr->result && ! expr->result->isVoid() ); 120 121 ast::ObjectDecl * ret = new ast::ObjectDecl{ 122 location, namer.newName(), expr->result, new ast::SingleInit{ location, expr }, 123 ast::Storage::Classes{}, ast::Linkage::Cforall }; 124 125 // if expression type is a reference, just need an initializer, otherwise construct 126 if ( ! expr->result.as< ast::ReferenceType >() ) { 127 // resolve ctor/dtor for the new object 128 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 129 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.context ); 130 // remove environments from subexpressions of stmtExpr 131 ast::Pass< EnvRemover > rm{ env }; 132 ret->init = ctorInit->accept( rm ); 115 return stmt; 116 } 117 }; 118 119 ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) { 120 assert( expr->result && !expr->result->isVoid() ); 121 122 ast::ObjectDecl * ret = new ast::ObjectDecl( 123 location, namer.newName(), expr->result, new ast::SingleInit( location, expr ), 124 ast::Storage::Classes{}, ast::Linkage::Cforall ); 125 126 // If expression type is a reference, just need an initializer, otherwise construct. 127 if ( ! expr->result.as< ast::ReferenceType >() ) { 128 // Resolve ctor/dtor for the new object. 129 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 130 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.context ); 131 // Remove environments from subexpressions of stmtExpr. 132 ast::Pass< EnvRemover > rm( env ); 133 ret->init = ctorInit->accept( rm ); 134 } 135 136 PRINT( std::cerr << "new object: " << ret << std::endl; ) 137 return ret; 138 } 139 140 ast::UntypedExpr * createFunc( 141 const std::string & fname, const ast::ObjectDecl * left, 142 const ast::ObjectDecl * right 143 ) { 144 assert( left ); 145 std::vector< ast::ptr< ast::Expr > > args; 146 args.emplace_back( new ast::VariableExpr( location, left ) ); 147 if ( right ) { args.emplace_back( new ast::VariableExpr( location, right ) ); } 148 149 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) { 150 args.front() = new ast::AddressExpr( location, args.front() ); 151 if ( right ) { args.back() = new ast::AddressExpr( location, args.back() ); } 152 return new ast::UntypedExpr( 153 location, new ast::NameExpr( location, "?=?" ), std::move( args ) ); 154 } else { 155 return new ast::UntypedExpr( 156 location, new ast::NameExpr( location, fname ), std::move( args ) ); 157 } 158 } 159 }; 160 161 /// Finds mass-assignment operations. 162 struct MassAssignMatcher final : public Matcher { 163 MassAssignMatcher( 164 TupleAssignSpotter & s, const CodeLocation & loc, 165 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 166 : Matcher( s, loc, l, r ) {} 167 168 std::vector< ast::ptr< ast::Expr > > match() override { 169 static UniqueName lhsNamer( "__massassign_L" ); 170 static UniqueName rhsNamer( "__massassign_R" ); 171 // Empty tuple case falls into this matcher. 172 assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 ); 173 174 ast::ptr< ast::ObjectDecl > rtmp = 175 1 == rhs.size() ? newObject( rhsNamer, rhs.front()->expr ) : nullptr; 176 177 std::vector< ast::ptr< ast::Expr > > out; 178 for ( ResolvExpr::CandidateRef & lhsCand : lhs ) { 179 // Create a temporary object for each value in 180 // the LHS and create a call involving the RHS. 181 ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr ); 182 out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) ); 183 tmpDecls.emplace_back( std::move( ltmp ) ); 184 } 185 if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) ); 186 187 return out; 188 } 189 }; 190 191 /// Finds multiple-assignment operations. 192 struct MultipleAssignMatcher final : public Matcher { 193 MultipleAssignMatcher( 194 TupleAssignSpotter & s, const CodeLocation & loc, 195 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 196 : Matcher( s, loc, l, r ) {} 197 198 std::vector< ast::ptr< ast::Expr > > match() override { 199 static UniqueName lhsNamer( "__multassign_L" ); 200 static UniqueName rhsNamer( "__multassign_R" ); 201 202 if ( lhs.size() != rhs.size() ) return {}; 203 204 // Produce a new temporary object for each value in 205 // the LHS and RHS and pairwise create the calls. 206 std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp; 207 208 std::vector< ast::ptr< ast::Expr > > out; 209 for ( unsigned i = 0; i < lhs.size(); ++i ) { 210 ResolvExpr::CandidateRef & lhsCand = lhs[i]; 211 ResolvExpr::CandidateRef & rhsCand = rhs[i]; 212 213 // Convert RHS to LHS type minus one reference -- 214 // important for case where LHS is && and RHS is lvalue. 215 auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >(); 216 rhsCand->expr = new ast::CastExpr( rhsCand->expr, lhsType->base ); 217 ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr ); 218 ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr ); 219 out.emplace_back( createFunc( spotter.fname, lobj, robj ) ); 220 ltmp.emplace_back( std::move( lobj ) ); 221 rtmp.emplace_back( std::move( robj ) ); 222 223 // Resolve the cast expression so that rhsCand return type is bound 224 // by the cast type as needed, and transfer the resulting environment. 225 ResolvExpr::CandidateFinder finder( spotter.crntFinder.context, env ); 226 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() ); 227 assert( 1 == finder.candidates.size() ); 228 env = std::move( finder.candidates.front()->env ); 229 } 230 231 splice( tmpDecls, ltmp ); 232 splice( tmpDecls, rtmp ); 233 234 return out; 235 } 236 }; 237 238 ResolvExpr::CandidateFinder & crntFinder; 239 std::string fname; 240 std::unique_ptr< Matcher > matcher; 241 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 ) ); 133 270 } 134 271 135 PRINT( std::cerr << "new object: " << ret << std::endl; ) 136 return ret; 137 } 138 139 ast::UntypedExpr * createFunc( 140 const std::string & fname, const ast::ObjectDecl * left, 141 const ast::ObjectDecl * right 142 ) { 143 assert( left ); 144 std::vector< ast::ptr< ast::Expr > > args; 145 args.emplace_back( new ast::VariableExpr{ location, left } ); 146 if ( right ) { args.emplace_back( new ast::VariableExpr{ location, right } ); } 147 148 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) { 149 args.front() = new ast::AddressExpr{ location, args.front() }; 150 if ( right ) { args.back() = new ast::AddressExpr{ location, args.back() }; } 151 return new ast::UntypedExpr{ 152 location, new ast::NameExpr{ location, "?=?" }, std::move(args) }; 153 } else { 154 return new ast::UntypedExpr{ 155 location, new ast::NameExpr{ location, fname }, std::move(args) }; 156 } 157 } 158 }; 159 160 /// Finds mass-assignment operations 161 struct MassAssignMatcher final : public Matcher { 162 MassAssignMatcher( 163 TupleAssignSpotter & s, const CodeLocation & loc, 164 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 165 : Matcher( s, loc, l, r ) {} 166 167 std::vector< ast::ptr< ast::Expr > > match() override { 168 static UniqueName lhsNamer( "__massassign_L" ); 169 static UniqueName rhsNamer( "__massassign_R" ); 170 // empty tuple case falls into this matcher 171 assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 ); 172 173 ast::ptr< ast::ObjectDecl > rtmp = 174 rhs.size() == 1 ? newObject( rhsNamer, rhs.front()->expr ) : nullptr; 175 176 std::vector< ast::ptr< ast::Expr > > out; 177 for ( ResolvExpr::CandidateRef & lhsCand : lhs ) { 178 // create a temporary object for each value in the LHS and create a call 179 // involving the RHS 180 ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr ); 181 out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) ); 182 tmpDecls.emplace_back( std::move( ltmp ) ); 183 } 184 if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) ); 185 186 return out; 187 } 188 }; 189 190 /// Finds multiple-assignment operations 191 struct MultipleAssignMatcher final : public Matcher { 192 MultipleAssignMatcher( 193 TupleAssignSpotter & s, const CodeLocation & loc, 194 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 195 : Matcher( s, loc, l, r ) {} 196 197 std::vector< ast::ptr< ast::Expr > > match() override { 198 static UniqueName lhsNamer( "__multassign_L" ); 199 static UniqueName rhsNamer( "__multassign_R" ); 200 201 if ( lhs.size() != rhs.size() ) return {}; 202 203 // produce a new temporary object for each value in the LHS and RHS and pairwise 204 // create the calls 205 std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp; 206 207 std::vector< ast::ptr< ast::Expr > > out; 208 for ( unsigned i = 0; i < lhs.size(); ++i ) { 209 ResolvExpr::CandidateRef & lhsCand = lhs[i]; 210 ResolvExpr::CandidateRef & rhsCand = rhs[i]; 211 212 // convert RHS to LHS type minus one reference -- important for case where LHS 213 // is && and RHS is lvalue 214 auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >(); 215 rhsCand->expr = new ast::CastExpr{ rhsCand->expr, lhsType->base }; 216 ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr ); 217 ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr ); 218 out.emplace_back( createFunc( spotter.fname, lobj, robj ) ); 219 ltmp.emplace_back( std::move( lobj ) ); 220 rtmp.emplace_back( std::move( robj ) ); 221 222 // resolve the cast expression so that rhsCand return type is bound by the cast 223 // type as needed, and transfer the resulting environment 224 ResolvExpr::CandidateFinder finder( spotter.crntFinder.context, env ); 225 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() ); 226 assert( finder.candidates.size() == 1 ); 227 env = std::move( finder.candidates.front()->env ); 228 } 229 230 splice( tmpDecls, ltmp ); 231 splice( tmpDecls, rtmp ); 232 233 return out; 234 } 235 }; 236 237 ResolvExpr::CandidateFinder & crntFinder; 238 std::string fname; 239 std::unique_ptr< Matcher > matcher; 240 241 public: 242 TupleAssignSpotter( ResolvExpr::CandidateFinder & f ) 243 : crntFinder( f ), fname(), matcher() {} 244 245 // find left- and right-hand-sides for mass or multiple assignment 246 void spot( 247 const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args 248 ) { 249 if ( auto op = expr->func.as< ast::NameExpr >() ) { 250 // skip non-assignment functions 251 if ( ! CodeGen::isCtorDtorAssign( op->name ) ) return; 252 fname = op->name; 253 254 // handled by CandidateFinder if applicable (both odd cases) 255 if ( args.empty() || ( args.size() == 1 && CodeGen::isAssignment( fname ) ) ) { 256 return; 257 } 258 259 // look over all possible left-hand-side 260 for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) { 261 // skip non-tuple LHS 262 if ( ! refToTuple( lhsCand->expr ) ) continue; 263 264 // explode is aware of casts - ensure every LHS is sent into explode with a 265 // reference cast 266 if ( ! lhsCand->expr.as< ast::CastExpr >() ) { 267 lhsCand->expr = new ast::CastExpr{ 268 lhsCand->expr, new ast::ReferenceType{ lhsCand->expr->result } }; 269 } 270 271 // explode the LHS so that each field of a tuple-valued expr is assigned 272 ResolvExpr::CandidateList lhs; 273 explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true ); 274 for ( ResolvExpr::CandidateRef & cand : lhs ) { 275 // each LHS value must be a reference - some come in with a cast, if not 276 // just cast to reference here 277 if ( ! cand->expr->result.as< ast::ReferenceType >() ) { 278 cand->expr = new ast::CastExpr{ 279 cand->expr, new ast::ReferenceType{ cand->expr->result } }; 280 } 281 } 282 283 if ( args.size() == 1 ) { 284 // mass default-initialization/destruction 285 ResolvExpr::CandidateList rhs{}; 286 matcher.reset( new MassAssignMatcher{ *this, expr->location, lhs, rhs } ); 287 match(); 288 } else if ( args.size() == 2 ) { 289 for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) { 290 ResolvExpr::CandidateList rhs; 291 if ( isTuple( rhsCand->expr ) ) { 292 // multiple assignment 293 explode( *rhsCand, crntFinder.context.symtab, back_inserter(rhs), true ); 294 matcher.reset( 295 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); 296 } else { 297 // mass assignment 298 rhs.emplace_back( rhsCand ); 299 matcher.reset( 300 new MassAssignMatcher{ *this, expr->location, lhs, rhs } ); 301 } 302 match(); 303 } 304 } else { 305 // expand all possible RHS possibilities 306 std::vector< ResolvExpr::CandidateList > rhsCands; 307 combos( 308 std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) ); 309 for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) { 310 // multiple assignment 311 ResolvExpr::CandidateList rhs; 312 explode( rhsCand, crntFinder.context.symtab, back_inserter(rhs), true ); 313 matcher.reset( 314 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); 315 match(); 316 } 272 // Explode the LHS so that each field of a tuple-valued expr is assigned. 273 ResolvExpr::CandidateList lhs; 274 explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true ); 275 for ( ResolvExpr::CandidateRef & cand : lhs ) { 276 // Each LHS value must be a reference - some come in 277 // with a cast, if not just cast to reference here. 278 if ( !cand->expr->result.as< ast::ReferenceType >() ) { 279 cand->expr = new ast::CastExpr( 280 cand->expr, new ast::ReferenceType( cand->expr->result ) ); 317 281 } 318 282 } 319 } 320 } 321 322 void match() { 323 assert( matcher ); 324 325 std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match(); 326 327 if ( ! ( matcher->lhs.empty() && matcher->rhs.empty() ) ) { 328 // if both LHS and RHS are empty than this is the empty tuple case, wherein it's 329 // okay for newAssigns to be empty. Otherwise, return early so that no new 330 // candidates are generated 331 if ( newAssigns.empty() ) return; 332 } 333 334 ResolvExpr::CandidateList crnt; 335 // now resolve new assignments 336 for ( const ast::Expr * expr : newAssigns ) { 337 PRINT( 338 std::cerr << "== resolving tuple assign ==" << std::endl; 339 std::cerr << expr << std::endl; 340 ) 341 342 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env ); 343 finder.allowVoid = true; 344 345 try { 346 finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() ); 347 } catch (...) { 348 // no match is not failure, just that this tuple assignment is invalid 349 return; 283 284 if ( 1 == args.size() ) { 285 // Mass default-initialization/destruction. 286 ResolvExpr::CandidateList rhs{}; 287 matcher.reset( new MassAssignMatcher( *this, expr->location, lhs, rhs ) ); 288 match(); 289 } else if ( 2 == args.size() ) { 290 for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) { 291 ResolvExpr::CandidateList rhs; 292 if ( isTuple( rhsCand->expr ) ) { 293 // Multiple assignment: 294 explode( *rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true ); 295 matcher.reset( 296 new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) ); 297 } else { 298 // Mass assignment: 299 rhs.emplace_back( rhsCand ); 300 matcher.reset( 301 new MassAssignMatcher( *this, expr->location, lhs, rhs ) ); 302 } 303 match(); 304 } 305 } else { 306 // Expand all possible RHS possibilities. 307 std::vector< ResolvExpr::CandidateList > rhsCands; 308 combos( 309 std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) ); 310 for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) { 311 // Multiple assignment: 312 ResolvExpr::CandidateList rhs; 313 explode( rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true ); 314 matcher.reset( 315 new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) ); 316 match(); 317 } 350 318 } 351 352 ResolvExpr::CandidateList & cands = finder.candidates; 353 assert( cands.size() == 1 ); 354 assert( cands.front()->expr ); 355 crnt.emplace_back( std::move( cands.front() ) ); 356 } 357 358 // extract expressions from the assignment candidates to produce a list of assignments 359 // that together form a sigle candidate 360 std::vector< ast::ptr< ast::Expr > > solved; 361 for ( ResolvExpr::CandidateRef & cand : crnt ) { 362 solved.emplace_back( cand->expr ); 363 matcher->combineState( *cand ); 364 } 365 366 crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >( 367 new ast::TupleAssignExpr{ 368 matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) }, 369 std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ), 370 ResolvExpr::sumCost( crnt ) + matcher->baseCost ) ); 371 } 372 }; 319 } 320 } 321 } 322 323 void match() { 324 assert( matcher ); 325 326 std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match(); 327 328 if ( !( matcher->lhs.empty() && matcher->rhs.empty() ) ) { 329 // If both LHS and RHS are empty than this is the empty tuple 330 // case, wherein it's okay for newAssigns to be empty. Otherwise, 331 // return early so that no new candidates are generated. 332 if ( newAssigns.empty() ) return; 333 } 334 335 ResolvExpr::CandidateList crnt; 336 // Now resolve new assignments. 337 for ( const ast::Expr * expr : newAssigns ) { 338 PRINT( 339 std::cerr << "== resolving tuple assign ==" << std::endl; 340 std::cerr << expr << std::endl; 341 ) 342 343 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env ); 344 finder.allowVoid = true; 345 346 try { 347 finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() ); 348 } catch (...) { 349 // No match is not failure, just that this tuple assignment is invalid. 350 return; 351 } 352 353 ResolvExpr::CandidateList & cands = finder.candidates; 354 assert( 1 == cands.size() ); 355 assert( cands.front()->expr ); 356 crnt.emplace_back( std::move( cands.front() ) ); 357 } 358 359 // extract expressions from the assignment candidates to produce a list of assignments 360 // that together form a sigle candidate 361 std::vector< ast::ptr< ast::Expr > > solved; 362 for ( ResolvExpr::CandidateRef & cand : crnt ) { 363 solved.emplace_back( cand->expr ); 364 matcher->combineState( *cand ); 365 } 366 367 crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >( 368 new ast::TupleAssignExpr( 369 matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) ), 370 std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ), 371 ResolvExpr::sumCost( crnt ) + matcher->baseCost ) ); 372 } 373 }; 374 373 375 } // anonymous namespace 374 376 … … 377 379 std::vector< ResolvExpr::CandidateFinder > & args 378 380 ) { 379 TupleAssignSpotter spotter { finder };381 TupleAssignSpotter spotter( finder ); 380 382 spotter.spot( assign, args ); 381 383 } -
src/Tuples/Tuples.cc
r3f219eb r0f6d2884 25 25 namespace { 26 26 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 31 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; 32 32 33 void previsit( ast::ApplicationExpr const * appExpr ) { 34 if ( ast::DeclWithType const * function = ast::getFunction( appExpr ) ) { 35 if ( function->linkage == ast::Linkage::Intrinsic 36 && ( function->name == "*?" || function->name == "?[?]" ) ) { 37 return; 38 } 33 void previsit( ast::ApplicationExpr const * appExpr ) { 34 if ( ast::DeclWithType const * function = ast::getFunction( appExpr ) ) { 35 if ( function->linkage == ast::Linkage::Intrinsic 36 && ( function->name == "*?" || function->name == "?[?]" ) ) { 37 return; 39 38 } 40 result = true; visit_children = false;41 39 } 42 void previsit( ast::UntypedExpr const * ) { 43 result = true; visit_children = false; 44 } 45 }; 40 result = true; visit_children = false; 41 } 42 void previsit( ast::UntypedExpr const * ) { 43 result = true; visit_children = false; 44 } 45 }; 46 46 47 struct ImpurityDetectorIgnoreUnique : public ImpurityDetector { 48 using ImpurityDetector::previsit; 49 void previsit( ast::UniqueExpr const * ) { 50 visit_children = false; 51 } 52 }; 47 struct ImpurityDetectorIgnoreUnique : public ImpurityDetector { 48 using ImpurityDetector::previsit; 49 void previsit( ast::UniqueExpr const * ) { 50 visit_children = false; 51 } 52 }; 53 53 54 } // namespace 54 55 -
src/Tuples/Tuples.h
r3f219eb r0f6d2884 24 24 25 25 namespace Tuples { 26 // TupleAssignment.cc27 void handleTupleAssignment(28 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,29 std::vector< ResolvExpr::CandidateFinder > & args );30 26 31 // TupleExpansion.cc 32 /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate 33 void expandMemberTuples( ast::TranslationUnit & translationUnit ); 27 // TupleAssignment.cc 28 void handleTupleAssignment( 29 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, 30 std::vector< ResolvExpr::CandidateFinder > & args ); 34 31 35 /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc. 36 void expandTuples( ast::TranslationUnit & translaionUnit ); 32 // TupleExpansion.cc 33 /// Expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate. 34 void expandMemberTuples( ast::TranslationUnit & translationUnit ); 37 35 38 /// replaces UniqueExprs with a temporary variable and one call 39 void expandUniqueExpr( ast::TranslationUnit & translationUnit );36 /// Replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc. 37 void expandTuples( ast::TranslationUnit & translaionUnit ); 40 38 41 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types 42 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs);39 /// Replaces UniqueExprs with a temporary variable and one call. 40 void expandUniqueExpr( ast::TranslationUnit & translationUnit ); 43 41 44 /// returns a TypeInstType if `type` is a ttype, nullptr otherwise 45 const ast::TypeInstType * isTtype( const ast::Type * type);42 /// Returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types. 43 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ); 46 44 47 /// returns true if the expression may contain side-effects. 48 bool maybeImpure( const ast::Expr * expr);45 /// Returns a TypeInstType if `type` is a ttype, nullptr otherwise 46 const ast::TypeInstType * isTtype( const ast::Type * type ); 49 47 50 /// Returns true if the expression may contain side-effect, 51 /// ignoring the presence of unique expressions. 52 bool maybeImpureIgnoreUnique( const ast::Expr * expr ); 48 /// Returns true if the expression may contain side-effects. 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 53 55 } // namespace Tuples 54 56
Note: See TracChangeset
for help on using the changeset viewer.