diff options
Diffstat (limited to 'source/slang/slang-linkable.cpp')
| -rw-r--r-- | source/slang/slang-linkable.cpp | 1037 |
1 files changed, 1037 insertions, 0 deletions
diff --git a/source/slang/slang-linkable.cpp b/source/slang/slang-linkable.cpp new file mode 100644 index 000000000..da4cec823 --- /dev/null +++ b/source/slang/slang-linkable.cpp @@ -0,0 +1,1037 @@ +// slang-linkable.cpp +#include "slang-linkable.h" + +#include "compiler-core/slang-artifact-container-util.h" +#include "compiler-core/slang-artifact-desc-util.h" +#include "compiler-core/slang-artifact-impl.h" +#include "core/slang-char-util.h" +#include "core/slang-memory-file-system.h" +#include "slang-check-impl.h" +#include "slang-compiler.h" +#include "slang-mangle.h" + +namespace Slang +{ + +// +// ModuleDependencyList +// + +void ModuleDependencyList::addDependency(Module* module) +{ + // If we depend on a module, then we depend on everything it depends on. + // + // Note: We are processing these sub-depenencies before adding the + // `module` itself, so that in the common case a module will always + // appear *after* everything it depends on. + // + // However, this rule is being violated in the compiler right now because + // the modules for hte top-level translation units of a compile request + // will be added to the list first (using `addLeafDependency`) to + // maintain compatibility with old behavior. This may be fixed later. + // + for (auto subDependency : module->getModuleDependencyList()) + { + _addDependency(subDependency); + } + _addDependency(module); +} + +void ModuleDependencyList::addLeafDependency(Module* module) +{ + _addDependency(module); +} + +void ModuleDependencyList::_addDependency(Module* module) +{ + if (m_moduleSet.contains(module)) + return; + + m_moduleList.add(module); + m_moduleSet.add(module); +} + +// +// FileDependencyList +// + +void FileDependencyList::addDependency(SourceFile* sourceFile) +{ + if (m_fileSet.contains(sourceFile)) + return; + + m_fileList.add(sourceFile); + m_fileSet.add(sourceFile); +} + +void FileDependencyList::addDependency(Module* module) +{ + for (SourceFile* sourceFile : module->getFileDependencyList()) + { + addDependency(sourceFile); + } +} + +// +// ComponentType +// + +ComponentType::ComponentType(Linkage* linkage) + : m_linkage(linkage) +{ +} + +ComponentType* asInternal(slang::IComponentType* inComponentType) +{ + // Note: we use a `queryInterface` here instead of just a `static_cast` + // to ensure that the `IComponentType` we get is the preferred/canonical + // one, which shares its address with the `ComponentType`. + // + // TODO: An alternative choice here would be to have a "magic" IID that + // we pass into `queryInterface` that returns the `ComponentType` directly + // (without even `addRef`-ing it). + // + ComPtr<slang::IComponentType> componentType; + inComponentType->queryInterface(SLANG_IID_PPV_ARGS(componentType.writeRef())); + return static_cast<ComponentType*>(componentType.get()); +} + +ISlangUnknown* ComponentType::getInterface(Guid const& guid) +{ + if (guid == ISlangUnknown::getTypeGuid() || guid == slang::IComponentType::getTypeGuid()) + { + return static_cast<slang::IComponentType*>(this); + } + if (guid == IModulePrecompileService_Experimental::getTypeGuid()) + return static_cast<slang::IModulePrecompileService_Experimental*>(this); + if (guid == IComponentType2::getTypeGuid()) + return static_cast<slang::IComponentType2*>(this); + return nullptr; +} + +SLANG_NO_THROW slang::ISession* SLANG_MCALL ComponentType::getSession() +{ + return m_linkage; +} + +SLANG_NO_THROW slang::ProgramLayout* SLANG_MCALL +ComponentType::getLayout(Int targetIndex, slang::IBlob** outDiagnostics) +{ + auto linkage = getLinkage(); + if (targetIndex < 0 || targetIndex >= linkage->targets.getCount()) + return nullptr; + auto target = linkage->targets[targetIndex]; + + DiagnosticSink sink(linkage->getSourceManager(), Lexer::sourceLocationLexer); + auto programLayout = getTargetProgram(target)->getOrCreateLayout(&sink); + sink.getBlobIfNeeded(outDiagnostics); + + return asExternal(programLayout); +} + +static ICastable* _findDiagnosticRepresentation(IArtifact* artifact) +{ + if (auto rep = findAssociatedRepresentation<IArtifactDiagnostics>(artifact)) + { + return rep; + } + + for (auto associated : artifact->getAssociated()) + { + if (isDerivedFrom(associated->getDesc().payload, ArtifactPayload::Diagnostics)) + { + return associated; + } + } + return nullptr; +} + +static IArtifact* _findObfuscatedSourceMap(IArtifact* artifact) +{ + // If we find any obfuscated source maps, we are done + for (auto associated : artifact->getAssociated()) + { + const auto desc = associated->getDesc(); + + if (isDerivedFrom(desc.payload, ArtifactPayload::SourceMap) && + isDerivedFrom(desc.style, ArtifactStyle::Obfuscated)) + { + return associated; + } + } + return nullptr; +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::getResultAsFileSystem( + SlangInt entryPointIndex, + Int targetIndex, + ISlangMutableFileSystem** outFileSystem) +{ + ComPtr<ISlangBlob> diagnostics; + ComPtr<ISlangBlob> code; + + SLANG_RETURN_ON_FAIL( + getEntryPointCode(entryPointIndex, targetIndex, diagnostics.writeRef(), code.writeRef())); + + auto linkage = getLinkage(); + + auto target = linkage->targets[targetIndex]; + + auto targetProgram = getTargetProgram(target); + + IArtifact* artifact = targetProgram->getExistingEntryPointResult(entryPointIndex); + + // Add diagnostics id needs be... + if (diagnostics && !_findDiagnosticRepresentation(artifact)) + { + // Add as an associated + + auto diagnosticsArtifact = Artifact::create( + ArtifactDesc::make(Artifact::Kind::HumanText, ArtifactPayload::Diagnostics)); + diagnosticsArtifact->addRepresentationUnknown(diagnostics); + + artifact->addAssociated(diagnosticsArtifact); + + SLANG_ASSERT(diagnosticsArtifact == _findDiagnosticRepresentation(artifact)); + } + + // Add obfuscated source maps + if (!_findObfuscatedSourceMap(artifact)) + { + List<IRModule*> irModules; + enumerateIRModules([&](IRModule* irModule) -> void { irModules.add(irModule); }); + + for (auto irModule : irModules) + { + if (auto obfuscatedSourceMap = irModule->getObfuscatedSourceMap()) + { + auto artifactDesc = ArtifactDesc::make( + ArtifactKind::Json, + ArtifactPayload::SourceMap, + ArtifactStyle::Obfuscated); + + // Create the source map artifact + auto sourceMapArtifact = Artifact::create( + artifactDesc, + obfuscatedSourceMap->get().m_file.getUnownedSlice()); + + sourceMapArtifact->addRepresentation(obfuscatedSourceMap); + + // associate with the artifact + artifact->addAssociated(sourceMapArtifact); + } + } + } + + // Turn into a file system and return + ComPtr<ISlangMutableFileSystem> fileSystem(new MemoryFileSystem); + + // Filter the containerArtifact into things that can be written + ComPtr<IArtifact> writeArtifact; + SLANG_RETURN_ON_FAIL(ArtifactContainerUtil::filter(artifact, writeArtifact)); + SLANG_RETURN_ON_FAIL(ArtifactContainerUtil::writeContainer(writeArtifact, "", fileSystem)); + + *outFileSystem = fileSystem.detach(); + + return SLANG_OK; +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::getEntryPointCode( + SlangInt entryPointIndex, + Int targetIndex, + slang::IBlob** outCode, + slang::IBlob** outDiagnostics) +{ + auto linkage = getLinkage(); + if (targetIndex < 0 || targetIndex >= linkage->targets.getCount()) + return SLANG_E_INVALID_ARG; + auto target = linkage->targets[targetIndex]; + + auto targetProgram = getTargetProgram(target); + + DiagnosticSink sink(linkage->getSourceManager(), Lexer::sourceLocationLexer); + applySettingsToDiagnosticSink(&sink, &sink, linkage->m_optionSet); + applySettingsToDiagnosticSink(&sink, &sink, m_optionSet); + + IArtifact* artifact = targetProgram->getOrCreateEntryPointResult(entryPointIndex, &sink); + sink.getBlobIfNeeded(outDiagnostics); + + if (artifact == nullptr) + return SLANG_FAIL; + + return artifact->loadBlob(ArtifactKeep::Yes, outCode); +} + +SLANG_NO_THROW void SLANG_MCALL ComponentType::getEntryPointHash( + SlangInt entryPointIndex, + SlangInt targetIndex, + slang::IBlob** outHash) +{ + DigestBuilder<SHA1> builder; + + // A note on enums that may be hashed in as part of the following two function calls: + // + // While enums are not guaranteed to be encoded the same way across all versions of + // the compiler, part of hashing the linkage is hashing in the compiler version. + // Consequently, any encoding differences as a result of different compiler versions + // will already be reflected in the resulting hash. + getLinkage()->buildHash(builder, targetIndex); + + buildHash(builder); + + // Add the name and name override for the specified entry point to the hash. + auto entryPoint = getEntryPoint(entryPointIndex); + if (entryPoint) + { + auto entryPointName = entryPoint->getName()->text; + builder.append(entryPointName); + auto entryPointMangledName = getEntryPointMangledName(entryPointIndex); + builder.append(entryPointMangledName); + auto entryPointNameOverride = getEntryPointNameOverride(entryPointIndex); + builder.append(entryPointNameOverride); + } + + auto hash = builder.finalize().toBlob(); + *outHash = hash.detach(); +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::getEntryPointHostCallable( + int entryPointIndex, + int targetIndex, + ISlangSharedLibrary** outSharedLibrary, + slang::IBlob** outDiagnostics) +{ + auto linkage = getLinkage(); + if (targetIndex < 0 || targetIndex >= linkage->targets.getCount()) + return SLANG_E_INVALID_ARG; + auto target = linkage->targets[targetIndex]; + + auto targetProgram = getTargetProgram(target); + + DiagnosticSink sink(linkage->getSourceManager(), Lexer::sourceLocationLexer); + applySettingsToDiagnosticSink(&sink, &sink, m_optionSet); + + IArtifact* artifact = targetProgram->getOrCreateEntryPointResult(entryPointIndex, &sink); + sink.getBlobIfNeeded(outDiagnostics); + + if (artifact == nullptr) + return SLANG_FAIL; + + return artifact->loadSharedLibrary(ArtifactKeep::Yes, outSharedLibrary); +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::getEntryPointMetadata( + SlangInt entryPointIndex, + Int targetIndex, + slang::IMetadata** outMetadata, + slang::IBlob** outDiagnostics) +{ + auto linkage = getLinkage(); + if (targetIndex < 0 || targetIndex >= linkage->targets.getCount()) + return SLANG_E_INVALID_ARG; + auto target = linkage->targets[targetIndex]; + + auto targetProgram = getTargetProgram(target); + + DiagnosticSink sink(linkage->getSourceManager(), Lexer::sourceLocationLexer); + applySettingsToDiagnosticSink(&sink, &sink, linkage->m_optionSet); + applySettingsToDiagnosticSink(&sink, &sink, m_optionSet); + + IArtifact* artifact = targetProgram->getOrCreateEntryPointResult(entryPointIndex, &sink); + sink.getBlobIfNeeded(outDiagnostics); + + if (artifact == nullptr) + return SLANG_E_NOT_AVAILABLE; + + auto metadata = findAssociatedRepresentation<IArtifactPostEmitMetadata>(artifact); + if (!metadata) + return SLANG_E_NOT_AVAILABLE; + + *outMetadata = static_cast<slang::IMetadata*>(metadata); + (*outMetadata)->addRef(); + return SLANG_OK; +} + +RefPtr<ComponentType> ComponentType::specialize( + SpecializationArg const* inSpecializationArgs, + SlangInt specializationArgCount, + DiagnosticSink* sink) +{ + if (specializationArgCount == 0) + { + return this; + } + + List<SpecializationArg> specializationArgs; + specializationArgs.addRange(inSpecializationArgs, specializationArgCount); + + // We next need to validate that the specialization arguments + // make sense, and also expand them to include any derived data + // (e.g., interface conformance witnesses) that doesn't get + // passed explicitly through the API interface. + // + RefPtr<SpecializationInfo> specializationInfo = + _validateSpecializationArgs(specializationArgs.getBuffer(), specializationArgCount, sink); + + return new SpecializedComponentType(this, specializationInfo, specializationArgs, sink); +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::specialize( + slang::SpecializationArg const* specializationArgs, + SlangInt specializationArgCount, + slang::IComponentType** outSpecializedComponentType, + ISlangBlob** outDiagnostics) +{ + DiagnosticSink sink(getLinkage()->getSourceManager(), Lexer::sourceLocationLexer); + + // First let's check if the number of arguments given matches + // the number of parameters that are present on this component type. + // + auto specializationParamCount = getSpecializationParamCount(); + if (specializationArgCount != specializationParamCount) + { + sink.diagnose( + SourceLoc(), + Diagnostics::mismatchSpecializationArguments, + specializationParamCount, + specializationArgCount); + sink.getBlobIfNeeded(outDiagnostics); + return SLANG_FAIL; + } + + List<SpecializationArg> expandedArgs; + for (Int aa = 0; aa < specializationArgCount; ++aa) + { + auto apiArg = specializationArgs[aa]; + + SpecializationArg expandedArg; + switch (apiArg.kind) + { + case slang::SpecializationArg::Kind::Type: + expandedArg.val = asInternal(apiArg.type); + break; + + default: + sink.getBlobIfNeeded(outDiagnostics); + return SLANG_FAIL; + } + expandedArgs.add(expandedArg); + } + + auto specializedComponentType = + specialize(expandedArgs.getBuffer(), expandedArgs.getCount(), &sink); + + sink.getBlobIfNeeded(outDiagnostics); + + *outSpecializedComponentType = specializedComponentType.detach(); + + return SLANG_OK; +} + +SLANG_NO_THROW SlangResult SLANG_MCALL +ComponentType::renameEntryPoint(const char* newName, IComponentType** outEntryPoint) +{ + RefPtr<RenamedEntryPointComponentType> result = + new RenamedEntryPointComponentType(this, newName); + *outEntryPoint = result.detach(); + return SLANG_OK; +} + +RefPtr<ComponentType> fillRequirements(ComponentType* inComponentType); + +SLANG_NO_THROW SlangResult SLANG_MCALL +ComponentType::link(slang::IComponentType** outLinkedComponentType, ISlangBlob** outDiagnostics) +{ + // TODO: It should be possible for `fillRequirements` to fail, + // in cases where we have a dependency that can't be automatically + // resolved. + // + SLANG_UNUSED(outDiagnostics); + + DiagnosticSink sink(getLinkage()->getSourceManager(), Lexer::sourceLocationLexer); + + try + { + auto linked = fillRequirements(this); + if (!linked) + return SLANG_FAIL; + + *outLinkedComponentType = ComPtr<slang::IComponentType>(linked).detach(); + return SLANG_OK; + } + catch (const AbortCompilationException& e) + { + outputExceptionDiagnostic(e, sink, outDiagnostics); + return SLANG_FAIL; + } + catch (const Exception& e) + { + outputExceptionDiagnostic(e, sink, outDiagnostics); + return SLANG_FAIL; + } + catch (...) + { + outputExceptionDiagnostic(sink, outDiagnostics); + return SLANG_FAIL; + } +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::linkWithOptions( + slang::IComponentType** outLinkedComponentType, + uint32_t count, + slang::CompilerOptionEntry* entries, + ISlangBlob** outDiagnostics) +{ + SLANG_RETURN_ON_FAIL(link(outLinkedComponentType, outDiagnostics)); + + auto linked = *outLinkedComponentType; + + if (linked) + { + static_cast<ComponentType*>(linked)->getOptionSet().load(count, entries); + } + + return SLANG_OK; +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::getEntryPointCompileResult( + SlangInt entryPointIndex, + Int targetIndex, + slang::ICompileResult** outCompileResult, + slang::IBlob** outDiagnostics) +{ + auto linkage = getLinkage(); + if (targetIndex < 0 || targetIndex >= linkage->targets.getCount()) + return SLANG_E_INVALID_ARG; + auto target = linkage->targets[targetIndex]; + + auto targetProgram = getTargetProgram(target); + + DiagnosticSink sink(linkage->getSourceManager(), Lexer::sourceLocationLexer); + applySettingsToDiagnosticSink(&sink, &sink, linkage->m_optionSet); + applySettingsToDiagnosticSink(&sink, &sink, m_optionSet); + + IArtifact* artifact = targetProgram->getOrCreateEntryPointResult(entryPointIndex, &sink); + sink.getBlobIfNeeded(outDiagnostics); + if (artifact == nullptr) + return SLANG_E_NOT_AVAILABLE; + + *outCompileResult = static_cast<slang::ICompileResult*>(artifact); + (*outCompileResult)->addRef(); + return SLANG_OK; +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::getTargetCompileResult( + Int targetIndex, + slang::ICompileResult** outCompileResult, + slang::IBlob** outDiagnostics) +{ + IArtifact* artifact = getTargetArtifact(targetIndex, outDiagnostics); + if (artifact == nullptr) + return SLANG_E_NOT_AVAILABLE; + + *outCompileResult = static_cast<slang::ICompileResult*>(artifact); + (*outCompileResult)->addRef(); + return SLANG_OK; +} + +/// Visitor used by `ComponentType::enumerateModules` +struct EnumerateModulesVisitor : ComponentTypeVisitor +{ + EnumerateModulesVisitor(ComponentType::EnumerateModulesCallback callback, void* userData) + : m_callback(callback), m_userData(userData) + { + } + + ComponentType::EnumerateModulesCallback m_callback; + void* m_userData; + + void visitEntryPoint(EntryPoint*, EntryPoint::EntryPointSpecializationInfo*) SLANG_OVERRIDE {} + + void visitRenamedEntryPoint( + RenamedEntryPointComponentType* entryPoint, + EntryPoint::EntryPointSpecializationInfo* specializationInfo) SLANG_OVERRIDE + { + entryPoint->getBase()->acceptVisitor(this, specializationInfo); + } + + void visitModule(Module* module, Module::ModuleSpecializationInfo*) SLANG_OVERRIDE + { + m_callback(module, m_userData); + } + + void visitComposite( + CompositeComponentType* composite, + CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE + { + visitChildren(composite, specializationInfo); + } + + void visitSpecialized(SpecializedComponentType* specialized) SLANG_OVERRIDE + { + visitChildren(specialized); + } + + void visitTypeConformance(TypeConformance* conformance) SLANG_OVERRIDE + { + SLANG_UNUSED(conformance); + } +}; + + +void ComponentType::enumerateModules(EnumerateModulesCallback callback, void* userData) +{ + EnumerateModulesVisitor visitor(callback, userData); + acceptVisitor(&visitor, nullptr); +} + +/// Visitor used by `ComponentType::enumerateIRModules` +struct EnumerateIRModulesVisitor : ComponentTypeVisitor +{ + EnumerateIRModulesVisitor(ComponentType::EnumerateIRModulesCallback callback, void* userData) + : m_callback(callback), m_userData(userData) + { + } + + ComponentType::EnumerateIRModulesCallback m_callback; + void* m_userData; + + void visitEntryPoint(EntryPoint*, EntryPoint::EntryPointSpecializationInfo*) SLANG_OVERRIDE {} + + void visitRenamedEntryPoint( + RenamedEntryPointComponentType* entryPoint, + EntryPoint::EntryPointSpecializationInfo* specializationInfo) SLANG_OVERRIDE + { + entryPoint->getBase()->acceptVisitor(this, specializationInfo); + } + + void visitModule(Module* module, Module::ModuleSpecializationInfo*) SLANG_OVERRIDE + { + m_callback(module->getIRModule(), m_userData); + } + + void visitComposite( + CompositeComponentType* composite, + CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE + { + visitChildren(composite, specializationInfo); + } + + void visitSpecialized(SpecializedComponentType* specialized) SLANG_OVERRIDE + { + visitChildren(specialized); + + m_callback(specialized->getIRModule(), m_userData); + } + + void visitTypeConformance(TypeConformance* conformance) SLANG_OVERRIDE + { + m_callback(conformance->getIRModule(), m_userData); + } +}; + +void ComponentType::enumerateIRModules(EnumerateIRModulesCallback callback, void* userData) +{ + EnumerateIRModulesVisitor visitor(callback, userData); + acceptVisitor(&visitor, nullptr); +} + +IArtifact* ComponentType::getTargetArtifact(Int targetIndex, slang::IBlob** outDiagnostics) +{ + auto linkage = getLinkage(); + if (targetIndex < 0 || targetIndex >= linkage->targets.getCount()) + return nullptr; + ComPtr<IArtifact> artifact; + if (m_targetArtifacts.tryGetValue(targetIndex, artifact)) + { + return artifact.get(); + } + + // If the user hasn't specified any entry points, then we should + // discover all entrypoints that are defined in linked modules, and + // include all of them in the compile. + // + if (getEntryPointCount() == 0) + { + List<Module*> modules; + this->enumerateModules([&](Module* module) { modules.add(module); }); + List<RefPtr<ComponentType>> components; + components.add(this); + bool entryPointsDiscovered = false; + for (auto module : modules) + { + for (auto entryPoint : module->getEntryPoints()) + { + components.add(entryPoint); + entryPointsDiscovered = true; + } + } + + // If any entry points were discovered, then we should emit the program with entrypoints + // linked. + if (entryPointsDiscovered) + { + RefPtr<CompositeComponentType> composite = + new CompositeComponentType(linkage, components); + ComPtr<IComponentType> linkedComponentType; + SLANG_RETURN_NULL_ON_FAIL( + composite->link(linkedComponentType.writeRef(), outDiagnostics)); + auto targetArtifact = static_cast<ComponentType*>(linkedComponentType.get()) + ->getTargetArtifact(targetIndex, outDiagnostics); + if (targetArtifact) + { + m_targetArtifacts[targetIndex] = targetArtifact; + } + return targetArtifact; + } + } + + auto target = linkage->targets[targetIndex]; + auto targetProgram = getTargetProgram(target); + + DiagnosticSink sink(linkage->getSourceManager(), Lexer::sourceLocationLexer); + applySettingsToDiagnosticSink(&sink, &sink, linkage->m_optionSet); + applySettingsToDiagnosticSink(&sink, &sink, m_optionSet); + + IArtifact* targetArtifact = targetProgram->getOrCreateWholeProgramResult(&sink); + sink.getBlobIfNeeded(outDiagnostics); + m_targetArtifacts[targetIndex] = ComPtr<IArtifact>(targetArtifact); + return targetArtifact; +} + +SLANG_NO_THROW SlangResult SLANG_MCALL +ComponentType::getTargetCode(Int targetIndex, slang::IBlob** outCode, slang::IBlob** outDiagnostics) +{ + IArtifact* artifact = getTargetArtifact(targetIndex, outDiagnostics); + + if (artifact == nullptr) + return SLANG_FAIL; + + return artifact->loadBlob(ArtifactKeep::Yes, outCode); +} + +SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::getTargetMetadata( + Int targetIndex, + slang::IMetadata** outMetadata, + slang::IBlob** outDiagnostics) +{ + IArtifact* artifact = getTargetArtifact(targetIndex, outDiagnostics); + + if (artifact == nullptr) + return SLANG_FAIL; + + auto metadata = findAssociatedRepresentation<IArtifactPostEmitMetadata>(artifact); + if (!metadata) + return SLANG_E_NOT_AVAILABLE; + *outMetadata = static_cast<slang::IMetadata*>(metadata); + (*outMetadata)->addRef(); + return SLANG_OK; +} + +Type* ComponentType::getTypeFromString(String const& typeStr, DiagnosticSink* sink) +{ + // If we've looked up this type name before, + // then we can re-use it. + // + Type* type = nullptr; + if (m_types.tryGetValue(typeStr, type)) + return type; + + + // TODO(JS): For now just used the linkages ASTBuilder to keep on scope + // + // The parseTermString uses the linkage ASTBuilder for it's parsing. + // + // It might be possible to just create a temporary ASTBuilder - the worry though is + // that the parsing sets a member variable in AST node to one of these scopes, and then + // it become a dangling pointer. So for now we go with the linkages. + auto astBuilder = getLinkage()->getASTBuilder(); + + // Otherwise, we need to start looking in + // the modules that were directly or + // indirectly referenced. + // + Scope* scope = _getOrCreateScopeForLegacyLookup(astBuilder); + + auto linkage = getLinkage(); + + SLANG_AST_BUILDER_RAII(linkage->getASTBuilder()); + + Expr* typeExpr = linkage->parseTermString(typeStr, scope); + SharedSemanticsContext sharedSemanticsContext(linkage, nullptr, sink); + SemanticsVisitor visitor(&sharedSemanticsContext); + type = visitor.TranslateTypeNode(typeExpr); + auto typeOut = visitor.tryCoerceToProperType(TypeExp(type)); + if (typeOut.type) + type = typeOut.type; + + if (type) + { + m_types[typeStr] = type; + } + return type; +} + +Expr* ComponentType::findDeclFromString(String const& name, DiagnosticSink* sink) +{ + // If we've looked up this type name before, + // then we can re-use it. + // + Expr* result = nullptr; + if (m_decls.tryGetValue(name, result)) + return result; + + + // TODO(JS): For now just used the linkages ASTBuilder to keep on scope + // + // The parseTermString uses the linkage ASTBuilder for it's parsing. + // + // It might be possible to just create a temporary ASTBuilder - the worry though is + // that the parsing sets a member variable in AST node to one of these scopes, and then + // it become a dangling pointer. So for now we go with the linkages. + auto astBuilder = getLinkage()->getASTBuilder(); + + // Otherwise, we need to start looking in + // the modules that were directly or + // indirectly referenced. + // + Scope* scope = _getOrCreateScopeForLegacyLookup(astBuilder); + + auto linkage = getLinkage(); + + SLANG_AST_BUILDER_RAII(linkage->getASTBuilder()); + + Expr* expr = linkage->parseTermString(name, scope); + + SemanticsContext context(linkage->getSemanticsForReflection()); + context = context.allowStaticReferenceToNonStaticMember().withSink(sink); + + SemanticsVisitor visitor(context); + + auto checkedExpr = visitor.CheckTerm(expr); + + if (as<DeclRefExpr>(checkedExpr) || as<OverloadedExpr>(checkedExpr)) + { + result = checkedExpr; + } + + m_decls[name] = result; + return result; +} + +static bool _isSimpleName(String const& name) +{ + for (char c : name) + { + if (!CharUtil::isAlphaOrDigit(c) && c != '_' && c != '$') + return false; + } + return true; +} + +Expr* ComponentType::findDeclFromStringInType( + Type* type, + String const& name, + LookupMask mask, + DiagnosticSink* sink) +{ + // Only look up in the type if it is a DeclRefType + if (!as<DeclRefType>(type)) + return nullptr; + + // TODO(JS): For now just used the linkages ASTBuilder to keep on scope + // + // The parseTermString uses the linkage ASTBuilder for it's parsing. + // + // It might be possible to just create a temporary ASTBuilder - the worry though is + // that the parsing sets a member variable in AST node to one of these scopes, and then + // it become a dangling pointer. So for now we go with the linkages. + auto astBuilder = getLinkage()->getASTBuilder(); + + // Otherwise, we need to start looking in + // the modules that were directly or + // indirectly referenced. + // + Scope* scope = _getOrCreateScopeForLegacyLookup(astBuilder); + + auto linkage = getLinkage(); + + SLANG_AST_BUILDER_RAII(linkage->getASTBuilder()); + + Expr* expr = nullptr; + + if (_isSimpleName(name)) + { + auto varExpr = astBuilder->create<VarExpr>(); + varExpr->scope = scope; + varExpr->name = getLinkage()->getNamePool()->getName(name); + expr = varExpr; + } + else + { + expr = linkage->parseTermString(name, scope); + } + SemanticsContext context(linkage->getSemanticsForReflection()); + context = context.allowStaticReferenceToNonStaticMember().withSink(sink); + + SemanticsVisitor visitor(context); + + GenericAppExpr* genericOuterExpr = nullptr; + if (as<GenericAppExpr>(expr)) + { + // Unwrap the generic application, and re-wrap it around the static-member expr + genericOuterExpr = as<GenericAppExpr>(expr); + expr = genericOuterExpr->functionExpr; + } + + if (!as<VarExpr>(expr)) + return nullptr; + + auto rs = astBuilder->create<StaticMemberExpr>(); + auto typeExpr = astBuilder->create<SharedTypeExpr>(); + auto typetype = astBuilder->getOrCreate<TypeType>(type); + typeExpr->type = typetype; + rs->baseExpression = typeExpr; + rs->name = as<VarExpr>(expr)->name; + + expr = rs; + + // If we have a generic-app expression, re-wrap the static-member expr + if (genericOuterExpr) + { + genericOuterExpr->functionExpr = expr; + expr = genericOuterExpr; + } + + auto checkedTerm = visitor.CheckTerm(expr); + + // Check if checkedTerm is overloaded functions and avoid resolving if so + // to preserve all function overloads with different signatures + Expr* resolvedTerm = checkedTerm; + if (auto overloadedExpr = as<OverloadedExpr>(checkedTerm)) + { + // Check if all candidates are function references + bool allAreFunctions = true; + for (auto item : overloadedExpr->lookupResult2.items) + { + if (!as<FunctionDeclBase>(item.declRef.getDecl())) + { + allAreFunctions = false; + break; + } + } + + // If not all are functions, resolve the overload as usual + if (!allAreFunctions) + { + resolvedTerm = visitor.maybeResolveOverloadedExpr(checkedTerm, mask, sink); + } + } + else + { + // Not overloaded, resolve as usual + resolvedTerm = visitor.maybeResolveOverloadedExpr(checkedTerm, mask, sink); + } + + if (auto overloadedExpr = as<OverloadedExpr>(resolvedTerm)) + { + return overloadedExpr; + } + if (auto declRefExpr = as<DeclRefExpr>(resolvedTerm)) + { + return declRefExpr; + } + + return nullptr; +} + +bool ComponentType::isSubType(Type* subType, Type* superType) +{ + SemanticsContext context(getLinkage()->getSemanticsForReflection()); + SemanticsVisitor visitor(context); + + return (visitor.isSubtype(subType, superType, IsSubTypeOptions::None) != nullptr); +} + +static void collectExportedConstantInContainer( + Dictionary<String, IntVal*>& dict, + ASTBuilder* builder, + ContainerDecl* containerDecl) +{ + for (auto varMember : containerDecl->getDirectMemberDeclsOfType<VarDeclBase>()) + { + if (!varMember->val) + continue; + bool isExported = false; + bool isConst = false; + bool isExtern = false; + for (auto modifier : varMember->modifiers) + { + if (as<HLSLExportModifier>(modifier)) + isExported = true; + if (as<ExternAttribute>(modifier) || as<ExternModifier>(modifier)) + { + isExtern = true; + isExported = true; + } + if (as<ConstModifier>(modifier)) + isConst = true; + } + if (isExported && isConst) + { + auto mangledName = getMangledName(builder, varMember); + if (isExtern && dict.containsKey(mangledName)) + continue; + dict[mangledName] = varMember->val; + } + } + + for (auto member : containerDecl->getDirectMemberDecls()) + { + if (as<NamespaceDecl>(member) || as<FileDecl>(member)) + { + collectExportedConstantInContainer(dict, builder, (ContainerDecl*)member); + } + } +} + +Dictionary<String, IntVal*>& ComponentType::getMangledNameToIntValMap() +{ + if (m_mapMangledNameToIntVal) + { + return *m_mapMangledNameToIntVal; + } + m_mapMangledNameToIntVal = std::make_unique<Dictionary<String, IntVal*>>(); + auto astBuilder = getLinkage()->getASTBuilder(); + SLANG_AST_BUILDER_RAII(astBuilder); + Scope* scope = _getOrCreateScopeForLegacyLookup(astBuilder); + for (; scope; scope = scope->nextSibling) + { + if (scope->containerDecl) + collectExportedConstantInContainer( + *m_mapMangledNameToIntVal, + astBuilder, + scope->containerDecl); + } + return *m_mapMangledNameToIntVal; +} + +ConstantIntVal* ComponentType::tryFoldIntVal(IntVal* intVal) +{ + auto astBuilder = getLinkage()->getASTBuilder(); + SLANG_AST_BUILDER_RAII(astBuilder); + return as<ConstantIntVal>(intVal->linkTimeResolve(getMangledNameToIntValMap())); +} + +TargetProgram* ComponentType::getTargetProgram(TargetRequest* target) +{ + RefPtr<TargetProgram> targetProgram; + if (!m_targetPrograms.tryGetValue(target, targetProgram)) + { + targetProgram = new TargetProgram(this, target); + m_targetPrograms[target] = targetProgram; + } + return targetProgram; +} + +} // namespace Slang |
