diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2024-10-29 14:49:26 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-29 14:49:26 +0800 |
| commit | f65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch) | |
| tree | ea1d61342cd29368e19135000ec2948813096205 /source/slang/slang-mangle.cpp | |
| parent | a729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff) | |
format
* format
* Minor test fixes
* enable checking cpp format in ci
Diffstat (limited to 'source/slang/slang-mangle.cpp')
| -rw-r--r-- | source/slang/slang-mangle.cpp | 1382 |
1 files changed, 675 insertions, 707 deletions
diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp index 438ab2187..eb26540b4 100644 --- a/source/slang/slang-mangle.cpp +++ b/source/slang/slang-mangle.cpp @@ -1,834 +1,802 @@ #include "slang-mangle.h" #include "../compiler-core/slang-name.h" -#include "slang-syntax.h" #include "slang-check.h" +#include "slang-syntax.h" namespace Slang { - struct ManglingContext - { - ManglingContext(ASTBuilder* inAstBuilder): - astBuilder(inAstBuilder) - { - } - ASTBuilder* astBuilder; - StringBuilder sb; - }; - - void emitRaw( - ManglingContext* context, - char const* text) +struct ManglingContext +{ + ManglingContext(ASTBuilder* inAstBuilder) + : astBuilder(inAstBuilder) { - context->sb.append(text); } + ASTBuilder* astBuilder; + StringBuilder sb; +}; - void emit( - ManglingContext* context, - UInt value) +void emitRaw(ManglingContext* context, char const* text) +{ + context->sb.append(text); +} + +void emit(ManglingContext* context, UInt value) +{ + context->sb.append(value); +} + +void emit(ManglingContext* context, String const& value) +{ + context->sb.append(value); +} + +void emitNameImpl(ManglingContext* context, UnownedStringSlice str) +{ + Index length = str.getLength(); + // If the name consists of only traditional "identifer characters" + // (`[a-zA-Z_]`), then we want to emit it more or less directly. + // + bool allAllowed = true; + for (auto c : str) { - context->sb.append(value); + if (('a' <= c) && (c <= 'z')) + continue; + if (('A' <= c) && (c <= 'Z')) + continue; + if (('0' <= c) && (c <= '9')) + continue; + if (c == '_') + continue; + + allAllowed = false; + break; } - - void emit( - ManglingContext* context, - String const& value) + if (allAllowed) { - context->sb.append(value); + // We prefix the string with its byte length, so that + // decoding doesn't have to worry about finding a terminator. + // + // Note: in this case `length` is the same as the number of + // code points and the number of extended grapheme clusters, + // since the entire name is within the ASCII subset. + // + emit(context, length); + context->sb.append(str); } - - void emitNameImpl(ManglingContext* context, UnownedStringSlice str) + else { - Index length = str.getLength(); - // If the name consists of only traditional "identifer characters" - // (`[a-zA-Z_]`), then we want to emit it more or less directly. + // Other names that aren't pure ASCII require escaping. We + // will use a rather simple escaping scheme where the basic + // ASCII alphanumeric code points go through unmodified, + // and we use `_` as a kind of escape character. + // + StringBuilder encoded; + + // TODO: This loop probalby ought to be over code points + // rather than bytes. // - bool allAllowed = true; for (auto c : str) { - if (('a' <= c) && (c <= 'z')) - continue; - if (('A' <= c) && (c <= 'Z')) - continue; - if (('0' <= c) && (c <= '9')) - continue; - if (c == '_') - continue; - - allAllowed = false; - break; - } - if (allAllowed) - { - // We prefix the string with its byte length, so that - // decoding doesn't have to worry about finding a terminator. - // - // Note: in this case `length` is the same as the number of - // code points and the number of extended grapheme clusters, - // since the entire name is within the ASCII subset. - // - emit(context, length); - context->sb.append(str); - } - else - { - // Other names that aren't pure ASCII require escaping. We - // will use a rather simple escaping scheme where the basic - // ASCII alphanumeric code points go through unmodified, - // and we use `_` as a kind of escape character. - // - StringBuilder encoded; - - // TODO: This loop probalby ought to be over code points - // rather than bytes. - // - for (auto c : str) + if (('a' <= c) && (c <= 'z') || ('A' <= c) && (c <= 'Z') || ('0' <= c) && (c <= '9')) { - if (('a' <= c) && (c <= 'z') || ('A' <= c) && (c <= 'Z') || - ('0' <= c) && (c <= '9')) - { - encoded.append(c); - } - else if (c == '_') - { - encoded.append("_u"); - } - else - { - // Any byte that isn't within the allowed ranges - // we be turned into hex, prefixed with `_` and - // suffixed with `x`. - // - encoded.append("_"); - encoded.append(uint32_t((unsigned char)c), 16); - encoded.appendChar('x'); - } + encoded.append(c); + } + else if (c == '_') + { + encoded.append("_u"); + } + else + { + // Any byte that isn't within the allowed ranges + // we be turned into hex, prefixed with `_` and + // suffixed with `x`. + // + encoded.append("_"); + encoded.append(uint32_t((unsigned char)c), 16); + encoded.appendChar('x'); } - - context->sb.append("R"); - emit(context, encoded.getLength()); - context->sb.append(encoded); } - // TODO: This logic does not rule out consecutive underscores, - // even though the GLSL target does not support consecutive underscores - // (or leading underscores, IIRC) in user identifiers. - // - // Realistically, that is best dealt with as a quirk of tha particular - // target, rather than adding complexity here. + context->sb.append("R"); + emit(context, encoded.getLength()); + context->sb.append(encoded); } - void emitName( - ManglingContext* context, - Name* name) - { - String str = getText(name); - emitNameImpl(context, str.getUnownedSlice()); - } + // TODO: This logic does not rule out consecutive underscores, + // even though the GLSL target does not support consecutive underscores + // (or leading underscores, IIRC) in user identifiers. + // + // Realistically, that is best dealt with as a quirk of tha particular + // target, rather than adding complexity here. +} + +void emitName(ManglingContext* context, Name* name) +{ + String str = getText(name); + emitNameImpl(context, str.getUnownedSlice()); +} - void emitVal( - ManglingContext* context, - Val* val); +void emitVal(ManglingContext* context, Val* val); - void emitQualifiedName( - ManglingContext* context, - DeclRef<Decl> declRef, - bool includeModuleName); +void emitQualifiedName(ManglingContext* context, DeclRef<Decl> declRef, bool includeModuleName); - void emitSimpleIntVal( - ManglingContext* context, - Val* val) +void emitSimpleIntVal(ManglingContext* context, Val* val) +{ + if (auto constVal = as<ConstantIntVal>(val)) { - if( auto constVal = as<ConstantIntVal>(val) ) + auto cVal = constVal->getValue(); + if (cVal >= 0 && cVal <= 9) { - auto cVal = constVal->getValue(); - if(cVal >= 0 && cVal <= 9 ) - { - emit(context, (UInt)cVal); - return; - } + emit(context, (UInt)cVal); + return; } - - // Fallback: - emitVal(context, val); } - void emitBaseType( - ManglingContext* context, - BaseType baseType) + // Fallback: + emitVal(context, val); +} + +void emitBaseType(ManglingContext* context, BaseType baseType) +{ + switch (baseType) { - switch( baseType ) - { - case BaseType::Void: emitRaw(context, "V"); break; - case BaseType::Bool: emitRaw(context, "b"); break; - case BaseType::Int8: emitRaw(context, "c"); break; - case BaseType::Int16: emitRaw(context, "s"); break; - case BaseType::Int: emitRaw(context, "i"); break; - case BaseType::Int64: emitRaw(context, "I"); break; - case BaseType::UInt8: emitRaw(context, "C"); break; - case BaseType::UInt16: emitRaw(context, "S"); break; - case BaseType::UInt: emitRaw(context, "u"); break; - case BaseType::UInt64: emitRaw(context, "U"); break; - case BaseType::Half: emitRaw(context, "h"); break; - case BaseType::Float: emitRaw(context, "f"); break; - case BaseType::Double: emitRaw(context, "d"); break; - case BaseType::UIntPtr: emitRaw(context, "up"); break; - case BaseType::IntPtr: emitRaw(context, "ip"); break; - break; - - default: - SLANG_UNEXPECTED("unimplemented case in base type mangling"); - break; - } + case BaseType::Void: emitRaw(context, "V"); break; + case BaseType::Bool: emitRaw(context, "b"); break; + case BaseType::Int8: emitRaw(context, "c"); break; + case BaseType::Int16: emitRaw(context, "s"); break; + case BaseType::Int: emitRaw(context, "i"); break; + case BaseType::Int64: emitRaw(context, "I"); break; + case BaseType::UInt8: emitRaw(context, "C"); break; + case BaseType::UInt16: emitRaw(context, "S"); break; + case BaseType::UInt: emitRaw(context, "u"); break; + case BaseType::UInt64: emitRaw(context, "U"); break; + case BaseType::Half: emitRaw(context, "h"); break; + case BaseType::Float: emitRaw(context, "f"); break; + case BaseType::Double: emitRaw(context, "d"); break; + case BaseType::UIntPtr: emitRaw(context, "up"); break; + case BaseType::IntPtr: + emitRaw(context, "ip"); + break; + break; + + default: SLANG_UNEXPECTED("unimplemented case in base type mangling"); break; } +} - void emitType( - ManglingContext* context, - Type* type) - { - // TODO: actually implement this bit... +void emitType(ManglingContext* context, Type* type) +{ + // TODO: actually implement this bit... - if( auto basicType = dynamicCast<BasicExpressionType>(type) ) - { - emitBaseType(context, basicType->getBaseType()); - } - else if( auto vecType = dynamicCast<VectorExpressionType>(type) ) - { - emitRaw(context, "v"); - emitSimpleIntVal(context, vecType->getElementCount()); - emitType(context, vecType->getElementType()); - } - else if( auto matType = dynamicCast<MatrixExpressionType>(type) ) - { - emitRaw(context, "m"); - emitSimpleIntVal(context, matType->getRowCount()); - emitRaw(context, "x"); - emitSimpleIntVal(context, matType->getColumnCount()); - emitType(context, matType->getElementType()); - } - else if( auto namedType = dynamicCast<NamedExpressionType>(type) ) - { - emitType(context, getType(context->astBuilder, namedType->getDeclRef())); - } - else if( auto declRefType = dynamicCast<DeclRefType>(type) ) - { - emitQualifiedName(context, declRefType->getDeclRef(), true); - } - else if (auto arrType = dynamicCast<ArrayExpressionType>(type)) - { - emitRaw(context, "a"); - emitSimpleIntVal(context, arrType->getElementCount()); - emitType(context, arrType->getElementType()); - } - else if( auto thisType = dynamicCast<ThisType>(type) ) - { - emitRaw(context, "t"); - emitQualifiedName(context, thisType->getInterfaceDeclRef(), true); - } - else if (const auto errorType = dynamicCast<ErrorType>(type)) - { - emitRaw(context, "E"); - } - else if (const auto bottomType = dynamicCast<BottomType>(type)) - { - emitRaw(context, "B"); - } - else if (auto funcType = dynamicCast<FuncType>(type)) - { - emitRaw(context, "F"); - auto n = funcType->getParamCount(); - emit(context, n); - for(Index i = 0; i < n; ++i) - emitType(context, funcType->getParamType(i)); - emitType(context, funcType->getResultType()); - emitType(context, funcType->getErrorType()); - } - else if (auto tupleType = dynamicCast<TupleType>(type)) - { - emitRaw(context, "Tu"); - auto n = tupleType->getMemberCount(); - emit(context, n); - for(Index i = 0; i < n; ++i) - emitType(context, tupleType->getMember(i)); - } - else if (auto modifiedType = dynamicCast<ModifiedType>(type)) - { - emitRaw(context, "Tm"); - emitType(context, modifiedType->getBase()); - auto n = modifiedType->getModifierCount(); - emit(context, n); - for (Index i = 0; i < n; ++i) - emitVal(context, modifiedType->getModifier(i)); - } - else if (auto andType = as<AndType>(type)) - { - emitRaw(context, "Ta"); - emitType(context, andType->getLeft()); - emitType(context, andType->getRight()); - } - else if (auto expandType = as<ExpandType>(type)) - { - emitRaw(context, "Tx"); - emitType(context, expandType->getPatternType()); - } - else if (auto eachType = as<EachType>(type)) - { - emitRaw(context, "Te"); - emitType(context, eachType->getElementType()); - } - else if (auto typePack = as<ConcreteTypePack>(type)) - { - emitRaw(context, "Tp"); - emit(context, typePack->getTypeCount()); - for (Index i = 0; i < typePack->getTypeCount(); i++) - emitType(context, typePack->getElementType(i)); - } - else - { - SLANG_UNEXPECTED("unimplemented case in type mangling"); - } + if (auto basicType = dynamicCast<BasicExpressionType>(type)) + { + emitBaseType(context, basicType->getBaseType()); + } + else if (auto vecType = dynamicCast<VectorExpressionType>(type)) + { + emitRaw(context, "v"); + emitSimpleIntVal(context, vecType->getElementCount()); + emitType(context, vecType->getElementType()); + } + else if (auto matType = dynamicCast<MatrixExpressionType>(type)) + { + emitRaw(context, "m"); + emitSimpleIntVal(context, matType->getRowCount()); + emitRaw(context, "x"); + emitSimpleIntVal(context, matType->getColumnCount()); + emitType(context, matType->getElementType()); + } + else if (auto namedType = dynamicCast<NamedExpressionType>(type)) + { + emitType(context, getType(context->astBuilder, namedType->getDeclRef())); } + else if (auto declRefType = dynamicCast<DeclRefType>(type)) + { + emitQualifiedName(context, declRefType->getDeclRef(), true); + } + else if (auto arrType = dynamicCast<ArrayExpressionType>(type)) + { + emitRaw(context, "a"); + emitSimpleIntVal(context, arrType->getElementCount()); + emitType(context, arrType->getElementType()); + } + else if (auto thisType = dynamicCast<ThisType>(type)) + { + emitRaw(context, "t"); + emitQualifiedName(context, thisType->getInterfaceDeclRef(), true); + } + else if (const auto errorType = dynamicCast<ErrorType>(type)) + { + emitRaw(context, "E"); + } + else if (const auto bottomType = dynamicCast<BottomType>(type)) + { + emitRaw(context, "B"); + } + else if (auto funcType = dynamicCast<FuncType>(type)) + { + emitRaw(context, "F"); + auto n = funcType->getParamCount(); + emit(context, n); + for (Index i = 0; i < n; ++i) + emitType(context, funcType->getParamType(i)); + emitType(context, funcType->getResultType()); + emitType(context, funcType->getErrorType()); + } + else if (auto tupleType = dynamicCast<TupleType>(type)) + { + emitRaw(context, "Tu"); + auto n = tupleType->getMemberCount(); + emit(context, n); + for (Index i = 0; i < n; ++i) + emitType(context, tupleType->getMember(i)); + } + else if (auto modifiedType = dynamicCast<ModifiedType>(type)) + { + emitRaw(context, "Tm"); + emitType(context, modifiedType->getBase()); + auto n = modifiedType->getModifierCount(); + emit(context, n); + for (Index i = 0; i < n; ++i) + emitVal(context, modifiedType->getModifier(i)); + } + else if (auto andType = as<AndType>(type)) + { + emitRaw(context, "Ta"); + emitType(context, andType->getLeft()); + emitType(context, andType->getRight()); + } + else if (auto expandType = as<ExpandType>(type)) + { + emitRaw(context, "Tx"); + emitType(context, expandType->getPatternType()); + } + else if (auto eachType = as<EachType>(type)) + { + emitRaw(context, "Te"); + emitType(context, eachType->getElementType()); + } + else if (auto typePack = as<ConcreteTypePack>(type)) + { + emitRaw(context, "Tp"); + emit(context, typePack->getTypeCount()); + for (Index i = 0; i < typePack->getTypeCount(); i++) + emitType(context, typePack->getElementType(i)); + } + else + { + SLANG_UNEXPECTED("unimplemented case in type mangling"); + } +} - void emitVal( - ManglingContext* context, - Val* val) +void emitVal(ManglingContext* context, Val* val) +{ + if (auto type = dynamicCast<Type>(val)) { - if( auto type = dynamicCast<Type>(val) ) - { - emitType(context, type); - } - else if( const auto witness = dynamicCast<Witness>(val) ) - { - // We don't emit witnesses as part of a mangled - // name, because the way that the front-end - // arrived at the witness is not important; - // what matters is that the type constraint - // was satisfied. - // - // TODO: make sure we can't get name collisions - // between specializations of declarations - // with the same numbers of generic parameters, - // but different constraints. We might have - // to mangle in the constraints even when - // the whole thing is specialized... - } - else if( auto genericParamIntVal = dynamicCast<GenericParamIntVal>(val) ) - { - // TODO: we shouldn't be including the names of generic parameters - // anywhere in mangled names, since changing parameter names - // shouldn't break binary compatibility. - // - // The right solution in the long term is for generic parameters - // (both types and values) to be mangled in terms of their - // "depth" (how many outer generics) and "index" (which - // parameter are they at the specified depth). - emitRaw(context, "K"); - emitName(context, genericParamIntVal->getDeclRef().getName()); - } - else if( auto constantIntVal = dynamicCast<ConstantIntVal>(val) ) - { - // TODO: need to figure out what prefix/suffix is needed - // to allow demangling later. - emitRaw(context, "k"); - emit(context, (UInt) constantIntVal->getValue()); - } - else if (auto funcCallIntVal = dynamicCast<FuncCallIntVal>(val)) - { - emitRaw(context, "KC"); - emit(context, funcCallIntVal->getArgs().getCount()); - emitName(context, funcCallIntVal->getFuncDeclRef().getName()); - for (Index i = 0; i < funcCallIntVal->getArgs().getCount(); i++) - emitVal(context, funcCallIntVal->getArgs()[i]); - } - else if (auto lookupIntVal = dynamicCast<WitnessLookupIntVal>(val)) - { - emitRaw(context, "KL"); - emitVal(context, lookupIntVal->getWitness()); - emitName(context, lookupIntVal->getKey()->getName()); - } - else if (const auto polynomialIntVal = dynamicCast<PolynomialIntVal>(val)) - { - emitRaw(context, "KX"); - emit(context, (UInt)polynomialIntVal->getConstantTerm()); - emit(context, (UInt)polynomialIntVal->getTerms().getCount()); - for (auto term : polynomialIntVal->getTerms()) + emitType(context, type); + } + else if (const auto witness = dynamicCast<Witness>(val)) + { + // We don't emit witnesses as part of a mangled + // name, because the way that the front-end + // arrived at the witness is not important; + // what matters is that the type constraint + // was satisfied. + // + // TODO: make sure we can't get name collisions + // between specializations of declarations + // with the same numbers of generic parameters, + // but different constraints. We might have + // to mangle in the constraints even when + // the whole thing is specialized... + } + else if (auto genericParamIntVal = dynamicCast<GenericParamIntVal>(val)) + { + // TODO: we shouldn't be including the names of generic parameters + // anywhere in mangled names, since changing parameter names + // shouldn't break binary compatibility. + // + // The right solution in the long term is for generic parameters + // (both types and values) to be mangled in terms of their + // "depth" (how many outer generics) and "index" (which + // parameter are they at the specified depth). + emitRaw(context, "K"); + emitName(context, genericParamIntVal->getDeclRef().getName()); + } + else if (auto constantIntVal = dynamicCast<ConstantIntVal>(val)) + { + // TODO: need to figure out what prefix/suffix is needed + // to allow demangling later. + emitRaw(context, "k"); + emit(context, (UInt)constantIntVal->getValue()); + } + else if (auto funcCallIntVal = dynamicCast<FuncCallIntVal>(val)) + { + emitRaw(context, "KC"); + emit(context, funcCallIntVal->getArgs().getCount()); + emitName(context, funcCallIntVal->getFuncDeclRef().getName()); + for (Index i = 0; i < funcCallIntVal->getArgs().getCount(); i++) + emitVal(context, funcCallIntVal->getArgs()[i]); + } + else if (auto lookupIntVal = dynamicCast<WitnessLookupIntVal>(val)) + { + emitRaw(context, "KL"); + emitVal(context, lookupIntVal->getWitness()); + emitName(context, lookupIntVal->getKey()->getName()); + } + else if (const auto polynomialIntVal = dynamicCast<PolynomialIntVal>(val)) + { + emitRaw(context, "KX"); + emit(context, (UInt)polynomialIntVal->getConstantTerm()); + emit(context, (UInt)polynomialIntVal->getTerms().getCount()); + for (auto term : polynomialIntVal->getTerms()) + { + emit(context, (UInt)term->getConstFactor()); + emit(context, (UInt)term->getParamFactors().getCount()); + for (auto factor : term->getParamFactors()) { - emit(context, (UInt)term->getConstFactor()); - emit(context, (UInt)term->getParamFactors().getCount()); - for (auto factor : term->getParamFactors()) - { - emitVal(context, factor->getParam()); - emit(context, (UInt)factor->getPower()); - } + emitVal(context, factor->getParam()); + emit(context, (UInt)factor->getPower()); } } - else if (const auto typecastIntVal = dynamicCast<TypeCastIntVal>(val)) - { - emitRaw(context, "KK"); - emitVal(context, typecastIntVal->getType()); - emitVal(context, typecastIntVal->getBase()); - } - else if (auto modifier = as<ModifierVal>(val)) - { - emitNameImpl(context, UnownedStringSlice(modifier->getClassInfo().m_name)); - } - else - { - SLANG_UNEXPECTED("unimplemented case in val mangling"); - } } + else if (const auto typecastIntVal = dynamicCast<TypeCastIntVal>(val)) + { + emitRaw(context, "KK"); + emitVal(context, typecastIntVal->getType()); + emitVal(context, typecastIntVal->getBase()); + } + else if (auto modifier = as<ModifierVal>(val)) + { + emitNameImpl(context, UnownedStringSlice(modifier->getClassInfo().m_name)); + } + else + { + SLANG_UNEXPECTED("unimplemented case in val mangling"); + } +} - void emitQualifiedName( - ManglingContext* context, - DeclRef<Decl> declRef, - bool includeModuleName) +void emitQualifiedName(ManglingContext* context, DeclRef<Decl> declRef, bool includeModuleName) +{ + if (!includeModuleName) { - if (!includeModuleName) - { - if (as<ModuleDecl>(declRef)) - return; - } - else + if (as<ModuleDecl>(declRef)) + return; + } + else + { + for (auto modifier : declRef.getDecl()->modifiers) { - for (auto modifier : declRef.getDecl()->modifiers) + if (as<ExternModifier>(modifier) || as<HLSLExportModifier>(modifier)) { - if (as<ExternModifier>(modifier) || as<HLSLExportModifier>(modifier)) - { - includeModuleName = false; - break; - } + includeModuleName = false; + break; } } + } - if (declRef.getDecl()->hasModifier<ExternCppModifier>()) - { - emit(context, declRef.getDecl()->getName()->text); - return; - } + if (declRef.getDecl()->hasModifier<ExternCppModifier>()) + { + emit(context, declRef.getDecl()->getName()->text); + return; + } - auto parentDeclRef = declRef.getParent(); - if (as<FileDecl>(parentDeclRef)) - parentDeclRef = parentDeclRef.getParent(); + auto parentDeclRef = declRef.getParent(); + if (as<FileDecl>(parentDeclRef)) + parentDeclRef = parentDeclRef.getParent(); - auto parentGenericDeclRef = parentDeclRef.as<GenericDecl>(); - if( parentDeclRef ) - { - emitQualifiedName(context, parentDeclRef, includeModuleName); - } + auto parentGenericDeclRef = parentDeclRef.as<GenericDecl>(); + if (parentDeclRef) + { + emitQualifiedName(context, parentDeclRef, includeModuleName); + } - // A generic declaration is kind of a pseudo-declaration - // as far as the user is concerned; so we don't want - // to emit its name. - if(auto genericDeclRef = declRef.as<GenericDecl>()) - { - return; - } + // A generic declaration is kind of a pseudo-declaration + // as far as the user is concerned; so we don't want + // to emit its name. + if (auto genericDeclRef = declRef.as<GenericDecl>()) + { + return; + } - // Inheritance declarations don't have meaningful names, - // and so we should emit them based on the type - // that is doing the inheriting. - if(auto inheritanceDeclRef = declRef.as<TypeConstraintDecl>()) + // Inheritance declarations don't have meaningful names, + // and so we should emit them based on the type + // that is doing the inheriting. + if (auto inheritanceDeclRef = declRef.as<TypeConstraintDecl>()) + { + emit(context, "I"); + emitType(context, getSup(context->astBuilder, inheritanceDeclRef)); + return; + } + + // Similarly, an extension doesn't have a name worth + // emitting, and we should base things on its target + // type instead. + if (auto extensionDeclRef = declRef.as<ExtensionDecl>()) + { + // TODO: as a special case, an "unconditional" extension + // that is in the same module as the type it extends should + // be treated as equivalent to the type itself. + emit(context, "X"); + emitType(context, getTargetType(context->astBuilder, extensionDeclRef)); + for (auto inheritanceDecl : + getMembersOfType<InheritanceDecl>(context->astBuilder, extensionDeclRef)) { emit(context, "I"); - emitType(context, getSup(context->astBuilder, inheritanceDeclRef)); - return; + emitType(context, getSup(context->astBuilder, inheritanceDecl)); } + return; + } - // Similarly, an extension doesn't have a name worth - // emitting, and we should base things on its target - // type instead. - if(auto extensionDeclRef = declRef.as<ExtensionDecl>()) - { - // TODO: as a special case, an "unconditional" extension - // that is in the same module as the type it extends should - // be treated as equivalent to the type itself. - emit(context, "X"); - emitType(context, getTargetType(context->astBuilder, extensionDeclRef)); - for (auto inheritanceDecl : getMembersOfType<InheritanceDecl>(context->astBuilder, extensionDeclRef)) - { - emit(context, "I"); - emitType(context, getSup(context->astBuilder, inheritanceDecl)); - } - return; - } + // TODO: we should special case GenericTypeParamDecl and GenericValueParamDecl nodes + // instead of just dumping their names here to avoid the name of a generic parameter + // to have affect the binary signature. + // For each generic parameter, we should assign it a unique ID (i, j), where i is the + // nesting level of the generic, and j is the sequential order of the parameter within + // its generic parent, and use this 2D ID to refer to such a parameter. + emitName(context, declRef.getName()); - // TODO: we should special case GenericTypeParamDecl and GenericValueParamDecl nodes - // instead of just dumping their names here to avoid the name of a generic parameter - // to have affect the binary signature. - // For each generic parameter, we should assign it a unique ID (i, j), where i is the - // nesting level of the generic, and j is the sequential order of the parameter within - // its generic parent, and use this 2D ID to refer to such a parameter. - emitName(context, declRef.getName()); + // Special case: accessors need some way to distinguish themselves + // so that a getter/setter/ref-er don't all compile to the same name. + { + if (declRef.is<GetterDecl>()) + emitRaw(context, "Ag"); + if (declRef.is<SetterDecl>()) + emitRaw(context, "As"); + if (declRef.is<RefAccessorDecl>()) + emitRaw(context, "Ar"); + } - // Special case: accessors need some way to distinguish themselves - // so that a getter/setter/ref-er don't all compile to the same name. - { - if (declRef.is<GetterDecl>()) emitRaw(context, "Ag"); - if (declRef.is<SetterDecl>()) emitRaw(context, "As"); - if (declRef.is<RefAccessorDecl>()) emitRaw(context, "Ar"); - } + // Special case: need a way to tell prefix and postfix unary + // operators apart. + { + if (declRef.getDecl()->hasModifier<PostfixModifier>()) + emitRaw(context, "P"); + if (declRef.getDecl()->hasModifier<PrefixModifier>()) + emitRaw(context, "p"); + } - // Special case: need a way to tell prefix and postfix unary - // operators apart. - { - if(declRef.getDecl()->hasModifier<PostfixModifier>()) emitRaw(context, "P"); - if(declRef.getDecl()->hasModifier<PrefixModifier>()) emitRaw(context, "p"); - } + // Are we the "inner" declaration beneath a generic decl? + if (parentGenericDeclRef && (parentGenericDeclRef.getDecl()->inner == declRef.getDecl())) + { + // There are two cases here: either we have specializations + // in place for the parent generic declaration, or we don't. - // Are we the "inner" declaration beneath a generic decl? - if(parentGenericDeclRef && (parentGenericDeclRef.getDecl()->inner == declRef.getDecl())) + auto substArgs = + tryGetGenericArguments(SubstitutionSet(declRef), parentGenericDeclRef.getDecl()); + if (substArgs.getCount()) { - // There are two cases here: either we have specializations - // in place for the parent generic declaration, or we don't. - - auto substArgs = tryGetGenericArguments(SubstitutionSet(declRef), parentGenericDeclRef.getDecl()); - if (substArgs.getCount()) + // This is the case where we *do* have substitutions. + emitRaw(context, "G"); + UInt genericArgCount = substArgs.getCount(); + emit(context, genericArgCount); + for (auto aa : substArgs) { - // This is the case where we *do* have substitutions. - emitRaw(context, "G"); - UInt genericArgCount = substArgs.getCount(); - emit(context, genericArgCount); - for (auto aa : substArgs) - { - emitVal(context, aa); - } + emitVal(context, aa); } - else + } + else + { + // We don't have substitutions, so we will emit + // information about the parameters of the generic here. + emitRaw(context, "g"); + UInt genericParameterCount = 0; + for (auto mm : + getMembers(context->astBuilder, parentGenericDeclRef.as<ContainerDecl>())) { - // We don't have substitutions, so we will emit - // information about the parameters of the generic here. - emitRaw(context, "g"); - UInt genericParameterCount = 0; - for( auto mm : getMembers(context->astBuilder, parentGenericDeclRef.as<ContainerDecl>()) ) + if (mm.is<GenericTypeParamDecl>()) { - if(mm.is<GenericTypeParamDecl>()) - { - genericParameterCount++; - } - else if(mm.is<GenericValueParamDecl>()) - { - genericParameterCount++; - } - else if(mm.is<GenericTypeConstraintDecl>()) - { - genericParameterCount++; - } - else if (mm.is<GenericTypePackParamDecl>()) - { - genericParameterCount++; - } - else - { - } + genericParameterCount++; } - - emit(context, genericParameterCount); - - OrderedDictionary<GenericTypeParamDeclBase*, List<Type*>> genericConstraints; - for (auto mm : getMembers(context->astBuilder, parentGenericDeclRef)) + else if (mm.is<GenericValueParamDecl>()) { - if (auto genericTypeParamDecl = mm.as<GenericTypeParamDecl>()) - { - emitRaw(context, "T"); - } - if (auto genericTypePackParamDecl = mm.as<GenericTypePackParamDecl>()) - { - emitRaw(context, "TP"); - } - else if (auto genericValueParamDecl = mm.as<GenericValueParamDecl>()) - { - emitRaw(context, "v"); - emitType(context, getType(context->astBuilder, genericValueParamDecl)); - } - else - {} + genericParameterCount++; } - - auto canonicalizedConstraints = getCanonicalGenericConstraints(context->astBuilder, parentGenericDeclRef); - for (auto& constraint : canonicalizedConstraints) + else if (mm.is<GenericTypeConstraintDecl>()) { - for (auto type : constraint.value) - { - emitRaw(context, "C"); - emitQualifiedName(context, makeDeclRef(constraint.key), true); - emitType(context, type); - } + genericParameterCount++; } - - } - } - - // If the declaration has parameters, then we need to emit - // those parameters to distinguish it from other declarations - // of the same name that might have different parameters. - // - // We'll also go ahead and emit the result type as well, - // just for completeness. - // - if( auto callableDeclRef = declRef.as<CallableDecl>()) - { - auto parameters = getParameters(context->astBuilder, callableDeclRef); - UInt parameterCount = parameters.getCount(); - - emitRaw(context, "p"); - emit(context, parameterCount); - emitRaw(context, "p"); - - for(auto paramDeclRef : parameters) - { - // parameter modifier makes big difference in the spirv code generation, for example - // "out"/"inout" parameter will be passed by pointer. Therefore, we need to - // distinguish them in the mangled name to avoid name collision. - ParameterDirection paramDirection = getParameterDirection(paramDeclRef.getDecl()); - switch (paramDirection) + else if (mm.is<GenericTypePackParamDecl>()) + { + genericParameterCount++; + } + else { - case kParameterDirection_Ref: - emitRaw(context, "r_"); - break; - case kParameterDirection_ConstRef: - emitRaw(context, "c_"); - break; - case kParameterDirection_Out: - emitRaw(context, "o_"); - break; - case kParameterDirection_InOut: - emitRaw(context, "io_"); - break; - case kParameterDirection_In: - emitRaw(context, "i_"); - break; - default: - StringBuilder errMsg; - errMsg << "Unknown parameter direction: " << paramDirection; - SLANG_ABORT_COMPILATION(errMsg.toString().begin()); - break; } - emitType(context, getType(context->astBuilder, paramDeclRef)); } - // Don't print result type for an initializer/constructor, - // since it is implicit in the qualified name. - if (!callableDeclRef.is<ConstructorDecl>()) - { - emitType(context, getResultType(context->astBuilder, callableDeclRef)); - } + emit(context, genericParameterCount); - // Include key modifiers in the mangled name so we never deduplicate - // things like a nonmutating method and a mutating method. - bool isMutating = false; - bool isRefThis = false; - bool isFwdDiff = false; - bool isBwdDiff = false; - bool isNoDiffThis = false; - for (auto modifier : callableDeclRef.getDecl()->modifiers) + OrderedDictionary<GenericTypeParamDeclBase*, List<Type*>> genericConstraints; + for (auto mm : getMembers(context->astBuilder, parentGenericDeclRef)) { - if (as<MutatingAttribute>(modifier)) + if (auto genericTypeParamDecl = mm.as<GenericTypeParamDecl>()) { - isMutating = true; + emitRaw(context, "T"); } - else if (as<RefAttribute>(modifier)) + if (auto genericTypePackParamDecl = mm.as<GenericTypePackParamDecl>()) { - isRefThis = true; + emitRaw(context, "TP"); } - else if (as<ForwardDifferentiableAttribute>(modifier)) + else if (auto genericValueParamDecl = mm.as<GenericValueParamDecl>()) { - isFwdDiff = true; + emitRaw(context, "v"); + emitType(context, getType(context->astBuilder, genericValueParamDecl)); } - else if (as<BackwardDifferentiableAttribute>(modifier)) + else { - isBwdDiff = true; } - else if (as<NoDiffThisAttribute>(modifier)) + } + + auto canonicalizedConstraints = + getCanonicalGenericConstraints(context->astBuilder, parentGenericDeclRef); + for (auto& constraint : canonicalizedConstraints) + { + for (auto type : constraint.value) { - isNoDiffThis = true; + emitRaw(context, "C"); + emitQualifiedName(context, makeDeclRef(constraint.key), true); + emitType(context, type); } } - - if (isMutating) - emitRaw(context, "m"); - if (isRefThis) - emitRaw(context, "r"); - if (isFwdDiff) - emitRaw(context, "f"); - if (isBwdDiff) - emitRaw(context, "b"); - if (isNoDiffThis) - emitRaw(context, "n"); } } - void mangleName( - ManglingContext* context, - DeclRef<Decl> declRef) + // If the declaration has parameters, then we need to emit + // those parameters to distinguish it from other declarations + // of the same name that might have different parameters. + // + // We'll also go ahead and emit the result type as well, + // just for completeness. + // + if (auto callableDeclRef = declRef.as<CallableDecl>()) { - // TODO: catch cases where the declaration should - // forward to something else? E.g., what if we - // are asked to mangle the name of a `typedef`? + auto parameters = getParameters(context->astBuilder, callableDeclRef); + UInt parameterCount = parameters.getCount(); - auto decl = declRef.getDecl(); - if (!decl) return; + emitRaw(context, "p"); + emit(context, parameterCount); + emitRaw(context, "p"); - // Handle `__extern_cpp` modifier by simply emitting - // the given name. - if (decl->hasModifier<ExternCppModifier>()) + for (auto paramDeclRef : parameters) { - emit(context, decl->getName()->text); - return; + // parameter modifier makes big difference in the spirv code generation, for example + // "out"/"inout" parameter will be passed by pointer. Therefore, we need to + // distinguish them in the mangled name to avoid name collision. + ParameterDirection paramDirection = getParameterDirection(paramDeclRef.getDecl()); + switch (paramDirection) + { + case kParameterDirection_Ref: emitRaw(context, "r_"); break; + case kParameterDirection_ConstRef: emitRaw(context, "c_"); break; + case kParameterDirection_Out: emitRaw(context, "o_"); break; + case kParameterDirection_InOut: emitRaw(context, "io_"); break; + case kParameterDirection_In: emitRaw(context, "i_"); break; + default: + StringBuilder errMsg; + errMsg << "Unknown parameter direction: " << paramDirection; + SLANG_ABORT_COMPILATION(errMsg.toString().begin()); + break; + } + emitType(context, getType(context->astBuilder, paramDeclRef)); } - // We will start with a unique prefix to avoid - // clashes with user-defined symbols: - emitRaw(context, "_S"); - - // Next we will add a bit of info to register - // the *kind* of declaration we are dealing with. - // - // Functions will get no prefix, since we assume - // they are a common case: - if(as<FuncDecl>(decl)) - {} - // Types will get a `T` prefix: - else if(as<AggTypeDecl>(decl)) - emitRaw(context, "T"); - else if(as<TypeDefDecl>(decl)) - emitRaw(context, "T"); - // Variables will get a `V` prefix: - // - // TODO: probably need to pull constant-buffer - // declarations out of this... - else if(as<VarDeclBase>(decl)) - emitRaw(context, "V"); - else if(DeclRef<GenericDecl> genericDecl = declRef.as<GenericDecl>()) + // Don't print result type for an initializer/constructor, + // since it is implicit in the qualified name. + if (!callableDeclRef.is<ConstructorDecl>()) { - // Mark that this is a generic, so we can differentiate bewteen when - // mangling the generic and the inner entity - emitRaw(context, "G"); - - SLANG_ASSERT(SubstitutionSet(genericDecl).findGenericAppDeclRef() == nullptr); - - auto innerDecl = getInner(genericDecl); - - emitQualifiedName(context, makeDeclRef(innerDecl), true); - return; - } - else if (auto fwdReq = as<ForwardDerivativeRequirementDecl>(decl)) - { - emitRaw(context, "FwdReq_"); - emitQualifiedName(context, fwdReq->originalRequirementDecl, true); - return; - } - else if (auto bwdReq = as<BackwardDerivativeRequirementDecl>(decl)) - { - emitRaw(context, "BwdReq_"); - emitQualifiedName(context, bwdReq->originalRequirementDecl, true); - return; + emitType(context, getResultType(context->astBuilder, callableDeclRef)); } - else + + // Include key modifiers in the mangled name so we never deduplicate + // things like a nonmutating method and a mutating method. + bool isMutating = false; + bool isRefThis = false; + bool isFwdDiff = false; + bool isBwdDiff = false; + bool isNoDiffThis = false; + for (auto modifier : callableDeclRef.getDecl()->modifiers) { - // TODO: handle other cases + if (as<MutatingAttribute>(modifier)) + { + isMutating = true; + } + else if (as<RefAttribute>(modifier)) + { + isRefThis = true; + } + else if (as<ForwardDifferentiableAttribute>(modifier)) + { + isFwdDiff = true; + } + else if (as<BackwardDifferentiableAttribute>(modifier)) + { + isBwdDiff = true; + } + else if (as<NoDiffThisAttribute>(modifier)) + { + isNoDiffThis = true; + } } - // Now we encode the qualified name of the decl. - - emitQualifiedName(context, declRef, true); + if (isMutating) + emitRaw(context, "m"); + if (isRefThis) + emitRaw(context, "r"); + if (isFwdDiff) + emitRaw(context, "f"); + if (isBwdDiff) + emitRaw(context, "b"); + if (isNoDiffThis) + emitRaw(context, "n"); } +} + +void mangleName(ManglingContext* context, DeclRef<Decl> declRef) +{ + // TODO: catch cases where the declaration should + // forward to something else? E.g., what if we + // are asked to mangle the name of a `typedef`? - static String getMangledName(ASTBuilder* astBuilder, DeclRef<Decl> const& declRef) + auto decl = declRef.getDecl(); + if (!decl) + return; + + // Handle `__extern_cpp` modifier by simply emitting + // the given name. + if (decl->hasModifier<ExternCppModifier>()) { - SLANG_AST_BUILDER_RAII(astBuilder); - ManglingContext context(astBuilder); - mangleName(&context, declRef); - return context.sb.produceString(); + emit(context, decl->getName()->text); + return; } - String getMangledName(ASTBuilder* astBuilder, DeclRefBase* declRef) - { - SLANG_AST_BUILDER_RAII(astBuilder); + // We will start with a unique prefix to avoid + // clashes with user-defined symbols: + emitRaw(context, "_S"); - return getMangledName(astBuilder, DeclRef<Decl>(declRef)); + // Next we will add a bit of info to register + // the *kind* of declaration we are dealing with. + // + // Functions will get no prefix, since we assume + // they are a common case: + if (as<FuncDecl>(decl)) + { } - - String getMangledName(ASTBuilder* astBuilder, Decl* decl) + // Types will get a `T` prefix: + else if (as<AggTypeDecl>(decl)) + emitRaw(context, "T"); + else if (as<TypeDefDecl>(decl)) + emitRaw(context, "T"); + // Variables will get a `V` prefix: + // + // TODO: probably need to pull constant-buffer + // declarations out of this... + else if (as<VarDeclBase>(decl)) + emitRaw(context, "V"); + else if (DeclRef<GenericDecl> genericDecl = declRef.as<GenericDecl>()) { - SLANG_AST_BUILDER_RAII(astBuilder); + // Mark that this is a generic, so we can differentiate bewteen when + // mangling the generic and the inner entity + emitRaw(context, "G"); + + SLANG_ASSERT(SubstitutionSet(genericDecl).findGenericAppDeclRef() == nullptr); - return getMangledName(astBuilder, makeDeclRef(decl)); + auto innerDecl = getInner(genericDecl); + + emitQualifiedName(context, makeDeclRef(innerDecl), true); + return; } - - String getMangledNameForConformanceWitness( - ASTBuilder* astBuilder, - DeclRef<Decl> sub, - DeclRef<Decl> sup) + else if (auto fwdReq = as<ForwardDerivativeRequirementDecl>(decl)) { - SLANG_AST_BUILDER_RAII(astBuilder); - ManglingContext context(astBuilder); - emitRaw(&context, "_SW"); - emitQualifiedName(&context, sub, true); - emitQualifiedName(&context, sup, true); - return context.sb.produceString(); + emitRaw(context, "FwdReq_"); + emitQualifiedName(context, fwdReq->originalRequirementDecl, true); + return; } - - String getMangledNameForConformanceWitness( - ASTBuilder* astBuilder, - DeclRef<Decl> sub, - Type* sup) + else if (auto bwdReq = as<BackwardDerivativeRequirementDecl>(decl)) { - SLANG_AST_BUILDER_RAII(astBuilder); - // The mangled form for a witness that `sub` - // conforms to `sup` will be named: - // - // {Conforms(sub,sup)} => _SW{sub}{sup} - // - ManglingContext context(astBuilder); - emitRaw(&context, "_SW"); - emitQualifiedName(&context, sub, true); - emitType(&context, sup); - return context.sb.produceString(); + emitRaw(context, "BwdReq_"); + emitQualifiedName(context, bwdReq->originalRequirementDecl, true); + return; } - - String getMangledNameForConformanceWitness( - ASTBuilder* astBuilder, - Type* sub, - Type* sup) + else { - SLANG_AST_BUILDER_RAII(astBuilder); - // The mangled form for a witness that `sub` - // conforms to `sup` will be named: - // - // {Conforms(sub,sup)} => _SW{sub}{sup} - // - ManglingContext context(astBuilder); - emitRaw(&context, "_SW"); - emitType(&context, sub); - emitType(&context, sup); - return context.sb.produceString(); + // TODO: handle other cases } - String getMangledTypeName(ASTBuilder* astBuilder, Type* type) - { - SLANG_AST_BUILDER_RAII(astBuilder); - ManglingContext context(astBuilder); - emitType(&context, type); - return context.sb.produceString(); - } + // Now we encode the qualified name of the decl. - String getMangledNameFromNameString(const UnownedStringSlice& name) - { - ManglingContext context(nullptr); - emitNameImpl(&context, name); - return context.sb.produceString(); - } + emitQualifiedName(context, declRef, true); +} - String getHashedName(const UnownedStringSlice& mangledName) - { - StableHashCode64 hash = getStableHashCode64(mangledName.begin(), mangledName.getLength()); +static String getMangledName(ASTBuilder* astBuilder, DeclRef<Decl> const& declRef) +{ + SLANG_AST_BUILDER_RAII(astBuilder); + ManglingContext context(astBuilder); + mangleName(&context, declRef); + return context.sb.produceString(); +} + +String getMangledName(ASTBuilder* astBuilder, DeclRefBase* declRef) +{ + SLANG_AST_BUILDER_RAII(astBuilder); - StringBuilder builder; - builder << "_Sh"; - builder.append(uint64_t(hash), 16); + return getMangledName(astBuilder, DeclRef<Decl>(declRef)); +} - return builder; - } +String getMangledName(ASTBuilder* astBuilder, Decl* decl) +{ + SLANG_AST_BUILDER_RAII(astBuilder); + return getMangledName(astBuilder, makeDeclRef(decl)); } + +String getMangledNameForConformanceWitness( + ASTBuilder* astBuilder, + DeclRef<Decl> sub, + DeclRef<Decl> sup) +{ + SLANG_AST_BUILDER_RAII(astBuilder); + ManglingContext context(astBuilder); + emitRaw(&context, "_SW"); + emitQualifiedName(&context, sub, true); + emitQualifiedName(&context, sup, true); + return context.sb.produceString(); +} + +String getMangledNameForConformanceWitness(ASTBuilder* astBuilder, DeclRef<Decl> sub, Type* sup) +{ + SLANG_AST_BUILDER_RAII(astBuilder); + // The mangled form for a witness that `sub` + // conforms to `sup` will be named: + // + // {Conforms(sub,sup)} => _SW{sub}{sup} + // + ManglingContext context(astBuilder); + emitRaw(&context, "_SW"); + emitQualifiedName(&context, sub, true); + emitType(&context, sup); + return context.sb.produceString(); +} + +String getMangledNameForConformanceWitness(ASTBuilder* astBuilder, Type* sub, Type* sup) +{ + SLANG_AST_BUILDER_RAII(astBuilder); + // The mangled form for a witness that `sub` + // conforms to `sup` will be named: + // + // {Conforms(sub,sup)} => _SW{sub}{sup} + // + ManglingContext context(astBuilder); + emitRaw(&context, "_SW"); + emitType(&context, sub); + emitType(&context, sup); + return context.sb.produceString(); +} + +String getMangledTypeName(ASTBuilder* astBuilder, Type* type) +{ + SLANG_AST_BUILDER_RAII(astBuilder); + ManglingContext context(astBuilder); + emitType(&context, type); + return context.sb.produceString(); +} + +String getMangledNameFromNameString(const UnownedStringSlice& name) +{ + ManglingContext context(nullptr); + emitNameImpl(&context, name); + return context.sb.produceString(); +} + +String getHashedName(const UnownedStringSlice& mangledName) +{ + StableHashCode64 hash = getStableHashCode64(mangledName.begin(), mangledName.getLength()); + + StringBuilder builder; + builder << "_Sh"; + builder.append(uint64_t(hash), 16); + + return builder; +} + +} // namespace Slang |
