summaryrefslogtreecommitdiffstats
path: root/source/slang/slang.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang.cpp')
-rw-r--r--source/slang/slang.cpp8070
1 files changed, 0 insertions, 8070 deletions
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 839ba7938..a428e7928 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -48,102 +48,9 @@
// Used to print exception type names in internal-compiler-error messages
#include <typeinfo>
-extern Slang::String get_slang_cuda_prelude();
-extern Slang::String get_slang_cpp_prelude();
-extern Slang::String get_slang_hlsl_prelude();
-
namespace Slang
{
-
-/* static */ const BaseTypeInfo BaseTypeInfo::s_info[Index(BaseType::CountOf)] = {
- {0, 0, uint8_t(BaseType::Void)},
- {uint8_t(sizeof(bool)), 0, uint8_t(BaseType::Bool)},
- {uint8_t(sizeof(int8_t)),
- BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer,
- uint8_t(BaseType::Int8)},
- {uint8_t(sizeof(int16_t)),
- BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer,
- uint8_t(BaseType::Int16)},
- {uint8_t(sizeof(int32_t)),
- BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer,
- uint8_t(BaseType::Int)},
- {uint8_t(sizeof(int64_t)),
- BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer,
- uint8_t(BaseType::Int64)},
- {uint8_t(sizeof(uint8_t)), BaseTypeInfo::Flag::Integer, uint8_t(BaseType::UInt8)},
- {uint8_t(sizeof(uint16_t)), BaseTypeInfo::Flag::Integer, uint8_t(BaseType::UInt16)},
- {uint8_t(sizeof(uint32_t)), BaseTypeInfo::Flag::Integer, uint8_t(BaseType::UInt)},
- {uint8_t(sizeof(uint64_t)), BaseTypeInfo::Flag::Integer, uint8_t(BaseType::UInt64)},
- {uint8_t(sizeof(uint16_t)), BaseTypeInfo::Flag::FloatingPoint, uint8_t(BaseType::Half)},
- {uint8_t(sizeof(float)), BaseTypeInfo::Flag::FloatingPoint, uint8_t(BaseType::Float)},
- {uint8_t(sizeof(double)), BaseTypeInfo::Flag::FloatingPoint, uint8_t(BaseType::Double)},
- {uint8_t(sizeof(char)),
- BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer,
- uint8_t(BaseType::Char)},
- {uint8_t(sizeof(intptr_t)),
- BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer,
- uint8_t(BaseType::IntPtr)},
- {uint8_t(sizeof(uintptr_t)), BaseTypeInfo::Flag::Integer, uint8_t(BaseType::UIntPtr)},
-};
-
-/* static */ bool BaseTypeInfo::check()
-{
- for (Index i = 0; i < SLANG_COUNT_OF(s_info); ++i)
- {
- if (s_info[i].baseType != i)
- {
- SLANG_ASSERT(!"Inconsistency between the s_info table and BaseInfo");
- return false;
- }
- }
- return true;
-}
-
-/* static */ UnownedStringSlice BaseTypeInfo::asText(BaseType baseType)
-{
- switch (baseType)
- {
- case BaseType::Void:
- return UnownedStringSlice::fromLiteral("void");
- case BaseType::Bool:
- return UnownedStringSlice::fromLiteral("bool");
- case BaseType::Int8:
- return UnownedStringSlice::fromLiteral("int8_t");
- case BaseType::Int16:
- return UnownedStringSlice::fromLiteral("int16_t");
- case BaseType::Int:
- return UnownedStringSlice::fromLiteral("int");
- case BaseType::Int64:
- return UnownedStringSlice::fromLiteral("int64_t");
- case BaseType::UInt8:
- return UnownedStringSlice::fromLiteral("uint8_t");
- case BaseType::UInt16:
- return UnownedStringSlice::fromLiteral("uint16_t");
- case BaseType::UInt:
- return UnownedStringSlice::fromLiteral("uint");
- case BaseType::UInt64:
- return UnownedStringSlice::fromLiteral("uint64_t");
- case BaseType::Half:
- return UnownedStringSlice::fromLiteral("half");
- case BaseType::Float:
- return UnownedStringSlice::fromLiteral("float");
- case BaseType::Double:
- return UnownedStringSlice::fromLiteral("double");
- case BaseType::Char:
- return UnownedStringSlice::fromLiteral("char");
- case BaseType::IntPtr:
- return UnownedStringSlice::fromLiteral("intptr_t");
- case BaseType::UIntPtr:
- return UnownedStringSlice::fromLiteral("uintptr_t");
- default:
- {
- SLANG_ASSERT(!"Unknown basic type");
- return UnownedStringSlice();
- }
- }
-}
-
const char* getBuildTagString()
{
if (UnownedStringSlice(SLANG_TAG_VERSION) == "0.0.0-unknown")
@@ -158,1102 +65,6 @@ const char* getBuildTagString()
return SLANG_TAG_VERSION;
}
-
-void Session::init()
-{
- SLANG_ASSERT(BaseTypeInfo::check());
-
-#if SLANG_ENABLE_IR_BREAK_ALLOC
- // Read environment variable for IR debugging
- StringBuilder irBreakEnv;
- if (SLANG_SUCCEEDED(PlatformUtil::getEnvironmentVariable(
- UnownedStringSlice("SLANG_DEBUG_IR_BREAK"),
- irBreakEnv)))
- {
- String envValue = irBreakEnv.produceString();
- if (envValue.getLength())
- {
- _slangIRAllocBreak = stringToInt(envValue);
- _slangIRPrintStackAtBreak = true;
- }
- }
-#endif
-
- _initCodeGenTransitionMap();
-
- ::memset(m_downstreamCompilerLocators, 0, sizeof(m_downstreamCompilerLocators));
- DownstreamCompilerUtil::setDefaultLocators(m_downstreamCompilerLocators);
- m_downstreamCompilerSet = new DownstreamCompilerSet;
-
- m_completionTokenName = getNamePool()->getName("#?");
-
- m_sharedLibraryLoader = DefaultSharedLibraryLoader::getSingleton();
-
- // Set up the command line options
- initCommandOptions(m_commandOptions);
-
- // Set up shared AST builder
- m_sharedASTBuilder = new SharedASTBuilder;
- m_sharedASTBuilder->init(this);
-
- // And the global ASTBuilder
- auto builtinAstBuilder = m_sharedASTBuilder->getInnerASTBuilder();
- globalAstBuilder = builtinAstBuilder;
-
- // Make sure our source manager is initialized
- builtinSourceManager.initialize(nullptr, nullptr);
-
- // Built in linkage uses the built in builder
- m_builtinLinkage = new Linkage(this, builtinAstBuilder, nullptr);
- m_builtinLinkage->m_optionSet.set(CompilerOptionName::DebugInformation, DebugInfoLevel::None);
-
- // Because the `Session` retains the builtin `Linkage`,
- // we need to make sure that the parent pointer inside
- // `Linkage` doesn't create a retain cycle.
- //
- // This operation ensures that the parent pointer will
- // just be a raw pointer, so that the builtin linkage
- // doesn't keep the parent session alive.
- //
- m_builtinLinkage->_stopRetainingParentSession();
-
- // Create scopes for various language builtins.
- //
- // TODO: load these on-demand to avoid parsing
- // the core module code for languages the user won't use.
-
- baseLanguageScope = builtinAstBuilder->create<Scope>();
-
- // Will stay in scope as long as ASTBuilder
- baseModuleDecl =
- populateBaseLanguageModule(m_builtinLinkage->getASTBuilder(), baseLanguageScope);
-
- coreLanguageScope = builtinAstBuilder->create<Scope>();
- coreLanguageScope->nextSibling = baseLanguageScope;
-
- hlslLanguageScope = builtinAstBuilder->create<Scope>();
- hlslLanguageScope->nextSibling = coreLanguageScope;
-
- slangLanguageScope = builtinAstBuilder->create<Scope>();
- slangLanguageScope->nextSibling = hlslLanguageScope;
-
- glslLanguageScope = builtinAstBuilder->create<Scope>();
- glslLanguageScope->nextSibling = slangLanguageScope;
-
- glslModuleName = getNameObj("glsl");
-
- {
- for (Index i = 0; i < Index(SourceLanguage::CountOf); ++i)
- {
- m_defaultDownstreamCompilers[i] = PassThroughMode::None;
- }
- m_defaultDownstreamCompilers[Index(SourceLanguage::C)] = PassThroughMode::GenericCCpp;
- m_defaultDownstreamCompilers[Index(SourceLanguage::CPP)] = PassThroughMode::GenericCCpp;
- m_defaultDownstreamCompilers[Index(SourceLanguage::CUDA)] = PassThroughMode::NVRTC;
- }
-
- // Set up default prelude code for target languages that need a prelude
- m_languagePreludes[Index(SourceLanguage::CUDA)] = get_slang_cuda_prelude();
- m_languagePreludes[Index(SourceLanguage::CPP)] = get_slang_cpp_prelude();
- m_languagePreludes[Index(SourceLanguage::HLSL)] = get_slang_hlsl_prelude();
-
- if (!spirvCoreGrammarInfo)
- spirvCoreGrammarInfo = SPIRVCoreGrammarInfo::getEmbeddedVersion();
-}
-
-Module* Session::getBuiltinModule(slang::BuiltinModuleName name)
-{
- auto info = getBuiltinModuleInfo(name);
- auto builtinLinkage = getBuiltinLinkage();
- auto moduleNameObj = builtinLinkage->getNamePool()->getName(info.name);
- RefPtr<Module> module;
- if (builtinLinkage->mapNameToLoadedModules.tryGetValue(moduleNameObj, module))
- return module.get();
- return nullptr;
-}
-
-void Session::_initCodeGenTransitionMap()
-{
- // TODO(JS): Might want to do something about these in the future...
-
- // PassThroughMode getDownstreamCompilerRequiredForTarget(CodeGenTarget target);
- // SourceLanguage getDefaultSourceLanguageForDownstreamCompiler(PassThroughMode compiler);
-
- // Set up the default ways to do compilations between code gen targets
- auto& map = m_codeGenTransitionMap;
-
- // TODO(JS): There currently isn't a 'downstream compiler' for direct spirv output. If we did
- // it would presumably a transition from SlangIR to SPIRV.
-
- // For C and C++ we default to use the 'genericCCpp' compiler
- {
- const CodeGenTarget sources[] = {CodeGenTarget::CSource, CodeGenTarget::CPPSource};
- for (auto source : sources)
- {
- // We *don't* add a default for host callable, as we will determine what is suitable
- // depending on what is available. We prefer LLVM if that's available. If it's not we
- // can use generic C/C++ compiler
-
- map.addTransition(
- source,
- CodeGenTarget::ShaderSharedLibrary,
- PassThroughMode::GenericCCpp);
- map.addTransition(
- source,
- CodeGenTarget::HostSharedLibrary,
- PassThroughMode::GenericCCpp);
- map.addTransition(source, CodeGenTarget::HostExecutable, PassThroughMode::GenericCCpp);
- map.addTransition(source, CodeGenTarget::ObjectCode, PassThroughMode::GenericCCpp);
- }
- }
-
-
- // Add all the straightforward transitions
- map.addTransition(CodeGenTarget::CUDASource, CodeGenTarget::PTX, PassThroughMode::NVRTC);
- map.addTransition(CodeGenTarget::HLSL, CodeGenTarget::DXBytecode, PassThroughMode::Fxc);
- map.addTransition(CodeGenTarget::HLSL, CodeGenTarget::DXIL, PassThroughMode::Dxc);
- map.addTransition(CodeGenTarget::GLSL, CodeGenTarget::SPIRV, PassThroughMode::Glslang);
- map.addTransition(CodeGenTarget::Metal, CodeGenTarget::MetalLib, PassThroughMode::MetalC);
- map.addTransition(CodeGenTarget::WGSL, CodeGenTarget::WGSLSPIRV, PassThroughMode::Tint);
- // To assembly
- map.addTransition(CodeGenTarget::SPIRV, CodeGenTarget::SPIRVAssembly, PassThroughMode::Glslang);
- // We use glslang to turn SPIR-V into SPIR-V assembly.
- map.addTransition(
- CodeGenTarget::WGSLSPIRV,
- CodeGenTarget::WGSLSPIRVAssembly,
- PassThroughMode::Glslang);
- map.addTransition(CodeGenTarget::DXIL, CodeGenTarget::DXILAssembly, PassThroughMode::Dxc);
- map.addTransition(
- CodeGenTarget::DXBytecode,
- CodeGenTarget::DXBytecodeAssembly,
- PassThroughMode::Fxc);
- map.addTransition(
- CodeGenTarget::MetalLib,
- CodeGenTarget::MetalLibAssembly,
- PassThroughMode::MetalC);
-}
-
-void Session::addBuiltins(char const* sourcePath, char const* source)
-{
- auto sourceBlob = StringBlob::moveCreate(String(source));
-
- // TODO(tfoley): Add ability to directly new builtins to the appropriate scope
- Module* module = nullptr;
- addBuiltinSource(coreLanguageScope, sourcePath, sourceBlob, module);
- if (module)
- coreModules.add(module);
-}
-
-void Session::setSharedLibraryLoader(ISlangSharedLibraryLoader* loader)
-{
- // External API allows passing of nullptr to reset the loader
- loader = loader ? loader : DefaultSharedLibraryLoader::getSingleton();
-
- _setSharedLibraryLoader(loader);
-}
-
-ISlangSharedLibraryLoader* Session::getSharedLibraryLoader()
-{
- return (m_sharedLibraryLoader == DefaultSharedLibraryLoader::getSingleton())
- ? nullptr
- : m_sharedLibraryLoader.get();
-}
-
-SlangResult Session::checkCompileTargetSupport(SlangCompileTarget inTarget)
-{
- auto target = CodeGenTarget(inTarget);
-
- const PassThroughMode mode = getDownstreamCompilerRequiredForTarget(target);
- return (mode != PassThroughMode::None) ? checkPassThroughSupport(SlangPassThrough(mode))
- : SLANG_OK;
-}
-
-SlangResult Session::checkPassThroughSupport(SlangPassThrough inPassThrough)
-{
- return checkExternalCompilerSupport(this, PassThroughMode(inPassThrough));
-}
-
-void Session::writeCoreModuleDoc(String config)
-{
- ASTBuilder* astBuilder = getBuiltinLinkage()->getASTBuilder();
- SourceManager* sourceManager = getBuiltinSourceManager();
-
- DiagnosticSink sink(sourceManager, Lexer::sourceLocationLexer);
-
- List<String> docStrings;
-
- // For all the modules add their doc output to docStrings
- for (Module* m : coreModules)
- {
- RefPtr<ASTMarkup> markup(new ASTMarkup);
- ASTMarkupUtil::extract(m->getModuleDecl(), sourceManager, &sink, markup);
-
- DocMarkdownWriter writer(markup, astBuilder, &sink);
- auto rootPage = writer.writeAll(config.getUnownedSlice());
- File::writeAllText("toc.html", writer.writeTOC());
- rootPage->writeToDisk();
- rootPage->writeSummary(toSlice("summary.txt"));
- }
- ComPtr<ISlangBlob> diagnosticBlob;
- sink.getBlobIfNeeded(diagnosticBlob.writeRef());
- if (diagnosticBlob && diagnosticBlob->getBufferSize() != 0)
- {
- // Write the diagnostic blob to stdout.
- fprintf(stderr, "%s", (const char*)diagnosticBlob->getBufferPointer());
- }
-}
-
-const char* getBuiltinModuleNameStr(slang::BuiltinModuleName name)
-{
- const char* result = nullptr;
- switch (name)
- {
- case slang::BuiltinModuleName::Core:
- result = "core";
- break;
- case slang::BuiltinModuleName::GLSL:
- result = "glsl";
- break;
- default:
- SLANG_UNEXPECTED("Unknown builtin module");
- }
- return result;
-}
-
-TypeCheckingCache* Session::getTypeCheckingCache()
-{
- return static_cast<TypeCheckingCache*>(m_typeCheckingCache.get());
-}
-
-Session::BuiltinModuleInfo Session::getBuiltinModuleInfo(slang::BuiltinModuleName name)
-{
- Session::BuiltinModuleInfo result;
-
- result.name = getBuiltinModuleNameStr(name);
-
- switch (name)
- {
- case slang::BuiltinModuleName::Core:
- result.languageScope = coreLanguageScope;
- break;
- case slang::BuiltinModuleName::GLSL:
- result.name = "glsl";
- result.languageScope = glslLanguageScope;
- break;
- default:
- SLANG_UNEXPECTED("Unknown builtin module");
- }
- return result;
-}
-
-SlangResult Session::compileCoreModule(slang::CompileCoreModuleFlags compileFlags)
-{
- return compileBuiltinModule(slang::BuiltinModuleName::Core, compileFlags);
-}
-
-void Session::getBuiltinModuleSource(StringBuilder& sb, slang::BuiltinModuleName moduleName)
-{
- switch (moduleName)
- {
- case slang::BuiltinModuleName::Core:
- sb << (const char*)getCoreLibraryCode()->getBufferPointer()
- << (const char*)getHLSLLibraryCode()->getBufferPointer()
- << (const char*)getAutodiffLibraryCode()->getBufferPointer();
- break;
- case slang::BuiltinModuleName::GLSL:
- sb << (const char*)getGLSLLibraryCode()->getBufferPointer();
- break;
- }
-}
-
-SlangResult Session::compileBuiltinModule(
- slang::BuiltinModuleName moduleName,
- slang::CompileCoreModuleFlags compileFlags)
-{
- SLANG_AST_BUILDER_RAII(m_builtinLinkage->getASTBuilder());
-
-#ifdef _DEBUG
- time_t beginTime = 0;
- if (moduleName == slang::BuiltinModuleName::Core)
- {
- // Print a message in debug builds to notice the user that compiling the core module
- // can take a while.
- time(&beginTime);
- fprintf(stderr, "Compiling core module on debug build, this can take a while.\n");
- }
-#endif
- BuiltinModuleInfo builtinModuleInfo = getBuiltinModuleInfo(moduleName);
- auto moduleNameObj = m_builtinLinkage->getNamePool()->getName(builtinModuleInfo.name);
- if (m_builtinLinkage->mapNameToLoadedModules.tryGetValue(moduleNameObj))
- {
- // Already have the builtin module loaded
- return SLANG_FAIL;
- }
-
- StringBuilder moduleSrcBuilder;
- getBuiltinModuleSource(moduleSrcBuilder, moduleName);
-
- // TODO(JS): Could make this return a SlangResult as opposed to exception
- auto moduleSrcBlob = StringBlob::moveCreate(moduleSrcBuilder.produceString());
- Module* compiledModule = nullptr;
- addBuiltinSource(
- builtinModuleInfo.languageScope,
- builtinModuleInfo.name,
- moduleSrcBlob,
- compiledModule);
-
- if (moduleName == slang::BuiltinModuleName::Core)
- {
- // We need to retain this AST so that we can use it in other code
- // (Note that the `Scope` type does not retain the AST it points to)
- coreModules.add(compiledModule);
- }
-
- if (compileFlags & slang::CompileCoreModuleFlag::WriteDocumentation)
- {
- // Load config file first.
- String configText;
- if (SLANG_FAILED(File::readAllText("config.txt", configText)))
- {
- fprintf(
- stderr,
- "Error writing documentation: config file not found on current working "
- "directory.\n");
- }
- else
- {
- writeCoreModuleDoc(configText);
- }
- }
-
- finalizeSharedASTBuilder();
-
-#ifdef _DEBUG
- if (moduleName == slang::BuiltinModuleName::Core)
- {
- time_t endTime;
- time(&endTime);
- fprintf(stderr, "Compiling core module took %.2f seconds.\n", difftime(endTime, beginTime));
- }
-#endif
- return SLANG_OK;
-}
-
-SlangResult Session::loadCoreModule(const void* coreModule, size_t coreModuleSizeInBytes)
-{
- return loadBuiltinModule(slang::BuiltinModuleName::Core, coreModule, coreModuleSizeInBytes);
-}
-
-SlangResult Session::loadBuiltinModule(
- slang::BuiltinModuleName moduleName,
- const void* moduleData,
- size_t sizeInBytes)
-{
- SLANG_PROFILE;
-
-
- SLANG_AST_BUILDER_RAII(m_builtinLinkage->getASTBuilder());
-
- BuiltinModuleInfo builtinModuleInfo = getBuiltinModuleInfo(moduleName);
- auto nameObj = m_builtinLinkage->getNamePool()->getName(builtinModuleInfo.name);
- if (m_builtinLinkage->mapNameToLoadedModules.containsKey(nameObj))
- {
- // Already have a core module loaded
- return SLANG_FAIL;
- }
-
- // Make a file system to read it from
- ComPtr<ISlangFileSystemExt> fileSystem;
- SLANG_RETURN_ON_FAIL(loadArchiveFileSystem(moduleData, sizeInBytes, fileSystem));
-
- // Let's try loading serialized modules and adding them
- Module* module = nullptr;
- SLANG_RETURN_ON_FAIL(_readBuiltinModule(
- fileSystem,
- builtinModuleInfo.languageScope,
- builtinModuleInfo.name,
- module));
-
- if (moduleName == slang::BuiltinModuleName::Core)
- {
- // We need to retain this AST so that we can use it in other code
- // (Note that the `Scope` type does not retain the AST it points to)
- coreModules.add(module);
- }
-
- finalizeSharedASTBuilder();
- return SLANG_OK;
-}
-
-SlangResult Session::saveCoreModule(SlangArchiveType archiveType, ISlangBlob** outBlob)
-{
- return saveBuiltinModule(slang::BuiltinModuleName::Core, archiveType, outBlob);
-}
-
-SlangResult Session::saveBuiltinModule(
- slang::BuiltinModuleName moduleTag,
- SlangArchiveType archiveType,
- ISlangBlob** outBlob)
-{
- // If no builtin modules have been loaded, then there is
- // nothing to save, and we fail immediately.
- //
- if (m_builtinLinkage->mapNameToLoadedModules.getCount() == 0)
- {
- return SLANG_FAIL;
- }
-
- // The module will need to be looked up by its name, and
- // will also be serialized out to a path with a matching name.
- //
- BuiltinModuleInfo moduleInfo = getBuiltinModuleInfo(moduleTag);
- const char* moduleName = moduleInfo.name;
-
- // If we cannot find a loaded module in the linkage with
- // the appropriate name, then for some reason it hasn't
- // been loaded, and we fail.
- //
- RefPtr<Module> module;
- m_builtinLinkage->mapNameToLoadedModules.tryGetValue(
- getNameObj(UnownedStringSlice(moduleName)),
- module);
- if (!module)
- {
- return SLANG_FAIL;
- }
-
- // AST serialization needs access to an AST builder, so
- // we establish a current builder for the duration of
- // the serialization process.
- //
- SLANG_AST_BUILDER_RAII(m_builtinLinkage->getASTBuilder());
-
- // The serialized module will be represented as a logical
- // file in an archive, so we create a logical file system
- // to represent that archive.
- //
- ComPtr<ISlangMutableFileSystem> fileSystem;
- SLANG_RETURN_ON_FAIL(createArchiveFileSystem(archiveType, fileSystem));
- //
- // The created file system must support the `IArchiveFileSystem`
- // interface (since we created it with `createArchiveFileSystem`).
- //
- auto archiveFileSystem = as<IArchiveFileSystem>(fileSystem);
- if (!archiveFileSystem)
- {
- return SLANG_FAIL;
- }
-
- // The output file name that we'll write to in that file system
- // is just the builtin module name with a `.slang-module` suffix.
- //
- StringBuilder moduleFileName;
- moduleFileName << moduleName << ".slang-module";
-
- // The module serialization step has some options that we need
- // to configure appropriately.
- //
- SerialContainerUtil::WriteOptions options;
- //
- // We want builtin modules to be saved with their source location
- // information.
- //
- // And in order to work with source locations, the serialization
- // process will also need access to the source manager that
- // can translate locations into their humane format.
- //
- options.sourceManagerToUseWhenSerializingSourceLocs = m_builtinLinkage->getSourceManager();
-
- // At this point we can finally delegate down to the next level,
- // which handles the serialization of a Slang module into a
- // byte stream.
- //
- OwnedMemoryStream stream(FileAccess::Write);
- SLANG_RETURN_ON_FAIL(SerialContainerUtil::write(module, options, &stream));
- auto contents = stream.getContents();
-
- // Once the stream that represents the module has been written, we can
- // write it to a file in the logical file system.
- //
- // TODO(tfoley): why can't the file system let us open the file for output?
- //
- SLANG_RETURN_ON_FAIL(fileSystem->saveFile(
- moduleFileName.getBuffer(),
- contents.getBuffer(),
- contents.getCount()));
-
- // And finally, we can ask the archive file system to serialize itself
- // out as a blob of bytes, which yields the final serialized representation
- // of the module.
- //
- SLANG_RETURN_ON_FAIL(archiveFileSystem->storeArchive(
- // The `true` here indicates that the blob that gets created should own
- // its content, independent from the file system object itself; otherwise
- // the file system might return a blob that shares storage with itself.
- true,
- outBlob));
-
- return SLANG_OK;
-}
-
-SlangResult Session::_readBuiltinModule(
- ISlangFileSystem* fileSystem,
- Scope* scope,
- String moduleName,
- Module*& outModule)
-{
- // Get the name of the module
- StringBuilder moduleFilename;
- moduleFilename << moduleName << ".slang-module";
-
- // Load it
- ComPtr<ISlangBlob> fileContents;
- SLANG_RETURN_ON_FAIL(fileSystem->loadFile(moduleFilename.getBuffer(), fileContents.writeRef()));
-
- RIFF::RootChunk const* rootChunk = RIFF::RootChunk::getFromBlob(fileContents);
- if (!rootChunk)
- {
- return SLANG_FAIL;
- }
-
- Linkage* linkage = getBuiltinLinkage();
- SourceManager* sourceManager = getBuiltinSourceManager();
- NamePool* sessionNamePool = &namePool;
-
- auto moduleChunk = ModuleChunk::find(rootChunk);
- if (!moduleChunk)
- return SLANG_FAIL;
-
- SHA1::Digest moduleDigest = moduleChunk->getDigest();
-
- auto irChunk = moduleChunk->findIR();
- if (!irChunk)
- return SLANG_FAIL;
-
- auto astChunk = moduleChunk->findAST();
- if (!astChunk)
- return SLANG_FAIL;
-
- // Source location information is stored as a distinct
- // chunk from the IR and AST, so we need to search for
- // that chunk and then set up the information for use
- // in the IR and AST deserialization (if we find anything).
- //
- RefPtr<SerialSourceLocReader> sourceLocReader;
- if (auto debugChunk = DebugChunk::find(moduleChunk))
- {
- SLANG_RETURN_ON_FAIL(
- readSourceLocationsFromDebugChunk(debugChunk, sourceManager, sourceLocReader));
- }
-
- // At this point we create the `Module` object that will
- // represent the builtin module we are reading, although
- // it is still possible that deserialization will fail
- // at one of the following steps.
- //
- auto astBuilder = linkage->getASTBuilder();
- RefPtr<Module> module(new Module(linkage, astBuilder));
- module->setName(moduleName);
- module->setDigest(moduleDigest);
-
-
- // Next, we set about deserializing the AST representation
- // of the module.
- //
- auto moduleDecl = readSerializedModuleAST(
- linkage,
- astBuilder,
- nullptr, // no sink
- fileContents,
- astChunk,
- sourceLocReader,
- SourceLoc());
- if (!moduleDecl)
- {
- return SLANG_FAIL;
- }
- moduleDecl->module = module;
- module->setModuleDecl(moduleDecl);
-
- // After the AST module has been read in, we next look
- // to deserialize the IR module.
- //
- RefPtr<IRModule> irModule;
- SLANG_RETURN_ON_FAIL(readSerializedModuleIR(irChunk, this, sourceLocReader, irModule));
-
- irModule->setName(module->getNameObj());
- module->setIRModule(irModule);
-
- // Put in the loaded module map
- linkage->mapNameToLoadedModules.add(sessionNamePool->getName(moduleName), module);
-
-
- // Add the resulting code to the appropriate scope
- if (!scope->containerDecl)
- {
- // We are the first chunk of code to be loaded for this scope
- scope->containerDecl = moduleDecl;
- }
- else
- {
- // We need to create a new scope to link into the whole thing
- auto subScope = linkage->getASTBuilder()->create<Scope>();
- subScope->containerDecl = moduleDecl;
- subScope->nextSibling = scope->nextSibling;
- scope->nextSibling = subScope;
- }
-
- outModule = module.get();
-
- return SLANG_OK;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL
-Session::queryInterface(SlangUUID const& uuid, void** outObject)
-{
- if (uuid == Session::getTypeGuid())
- {
- addReference();
- *outObject = static_cast<Session*>(this);
- return SLANG_OK;
- }
-
- if (uuid == ISlangUnknown::getTypeGuid() || uuid == IGlobalSession::getTypeGuid())
- {
- addReference();
- *outObject = static_cast<slang::IGlobalSession*>(this);
- return SLANG_OK;
- }
-
- return SLANG_E_NO_INTERFACE;
-}
-
-static size_t _getStructureSize(const uint8_t* src)
-{
- size_t size = 0;
- ::memcpy(&size, src, sizeof(size_t));
- return size;
-}
-
-template<typename T>
-static T makeFromSizeVersioned(const uint8_t* src)
-{
- // The structure size must be size_t
- SLANG_COMPILE_TIME_ASSERT(sizeof(((T*)src)->structureSize) == sizeof(size_t));
-
- // The structureSize field *must* be the first element of T
- // Ideally would use SLANG_COMPILE_TIME_ASSERT, but that doesn't work on gcc.
- // Can't just assert, because determined to be a constant expression
- {
- auto offset = SLANG_OFFSET_OF(T, structureSize);
- SLANG_ASSERT(offset == 0);
- // Needed because offset is only 'used' by an assert
- SLANG_UNUSED(offset);
- }
-
- // The source size is held in the first element of T, and will be in the first bytes of src.
- const size_t srcSize = _getStructureSize(src);
- const size_t dstSize = sizeof(T);
-
- // If they are the same size, and appropriate alignment we can just cast and return
- if (srcSize == dstSize && (size_t(src) & (alignof(T) - 1)) == 0)
- {
- return *(const T*)src;
- }
-
- // Assumes T can default constructed sensibly
- T dst;
-
- // It's structure size should be setup and should be dstSize
- SLANG_ASSERT(dst.structureSize == dstSize);
-
- // The size to copy is the minimum on the two sizes
- const auto copySize = std::min(srcSize, dstSize);
- ::memcpy(&dst, src, copySize);
-
- // The final struct size is the destination size
- dst.structureSize = dstSize;
-
- return dst;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL
-Session::createSession(slang::SessionDesc const& inDesc, slang::ISession** outSession)
-{
- RefPtr<ASTBuilder> astBuilder(new ASTBuilder(m_sharedASTBuilder, "Session::astBuilder"));
- slang::SessionDesc desc = makeFromSizeVersioned<slang::SessionDesc>((uint8_t*)&inDesc);
-
- RefPtr<Linkage> linkage = new Linkage(this, astBuilder, getBuiltinLinkage());
-
- if (desc.skipSPIRVValidation)
- {
- linkage->m_optionSet.set(CompilerOptionName::SkipSPIRVValidation, true);
- }
-
- {
- std::lock_guard<std::mutex> lock(m_typeCheckingCacheMutex);
- if (m_typeCheckingCache)
- linkage->m_typeCheckingCache =
- new TypeCheckingCache(*static_cast<TypeCheckingCache*>(m_typeCheckingCache.get()));
- }
-
- Int searchPathCount = desc.searchPathCount;
- for (Int ii = 0; ii < searchPathCount; ++ii)
- {
- linkage->addSearchPath(desc.searchPaths[ii]);
- }
-
- Int macroCount = desc.preprocessorMacroCount;
- for (Int ii = 0; ii < macroCount; ++ii)
- {
- auto& macro = desc.preprocessorMacros[ii];
- linkage->addPreprocessorDefine(macro.name, macro.value);
- }
-
- if (desc.fileSystem)
- {
- linkage->setFileSystem(desc.fileSystem);
- }
-
- if (desc.structureSize >= offsetof(slang::SessionDesc, enableEffectAnnotations))
- {
- linkage->m_optionSet.set(
- CompilerOptionName::EnableEffectAnnotations,
- desc.enableEffectAnnotations);
- }
-
- linkage->m_optionSet.load(desc.compilerOptionEntryCount, desc.compilerOptionEntries);
-
- if (!linkage->m_optionSet.hasOption(CompilerOptionName::MatrixLayoutColumn) &&
- !linkage->m_optionSet.hasOption(CompilerOptionName::MatrixLayoutRow))
- linkage->setMatrixLayoutMode(desc.defaultMatrixLayoutMode);
-
- {
- const Int targetCount = desc.targetCount;
- const uint8_t* targetDescPtr = reinterpret_cast<const uint8_t*>(desc.targets);
- for (Int ii = 0; ii < targetCount; ++ii, targetDescPtr += _getStructureSize(targetDescPtr))
- {
- const auto targetDesc = makeFromSizeVersioned<slang::TargetDesc>(targetDescPtr);
- linkage->addTarget(targetDesc);
- }
- }
-
- // If any target requires debug info, then we will need to enable debug info when lowering to
- // target-agnostic IR. The target-agnostic IR will only include debug info if the linkage IR
- // options specify that it should, so make sure the linkage debug info level is greater than or
- // equal to that of any target.
- DebugInfoLevel linkageDebugInfoLevel = linkage->m_optionSet.getDebugInfoLevel();
- for (auto target : linkage->targets)
- linkageDebugInfoLevel =
- Math::Max(linkageDebugInfoLevel, target->getOptionSet().getDebugInfoLevel());
- linkage->m_optionSet.set(CompilerOptionName::DebugInformation, linkageDebugInfoLevel);
-
- // Add any referenced modules to the linkage
- for (auto& option : linkage->m_optionSet.options)
- {
- if (option.key != CompilerOptionName::ReferenceModule)
- continue;
- for (auto& path : option.value)
- {
- DiagnosticSink sink;
- ComPtr<IArtifact> artifact;
- SlangResult result = createArtifactFromReferencedModule(
- path.stringValue,
- SourceLoc{},
- &sink,
- artifact.writeRef());
- if (SLANG_FAILED(result))
- {
- sink.diagnose(SourceLoc{}, Diagnostics::unableToReadFile, path.stringValue);
- return result;
- }
- linkage->m_libModules.add(artifact);
- }
- }
-
- *outSession = asExternal(linkage.detach());
- return SLANG_OK;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL
-Session::createCompileRequest(slang::ICompileRequest** outCompileRequest)
-{
- auto req = new EndToEndCompileRequest(this);
-
- // Give it a ref (for output)
- req->addRef();
- // Check it is what we think it should be
- SLANG_ASSERT(req->debugGetReferenceCount() == 1);
-
- *outCompileRequest = req;
- return SLANG_OK;
-}
-
-SLANG_NO_THROW SlangProfileID SLANG_MCALL Session::findProfile(char const* name)
-{
- return SlangProfileID(Slang::Profile::lookUp(name).raw);
-}
-
-SLANG_NO_THROW SlangCapabilityID SLANG_MCALL Session::findCapability(char const* name)
-{
- return SlangCapabilityID(Slang::findCapabilityName(UnownedTerminatedStringSlice(name)));
-}
-
-SLANG_NO_THROW void SLANG_MCALL
-Session::setDownstreamCompilerPath(SlangPassThrough inPassThrough, char const* path)
-{
- PassThroughMode passThrough = PassThroughMode(inPassThrough);
- SLANG_ASSERT(
- int(passThrough) > int(PassThroughMode::None) &&
- int(passThrough) < int(PassThroughMode::CountOf));
-
- if (m_downstreamCompilerPaths[int(passThrough)] != path)
- {
- // Make access redetermine compiler
- resetDownstreamCompiler(passThrough);
- // Set the path
- m_downstreamCompilerPaths[int(passThrough)] = path;
- }
-}
-
-SLANG_NO_THROW void SLANG_MCALL
-Session::setDownstreamCompilerPrelude(SlangPassThrough inPassThrough, char const* prelude)
-{
- PassThroughMode downstreamCompiler = PassThroughMode(inPassThrough);
- SLANG_ASSERT(
- int(downstreamCompiler) > int(PassThroughMode::None) &&
- int(downstreamCompiler) < int(PassThroughMode::CountOf));
- const SourceLanguage sourceLanguage =
- getDefaultSourceLanguageForDownstreamCompiler(downstreamCompiler);
- setLanguagePrelude(SlangSourceLanguage(sourceLanguage), prelude);
-}
-
-SLANG_NO_THROW void SLANG_MCALL
-Session::getDownstreamCompilerPrelude(SlangPassThrough inPassThrough, ISlangBlob** outPrelude)
-{
- PassThroughMode downstreamCompiler = PassThroughMode(inPassThrough);
- SLANG_ASSERT(
- int(downstreamCompiler) > int(PassThroughMode::None) &&
- int(downstreamCompiler) < int(PassThroughMode::CountOf));
- const SourceLanguage sourceLanguage =
- getDefaultSourceLanguageForDownstreamCompiler(downstreamCompiler);
- getLanguagePrelude(SlangSourceLanguage(sourceLanguage), outPrelude);
-}
-
-SLANG_NO_THROW void SLANG_MCALL
-Session::setLanguagePrelude(SlangSourceLanguage inSourceLanguage, char const* prelude)
-{
- SourceLanguage sourceLanguage = SourceLanguage(inSourceLanguage);
- SLANG_ASSERT(
- int(sourceLanguage) > int(SourceLanguage::Unknown) &&
- int(sourceLanguage) < int(SourceLanguage::CountOf));
-
- SLANG_ASSERT(sourceLanguage != SourceLanguage::Unknown);
-
- if (sourceLanguage != SourceLanguage::Unknown)
- {
- m_languagePreludes[int(sourceLanguage)] = prelude;
- }
-}
-
-SLANG_NO_THROW void SLANG_MCALL
-Session::getLanguagePrelude(SlangSourceLanguage inSourceLanguage, ISlangBlob** outPrelude)
-{
- SourceLanguage sourceLanguage = SourceLanguage(inSourceLanguage);
-
- *outPrelude = nullptr;
- if (sourceLanguage != SourceLanguage::Unknown)
- {
- SLANG_ASSERT(
- int(sourceLanguage) > int(SourceLanguage::Unknown) &&
- int(sourceLanguage) < int(SourceLanguage::CountOf));
- *outPrelude =
- Slang::StringUtil::createStringBlob(m_languagePreludes[int(sourceLanguage)]).detach();
- }
-}
-
-SLANG_NO_THROW const char* SLANG_MCALL Session::getBuildTagString()
-{
- return ::Slang::getBuildTagString();
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL Session::setDefaultDownstreamCompiler(
- SlangSourceLanguage sourceLanguage,
- SlangPassThrough defaultCompiler)
-{
- if (DownstreamCompilerInfo::canCompile(defaultCompiler, sourceLanguage))
- {
- m_defaultDownstreamCompilers[int(sourceLanguage)] = PassThroughMode(defaultCompiler);
- return SLANG_OK;
- }
- return SLANG_FAIL;
-}
-
-SlangPassThrough SLANG_MCALL
-Session::getDefaultDownstreamCompiler(SlangSourceLanguage inSourceLanguage)
-{
- SLANG_ASSERT(inSourceLanguage >= 0 && inSourceLanguage < SLANG_SOURCE_LANGUAGE_COUNT_OF);
- auto sourceLanguage = SourceLanguage(inSourceLanguage);
- return SlangPassThrough(m_defaultDownstreamCompilers[int(sourceLanguage)]);
-}
-
-void Session::setDownstreamCompilerForTransition(
- SlangCompileTarget source,
- SlangCompileTarget target,
- SlangPassThrough compiler)
-{
- if (compiler == SLANG_PASS_THROUGH_NONE)
- {
- // Removing the transition means a default can be used
- m_codeGenTransitionMap.removeTransition(CodeGenTarget(source), CodeGenTarget(target));
- }
- else
- {
- m_codeGenTransitionMap.addTransition(
- CodeGenTarget(source),
- CodeGenTarget(target),
- PassThroughMode(compiler));
- }
-}
-
-SlangPassThrough Session::getDownstreamCompilerForTransition(
- SlangCompileTarget inSource,
- SlangCompileTarget inTarget)
-{
- const CodeGenTarget source = CodeGenTarget(inSource);
- const CodeGenTarget target = CodeGenTarget(inTarget);
-
- if (m_codeGenTransitionMap.hasTransition(source, target))
- {
- return (SlangPassThrough)m_codeGenTransitionMap.getTransition(source, target);
- }
-
- const auto desc = ArtifactDescUtil::makeDescForCompileTarget(inTarget);
-
- // Special case host-callable
- if ((desc.kind == ArtifactKind::HostCallable) &&
- (source == CodeGenTarget::CSource || source == CodeGenTarget::CPPSource))
- {
- // We prefer LLVM if it's available
- if (const auto llvm = getOrLoadDownstreamCompiler(PassThroughMode::LLVM, nullptr))
- {
- return SLANG_PASS_THROUGH_LLVM;
- }
- }
-
- // Use the legacy 'sourceLanguage' default mechanism.
- // This says nothing about the target type, so it is *assumed* the target type is possible
- // If not it will fail when trying to compile to an unknown target
- const SourceLanguage sourceLanguage =
- (SourceLanguage)TypeConvertUtil::getSourceLanguageFromTarget(inSource);
- if (sourceLanguage != SourceLanguage::Unknown)
- {
- return getDefaultDownstreamCompiler(SlangSourceLanguage(sourceLanguage));
- }
-
- // Unknwon
- return SLANG_PASS_THROUGH_NONE;
-}
-
-IDownstreamCompiler* Session::getDownstreamCompiler(CodeGenTarget source, CodeGenTarget target)
-{
- PassThroughMode compilerType = (PassThroughMode)getDownstreamCompilerForTransition(
- SlangCompileTarget(source),
- SlangCompileTarget(target));
- return getOrLoadDownstreamCompiler(compilerType, nullptr);
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL Session::setSPIRVCoreGrammar(char const* jsonPath)
-{
- if (!jsonPath)
- {
- spirvCoreGrammarInfo = SPIRVCoreGrammarInfo::getEmbeddedVersion();
- SLANG_ASSERT(spirvCoreGrammarInfo);
- }
- else
- {
- SourceManager* sourceManager = getBuiltinSourceManager();
- SLANG_ASSERT(sourceManager);
- DiagnosticSink sink(sourceManager, Lexer::sourceLocationLexer);
-
- String contents;
- const auto readRes = File::readAllText(jsonPath, contents);
- if (SLANG_FAILED(readRes))
- {
- sink.diagnose(SourceLoc{}, Diagnostics::unableToReadFile, jsonPath);
- return readRes;
- }
- const auto pathInfo = PathInfo::makeFromString(jsonPath);
- const auto sourceFile = sourceManager->createSourceFileWithString(pathInfo, contents);
- const auto sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc());
- spirvCoreGrammarInfo = SPIRVCoreGrammarInfo::loadFromJSON(*sourceView, sink);
- }
- return spirvCoreGrammarInfo ? SLANG_OK : SLANG_FAIL;
-}
-
-struct ParsedCommandLineData : public ISlangUnknown, public ComObject
-{
- SLANG_COM_OBJECT_IUNKNOWN_ALL
-
- ISlangUnknown* getInterface(const Slang::Guid& guid)
- {
- if (guid == ISlangUnknown::getTypeGuid())
- return this;
- return nullptr;
- }
- List<SerializedOptionsData> options;
- List<slang::TargetDesc> targets;
-};
-
-SLANG_NO_THROW SlangResult SLANG_MCALL Session::parseCommandLineArguments(
- int argc,
- const char* const* argv,
- slang::SessionDesc* outDesc,
- ISlangUnknown** outAllocation)
-{
- if (outDesc->structureSize < sizeof(slang::SessionDesc))
- return SLANG_E_BUFFER_TOO_SMALL;
- RefPtr<ParsedCommandLineData> outData = new ParsedCommandLineData();
- RefPtr<EndToEndCompileRequest> tempReq = new EndToEndCompileRequest(this);
- tempReq->processCommandLineArguments(argv, argc);
- outData->options.setCount(1 + tempReq->getLinkage()->targets.getCount());
- int optionDataIndex = 0;
- SerializedOptionsData& optionData = outData->options[optionDataIndex];
- optionDataIndex++;
- tempReq->getOptionSet().serialize(&optionData);
- tempReq->m_optionSetForDefaultTarget.serialize(&optionData);
- for (auto target : tempReq->getLinkage()->targets)
- {
- slang::TargetDesc tdesc;
- SerializedOptionsData& targetOptionData = outData->options[optionDataIndex];
- optionDataIndex++;
- tempReq->getTargetOptionSet(target).serialize(&targetOptionData);
- tdesc.compilerOptionEntryCount = (uint32_t)targetOptionData.entries.getCount();
- tdesc.compilerOptionEntries = targetOptionData.entries.getBuffer();
- outData->targets.add(tdesc);
- }
- outDesc->compilerOptionEntryCount = (uint32_t)optionData.entries.getCount();
- outDesc->compilerOptionEntries = optionData.entries.getBuffer();
- outDesc->targetCount = outData->targets.getCount();
- outDesc->targets = outData->targets.getBuffer();
- *outAllocation = outData.get();
- outData->addRef();
- return SLANG_OK;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL
-Session::getSessionDescDigest(slang::SessionDesc* sessionDesc, ISlangBlob** outBlob)
-{
- ComPtr<slang::ISession> tempSession;
- createSession(*sessionDesc, tempSession.writeRef());
- auto linkage = static_cast<Linkage*>(tempSession.get());
- DigestBuilder<SHA1> digestBuilder;
- linkage->buildHash(digestBuilder, -1);
- auto blob = digestBuilder.finalize().toBlob();
- *outBlob = blob.detach();
- return SLANG_OK;
-}
-
Profile getEffectiveProfile(EntryPoint* entryPoint, TargetRequest* target)
{
auto entryPointProfile = entryPoint->getProfile();
@@ -1375,6885 +186,4 @@ Profile getEffectiveProfile(EntryPoint* entryPoint, TargetRequest* target)
return effectiveProfile;
}
-
-//
-
-Linkage::Linkage(Session* session, ASTBuilder* astBuilder, Linkage* builtinLinkage)
- : m_session(session)
- , m_retainedSession(session)
- , m_sourceManager(&m_defaultSourceManager)
- , m_astBuilder(astBuilder)
- , m_cmdLineContext(new CommandLineContext())
- , m_stringSlicePool(StringSlicePool::Style::Default)
-{
- namePool = session->getNamePool();
-
- m_defaultSourceManager.initialize(session->getBuiltinSourceManager(), nullptr);
-
- setFileSystem(nullptr);
-
- // Copy of the built in linkages modules
- if (builtinLinkage)
- {
- for (const auto& nameToMod : builtinLinkage->mapNameToLoadedModules)
- mapNameToLoadedModules.add(nameToMod);
- }
-
- m_semanticsForReflection = new SharedSemanticsContext(this, nullptr, nullptr);
-}
-
-SharedSemanticsContext* Linkage::getSemanticsForReflection()
-{
- return m_semanticsForReflection.get();
-}
-
-ISlangUnknown* Linkage::getInterface(const Guid& guid)
-{
- if (guid == ISlangUnknown::getTypeGuid() || guid == ISession::getTypeGuid())
- return asExternal(this);
-
- return nullptr;
-}
-
-Linkage::~Linkage()
-{
- // Upstream type checking cache.
- if (m_typeCheckingCache)
- {
- auto globalSession = getSessionImpl();
- std::lock_guard<std::mutex> lock(globalSession->m_typeCheckingCacheMutex);
- if (!globalSession->m_typeCheckingCache ||
- globalSession->getTypeCheckingCache()->resolvedOperatorOverloadCache.getCount() <
- getTypeCheckingCache()->resolvedOperatorOverloadCache.getCount())
- {
- globalSession->m_typeCheckingCache = m_typeCheckingCache;
- getTypeCheckingCache()->version++;
- }
- destroyTypeCheckingCache();
- }
-}
-
-SearchDirectoryList& Linkage::getSearchDirectories()
-{
- auto list = m_optionSet.getArray(CompilerOptionName::Include);
- if (list.getCount() != searchDirectoryCache.searchDirectories.getCount())
- {
- searchDirectoryCache.searchDirectories.clear();
- for (auto dir : list)
- searchDirectoryCache.searchDirectories.add(SearchDirectory(dir.stringValue));
- }
- return searchDirectoryCache;
-}
-
-TypeCheckingCache* Linkage::getTypeCheckingCache()
-{
- if (!m_typeCheckingCache)
- {
- m_typeCheckingCache = new TypeCheckingCache();
- }
- return static_cast<TypeCheckingCache*>(m_typeCheckingCache.get());
-}
-
-void Linkage::destroyTypeCheckingCache()
-{
- m_typeCheckingCache = nullptr;
-}
-
-SLANG_NO_THROW slang::IGlobalSession* SLANG_MCALL Linkage::getGlobalSession()
-{
- return asExternal(getSessionImpl());
-}
-
-void Linkage::addTarget(slang::TargetDesc const& desc)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- auto targetIndex = addTarget(CodeGenTarget(desc.format));
- auto target = targets[targetIndex];
-
- auto& optionSet = target->getOptionSet();
- optionSet.inheritFrom(m_optionSet);
-
- optionSet.set(CompilerOptionName::FloatingPointMode, FloatingPointMode(desc.floatingPointMode));
- optionSet.addTargetFlags(desc.flags);
- optionSet.setProfile(Profile(desc.profile));
- optionSet.set(CompilerOptionName::LineDirectiveMode, LineDirectiveMode(desc.lineDirectiveMode));
- optionSet.set(CompilerOptionName::GLSLForceScalarLayout, desc.forceGLSLScalarBufferLayout);
-
- CompilerOptionSet targetOptions;
- targetOptions.load(desc.compilerOptionEntryCount, desc.compilerOptionEntries);
- optionSet.overrideWith(targetOptions);
-}
-
-#if 0
- SLANG_NO_THROW SlangInt SLANG_MCALL Linkage::getTargetCount()
- {
- return targets.getCount();
- }
-
- SLANG_NO_THROW slang::ITarget* SLANG_MCALL Linkage::getTargetByIndex(SlangInt index)
- {
- if (index < 0) return nullptr;
- if (index >= targets.getCount()) return nullptr;
- return asExternal(targets[index]);
- }
-#endif
-
-static void outputExceptionDiagnostic(
- const AbortCompilationException& exception,
- DiagnosticSink& sink,
- slang::IBlob** outDiagnostics)
-{
- sink.diagnoseRaw(Severity::Error, exception.Message.getUnownedSlice());
- sink.getBlobIfNeeded(outDiagnostics);
-}
-
-static void outputExceptionDiagnostic(
- const Exception& exception,
- DiagnosticSink& sink,
- slang::IBlob** outDiagnostics)
-{
- try
- {
- sink.diagnoseRaw(Severity::Internal, exception.Message.getUnownedSlice());
- }
- catch (const AbortCompilationException&)
- {
- // Catch and ignore the AbortCompilationException that diagnoseRaw throws
- // for Internal severity to prevent exception leak from loadModule
- }
- sink.getBlobIfNeeded(outDiagnostics);
-}
-
-static void outputExceptionDiagnostic(DiagnosticSink& sink, slang::IBlob** outDiagnostics)
-{
- try
- {
- sink.diagnoseRaw(Severity::Fatal, "An unknown exception occurred");
- }
- catch (const AbortCompilationException&)
- {
- // Catch and ignore the AbortCompilationException that diagnoseRaw throws
- // for Fatal severity to prevent exception leak from loadModule
- }
- sink.getBlobIfNeeded(outDiagnostics);
-}
-
-SLANG_NO_THROW slang::IModule* SLANG_MCALL
-Linkage::loadModule(const char* moduleName, slang::IBlob** outDiagnostics)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- DiagnosticSink sink(getSourceManager(), Lexer::sourceLocationLexer);
- applySettingsToDiagnosticSink(&sink, &sink, m_optionSet);
-
- if (isInLanguageServer())
- {
- sink.setFlags(DiagnosticSink::Flag::HumaneLoc | DiagnosticSink::Flag::LanguageServer);
- }
-
- try
- {
- auto name = getNamePool()->getName(moduleName);
-
- auto module = findOrImportModule(name, SourceLoc(), &sink);
- sink.getBlobIfNeeded(outDiagnostics);
-
- return asExternal(module);
- }
- catch (const AbortCompilationException& e)
- {
- outputExceptionDiagnostic(e, sink, outDiagnostics);
- return nullptr;
- }
- catch (const Exception& e)
- {
- outputExceptionDiagnostic(e, sink, outDiagnostics);
- return nullptr;
- }
- catch (...)
- {
- outputExceptionDiagnostic(sink, outDiagnostics);
- return nullptr;
- }
-}
-
-slang::IModule* Linkage::loadModuleFromBlob(
- const char* moduleName,
- const char* path,
- slang::IBlob* source,
- ModuleBlobType blobType,
- slang::IBlob** outDiagnostics)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- DiagnosticSink sink(getSourceManager(), Lexer::sourceLocationLexer);
- applySettingsToDiagnosticSink(&sink, &sink, m_optionSet);
-
- if (isInLanguageServer())
- {
- sink.setFlags(DiagnosticSink::Flag::HumaneLoc | DiagnosticSink::Flag::LanguageServer);
- }
-
-
- try
- {
- auto getDigestStr = [](auto x)
- {
- DigestBuilder<SHA1> digestBuilder;
- digestBuilder.append(x);
- return digestBuilder.finalize().toString();
- };
-
- String moduleNameStr = moduleName;
- if (!moduleName)
- moduleNameStr = getDigestStr(source);
-
- auto name = getNamePool()->getName(moduleNameStr);
- RefPtr<LoadedModule> loadedModule;
- if (mapNameToLoadedModules.tryGetValue(name, loadedModule))
- {
- return loadedModule;
- }
- String pathStr = path;
- if (pathStr.getLength() == 0)
- {
- // If path is empty, use a digest from source as path.
- pathStr = getDigestStr(source);
- }
- auto pathInfo = PathInfo::makeFromString(pathStr);
- if (File::exists(pathStr))
- {
- String cannonicalPath;
- if (SLANG_SUCCEEDED(Path::getCanonical(pathStr, cannonicalPath)))
- {
- pathInfo = PathInfo::makeNormal(pathStr, cannonicalPath);
- }
- }
- RefPtr<Module> module =
- loadModuleImpl(name, pathInfo, source, SourceLoc(), &sink, nullptr, blobType);
- sink.getBlobIfNeeded(outDiagnostics);
- return asExternal(module.get());
- }
- catch (const AbortCompilationException& e)
- {
- outputExceptionDiagnostic(e, sink, outDiagnostics);
- return nullptr;
- }
- catch (const Exception& e)
- {
- outputExceptionDiagnostic(e, sink, outDiagnostics);
- return nullptr;
- }
- catch (...)
- {
- outputExceptionDiagnostic(sink, outDiagnostics);
- return nullptr;
- }
-}
-
-SLANG_NO_THROW slang::IModule* SLANG_MCALL Linkage::loadModuleFromSource(
- const char* moduleName,
- const char* path,
- slang::IBlob* source,
- slang::IBlob** outDiagnostics)
-{
- return loadModuleFromBlob(moduleName, path, source, ModuleBlobType::Source, outDiagnostics);
-}
-
-SLANG_NO_THROW slang::IModule* SLANG_MCALL Linkage::loadModuleFromSourceString(
- const char* moduleName,
- const char* path,
- const char* source,
- slang::IBlob** outDiagnostics)
-{
- auto sourceBlob = StringBlob::create(UnownedStringSlice(source));
- return loadModuleFromSource(moduleName, path, sourceBlob.get(), outDiagnostics);
-}
-
-SLANG_NO_THROW slang::IModule* SLANG_MCALL Linkage::loadModuleFromIRBlob(
- const char* moduleName,
- const char* path,
- slang::IBlob* source,
- slang::IBlob** outDiagnostics)
-{
- return loadModuleFromBlob(moduleName, path, source, ModuleBlobType::IR, outDiagnostics);
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::loadModuleInfoFromIRBlob(
- slang::IBlob* source,
- SlangInt& outModuleVersion,
- const char*& outModuleCompilerVersion,
- const char*& outModuleName)
-{
- // We start by reading the content of the file as
- // an in-memory RIFF container.
- //
- auto rootChunk = RIFF::RootChunk::getFromBlob(source);
- if (!rootChunk)
- {
- return SLANG_FAIL;
- }
-
- auto moduleChunk = ModuleChunk::find(rootChunk);
- if (!moduleChunk)
- {
- return SLANG_FAIL;
- }
-
- auto irChunk = moduleChunk->findIR();
- if (!irChunk)
- {
- return SLANG_FAIL;
- }
-
- RefPtr<IRModule> irModule;
- String compilerVersion;
- UInt version;
- String name;
- SLANG_RETURN_ON_FAIL(readSerializedModuleInfo(irChunk, compilerVersion, version, name));
- const auto compilerVersionSlice = m_stringSlicePool.addAndGetSlice(compilerVersion);
- const auto nameSlice = m_stringSlicePool.addAndGetSlice(name);
- outModuleCompilerVersion = compilerVersionSlice.begin();
- outModuleName = nameSlice.begin();
- outModuleVersion = SlangInt(version);
-
- return SLANG_OK;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::createCompositeComponentType(
- slang::IComponentType* const* componentTypes,
- SlangInt componentTypeCount,
- slang::IComponentType** outCompositeComponentType,
- ISlangBlob** outDiagnostics)
-{
- if (outCompositeComponentType == nullptr)
- return SLANG_E_INVALID_ARG;
-
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- // Attempting to create a "composite" of just one component type should
- // just return the component type itself, to avoid redundant work.
- //
- if (componentTypeCount == 1)
- {
- auto componentType = componentTypes[0];
- componentType->addRef();
- *outCompositeComponentType = componentType;
- return SLANG_OK;
- }
-
- DiagnosticSink sink(getSourceManager(), Lexer::sourceLocationLexer);
- applySettingsToDiagnosticSink(&sink, &sink, m_optionSet);
-
- List<RefPtr<ComponentType>> childComponents;
- for (Int cc = 0; cc < componentTypeCount; ++cc)
- {
- childComponents.add(asInternal(componentTypes[cc]));
- }
-
- RefPtr<ComponentType> composite = CompositeComponentType::create(this, childComponents);
-
- sink.getBlobIfNeeded(outDiagnostics);
-
- *outCompositeComponentType = asExternal(composite.detach());
- return SLANG_OK;
-}
-
-SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::specializeType(
- slang::TypeReflection* inUnspecializedType,
- slang::SpecializationArg const* specializationArgs,
- SlangInt specializationArgCount,
- ISlangBlob** outDiagnostics)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- auto unspecializedType = asInternal(inUnspecializedType);
-
- List<Type*> typeArgs;
-
- for (Int ii = 0; ii < specializationArgCount; ++ii)
- {
- auto& arg = specializationArgs[ii];
- if (arg.kind != slang::SpecializationArg::Kind::Type)
- return nullptr;
-
- typeArgs.add(asInternal(arg.type));
- }
-
- DiagnosticSink sink(getSourceManager(), Lexer::sourceLocationLexer);
- auto specializedType =
- specializeType(unspecializedType, typeArgs.getCount(), typeArgs.getBuffer(), &sink);
- sink.getBlobIfNeeded(outDiagnostics);
-
- return asExternal(specializedType);
-}
-
-DeclRef<GenericDecl> getGenericParentDeclRef(
- ASTBuilder* astBuilder,
- SemanticsVisitor* visitor,
- DeclRef<Decl> declRef)
-{
- // Create substituted parent decl ref.
- auto decl = declRef.getDecl();
-
- while (decl && !as<GenericDecl>(decl))
- {
- decl = decl->parentDecl;
- }
-
- if (!decl)
- {
- // No generic parent
- return DeclRef<GenericDecl>();
- }
-
- auto genericDecl = as<GenericDecl>(decl);
- auto genericDeclRef =
- createDefaultSubstitutionsIfNeeded(astBuilder, visitor, DeclRef(genericDecl))
- .as<GenericDecl>();
- return substituteDeclRef(SubstitutionSet(declRef), astBuilder, genericDeclRef)
- .as<GenericDecl>();
-}
-
-bool Linkage::isSpecialized(DeclRef<Decl> declRef)
-{
- // For now, we only support two 'states': fully applied or not at all.
- // If we add support for partial specialization, we will need to update this logic.
- //
- // If it's not specialized, then declRef will be the one with default substitutions.
- //
- SemanticsVisitor visitor(getSemanticsForReflection());
-
- auto decl = declRef.getDecl();
- while (decl && !as<GenericDecl>(decl))
- {
- decl = decl->parentDecl;
- }
-
- if (!decl)
- return true; // no generics => always specialized
-
- auto defaultArgs = getDefaultSubstitutionArgs(getASTBuilder(), &visitor, as<GenericDecl>(decl));
- auto currentArgs =
- SubstitutionSet(declRef).findGenericAppDeclRef(as<GenericDecl>(decl))->getArgs();
-
- if (defaultArgs.getCount() != currentArgs.getCount()) // should really never happen.
- return true;
-
- for (Index i = 0; i < defaultArgs.getCount(); ++i)
- {
- if (defaultArgs[i] != currentArgs[i])
- return true;
- }
-
- return false;
-}
-
-bool isFuncGeneric(DeclRef<Decl> declRef)
-{
- if (auto funcDecl = as<FuncDecl>(declRef.getDecl()))
- {
- if (funcDecl->parentDecl && as<GenericDecl>(funcDecl->parentDecl))
- {
- return true;
- }
- }
-
- return false;
-}
-
-DeclRef<Decl> Linkage::specializeWithArgTypes(
- Expr* funcExpr,
- List<Type*> argTypes,
- DiagnosticSink* sink)
-{
- SemanticsVisitor visitor(getSemanticsForReflection());
- SemanticsVisitor::ExprLocalScope scope;
- visitor = visitor.withSink(sink).withExprLocalScope(&scope);
-
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- if (auto declRefFuncExpr = as<DeclRefExpr>(funcExpr))
- {
- if (isFuncGeneric(declRefFuncExpr->declRef) && !isSpecialized(declRefFuncExpr->declRef))
- {
- if (auto genericDeclRef = getGenericParentDeclRef(
- getCurrentASTBuilder(),
- &visitor,
- declRefFuncExpr->declRef))
- {
- auto genericDeclRefExpr = getCurrentASTBuilder()->create<DeclRefExpr>();
- genericDeclRefExpr->declRef = genericDeclRef;
- funcExpr = genericDeclRefExpr;
- }
- }
- }
-
- List<Expr*> argExprs;
- for (SlangInt aa = 0; aa < argTypes.getCount(); ++aa)
- {
- auto argType = argTypes[aa];
-
- // Create an 'empty' expr with the given type. Ideally, the expression itself should not
- // matter only its checked type.
- //
- auto argExpr = getCurrentASTBuilder()->create<VarExpr>();
- argExpr->type = argType;
- argExpr->type.isLeftValue = true;
- argExprs.add(argExpr);
- }
-
- // Construct invoke expr.
- auto invokeExpr = getCurrentASTBuilder()->create<InvokeExpr>();
- invokeExpr->functionExpr = funcExpr;
- invokeExpr->arguments = argExprs;
-
- auto checkedInvokeExpr = visitor.CheckInvokeExprWithCheckedOperands(invokeExpr);
-
- return as<DeclRefExpr>(as<InvokeExpr>(checkedInvokeExpr)->functionExpr)->declRef;
-}
-
-
-DeclRef<Decl> Linkage::specializeGeneric(
- DeclRef<Decl> declRef,
- List<Expr*> argExprs,
- DiagnosticSink* sink)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
- SLANG_ASSERT(declRef);
-
- SemanticsVisitor visitor(getSemanticsForReflection());
- visitor = visitor.withSink(sink);
-
- auto genericDeclRef = getGenericParentDeclRef(getASTBuilder(), &visitor, declRef);
-
- DeclRefExpr* declRefExpr = getASTBuilder()->create<DeclRefExpr>();
- declRefExpr->declRef = genericDeclRef;
-
- GenericAppExpr* genericAppExpr = getASTBuilder()->create<GenericAppExpr>();
- genericAppExpr->functionExpr = declRefExpr;
- genericAppExpr->arguments = argExprs;
-
- auto specializedDeclRef =
- as<DeclRefExpr>(visitor.checkGenericAppWithCheckedArgs(genericAppExpr))->declRef;
-
- return specializedDeclRef;
-}
-
-SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL Linkage::getTypeLayout(
- slang::TypeReflection* inType,
- SlangInt targetIndex,
- slang::LayoutRules rules,
- ISlangBlob** outDiagnostics)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- auto type = asInternal(inType);
-
- if (targetIndex < 0 || targetIndex >= targets.getCount())
- return nullptr;
-
- auto target = targets[targetIndex];
-
- // TODO: We need a way to pass through the layout rules
- // that the user requested (e.g., constant buffers vs.
- // structured buffer rules). Right now the API only
- // exposes a single case, so this isn't a big deal.
- //
- SLANG_UNUSED(rules);
-
- auto typeLayout = target->getTypeLayout(type, rules);
-
- // TODO: We currently don't have a path for capturing
- // errors that occur during layout (e.g., types that
- // are invalid because of target-specific layout constraints).
- //
- SLANG_UNUSED(outDiagnostics);
-
- return asExternal(typeLayout);
-}
-
-SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::getContainerType(
- slang::TypeReflection* inType,
- slang::ContainerType containerType,
- ISlangBlob** outDiagnostics)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- auto type = asInternal(inType);
-
- Type* containerTypeReflection = nullptr;
- ContainerTypeKey key = {inType, containerType};
- if (!m_containerTypes.tryGetValue(key, containerTypeReflection))
- {
- switch (containerType)
- {
- case slang::ContainerType::ConstantBuffer:
- {
- SemanticsVisitor visitor(getSemanticsForReflection());
- auto layoutType = getASTBuilder()->getDefaultLayoutType();
- Type* cbType = visitor.getConstantBufferType(type, layoutType);
- containerTypeReflection = cbType;
- }
- break;
- case slang::ContainerType::ParameterBlock:
- {
- ParameterBlockType* pbType = getASTBuilder()->getParameterBlockType(type);
- containerTypeReflection = pbType;
- }
- break;
- case slang::ContainerType::StructuredBuffer:
- {
- HLSLStructuredBufferType* sbType = getASTBuilder()->getStructuredBufferType(type);
- containerTypeReflection = sbType;
- }
- break;
- case slang::ContainerType::UnsizedArray:
- {
- ArrayExpressionType* arrType = getASTBuilder()->getArrayType(type, nullptr);
- containerTypeReflection = arrType;
- }
- break;
- default:
- containerTypeReflection = type;
- break;
- }
-
- m_containerTypes.add(key, containerTypeReflection);
- }
-
- SLANG_UNUSED(outDiagnostics);
-
- return asExternal(containerTypeReflection);
-}
-
-SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::getDynamicType()
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- return asExternal(getASTBuilder()->getSharedASTBuilder()->getDynamicType());
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL
-Linkage::getTypeRTTIMangledName(slang::TypeReflection* type, ISlangBlob** outNameBlob)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- auto internalType = asInternal(type);
- if (auto declRefType = as<DeclRefType>(internalType))
- {
- auto name = getMangledName(m_astBuilder, declRefType->getDeclRef());
- Slang::ComPtr<ISlangBlob> blob = Slang::StringUtil::createStringBlob(name);
- *outNameBlob = blob.detach();
- return SLANG_OK;
- }
- return SLANG_FAIL;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::getTypeConformanceWitnessMangledName(
- slang::TypeReflection* type,
- slang::TypeReflection* interfaceType,
- ISlangBlob** outNameBlob)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- auto subType = asInternal(type);
- auto supType = asInternal(interfaceType);
- auto name = getMangledNameForConformanceWitness(m_astBuilder, subType, supType);
- Slang::ComPtr<ISlangBlob> blob = Slang::StringUtil::createStringBlob(name);
- *outNameBlob = blob.detach();
- return SLANG_OK;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::getTypeConformanceWitnessSequentialID(
- slang::TypeReflection* type,
- slang::TypeReflection* interfaceType,
- uint32_t* outId)
-{
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- auto subType = asInternal(type);
- auto supType = asInternal(interfaceType);
-
- if (!subType || !supType)
- return SLANG_FAIL;
-
- auto name = getMangledNameForConformanceWitness(m_astBuilder, subType, supType);
- auto interfaceName = getMangledTypeName(m_astBuilder, supType);
- uint32_t resultIndex = 0;
- if (mapMangledNameToRTTIObjectIndex.tryGetValue(name, resultIndex))
- {
- if (outId)
- *outId = resultIndex;
- return SLANG_OK;
- }
- auto idAllocator = mapInterfaceMangledNameToSequentialIDCounters.tryGetValue(interfaceName);
- if (!idAllocator)
- {
- mapInterfaceMangledNameToSequentialIDCounters[interfaceName] = 0;
- idAllocator = mapInterfaceMangledNameToSequentialIDCounters.tryGetValue(interfaceName);
- }
- resultIndex = (*idAllocator);
- ++(*idAllocator);
- mapMangledNameToRTTIObjectIndex[name] = resultIndex;
- if (outId)
- *outId = resultIndex;
- return SLANG_OK;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::getDynamicObjectRTTIBytes(
- slang::TypeReflection* type,
- slang::TypeReflection* interfaceType,
- uint32_t* outBuffer,
- uint32_t bufferSize)
-{
- // Slang RTTI header format:
- // byte 0-7: pointer to RTTI struct describing the type. (not used for now, set to 1 for valid
- // types, and 0 to represent null).
- // byte 8-11: 32-bit sequential ID of the type conformance witness.
- // byte 12-15: unused.
-
- if (bufferSize < 16)
- return SLANG_E_BUFFER_TOO_SMALL;
-
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- SLANG_RETURN_ON_FAIL(getTypeConformanceWitnessSequentialID(type, interfaceType, outBuffer + 2));
-
- // Make the RTTI part non zero.
- outBuffer[0] = 1;
-
- return SLANG_OK;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL Linkage::createTypeConformanceComponentType(
- slang::TypeReflection* type,
- slang::TypeReflection* interfaceType,
- slang::ITypeConformance** outConformanceComponentType,
- SlangInt conformanceIdOverride,
- ISlangBlob** outDiagnostics)
-{
- if (outConformanceComponentType == nullptr)
- return SLANG_E_INVALID_ARG;
-
- SLANG_AST_BUILDER_RAII(getASTBuilder());
-
- RefPtr<TypeConformance> result;
- DiagnosticSink sink;
- applySettingsToDiagnosticSink(&sink, &sink, m_optionSet);
-
- try
- {
- SemanticsVisitor visitor(getSemanticsForReflection());
- visitor = visitor.withSink(&sink);
-
- auto witness = visitor.isSubtype(
- (Slang::Type*)type,
- (Slang::Type*)interfaceType,
- IsSubTypeOptions::None);
- if (auto subtypeWitness = as<SubtypeWitness>(witness))
- {
- result = new TypeConformance(this, subtypeWitness, conformanceIdOverride, &sink);
- }
- }
- catch (...)
- {
- }
- sink.getBlobIfNeeded(outDiagnostics);
- bool success = (result != nullptr);
- *outConformanceComponentType = result.detach();
- return success ? SLANG_OK : SLANG_FAIL;
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL
-Linkage::createCompileRequest(SlangCompileRequest** outCompileRequest)
-{
- auto compileRequest = new EndToEndCompileRequest(this);
- compileRequest->addRef();
- *outCompileRequest = asExternal(compileRequest);
- return SLANG_OK;
-}
-
-SLANG_NO_THROW SlangInt SLANG_MCALL Linkage::getLoadedModuleCount()
-{
- return loadedModulesList.getCount();
-}
-
-SLANG_NO_THROW slang::IModule* SLANG_MCALL Linkage::getLoadedModule(SlangInt index)
-{
- if (index >= 0 && index < loadedModulesList.getCount())
- return loadedModulesList[index].get();
- return nullptr;
-}
-
-void Linkage::buildHash(DigestBuilder<SHA1>& builder, SlangInt targetIndex)
-{
- // Add the Slang compiler version to the hash
- auto version = String(getBuildTagString());
- builder.append(version);
-
- // Add compiler options, including search path, preprocessor includes, etc.
- m_optionSet.buildHash(builder);
-
- auto addTargetDigest = [&](TargetRequest* targetReq)
- {
- targetReq->getOptionSet().buildHash(builder);
-
- const PassThroughMode passThroughMode =
- getDownstreamCompilerRequiredForTarget(targetReq->getTarget());
- const SourceLanguage sourceLanguage =
- getDefaultSourceLanguageForDownstreamCompiler(passThroughMode);
-
- // Add prelude for the given downstream compiler.
- ComPtr<ISlangBlob> prelude;
- getGlobalSession()->getLanguagePrelude(
- (SlangSourceLanguage)sourceLanguage,
- prelude.writeRef());
- if (prelude)
- {
- builder.append(prelude);
- }
-
- // TODO: Downstream compilers (specifically dxc) can currently #include additional
- // dependencies. This is currently the case for NVAPI headers included in the prelude. These
- // dependencies are currently not picked up by the shader cache which is a significant
- // issue. This can only be fixed by running the preprocessor in the slang compiler so dxc
- // (or any other downstream compiler for that matter) isn't resolving any includes
- // implicitly.
-
- // Add the downstream compiler version (if it exists) to the hash
- auto downstreamCompiler =
- getSessionImpl()->getOrLoadDownstreamCompiler(passThroughMode, nullptr);
- if (downstreamCompiler)
- {
- ComPtr<ISlangBlob> versionString;
- if (SLANG_SUCCEEDED(downstreamCompiler->getVersionString(versionString.writeRef())))
- {
- builder.append(versionString);
- }
- }
- };
-
- // Add the target specified by targetIndex
- if (targetIndex == -1)
- {
- // -1 means all targets.
- for (auto targetReq : targets)
- {
- addTargetDigest(targetReq);
- }
- }
- else
- {
- auto targetReq = targets[targetIndex];
- addTargetDigest(targetReq);
- }
-}
-
-SlangResult Linkage::addSearchPath(char const* path)
-{
- m_optionSet.add(CompilerOptionName::Include, String(path));
- return SLANG_OK;
-}
-
-SlangResult Linkage::addPreprocessorDefine(char const* name, char const* value)
-{
- CompilerOptionValue val;
- val.kind = CompilerOptionValueKind::String;
- val.stringValue = name;
- val.stringValue2 = value;
- m_optionSet.add(CompilerOptionName::MacroDefine, val);
- return SLANG_OK;
-}
-
-SlangResult Linkage::setMatrixLayoutMode(SlangMatrixLayoutMode mode)
-{
- m_optionSet.setMatrixLayoutMode((MatrixLayoutMode)mode);
- return SLANG_OK;
-}
-
-//
-// TargetRequest
-//
-
-TargetRequest::TargetRequest(Linkage* linkage, CodeGenTarget format)
- : linkage(linkage)
-{
- optionSet = linkage->m_optionSet;
- optionSet.add(CompilerOptionName::Target, format);
-}
-
-TargetRequest::TargetRequest(const TargetRequest& other)
- : RefObject(), linkage(other.linkage), optionSet(other.optionSet)
-{
-}
-
-
-Session* TargetRequest::getSession()
-{
- return linkage->getSessionImpl();
-}
-
-HLSLToVulkanLayoutOptions* TargetRequest::getHLSLToVulkanLayoutOptions()
-{
- if (!hlslToVulkanOptions)
- {
- hlslToVulkanOptions = new HLSLToVulkanLayoutOptions();
- hlslToVulkanOptions->loadFromOptionSet(optionSet);
- }
- return hlslToVulkanOptions.get();
-}
-
-void TargetRequest::setTargetCaps(CapabilitySet capSet)
-{
- cookedCapabilities = capSet;
-}
-
-CapabilitySet TargetRequest::getTargetCaps()
-{
- if (!cookedCapabilities.isEmpty())
- return cookedCapabilities;
-
- // The full `CapabilitySet` for the target will be computed
- // from the combination of the code generation format, and
- // the profile.
- //
- // Note: the preofile might have been set in a way that is
- // inconsistent with the output code format of SPIR-V, but
- // a profile of Direct3D Shader Model 5.1. In those cases,
- // the format should always override the implications in
- // the profile.
- //
- // TODO: This logic isn't currently taking int account
- // the information in the profile, because the current
- // `CapabilityAtom`s that we support don't include any
- // of the details there (e.g., the shader model versions).
- //
- // Eventually, we'd want to have a rich set of capability
- // atoms, so that most of the information about what operations
- // are available where can be directly encoded on the declarations.
-
- List<CapabilityName> atoms;
-
- // If the user specified a explicit profile, we should pull
- // a corresponding atom representing the target version from the profile.
- CapabilitySet profileCaps = optionSet.getProfile().getCapabilityName();
-
- bool isGLSLTarget = false;
- switch (getTarget())
- {
- case CodeGenTarget::GLSL:
- isGLSLTarget = true;
- atoms.add(CapabilityName::glsl);
- break;
- case CodeGenTarget::SPIRV:
- case CodeGenTarget::SPIRVAssembly:
- if (getOptionSet().shouldEmitSPIRVDirectly())
- {
- // Default to SPIRV 1.5 if the user has not specified a target version.
- bool hasTargetVersionAtom = false;
- if (!profileCaps.isEmpty())
- {
- profileCaps.join(CapabilitySet(CapabilityName::spirv_1_0));
- for (auto profileCapAtomSet : profileCaps.getAtomSets())
- {
- for (auto atom : profileCapAtomSet)
- {
- if (isTargetVersionAtom(asAtom(atom)))
- {
- atoms.add((CapabilityName)atom);
- hasTargetVersionAtom = true;
- }
- }
- }
- }
- if (!hasTargetVersionAtom)
- {
- atoms.add(CapabilityName::spirv_1_5);
- }
- // If the user specified any SPIR-V extensions in the profile,
- // pull them in.
- for (auto profileCapAtomSet : profileCaps.getAtomSets())
- {
- for (auto atom : profileCapAtomSet)
- {
- if (isSpirvExtensionAtom(asAtom(atom)))
- {
- atoms.add((CapabilityName)atom);
- hasTargetVersionAtom = true;
- }
- }
- }
- }
- else
- {
- isGLSLTarget = true;
- atoms.add(CapabilityName::glsl);
- profileCaps.addSpirvVersionFromOtherAsGlslSpirvVersion(profileCaps);
- }
- break;
-
- case CodeGenTarget::HLSL:
- case CodeGenTarget::DXBytecode:
- case CodeGenTarget::DXBytecodeAssembly:
- case CodeGenTarget::DXIL:
- case CodeGenTarget::DXILAssembly:
- atoms.add(CapabilityName::hlsl);
- break;
-
- case CodeGenTarget::CSource:
- atoms.add(CapabilityName::c);
- break;
-
- case CodeGenTarget::CPPSource:
- case CodeGenTarget::PyTorchCppBinding:
- case CodeGenTarget::HostExecutable:
- case CodeGenTarget::ShaderSharedLibrary:
- case CodeGenTarget::HostSharedLibrary:
- case CodeGenTarget::HostHostCallable:
- case CodeGenTarget::ShaderHostCallable:
- atoms.add(CapabilityName::cpp);
- break;
-
- case CodeGenTarget::CUDASource:
- case CodeGenTarget::PTX:
- atoms.add(CapabilityName::cuda);
- break;
-
- case CodeGenTarget::Metal:
- case CodeGenTarget::MetalLib:
- case CodeGenTarget::MetalLibAssembly:
- atoms.add(CapabilityName::metal);
- break;
-
- case CodeGenTarget::WGSLSPIRV:
- case CodeGenTarget::WGSLSPIRVAssembly:
- case CodeGenTarget::WGSL:
- atoms.add(CapabilityName::wgsl);
- break;
-
- default:
- break;
- }
-
- CapabilitySet targetCap = CapabilitySet(atoms);
-
- if (profileCaps.atLeastOneSetImpliedInOther(targetCap) ==
- CapabilitySet::ImpliesReturnFlags::Implied)
- targetCap.join(profileCaps);
-
- for (auto atomVal : optionSet.getArray(CompilerOptionName::Capability))
- {
- CapabilitySet toAdd;
- switch (atomVal.kind)
- {
- case CompilerOptionValueKind::Int:
- toAdd = CapabilitySet(CapabilityName(atomVal.intValue));
- break;
- case CompilerOptionValueKind::String:
- toAdd = CapabilitySet(findCapabilityName(atomVal.stringValue.getUnownedSlice()));
- break;
- }
-
- if (isGLSLTarget)
- targetCap.addSpirvVersionFromOtherAsGlslSpirvVersion(toAdd);
-
- if (!targetCap.isIncompatibleWith(toAdd))
- targetCap.join(toAdd);
- }
-
- cookedCapabilities = targetCap;
-
- SLANG_ASSERT(!cookedCapabilities.isInvalid());
-
- return cookedCapabilities;
-}
-
-
-TypeLayout* TargetRequest::getTypeLayout(Type* type, slang::LayoutRules rules)
-{
- SLANG_AST_BUILDER_RAII(getLinkage()->getASTBuilder());
-
- // TODO: We are not passing in a `ProgramLayout` here, although one
- // is nominally required to establish the global ordering of
- // generic type parameters, which might be referenced from field types.
- //
- // The solution here is to make sure that the reflection data for
- // uses of global generic/existential types does *not* include any
- // kind of index in that global ordering, and just refers to the
- // parameter instead (leaving the user to figure out how that
- // maps to the ordering via some API on the program layout).
- //
- auto layoutContext = getInitialLayoutContextForTarget(this, nullptr, rules);
-
- RefPtr<TypeLayout> result;
- auto key = TypeLayoutKey{type, rules};
- if (getTypeLayouts().tryGetValue(key, result))
- return result.Ptr();
- result = createTypeLayout(layoutContext, type);
- getTypeLayouts()[key] = result;
- return result.Ptr();
-}
-
-//
-// TranslationUnitRequest
-//
-
-TranslationUnitRequest::TranslationUnitRequest(FrontEndCompileRequest* compileRequest)
- : compileRequest(compileRequest)
-{
- module = new Module(compileRequest->getLinkage());
-}
-
-TranslationUnitRequest::TranslationUnitRequest(FrontEndCompileRequest* compileRequest, Module* m)
- : compileRequest(compileRequest), module(m), isChecked(true)
-{
- moduleName = getNamePool()->getName(m->getName());
-}
-
-Session* TranslationUnitRequest::getSession()
-{
- return compileRequest->getSession();
-}
-
-NamePool* TranslationUnitRequest::getNamePool()
-{
- return compileRequest->getNamePool();
-}
-
-SourceManager* TranslationUnitRequest::getSourceManager()
-{
- return compileRequest->getSourceManager();
-}
-
-Scope* TranslationUnitRequest::getLanguageScope()
-{
- Scope* languageScope = nullptr;
- switch (sourceLanguage)
- {
- case SourceLanguage::HLSL:
- languageScope = getSession()->hlslLanguageScope;
- break;
- case SourceLanguage::GLSL:
- languageScope = getSession()->glslLanguageScope;
- break;
- case SourceLanguage::Slang:
- default:
- languageScope = getSession()->slangLanguageScope;
- break;
- }
- return languageScope;
-}
-
-Dictionary<String, String> TranslationUnitRequest::getCombinedPreprocessorDefinitions()
-{
- Dictionary<String, String> combinedPreprocessorDefinitions;
- for (const auto& def : preprocessorDefinitions)
- combinedPreprocessorDefinitions.addIfNotExists(def);
- for (const auto& def : compileRequest->optionSet.getArray(CompilerOptionName::MacroDefine))
- combinedPreprocessorDefinitions.addIfNotExists(def.stringValue, def.stringValue2);
-
- // Define standard macros, if not already defined. This style assumes using `#if __SOME_VAR`
- // style, as in
- //
- // ```
- // #if __SLANG_COMPILER__
- // ```
- //
- // This choice is made because slang outputs a warning on using a variable in an #if if not
- // defined
- //
- // Of course this means using #ifndef/#ifdef/defined() is probably not appropraite with thes
- // variables.
- {
- // Used to identify level of HLSL language compatibility
- combinedPreprocessorDefinitions.addIfNotExists("__HLSL_VERSION", "2018");
-
- // Indicates this is being compiled by the slang *compiler*
- combinedPreprocessorDefinitions.addIfNotExists("__SLANG_COMPILER__", "1");
-
- // Set macro depending on source type
- switch (sourceLanguage)
- {
- case SourceLanguage::HLSL:
- // Used to indicate compiled as HLSL language
- combinedPreprocessorDefinitions.addIfNotExists("__HLSL__", "1");
- break;
- case SourceLanguage::Slang:
- // Used to indicate compiled as Slang language
- combinedPreprocessorDefinitions.addIfNotExists("__SLANG__", "1");
- break;
- default:
- break;
- }
-
- // If not set, define as 0.
- combinedPreprocessorDefinitions.addIfNotExists("__HLSL__", "0");
- combinedPreprocessorDefinitions.addIfNotExists("__SLANG__", "0");
- }
-
- return combinedPreprocessorDefinitions;
-}
-
-void TranslationUnitRequest::addSourceArtifact(IArtifact* sourceArtifact)
-{
- SLANG_ASSERT(sourceArtifact);
- m_sourceArtifacts.add(ComPtr<IArtifact>(sourceArtifact));
-}
-
-
-void TranslationUnitRequest::addSource(IArtifact* sourceArtifact, SourceFile* sourceFile)
-{
- SLANG_ASSERT(sourceArtifact && sourceFile);
- // Must be in sync!
- SLANG_ASSERT(m_sourceFiles.getCount() == m_sourceArtifacts.getCount());
-
- addSourceArtifact(sourceArtifact);
- _addSourceFile(sourceFile);
-}
-
-void TranslationUnitRequest::addIncludedSourceFileIfNotExist(SourceFile* sourceFile)
-{
- if (m_includedFileSet.contains(sourceFile))
- return;
-
- sourceFile->setIncludedFile();
- m_sourceFiles.add(sourceFile);
- m_includedFileSet.add(sourceFile);
-}
-
-PathInfo TranslationUnitRequest::_findSourcePathInfo(IArtifact* artifact)
-{
- auto pathRep = findRepresentation<IPathArtifactRepresentation>(artifact);
-
- if (pathRep && pathRep->getPathType() == SLANG_PATH_TYPE_FILE)
- {
- // See if we have a unique identity set with the path
- if (const auto uniqueIdentity = pathRep->getUniqueIdentity())
- {
- return PathInfo::makeNormal(pathRep->getPath(), uniqueIdentity);
- }
-
- // If we couldn't get a unique identity, just use the path
- return PathInfo::makePath(pathRep->getPath());
- }
-
- // If there isn't a path, we can try with the name
- const char* name = artifact->getName();
- if (name && name[0] != 0)
- {
- return PathInfo::makeFromString(name);
- }
-
- return PathInfo::makeUnknown();
-}
-
-SlangResult TranslationUnitRequest::requireSourceFiles()
-{
- SLANG_ASSERT(m_sourceFiles.getCount() <= m_sourceArtifacts.getCount());
-
- if (m_sourceFiles.getCount() == m_sourceArtifacts.getCount())
- {
- return SLANG_OK;
- }
-
- auto sink = compileRequest->getSink();
- SourceManager* sourceManager = compileRequest->getSourceManager();
-
- for (Index i = m_sourceFiles.getCount(); i < m_sourceArtifacts.getCount(); ++i)
- {
- IArtifact* artifact = m_sourceArtifacts[i];
-
- const PathInfo pathInfo = _findSourcePathInfo(artifact);
-
- SourceFile* sourceFile = nullptr;
- ComPtr<ISlangBlob> blob;
-
- // If we have a unique identity see if we have it already
- if (pathInfo.hasUniqueIdentity())
- {
- // See if this an already loaded source file
- sourceFile = sourceManager->findSourceFileRecursively(pathInfo.uniqueIdentity);
- // If we have a sourceFile see if it has a blob
- if (sourceFile)
- {
- blob = sourceFile->getContentBlob();
- }
- }
-
- // If we *don't* have a blob try and get a blob from the artifact
- if (!blob)
- {
- const SlangResult res = artifact->loadBlob(ArtifactKeep::Yes, blob.writeRef());
- if (SLANG_FAILED(res))
- {
- // Report couldn't load
- sink->diagnose(SourceLoc(), Diagnostics::cannotOpenFile, pathInfo.getName());
- return res;
- }
- }
-
- // If we don't have a blob on the artifact we can now add the one we have
- if (!findRepresentation<ISlangBlob>(artifact))
- {
- artifact->addRepresentationUnknown(blob);
- }
-
- // If we have a sourceFile check if it has contents, and set the blob if doesn't
- if (sourceFile)
- {
- if (!sourceFile->getContentBlob())
- {
- sourceFile->setContents(blob);
- }
- }
- else
- {
- // Create a new source file, using the pathInfo and blob
- sourceFile = sourceManager->createSourceFileWithBlob(pathInfo, blob);
- }
-
- auto uniqueIdentity = pathInfo.getMostUniqueIdentity();
- if (uniqueIdentity.getLength())
- sourceManager->addSourceFileIfNotExist(uniqueIdentity, sourceFile);
-
- // Finally add the source file
- _addSourceFile(sourceFile);
- }
-
- return SLANG_OK;
-}
-
-void TranslationUnitRequest::_addSourceFile(SourceFile* sourceFile)
-{
- m_sourceFiles.add(sourceFile);
-
- getModule()->addFileDependency(sourceFile);
- getModule()->getIncludedSourceFileMap().add(sourceFile, nullptr);
-}
-
-List<SourceFile*> const& TranslationUnitRequest::getSourceFiles()
-{
- return m_sourceFiles;
-}
-
-EndToEndCompileRequest::~EndToEndCompileRequest()
-{
- // Flush any writers associated with the request
- m_writers->flushWriters();
-
- m_linkage.setNull();
- m_frontEndReq.setNull();
-}
-
-static ISlangWriter* _getDefaultWriter(WriterChannel chan)
-{
- static FileWriter stdOut(stdout, WriterFlag::IsStatic | WriterFlag::IsUnowned);
- static FileWriter stdError(stderr, WriterFlag::IsStatic | WriterFlag::IsUnowned);
- static NullWriter nullWriter(WriterFlag::IsStatic | WriterFlag::IsConsole);
-
- switch (chan)
- {
- case WriterChannel::StdError:
- return &stdError;
- case WriterChannel::StdOutput:
- return &stdOut;
- case WriterChannel::Diagnostic:
- return &nullWriter;
- default:
- {
- SLANG_ASSERT(!"Unknown type");
- return &stdError;
- }
- }
-}
-
-void EndToEndCompileRequest::setWriter(WriterChannel chan, ISlangWriter* writer)
-{
- // If the user passed in null, we will use the default writer on that channel
- m_writers->setWriter(SlangWriterChannel(chan), writer ? writer : _getDefaultWriter(chan));
-
- // For diagnostic output, if the user passes in nullptr, we set on m_sink.writer as that enables
- // buffering on DiagnosticSink
- if (chan == WriterChannel::Diagnostic)
- {
- m_sink.writer = writer;
- }
-}
-
-SlangResult Linkage::loadFile(String const& path, PathInfo& outPathInfo, ISlangBlob** outBlob)
-{
- outPathInfo.type = PathInfo::Type::Unknown;
-
- SLANG_RETURN_ON_FAIL(m_fileSystemExt->loadFile(path.getBuffer(), outBlob));
-
- ComPtr<ISlangBlob> uniqueIdentity;
- // Get the unique identity
- if (SLANG_FAILED(
- m_fileSystemExt->getFileUniqueIdentity(path.getBuffer(), uniqueIdentity.writeRef())))
- {
- // We didn't get a unique identity, so go with just a found path
- outPathInfo.type = PathInfo::Type::FoundPath;
- outPathInfo.foundPath = path;
- }
- else
- {
- outPathInfo = PathInfo::makeNormal(path, StringUtil::getString(uniqueIdentity));
- }
- return SLANG_OK;
-}
-
-Expr* Linkage::parseTermString(String typeStr, Scope* scope)
-{
- // Create a SourceManager on the stack, so any allocations for 'SourceFile'/'SourceView' etc
- // will be cleaned up
- SourceManager localSourceManager;
- localSourceManager.initialize(getSourceManager(), nullptr);
-
- Slang::SourceFile* srcFile =
- localSourceManager.createSourceFileWithString(PathInfo::makeTypeParse(), typeStr);
-
- // We'll use a temporary diagnostic sink
- DiagnosticSink sink(&localSourceManager, nullptr);
-
- // RAII type to make make sure current SourceManager is restored after parse.
- // Use RAII - to make sure everything is reset even if an exception is thrown.
- struct ScopeReplaceSourceManager
- {
- ScopeReplaceSourceManager(Linkage* linkage, SourceManager* replaceManager)
- : m_linkage(linkage), m_originalSourceManager(linkage->getSourceManager())
- {
- linkage->setSourceManager(replaceManager);
- }
-
- ~ScopeReplaceSourceManager() { m_linkage->setSourceManager(m_originalSourceManager); }
-
- private:
- Linkage* m_linkage;
- SourceManager* m_originalSourceManager;
- };
-
- // We need to temporarily replace the SourceManager for this CompileRequest
- ScopeReplaceSourceManager scopeReplaceSourceManager(this, &localSourceManager);
-
- SourceLanguage sourceLanguage = SourceLanguage::Slang;
- SlangLanguageVersion languageVersion = m_optionSet.getLanguageVersion();
-
- auto tokens = preprocessSource(
- srcFile,
- &sink,
- nullptr,
- Dictionary<String, String>(),
- this,
- sourceLanguage,
- languageVersion);
-
- if (sourceLanguage == SourceLanguage::Unknown)
- sourceLanguage = SourceLanguage::Slang;
-
- return parseTermFromSourceFile(
- getASTBuilder(),
- tokens,
- &sink,
- scope,
- getNamePool(),
- sourceLanguage);
-}
-
-Type* checkProperType(Linkage* linkage, TypeExp typeExp, DiagnosticSink* sink);
-
-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;
-}
-
-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()));
-}
-
-CompileRequestBase::CompileRequestBase(Linkage* linkage, DiagnosticSink* sink)
- : m_linkage(linkage), m_sink(sink)
-{
-}
-
-
-FrontEndCompileRequest::FrontEndCompileRequest(
- Linkage* linkage,
- StdWriters* writers,
- DiagnosticSink* sink)
- : CompileRequestBase(linkage, sink), m_writers(writers)
-{
- optionSet.inheritFrom(linkage->m_optionSet);
-}
-
-/// Handlers for preprocessor callbacks to use when doing ordinary front-end compilation
-struct FrontEndPreprocessorHandler : PreprocessorHandler
-{
-public:
- FrontEndPreprocessorHandler(
- Module* module,
- ASTBuilder* astBuilder,
- DiagnosticSink* sink,
- TranslationUnitRequest* translationUnit)
- : m_module(module)
- , m_astBuilder(astBuilder)
- , m_sink(sink)
- , m_translationUnit(translationUnit)
- {
- }
-
-protected:
- Module* m_module;
- ASTBuilder* m_astBuilder;
- DiagnosticSink* m_sink;
- TranslationUnitRequest* m_translationUnit = nullptr;
-
- // The first task that this handler tries to deal with is
- // capturing all the files on which a module is dependent.
- //
- // That information is exposed through public APIs and used
- // by applications to decide when they need to "hot reload"
- // their shader code.
- //
- void handleFileDependency(SourceFile* sourceFile) SLANG_OVERRIDE
- {
- m_module->addFileDependency(sourceFile);
- m_translationUnit->addIncludedSourceFileIfNotExist(sourceFile);
- }
-
- // The second task that this handler deals with is detecting
- // whether any macro values were set in a given source file
- // that are semantically relevant to other stages of compilation.
- //
- void handleEndOfTranslationUnit(Preprocessor* preprocessor) SLANG_OVERRIDE
- {
- // We look at the preprocessor state after reading the entire
- // source file/string, in order to see if any macros have been
- // set that should be considered semantically relevant for
- // later stages of compilation.
- //
- // Note: Checking the macro environment *after* preprocessing is complete
- // means that we can treat macros introduced via `-D` options or the API
- // equivalently to macros introduced via `#define`s in user code.
- //
- // For now, the only case of semantically-relevant macros we need to worrry
- // about are the NVAPI macros used to establish the register/space to use.
- //
- static const char* kNVAPIRegisterMacroName = "NV_SHADER_EXTN_SLOT";
- static const char* kNVAPISpaceMacroName = "NV_SHADER_EXTN_REGISTER_SPACE";
-
- // For NVAPI use, the `NV_SHADER_EXTN_SLOT` macro is required to be defined.
- //
- String nvapiRegister;
- SourceLoc nvapiRegisterLoc;
- if (!SLANG_FAILED(findMacroValue(
- preprocessor,
- kNVAPIRegisterMacroName,
- nvapiRegister,
- nvapiRegisterLoc)))
- {
- // In contrast, NVAPI can be used without defining `NV_SHADER_EXTN_REGISTER_SPACE`,
- // which effectively defaults to `space0`.
- //
- String nvapiSpace = "space0";
- SourceLoc nvapiSpaceLoc;
- findMacroValue(preprocessor, kNVAPISpaceMacroName, nvapiSpace, nvapiSpaceLoc);
-
- // We are going to store the values of these macros on the AST-level `ModuleDecl`
- // so that they will be available to later processing stages.
- //
- auto moduleDecl = m_module->getModuleDecl();
-
- if (auto existingModifier = moduleDecl->findModifier<NVAPISlotModifier>())
- {
- // If there is already a modifier attached to the module (perhaps
- // because of preprocessing a different source file, or because
- // of settings established via command-line options), then we
- // need to validate that the values being set in this file
- // match those already set (or else there is likely to be
- // some kind of error in the user's code).
- //
- _validateNVAPIMacroMatch(
- kNVAPIRegisterMacroName,
- existingModifier->registerName,
- nvapiRegister,
- nvapiRegisterLoc);
- _validateNVAPIMacroMatch(
- kNVAPISpaceMacroName,
- existingModifier->spaceName,
- nvapiSpace,
- nvapiSpaceLoc);
- }
- else
- {
- // If there is no existing modifier on the module, then we
- // take responsibility for adding one, based on the macro
- // values we saw.
- //
- auto modifier = m_astBuilder->create<NVAPISlotModifier>();
- modifier->loc = nvapiRegisterLoc;
- modifier->registerName = nvapiRegister;
- modifier->spaceName = nvapiSpace;
-
- addModifier(moduleDecl, modifier);
- }
- }
- }
-
- /// Validate that a re-defintion of an NVAPI-related macro matches any previous definition
- void _validateNVAPIMacroMatch(
- char const* macroName,
- String const& existingValue,
- String const& newValue,
- SourceLoc loc)
- {
- if (existingValue != newValue)
- {
- m_sink->diagnose(
- loc,
- Diagnostics::nvapiMacroMismatch,
- macroName,
- existingValue,
- newValue);
- }
- }
-};
-
-
-// Holds the hierarchy of views, the children being views that were 'initiated' (have an initiating
-// SourceLoc) in the parent.
-typedef Dictionary<SourceView*, List<SourceView*>> ViewInitiatingHierarchy;
-
-// Calculate the hierarchy from the sourceManager
-static void _calcViewInitiatingHierarchy(
- SourceManager* sourceManager,
- ViewInitiatingHierarchy& outHierarchy)
-{
- const List<SourceView*> emptyList;
- outHierarchy.clear();
-
- // Iterate over all managers
- for (SourceManager* curManager = sourceManager; curManager;
- curManager = curManager->getParent())
- {
- // Iterate over all views
- for (SourceView* view : curManager->getSourceViews())
- {
- if (view->getInitiatingSourceLoc().isValid())
- {
- // Look up the view it came from
- SourceView* parentView =
- sourceManager->findSourceViewRecursively(view->getInitiatingSourceLoc());
- if (parentView)
- {
- List<SourceView*>& children = outHierarchy.getOrAddValue(parentView, emptyList);
- // It shouldn't have already been added
- SLANG_ASSERT(children.indexOf(view) < 0);
- children.add(view);
- }
- }
- }
- }
-
- // Order all the children, by their raw SourceLocs. This is desirable, so that a trivial
- // traversal will traverse children in the order they are initiated in the parent source. This
- // assumes they increase in SourceLoc implies an later within a source file - this is true
- // currently.
- for (auto& [_, value] : outHierarchy)
- {
- value.sort(
- [](SourceView* a, SourceView* b) -> bool {
- return a->getInitiatingSourceLoc().getRaw() < b->getInitiatingSourceLoc().getRaw();
- });
- }
-}
-
-// Given a source file, find the view that is the initial SourceView use of the source. It must have
-// an initiating SourceLoc that is not valid.
-static SourceView* _findInitialSourceView(SourceFile* sourceFile)
-{
- // TODO(JS):
- // This might be overkill - presumably the SourceView would belong to the same manager as it's
- // SourceFile? That is not enforced by the SourceManager in any way though so we just search all
- // managers, and all views.
- for (SourceManager* sourceManager = sourceFile->getSourceManager(); sourceManager;
- sourceManager = sourceManager->getParent())
- {
- for (SourceView* view : sourceManager->getSourceViews())
- {
- if (view->getSourceFile() == sourceFile && !view->getInitiatingSourceLoc().isValid())
- {
- return view;
- }
- }
- }
-
- return nullptr;
-}
-
-static void _outputInclude(SourceFile* sourceFile, Index depth, DiagnosticSink* sink)
-{
- StringBuilder buf;
-
- for (Index i = 0; i < depth; ++i)
- {
- buf << " ";
- }
-
- // Output the found path for now
- // TODO(JS). We could use the verbose paths flag to control what path is output -> as it may be
- // useful to output the full path for example
-
- const PathInfo& pathInfo = sourceFile->getPathInfo();
- buf << "'" << pathInfo.foundPath << "'";
-
- // TODO(JS)?
- // You might want to know where this include was from.
- // If I output this though there will be a problem... as the indenting won't be clearly shown.
- // Perhaps I output in two sections, one the hierarchy and the other the locations of the
- // includes?
-
- sink->diagnose(SourceLoc(), Diagnostics::includeOutput, buf);
-}
-
-static void _outputIncludesRec(
- SourceView* sourceView,
- Index depth,
- ViewInitiatingHierarchy& hierarchy,
- DiagnosticSink* sink)
-{
- SourceFile* sourceFile = sourceView->getSourceFile();
- const PathInfo& pathInfo = sourceFile->getPathInfo();
-
- switch (pathInfo.type)
- {
- case PathInfo::Type::TokenPaste:
- case PathInfo::Type::CommandLine:
- case PathInfo::Type::TypeParse:
- {
- // If any of these types we don't output
- return;
- }
- default:
- break;
- }
-
- // Okay output this file at the current depth
- _outputInclude(sourceFile, depth, sink);
-
- // Now recurse to all of the children at the next depth
- List<SourceView*>* children = hierarchy.tryGetValue(sourceView);
- if (children)
- {
- for (SourceView* child : *children)
- {
- _outputIncludesRec(child, depth + 1, hierarchy, sink);
- }
- }
-}
-
-static void _outputPreprocessorTokens(const TokenList& toks, ISlangWriter* writer)
-{
- if (writer == nullptr)
- {
- return;
- }
-
- StringBuilder buf;
- for (const auto& tok : toks)
- {
- buf << tok.getContent();
- // We'll separate tokens with space for now
- buf.appendChar(' ');
- }
-
- buf.appendChar('\n');
-
- writer->write(buf.getBuffer(), buf.getLength());
-}
-
-static void _outputIncludes(
- const List<SourceFile*>& sourceFiles,
- SourceManager* sourceManager,
- DiagnosticSink* sink)
-{
- // Set up the hierarchy to know how all the source views relate. This could be argued as
- // overkill, but makes recursive output pretty simple
- ViewInitiatingHierarchy hierarchy;
- _calcViewInitiatingHierarchy(sourceManager, hierarchy);
-
- // For all the source files
- for (SourceFile* sourceFile : sourceFiles)
- {
- if (sourceFile->isIncludedFile())
- continue;
-
- // Find an initial view (this is the view of this file, that doesn't have an initiating loc)
- SourceView* sourceView = _findInitialSourceView(sourceFile);
- if (!sourceView)
- {
- // Okay, didn't find one, so just output the file
- _outputInclude(sourceFile, 0, sink);
- }
- else
- {
- // Output from this view recursively
- _outputIncludesRec(sourceView, 0, hierarchy, sink);
- }
- }
-}
-
-void FrontEndCompileRequest::parseTranslationUnit(TranslationUnitRequest* translationUnit)
-{
- SLANG_PROFILE;
- if (translationUnit->isChecked)
- return;
-
- auto linkage = getLinkage();
-
- SLANG_AST_BUILDER_RAII(linkage->getASTBuilder());
-
- // TODO(JS): NOTE! Here we are using the searchDirectories on the linkage. This is because
- // currently the API only allows the setting search paths on linkage.
- //
- // Here we should probably be using the searchDirectories on the FrontEndCompileRequest.
- // If searchDirectories.parent pointed to the one in the Linkage would mean linkage paths
- // would be checked too (after those on the FrontEndCompileRequest).
- IncludeSystem includeSystem(
- &linkage->getSearchDirectories(),
- linkage->getFileSystemExt(),
- linkage->getSourceManager());
-
- auto combinedPreprocessorDefinitions = translationUnit->getCombinedPreprocessorDefinitions();
-
- auto module = translationUnit->getModule();
-
- ASTBuilder* astBuilder = module->getASTBuilder();
-
- ModuleDecl* translationUnitSyntax = astBuilder->create<ModuleDecl>();
-
- translationUnitSyntax->nameAndLoc.name = translationUnit->moduleName;
- translationUnitSyntax->module = module;
- module->setModuleDecl(translationUnitSyntax);
-
- // When compiling a module of code that belongs to the Slang
- // core module, we add a modifier to the module to act
- // as a marker, so that downstream code can detect declarations
- // that came from the core module (by walking up their
- // chain of ancestors and looking for the marker), and treat
- // them differently from user declarations.
- //
- // We are adding the marker here, before we even parse the
- // code in the module, in case the subsequent steps would
- // like to treat the core module differently. Alternatively
- // we could pass down the `m_isStandardLibraryCode` flag to
- // these passes.
- //
- if (m_isCoreModuleCode)
- {
- translationUnitSyntax->modifiers.first = astBuilder->create<FromCoreModuleModifier>();
- }
-
- // We use a custom handler for preprocessor callbacks, to
- // ensure that relevant state that is only visible during
- // preprocessoing can be communicated to later phases of
- // compilation.
- //
- FrontEndPreprocessorHandler preprocessorHandler(module, astBuilder, getSink(), translationUnit);
-
- for (auto sourceFile : translationUnit->getSourceFiles())
- {
- module->getIncludedSourceFileMap().addIfNotExists(sourceFile, nullptr);
- }
-
- for (auto sourceFile : translationUnit->getSourceFiles())
- {
- SourceLanguage sourceLanguage = translationUnit->sourceLanguage;
- SlangLanguageVersion languageVersion =
- translationUnit->compileRequest->optionSet.getLanguageVersion();
- auto tokens = preprocessSource(
- sourceFile,
- getSink(),
- &includeSystem,
- combinedPreprocessorDefinitions,
- getLinkage(),
- sourceLanguage,
- languageVersion,
- &preprocessorHandler);
-
- translationUnitSyntax->languageVersion = languageVersion;
-
- if (sourceLanguage == SourceLanguage::Unknown)
- sourceLanguage = translationUnit->sourceLanguage;
-
- Scope* languageScope = nullptr;
- switch (sourceLanguage)
- {
- case SourceLanguage::HLSL:
- languageScope = getSession()->hlslLanguageScope;
- break;
- case SourceLanguage::GLSL:
- languageScope = getSession()->glslLanguageScope;
- break;
- case SourceLanguage::Slang:
- default:
- languageScope = getSession()->slangLanguageScope;
- break;
- }
-
- if (optionSet.getBoolOption(CompilerOptionName::OutputIncludes))
- {
- _outputIncludes(
- translationUnit->getSourceFiles(),
- getSink()->getSourceManager(),
- getSink());
- }
-
- if (optionSet.getBoolOption(CompilerOptionName::PreprocessorOutput))
- {
- if (m_writers)
- {
- _outputPreprocessorTokens(
- tokens,
- m_writers->getWriter(SLANG_WRITER_CHANNEL_STD_OUTPUT));
- }
- // If we output the preprocessor output then we are done doing anything else
- return;
- }
-
- parseSourceFile(
- astBuilder,
- translationUnit,
- sourceLanguage,
- tokens,
- getSink(),
- languageScope,
- translationUnitSyntax);
-
- // Let's try dumping
-
- if (optionSet.getBoolOption(CompilerOptionName::DumpAst))
- {
- StringBuilder buf;
- SourceWriter writer(linkage->getSourceManager(), LineDirectiveMode::None, nullptr);
-
- ASTDumpUtil::dump(
- translationUnit->getModuleDecl(),
- ASTDumpUtil::Style::Flat,
- 0,
- &writer);
-
- const String& path = sourceFile->getPathInfo().foundPath;
- if (path.getLength())
- {
- String fileName = Path::getFileNameWithoutExt(path);
- fileName.append(".slang-ast");
-
- File::writeAllText(fileName, writer.getContent());
- }
- }
-
-#if 0
- // Test serialization
- {
- ASTSerialTestUtil::testSerialize(translationUnit->getModuleDecl(), getSession()->getNamePool(), getLinkage()->getASTBuilder()->getSharedASTBuilder(), getSourceManager());
- }
-#endif
- }
-}
-
-RefPtr<ComponentType> createUnspecializedGlobalComponentType(
- FrontEndCompileRequest* compileRequest);
-
-RefPtr<ComponentType> createUnspecializedGlobalAndEntryPointsComponentType(
- FrontEndCompileRequest* compileRequest,
- List<RefPtr<ComponentType>>& outUnspecializedEntryPoints);
-
-RefPtr<ComponentType> createSpecializedGlobalComponentType(EndToEndCompileRequest* endToEndReq);
-
-RefPtr<ComponentType> createSpecializedGlobalAndEntryPointsComponentType(
- EndToEndCompileRequest* endToEndReq,
- List<RefPtr<ComponentType>>& outSpecializedEntryPoints);
-
-void FrontEndCompileRequest::checkAllTranslationUnits()
-{
- SLANG_PROFILE;
-
- LoadedModuleDictionary loadedModules;
- if (additionalLoadedModules)
- loadedModules = *additionalLoadedModules;
-
- // Iterate over all translation units and
- // apply the semantic checking logic.
- for (auto& translationUnit : translationUnits)
- {
- if (translationUnit->isChecked)
- continue;
-
- checkTranslationUnit(translationUnit.Ptr(), loadedModules);
-
- // Add the checked module to list of loadedModules so that they can be
- // discovered by `findOrImportModule` when processing future `import` decls.
- // TODO: this does not handle the case where a translation unit to discover
- // another translation unit added later to the compilation request.
- // We should output an error message when we detect such a case, or support
- // this scenario with a recursive style checking.
- loadedModules.add(translationUnit->moduleName, translationUnit->getModule());
- }
- checkEntryPoints();
-}
-
-void FrontEndCompileRequest::generateIR()
-{
- SLANG_PROFILE;
- SLANG_AST_BUILDER_RAII(getLinkage()->getASTBuilder());
-
- // Our task in this function is to generate IR code
- // for all of the declarations in the translation
- // units that were loaded.
-
- // Each translation unit is its own little world
- // for code generation (we are not trying to
- // replicate the GLSL linkage model), and so
- // we will generate IR for each (if needed)
- // in isolation.
- for (auto& translationUnit : translationUnits)
- {
- // Skip if the module is precompiled.
- if (translationUnit->getModule()->getIRModule())
- continue;
-
- // We want to only run generateIRForTranslationUnit once here. This is for two side effects:
- // * it can dump ir
- // * it can generate diagnostics
-
- /// Generate IR for translation unit.
- RefPtr<IRModule> irModule(
- generateIRForTranslationUnit(getLinkage()->getASTBuilder(), translationUnit));
-
- if (verifyDebugSerialization)
- {
- SerialContainerUtil::WriteOptions options;
-
- options.sourceManagerToUseWhenSerializingSourceLocs = getSourceManager();
-
- // Verify debug information
- if (SLANG_FAILED(
- SerialContainerUtil::verifyIRSerialize(irModule, getSession(), options)))
- {
- getSink()->diagnose(
- irModule->getModuleInst()->sourceLoc,
- Diagnostics::serialDebugVerificationFailed);
- }
- }
-
- // Set the module on the translation unit
- translationUnit->getModule()->setIRModule(irModule);
- }
-}
-
-// Try to infer a single common source language for a request
-static SourceLanguage inferSourceLanguage(FrontEndCompileRequest* request)
-{
- SourceLanguage language = SourceLanguage::Unknown;
- for (auto& translationUnit : request->translationUnits)
- {
- // Allow any other language to overide Slang as a choice
- if (language == SourceLanguage::Unknown || language == SourceLanguage::Slang)
- {
- language = translationUnit->sourceLanguage;
- }
- else if (language == translationUnit->sourceLanguage)
- {
- // same language as we currently have, so keep going
- }
- else
- {
- // we found a mismatch, so inference fails
- return SourceLanguage::Unknown;
- }
- }
- return language;
-}
-
-SlangResult FrontEndCompileRequest::executeActionsInner()
-{
- SLANG_PROFILE_SECTION(frontEndExecute);
- SLANG_AST_BUILDER_RAII(getLinkage()->getASTBuilder());
-
- for (TranslationUnitRequest* translationUnit : translationUnits)
- {
- // Make sure SourceFile representation is available for all translationUnits
- SLANG_RETURN_ON_FAIL(translationUnit->requireSourceFiles());
- }
-
-
- // Parse everything from the input files requested
- for (TranslationUnitRequest* translationUnit : translationUnits)
- {
- parseTranslationUnit(translationUnit);
- }
-
- if (optionSet.getBoolOption(CompilerOptionName::PreprocessorOutput))
- {
- // If doing pre-processor output, then we are done
- return SLANG_OK;
- }
-
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
-
- // Perform semantic checking on the whole collection
- {
- SLANG_PROFILE_SECTION(SemanticChecking);
- checkAllTranslationUnits();
- }
-
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
-
- // After semantic checking is performed we can try and output doc information for this
- if (optionSet.getBoolOption(CompilerOptionName::Doc))
- {
- // TODO: implement the logic to output generated documents to target directory/zip file.
- }
-
- // Look up all the entry points that are expected,
- // and use them to populate the `program` member.
- //
- m_globalComponentType = createUnspecializedGlobalComponentType(this);
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
-
- m_globalAndEntryPointsComponentType =
- createUnspecializedGlobalAndEntryPointsComponentType(this, m_unspecializedEntryPoints);
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
-
- // We always generate IR for all the translation units.
- //
- // TODO: We may eventually have a mode where we skip
- // IR codegen and only produce an AST (e.g., for use when
- // debugging problems in the parser or semantic checking),
- // but for now there are no cases where not having IR
- // makes sense.
- //
- generateIR();
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
-
- // Do parameter binding generation, for each compilation target.
- //
- for (auto targetReq : getLinkage()->targets)
- {
- auto targetProgram = m_globalAndEntryPointsComponentType->getTargetProgram(targetReq);
- targetProgram->getOrCreateLayout(getSink());
- targetProgram->getOrCreateIRModuleForLayout(getSink());
- }
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
-
- return SLANG_OK;
-}
-
-EndToEndCompileRequest::EndToEndCompileRequest(Session* session)
- : m_session(session), m_sink(nullptr, Lexer::sourceLocationLexer)
-{
- RefPtr<ASTBuilder> astBuilder(
- new ASTBuilder(session->m_sharedASTBuilder, "EndToEnd::Linkage::astBuilder"));
- m_linkage = new Linkage(session, astBuilder, session->getBuiltinLinkage());
- init();
-}
-
-EndToEndCompileRequest::EndToEndCompileRequest(Linkage* linkage)
- : m_session(linkage->getSessionImpl())
- , m_linkage(linkage)
- , m_sink(nullptr, Lexer::sourceLocationLexer)
-{
- init();
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL
-EndToEndCompileRequest::queryInterface(SlangUUID const& uuid, void** outObject)
-{
- if (uuid == EndToEndCompileRequest::getTypeGuid())
- {
- // Special case to cast directly into internal type
- // NOTE! No addref(!)
- *outObject = this;
- return SLANG_OK;
- }
-
- if (uuid == ISlangUnknown::getTypeGuid() && uuid == ICompileRequest::getTypeGuid())
- {
- addReference();
- *outObject = static_cast<slang::ICompileRequest*>(this);
- return SLANG_OK;
- }
-
- return SLANG_E_NO_INTERFACE;
-}
-
-void EndToEndCompileRequest::init()
-{
- m_sink.setSourceManager(m_linkage->getSourceManager());
-
- m_writers = new StdWriters;
-
- // Set all the default writers
- for (int i = 0; i < int(WriterChannel::CountOf); ++i)
- {
- setWriter(WriterChannel(i), nullptr);
- }
-
- m_frontEndReq = new FrontEndCompileRequest(getLinkage(), m_writers, getSink());
-}
-
-SlangResult EndToEndCompileRequest::executeActionsInner()
-{
- SLANG_PROFILE_SECTION(endToEndActions);
- // If no code-generation target was specified, then try to infer one from the source language,
- // just to make sure we can do something reasonable when invoked from the command line.
- //
- // TODO: This logic should be moved into `options.cpp` or somewhere else
- // specific to the command-line tool.
- //
- if (getLinkage()->targets.getCount() == 0)
- {
- auto language = inferSourceLanguage(getFrontEndReq());
- switch (language)
- {
- case SourceLanguage::HLSL:
- getLinkage()->addTarget(CodeGenTarget::DXBytecode);
- break;
-
- case SourceLanguage::GLSL:
- getLinkage()->addTarget(CodeGenTarget::SPIRV);
- break;
-
- default:
- break;
- }
- }
-
- // Update compiler settings in target requests.
- for (auto target : getLinkage()->targets)
- target->getOptionSet().inheritFrom(getOptionSet());
- m_frontEndReq->optionSet = getOptionSet();
-
- // We only do parsing and semantic checking if we *aren't* doing
- // a pass-through compilation.
- //
- if (m_passThrough == PassThroughMode::None)
- {
- SLANG_RETURN_ON_FAIL(getFrontEndReq()->executeActionsInner());
- }
-
- if (getOptionSet().getBoolOption(CompilerOptionName::PreprocessorOutput))
- {
- return SLANG_OK;
- }
-
- // If command line specifies to skip codegen, we exit here.
- // Note: this is a debugging option.
- //
- if (getOptionSet().getBoolOption(CompilerOptionName::SkipCodeGen))
- {
- // We will use the program (and matching layout information)
- // that was computed in the front-end for all subsequent
- // reflection queries, etc.
- //
- m_specializedGlobalComponentType = getUnspecializedGlobalComponentType();
- m_specializedGlobalAndEntryPointsComponentType =
- getUnspecializedGlobalAndEntryPointsComponentType();
- m_specializedEntryPoints = getFrontEndReq()->getUnspecializedEntryPoints();
-
- SLANG_RETURN_ON_FAIL(maybeCreateContainer());
-
- SLANG_RETURN_ON_FAIL(maybeWriteContainer(m_containerOutputPath));
-
- return SLANG_OK;
- }
-
- // If requested, attempt to compile the translation unit all the way down to the target
- // language(s) and stash the result blobs in IR.
- for (auto target : getLinkage()->targets)
- {
- SlangCompileTarget targetEnum = SlangCompileTarget(target->getTarget());
- if (target->getOptionSet().getBoolOption(CompilerOptionName::EmbedDownstreamIR))
- {
- auto frontEndReq = getFrontEndReq();
-
- for (auto translationUnit : frontEndReq->translationUnits)
- {
- SLANG_RETURN_ON_FAIL(
- translationUnit->getModule()->precompileForTarget(targetEnum, nullptr));
-
- if (frontEndReq->optionSet.shouldDumpIR())
- {
- DiagnosticSinkWriter writer(frontEndReq->getSink());
-
- dumpIR(
- translationUnit->getModule()->getIRModule(),
- frontEndReq->m_irDumpOptions,
- "PRECOMPILE_FOR_TARGET_COMPLETE_ALL",
- frontEndReq->getSourceManager(),
- &writer);
-
- dumpIR(
- translationUnit->getModule()->getIRModule()->getModuleInst(),
- frontEndReq->m_irDumpOptions,
- frontEndReq->getSourceManager(),
- &writer);
- }
- }
- }
- }
-
- // If codegen is enabled, we need to move along to
- // apply any generic specialization that the user asked for.
- //
- if (m_passThrough == PassThroughMode::None)
- {
- m_specializedGlobalComponentType = createSpecializedGlobalComponentType(this);
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
-
- m_specializedGlobalAndEntryPointsComponentType =
- createSpecializedGlobalAndEntryPointsComponentType(this, m_specializedEntryPoints);
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
-
- // For each code generation target, we will generate specialized
- // parameter binding information (taking global generic
- // arguments into account at this time).
- //
- for (auto targetReq : getLinkage()->targets)
- {
- auto targetProgram =
- m_specializedGlobalAndEntryPointsComponentType->getTargetProgram(targetReq);
- targetProgram->getOrCreateLayout(getSink());
- }
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
- }
- else
- {
- // We need to create dummy `EntryPoint` objects
- // to make sure that the logic in `generateOutput`
- // sees something worth processing.
- //
- List<RefPtr<ComponentType>> dummyEntryPoints;
- for (auto entryPointReq : getFrontEndReq()->getEntryPointReqs())
- {
- RefPtr<EntryPoint> dummyEntryPoint = EntryPoint::createDummyForPassThrough(
- getLinkage(),
- entryPointReq->getName(),
- entryPointReq->getProfile());
-
- dummyEntryPoints.add(dummyEntryPoint);
- }
-
- RefPtr<ComponentType> composedProgram =
- CompositeComponentType::create(getLinkage(), dummyEntryPoints);
-
- m_specializedGlobalComponentType = getUnspecializedGlobalComponentType();
- m_specializedGlobalAndEntryPointsComponentType = composedProgram;
- m_specializedEntryPoints = getFrontEndReq()->getUnspecializedEntryPoints();
- }
-
- // Generate output code, in whatever format was requested
- generateOutput();
- if (getSink()->getErrorCount() != 0)
- return SLANG_FAIL;
-
- return SLANG_OK;
-}
-
-// Act as expected of the API-based compiler
-SlangResult EndToEndCompileRequest::executeActions()
-{
- SlangResult res = executeActionsInner();
-
- m_diagnosticOutput = getSink()->outputBuffer.produceString();
- return res;
-}
-
-int FrontEndCompileRequest::addTranslationUnit(SourceLanguage language, Name* moduleName)
-{
- RefPtr<TranslationUnitRequest> translationUnit = new TranslationUnitRequest(this);
- translationUnit->compileRequest = this;
- translationUnit->sourceLanguage = SourceLanguage(language);
-
- translationUnit->setModuleName(moduleName);
- return addTranslationUnit(translationUnit);
-}
-
-int FrontEndCompileRequest::addTranslationUnit(TranslationUnitRequest* translationUnit)
-{
- Index result = translationUnits.getCount();
- translationUnits.add(translationUnit);
- return (int)result;
-}
-
-void FrontEndCompileRequest::addTranslationUnitSourceArtifact(
- int translationUnitIndex,
- IArtifact* sourceArtifact)
-{
- auto translationUnit = translationUnits[translationUnitIndex];
-
- // Add the source file
- translationUnit->addSourceArtifact(sourceArtifact);
-
- if (!translationUnit->moduleName)
- {
- translationUnit->setModuleName(
- getNamePool()->getName(Path::getFileNameWithoutExt(sourceArtifact->getName())));
- }
- if (translationUnit->module->getFilePath() == nullptr)
- translationUnit->module->setPathInfo(PathInfo::makePath(sourceArtifact->getName()));
-}
-
-void FrontEndCompileRequest::addTranslationUnitSourceBlob(
- int translationUnitIndex,
- String const& path,
- ISlangBlob* sourceBlob)
-{
- auto translationUnit = translationUnits[translationUnitIndex];
- auto sourceDesc =
- ArtifactDescUtil::makeDescForSourceLanguage(asExternal(translationUnit->sourceLanguage));
-
- auto artifact = ArtifactUtil::createArtifact(sourceDesc, path.getBuffer());
- artifact->addRepresentationUnknown(sourceBlob);
-
- addTranslationUnitSourceArtifact(translationUnitIndex, artifact);
-}
-
-void FrontEndCompileRequest::addTranslationUnitSourceFile(
- int translationUnitIndex,
- String const& path)
-{
- // TODO: We need to consider whether a relative `path` should cause
- // us to look things up using the registered search paths.
- //
- // This behavior wouldn't make sense for command-line invocations
- // of `slangc`, but at least one API user wondered by the search
- // paths were not taken into account by this function.
- //
-
- auto fileSystemExt = getLinkage()->getFileSystemExt();
- auto translationUnit = getTranslationUnit(translationUnitIndex);
-
- auto sourceDesc =
- ArtifactDescUtil::makeDescForSourceLanguage(asExternal(translationUnit->sourceLanguage));
-
- auto sourceArtifact = ArtifactUtil::createArtifact(sourceDesc, path.getBuffer());
-
- auto extRep = new ExtFileArtifactRepresentation(path.getUnownedSlice(), fileSystemExt);
- sourceArtifact->addRepresentation(extRep);
-
- SlangResult existsRes = SLANG_OK;
-
- // If we require caching, we demand it's loaded here.
- //
- // In practice this probably means repro capture is enabled. So we want to
- // load the blob such that it's in the cache, even if it doesn't actually
- // have to be loaded for the compilation.
- if (getLinkage()->m_requireCacheFileSystem)
- {
- ComPtr<ISlangBlob> blob;
- // If we can load the blob, then it exists
- existsRes = sourceArtifact->loadBlob(ArtifactKeep::Yes, blob.writeRef());
- }
- else
- {
- existsRes = sourceArtifact->exists() ? SLANG_OK : SLANG_E_NOT_FOUND;
- }
-
- if (SLANG_FAILED(existsRes))
- {
- // Emit a diagnostic!
- getSink()->diagnose(SourceLoc(), Diagnostics::cannotOpenFile, path);
- return;
- }
-
- addTranslationUnitSourceArtifact(translationUnitIndex, sourceArtifact);
-}
-
-int FrontEndCompileRequest::addEntryPoint(
- int translationUnitIndex,
- String const& name,
- Profile entryPointProfile)
-{
- auto translationUnitReq = translationUnits[translationUnitIndex];
-
- Index result = m_entryPointReqs.getCount();
-
- RefPtr<FrontEndEntryPointRequest> entryPointReq = new FrontEndEntryPointRequest(
- this,
- translationUnitIndex,
- getNamePool()->getName(name),
- entryPointProfile);
-
- m_entryPointReqs.add(entryPointReq);
- // translationUnitReq->entryPoints.add(entryPointReq);
-
- return int(result);
-}
-
-int EndToEndCompileRequest::addEntryPoint(
- int translationUnitIndex,
- String const& name,
- Profile entryPointProfile,
- List<String> const& genericTypeNames)
-{
- getFrontEndReq()->addEntryPoint(translationUnitIndex, name, entryPointProfile);
-
- EntryPointInfo entryPointInfo;
- for (auto typeName : genericTypeNames)
- entryPointInfo.specializationArgStrings.add(typeName);
-
- Index result = m_entryPoints.getCount();
- m_entryPoints.add(_Move(entryPointInfo));
- return (int)result;
-}
-
-UInt Linkage::addTarget(CodeGenTarget target)
-{
- RefPtr<TargetRequest> targetReq = new TargetRequest(this, target);
-
- Index result = targets.getCount();
- targets.add(targetReq);
- return UInt(result);
-}
-
-void Linkage::loadParsedModule(
- RefPtr<FrontEndCompileRequest> compileRequest,
- RefPtr<TranslationUnitRequest> translationUnit,
- Name* name,
- const PathInfo& pathInfo)
-{
- // Note: we add the loaded module to our name->module listing
- // before doing semantic checking, so that if it tries to
- // recursively `import` itself, we can detect it.
- //
- RefPtr<Module> loadedModule = translationUnit->getModule();
-
- // Get a path
- String mostUniqueIdentity = pathInfo.getMostUniqueIdentity();
- SLANG_ASSERT(mostUniqueIdentity.getLength() > 0);
-
- mapPathToLoadedModule.add(mostUniqueIdentity, loadedModule);
- mapNameToLoadedModules.add(name, loadedModule);
-
- auto sink = translationUnit->compileRequest->getSink();
-
- int errorCountBefore = sink->getErrorCount();
- int errorCountAfter;
- try
- {
- compileRequest->checkAllTranslationUnits();
- }
- catch (...)
- {
- mapPathToLoadedModule.remove(mostUniqueIdentity);
- mapNameToLoadedModules.remove(name);
- throw;
- }
- errorCountAfter = sink->getErrorCount();
- if (isInLanguageServer())
- {
- // Don't generate IR as language server.
- // This means that we currently cannot report errors that are detected during IR passes.
- // Ideally we want to run those passes, but that is too risky for what it is worth right
- // now.
- }
- else
- {
- if (errorCountAfter != errorCountBefore)
- {
- // There must have been an error in the loaded module.
- // Remove from maps if there were errors during semantic checking
- mapPathToLoadedModule.remove(mostUniqueIdentity);
- mapNameToLoadedModules.remove(name);
- }
- else
- {
- // If we didn't run into any errors, then try to generate
- // IR code for the imported module.
- if (errorCountAfter == 0)
- {
- loadedModule->setIRModule(
- generateIRForTranslationUnit(getASTBuilder(), translationUnit));
- }
- }
- }
- loadedModulesList.add(loadedModule);
-}
-
-RefPtr<Module> Linkage::findOrLoadSerializedModuleForModuleLibrary(
- ISlangBlob* blobHoldingSerializedData,
- ModuleChunk const* moduleChunk,
- RIFF::ListChunk const* libraryChunk,
- DiagnosticSink* sink)
-{
- RefPtr<Module> resultModule;
-
- // We will attempt things in a few different steps, trying to
- // decode as little of the serialized module as necessary at
- // each step, so that we don't waste time on the heavyweight
- // stuff when we didn't need to.
- //
- // The first step is to simply decode the module name, and
- // see if we have a already loaded a matching module.
-
- auto moduleName = getNamePool()->getName(moduleChunk->getName());
- if (mapNameToLoadedModules.tryGetValue(moduleName, resultModule))
- return resultModule;
-
- // It is possible that the module has been loaded, but somehow
- // under a different name, so next we decode the list of file
- // paths that the module depends on, and then rely on the assumption
- // that the first of those paths represents the file for the module
- // itself to detect if we've already loaded a module from that
- // path.
- //
- // Note: While this is a distasteful assumption to make, it is
- // one that gets made in several parts of the compiler codebase
- // already. It isn't something that can be fixed in just one
- // place at this point.
-
- auto fileDependenciesList = moduleChunk->getFileDependencies();
- auto firstFileDependencyChunk = fileDependenciesList.getFirst();
- if (!firstFileDependencyChunk)
- return nullptr;
-
- auto modulePathInfo = PathInfo::makePath(firstFileDependencyChunk->getValue());
- if (mapPathToLoadedModule.tryGetValue(modulePathInfo.getMostUniqueIdentity(), resultModule))
- return resultModule;
-
- // If we failed to find a previously-loaded module, then we
- // will go ahead and load the module from the serialized form.
- //
- PathInfo filePathInfo;
- return loadSerializedModule(
- moduleName,
- modulePathInfo,
- blobHoldingSerializedData,
- moduleChunk,
- libraryChunk,
- SourceLoc(),
- sink);
-}
-
-RefPtr<Module> Linkage::loadSerializedModule(
- Name* moduleName,
- const PathInfo& moduleFilePathInfo,
- ISlangBlob* blobHoldingSerializedData,
- ModuleChunk const* moduleChunk,
- RIFF::ListChunk const* containerChunk,
- SourceLoc const& requestingLoc,
- DiagnosticSink* sink)
-{
- auto astBuilder = getASTBuilder();
- SLANG_AST_BUILDER_RAII(astBuilder);
-
- auto module = RefPtr(new Module(this, astBuilder));
- module->setName(moduleName);
-
- // Just as if we were processing an `import` declaration in
- // source code, we will track the fact that this serialized
- // modlue is (effectively) being imported, so that we can
- // diagnose anything troublesome, like an attempt at a
- // recursive import.
- //
- ModuleBeingImportedRAII moduleBeingImported(this, module, moduleName, requestingLoc);
-
- // We will register the module in our data structures to
- // track loaded modules, and then remove it in the case
- // where there is some kind of failure.
- //
- String mostUniqueIdentity = moduleFilePathInfo.getMostUniqueIdentity();
- SLANG_ASSERT(mostUniqueIdentity.getLength() > 0);
-
- mapPathToLoadedModule.add(mostUniqueIdentity, module);
- mapNameToLoadedModules.add(moduleName, module);
- try
- {
- if (SLANG_FAILED(loadSerializedModuleContents(
- module,
- moduleFilePathInfo,
- blobHoldingSerializedData,
- moduleChunk,
- containerChunk,
- sink)))
- {
- mapPathToLoadedModule.remove(mostUniqueIdentity);
- mapNameToLoadedModules.remove(moduleName);
- return nullptr;
- }
-
- loadedModulesList.add(module);
- return module;
- }
- catch (...)
- {
- mapPathToLoadedModule.remove(mostUniqueIdentity);
- mapNameToLoadedModules.remove(moduleName);
- throw;
- }
-}
-
-RefPtr<Module> Linkage::loadBinaryModuleImpl(
- Name* moduleName,
- const PathInfo& moduleFilePathInfo,
- ISlangBlob* moduleFileContents,
- SourceLoc const& requestingLoc,
- DiagnosticSink* sink)
-{
- auto astBuilder = getASTBuilder();
- SLANG_AST_BUILDER_RAII(astBuilder);
-
- // We start by reading the content of the file as
- // an in-memory RIFF container.
- //
- auto rootChunk = RIFF::RootChunk::getFromBlob(moduleFileContents);
- if (!rootChunk)
- {
- return nullptr;
- }
-
- auto moduleChunk = ModuleChunk::find(rootChunk);
- if (!moduleChunk)
- {
- return nullptr;
- }
-
- // Next, we attempt to check if the binary module is up to
- // date with the compilation options in use as well as
- // the contents of all the files its compilation depended
- // on (as determined by its hash).
- //
- String mostUniqueIdentity = moduleFilePathInfo.getMostUniqueIdentity();
- SLANG_ASSERT(mostUniqueIdentity.getLength() > 0);
- if (m_optionSet.getBoolOption(CompilerOptionName::UseUpToDateBinaryModule))
- {
- if (!isBinaryModuleUpToDate(moduleFilePathInfo.foundPath, moduleChunk))
- {
- return nullptr;
- }
- }
-
- // If everything seems reasonable, then we will go ahead and load
- // the module more completely from that serialized representation.
- //
- RefPtr<Module> module = loadSerializedModule(
- moduleName,
- moduleFilePathInfo,
- moduleFileContents,
- moduleChunk,
- rootChunk,
- requestingLoc,
- sink);
-
- return module;
-}
-
-void Linkage::_diagnoseErrorInImportedModule(DiagnosticSink* sink)
-{
- for (auto info = m_modulesBeingImported; info; info = info->next)
- {
- sink->diagnose(info->importLoc, Diagnostics::errorInImportedModule, info->name);
- }
- if (!isInLanguageServer())
- {
- sink->diagnose(SourceLoc(), Diagnostics::complationCeased);
- }
-}
-
-RefPtr<Module> Linkage::loadModuleImpl(
- Name* moduleName,
- const PathInfo& modulePathInfo,
- ISlangBlob* moduleBlob,
- SourceLoc const& requestingLoc,
- DiagnosticSink* sink,
- const LoadedModuleDictionary* additionalLoadedModules,
- ModuleBlobType blobType)
-{
- switch (blobType)
- {
- case ModuleBlobType::IR:
- return loadBinaryModuleImpl(moduleName, modulePathInfo, moduleBlob, requestingLoc, sink);
-
- case ModuleBlobType::Source:
- return loadSourceModuleImpl(
- moduleName,
- modulePathInfo,
- moduleBlob,
- requestingLoc,
- sink,
- additionalLoadedModules);
-
- default:
- SLANG_UNEXPECTED("unknown module blob type");
- UNREACHABLE_RETURN(nullptr);
- }
-}
-
-RefPtr<Module> Linkage::loadSourceModuleImpl(
- Name* name,
- const PathInfo& filePathInfo,
- ISlangBlob* sourceBlob,
- SourceLoc const& srcLoc,
- DiagnosticSink* sink,
- const LoadedModuleDictionary* additionalLoadedModules)
-{
- RefPtr<FrontEndCompileRequest> frontEndReq = new FrontEndCompileRequest(this, nullptr, sink);
-
- frontEndReq->additionalLoadedModules = additionalLoadedModules;
-
- RefPtr<TranslationUnitRequest> translationUnit = new TranslationUnitRequest(frontEndReq);
- translationUnit->compileRequest = frontEndReq;
- translationUnit->setModuleName(name);
- Stage impliedStage;
- translationUnit->sourceLanguage = SourceLanguage::Slang;
-
- // If we are loading from a file with apparaent glsl extension,
- // set the source language to GLSL to enable GLSL compatibility mode.
- if ((SourceLanguage)findSourceLanguageFromPath(filePathInfo.getName(), impliedStage) ==
- SourceLanguage::GLSL)
- {
- translationUnit->sourceLanguage = SourceLanguage::GLSL;
- }
-
- frontEndReq->addTranslationUnit(translationUnit);
-
- auto module = translationUnit->getModule();
-
- ModuleBeingImportedRAII moduleBeingImported(this, module, name, srcLoc);
-
- // Create an artifact for the source
- auto sourceArtifact = ArtifactUtil::createArtifact(
- ArtifactDesc::make(ArtifactKind::Source, ArtifactPayload::Slang, ArtifactStyle::Unknown));
-
- if (sourceBlob)
- {
- // If the user has already provided a source blob, use that.
- sourceArtifact->addRepresentation(
- new SourceBlobWithPathInfoArtifactRepresentation(filePathInfo, sourceBlob));
- }
- else if (
- filePathInfo.type == PathInfo::Type::Normal ||
- filePathInfo.type == PathInfo::Type::FoundPath)
- {
- // Create with the 'friendly' name
- // We create that it was loaded from the file system
- sourceArtifact->addRepresentation(new ExtFileArtifactRepresentation(
- filePathInfo.foundPath.getUnownedSlice(),
- getFileSystemExt()));
- }
- else
- {
- return nullptr;
- }
-
- translationUnit->addSourceArtifact(sourceArtifact);
-
- if (SLANG_FAILED(translationUnit->requireSourceFiles()))
- {
- // Some problem accessing source files
- return nullptr;
- }
- int errorCountBefore = sink->getErrorCount();
- frontEndReq->parseTranslationUnit(translationUnit);
- int errorCountAfter = sink->getErrorCount();
-
- if (errorCountAfter != errorCountBefore && !isInLanguageServer())
- {
- _diagnoseErrorInImportedModule(sink);
- // Something went wrong during the parsing, so we should bail out.
- return nullptr;
- }
-
- try
- {
- loadParsedModule(frontEndReq, translationUnit, name, filePathInfo);
- }
- catch (const Slang::AbortCompilationException&)
- {
- // Something is fatally wrong, we should return nullptr.
- module = nullptr;
- }
- errorCountAfter = sink->getErrorCount();
-
- if (errorCountAfter != errorCountBefore && !isInLanguageServer())
- {
- // If something is fatally wrong, we want to report
- // the diagnostic even if we are in language server
- // and processing a different module.
- _diagnoseErrorInImportedModule(sink);
- // Something went wrong during the parsing, so we should bail out.
- return nullptr;
- }
-
- if (!module)
- return nullptr;
-
- module->setPathInfo(filePathInfo);
- return module;
-}
-
-bool Linkage::isBeingImported(Module* module)
-{
- for (auto ii = m_modulesBeingImported; ii; ii = ii->next)
- {
- if (module == ii->module)
- return true;
- }
- return false;
-}
-
-// Derive a file name for the module, by taking the given
-// identifier, replacing all occurrences of `_` with `-`,
-// and then appending `.slang`.
-//
-// For example, `foo_bar` becomes `foo-bar.slang`.
-String getFileNameFromModuleName(Name* name, bool translateUnderScore)
-{
- String fileName;
- if (!getText(name).getUnownedSlice().endsWithCaseInsensitive(".slang"))
- {
- StringBuilder sb;
- for (auto c : getText(name))
- {
- if (translateUnderScore && c == '_')
- c = '-';
-
- sb.append(c);
- }
- sb.append(".slang");
- fileName = sb.produceString();
- }
- else
- {
- fileName = getText(name);
- }
- return fileName;
-}
-
-RefPtr<Module> Linkage::findOrImportModule(
- Name* moduleName,
- SourceLoc const& requestingLoc,
- DiagnosticSink* sink,
- const LoadedModuleDictionary* loadedModules)
-{
- // Have we already loaded a module matching this name?
- //
- RefPtr<LoadedModule> previouslyLoadedModule;
- if (mapNameToLoadedModules.tryGetValue(moduleName, previouslyLoadedModule))
- {
- // If the map shows a null module having been loaded,
- // then that means there was a prior load attempt,
- // but it failed, so we won't bother trying again.
- //
- if (!previouslyLoadedModule)
- return nullptr;
-
- // If state shows us that the module is already being
- // imported deeper on the call stack, then we've
- // hit a recursive case, and that is an error.
- //
- if (isBeingImported(previouslyLoadedModule))
- {
- // We seem to be in the middle of loading this module
- sink->diagnose(requestingLoc, Diagnostics::recursiveModuleImport, moduleName);
- return nullptr;
- }
-
- return previouslyLoadedModule;
- }
-
- // If the user is providing an additional list of loaded modules, we find
- // if the module being imported is in that list. This allows a translation
- // unit to use previously checked translation units in the same
- // FrontEndCompileRequest.
- {
- Module* previouslyLoadedLocalModule = nullptr;
- if (loadedModules && loadedModules->tryGetValue(moduleName, previouslyLoadedLocalModule))
- {
- return previouslyLoadedLocalModule;
- }
- }
-
- // If the name being requested matches the name of a built-in module,
- // then we will special-case the process by loading that builtin
- // module directly.
- //
- // TODO: right now this logic is only considering the built-in `glsl`
- // module, but it should probably be generalized so that we can more
- // easily support having multiple built-in modules rather than just
- // putting everything into `core`.
- //
- if (moduleName == getSessionImpl()->glslModuleName)
- {
- // This is a builtin glsl module, just load it from embedded definition.
- auto glslModule = getSessionImpl()->getBuiltinModule(slang::BuiltinModuleName::GLSL);
- if (!glslModule)
- {
- // Note: the way this logic is currently written, if the built-in
- // `glsl` module fails to load, then we will *not* fall back to
- // searching for a user-defined module in a file like `glsl.slang`.
- //
- // It is unclear if this should be the default behavior or not.
- // Should built-in modules be prioritized over user modules?
- // Should built-in modules shadow user modules, even when the
- // built-in module fails to load, for some reason?
- //
- sink->diagnose(requestingLoc, Diagnostics::glslModuleNotAvailable, moduleName);
- }
- return glslModule;
- }
-
- // We are going to use a loop to search for a suitable file to
- // load the module from, to account for a few key choices:
- //
- // * We can both load modules from a source `.slang` file,
- // or from a binary `.slang-module` file.
- //
- // * For a variety of reasons, the `import` logic has historically
- // translated underscores in a module name into dashes (so that
- // `import my_module` will look for `my-module.slang`), and we
- // try to support both that convention as well as a convention
- // that preserves underscores.
- //
- // To try to keep this logic as orthogonal as possible, we first
- // construct lists of the options we want to iterate over, and
- // then do the actual loop later.
-
- ShortList<ModuleBlobType, 2> typesToTry;
- if (isInLanguageServer())
- {
- // When in language server, we always prefer to use source module if it is available.
- typesToTry.add(ModuleBlobType::Source);
- typesToTry.add(ModuleBlobType::IR);
- }
- else
- {
- // Look for a precompiled module first, if not exist, load from source.
- typesToTry.add(ModuleBlobType::IR);
- typesToTry.add(ModuleBlobType::Source);
- }
-
- // We will always search for a file name that directly matches the
- // module name as written first, and then search for one with
- // underscores replaced by dashes. The latter is the original
- // behavior that `import` provided, but it seems safest to prefer
- // the exact name spelled in the user's code when there might
- // actually be ambiguity.
- //
- auto defaultSourceFileName = getFileNameFromModuleName(moduleName, false);
- auto alternativeSourceFileName = getFileNameFromModuleName(moduleName, true);
- String sourceFileNamesToTry[] = {defaultSourceFileName, alternativeSourceFileName};
-
- // We are going to look for the candidate file using the same
- // logic that would be used for a preprocessor `#include`,
- // so we set up the necessary state.
- //
- IncludeSystem includeSystem(&getSearchDirectories(), getFileSystemExt(), getSourceManager());
-
- // Just like with a `#include`, the search will take into
- // account the path to the file where the request to import
- // this module came from (e.g. the source file with the
- // `import` declaration), if such a path is available.
- //
- PathInfo requestingPathInfo =
- getSourceManager()->getPathInfo(requestingLoc, SourceLocType::Actual);
-
- for (auto type : typesToTry)
- {
- for (auto sourceFileName : sourceFileNamesToTry)
- {
- // The `sourceFileName` will have the `.slang` extension,
- // so if we are looking for a binary module, we need
- // to change the extension we will look for.
- //
- String fileName;
- switch (type)
- {
- case ModuleBlobType::Source:
- fileName = sourceFileName;
- break;
-
- case ModuleBlobType::IR:
- fileName = Path::replaceExt(sourceFileName, "slang-module");
- break;
- }
-
- // We now search for a file matching the desired name,
- // using the same logic as for a `#include`.
- //
- // TODO: We might want to consider how to handle the case
- // of an `import` with a relative path a little specially,
- // since it could in theory be possible for two `.slang`
- // files with the same base name to exist in different
- // directories in a project, and we'd want file-relative
- // `import`s to work for each, without having either one
- // be able to "claim" the bare identifier of the base
- // name for itself.
- //
- PathInfo filePathInfo;
- if (SLANG_FAILED(
- includeSystem.findFile(fileName, requestingPathInfo.foundPath, filePathInfo)))
- {
- // If we failed to find the file at this step, we
- // will continue the search for our other options.
- //
- continue;
- }
-
- // We will *again* search for a previously loaded module.
- //
- // It is possible that the same file will have been loaded
- // as a module under two different module names. The easiest
- // way for this to happen is if there are `import` declarations
- // using both the underscore and dash conventions (e.g., both
- // `import "my-module.slang"` and `import my_module`).
- //
- // This case may also arise if one file `import`s a module using
- // just an identifier for its name, but another `import`s it
- // using a path (e.g., `import "subdir/file.slang"`).
- //
- // No matter how the situation arises, we only want to have one
- // copy of the "same" module loaded at a given time, so we
- // will re-use the existing module if we find one here.
- //
- if (mapPathToLoadedModule.tryGetValue(
- filePathInfo.getMostUniqueIdentity(),
- previouslyLoadedModule))
- {
- // TODO: If we find a previously-loaded module at this step,
- // then we should probably register that module under the
- // given `moduleName` in the map of loaded modules, so
- // that subsequent `import`s using the same form will find it.
- //
- return previouslyLoadedModule;
- }
-
- // Now we try to load the content of the file.
- //
- // If for some reason we could find a file at the
- // given path, but for some reason couldn't *open*
- // and *read* it, then we continue the search
- // using whatever other candidate file names are left.
- //
- ComPtr<ISlangBlob> fileContents;
- if (SLANG_FAILED(includeSystem.loadFile(filePathInfo, fileContents)))
- {
- continue;
- }
-
- // If we found a real file and were able to load its contents,
- // then we'll go ahead and try to load a module from it,
- // whether by compiling it or decoding the binary.
- //
- auto module = loadModuleImpl(
- moduleName,
- filePathInfo,
- fileContents,
- requestingLoc,
- sink,
- loadedModules,
- type);
-
- // If the attempt to load the module from the given path
- // was successful, we go ahead and use it, without trying
- // out any other options.
- //
- if (module)
- return module;
- }
- }
-
- // If we tried out all of our candidate file names
- // and failed with each of them, then we diagnose
- // an error based on the original *source* file
- // name.
- //
- // TODO: this should really be an error message
- // that clearly states something like "no file
- // suitable for module `whatever` was found
- // and loaded.
- //
- // Ideally that error message would include whatever
- // of the candidate file names from the loop above
- // got furthest along in the process (or just a
- // list of the file names that were tried, if
- // nothing was even found via the include system).
- //
- sink->diagnose(requestingLoc, Diagnostics::cannotOpenFile, defaultSourceFileName);
-
- // If the attempt to import the module failed, then
- // we will stick a null pointer into the map of loaded
- // modules, so that subsequent attempts to load a module
- // with this name will return null without having to
- // go through all the above steps yet again.
- //
- mapNameToLoadedModules[moduleName] = nullptr;
- return nullptr;
-}
-
-SourceFile* Linkage::loadSourceFile(String pathFrom, String path)
-{
- IncludeSystem includeSystem(&getSearchDirectories(), getFileSystemExt(), getSourceManager());
- ComPtr<slang::IBlob> blob;
- PathInfo pathInfo;
- SLANG_RETURN_NULL_ON_FAIL(includeSystem.findFile(path, pathFrom, pathInfo));
- SourceFile* sourceFile = nullptr;
- SLANG_RETURN_NULL_ON_FAIL(includeSystem.loadFile(pathInfo, blob, sourceFile));
- return sourceFile;
-}
-
-// Check if a serialized module is up-to-date with current compiler options and source files.
-bool Linkage::isBinaryModuleUpToDate(String fromPath, RIFF::ListChunk const* baseChunk)
-{
- auto moduleChunk = ModuleChunk::find(baseChunk);
- if (!moduleChunk)
- return false;
-
- SHA1::Digest existingDigest = moduleChunk->getDigest();
-
- DigestBuilder<SHA1> digestBuilder;
- auto version = String(getBuildTagString());
- digestBuilder.append(version);
- m_optionSet.buildHash(digestBuilder);
-
- // Find the canonical path of the directory containing the module source file.
- String moduleSrcPath = "";
-
- auto dependencyChunks = moduleChunk->getFileDependencies();
- if (auto firstDependencyChunk = dependencyChunks.getFirst())
- {
- moduleSrcPath = firstDependencyChunk->getValue();
-
- IncludeSystem includeSystem(
- &getSearchDirectories(),
- getFileSystemExt(),
- getSourceManager());
- PathInfo modulePathInfo;
- if (SLANG_SUCCEEDED(includeSystem.findFile(moduleSrcPath, fromPath, modulePathInfo)))
- {
- moduleSrcPath = modulePathInfo.foundPath;
- Path::getCanonical(moduleSrcPath, moduleSrcPath);
- }
- }
-
- for (auto dependencyChunk : dependencyChunks)
- {
- auto file = dependencyChunk->getValue();
- auto sourceFile = loadSourceFile(fromPath, file);
- if (!sourceFile)
- {
- // If we cannot find the source file from `fromPath`,
- // try again from the module's source file path.
- if (dependencyChunks.getFirst())
- sourceFile = loadSourceFile(moduleSrcPath, file);
- }
- if (!sourceFile)
- return false;
- digestBuilder.append(sourceFile->getDigest());
- }
- return digestBuilder.finalize() == existingDigest;
-}
-
-SLANG_NO_THROW bool SLANG_MCALL
-Linkage::isBinaryModuleUpToDate(const char* modulePath, slang::IBlob* binaryModuleBlob)
-{
- auto rootChunk = RIFF::RootChunk::getFromBlob(binaryModuleBlob);
- if (!rootChunk)
- return false;
- return isBinaryModuleUpToDate(modulePath, rootChunk);
-}
-
-SourceFile* Linkage::findFile(Name* name, SourceLoc loc, IncludeSystem& outIncludeSystem)
-{
- auto impl = [&](bool translateUnderScore) -> SourceFile*
- {
- auto fileName = getFileNameFromModuleName(name, translateUnderScore);
-
- // Next, try to find the file of the given name,
- // using our ordinary include-handling logic.
-
- auto& searchDirs = getSearchDirectories();
- outIncludeSystem = IncludeSystem(&searchDirs, getFileSystemExt(), getSourceManager());
-
- // Get the original path info
- PathInfo pathIncludedFromInfo = getSourceManager()->getPathInfo(loc, SourceLocType::Actual);
- PathInfo filePathInfo;
-
- ComPtr<ISlangBlob> fileContents;
-
- // We have to load via the found path - as that is how file was originally loaded
- if (SLANG_FAILED(
- outIncludeSystem.findFile(fileName, pathIncludedFromInfo.foundPath, filePathInfo)))
- {
- return nullptr;
- }
- // Otherwise, try to load it.
- SourceFile* sourceFile;
- if (SLANG_FAILED(outIncludeSystem.loadFile(filePathInfo, fileContents, sourceFile)))
- {
- return nullptr;
- }
- return sourceFile;
- };
- if (auto rs = impl(false))
- return rs;
- return impl(true);
-}
-
-Linkage::IncludeResult Linkage::findAndIncludeFile(
- Module* module,
- TranslationUnitRequest* translationUnit,
- Name* name,
- SourceLoc const& loc,
- DiagnosticSink* sink)
-{
- IncludeResult result;
- result.fileDecl = nullptr;
- result.isNew = false;
-
- IncludeSystem includeSystem;
- auto sourceFile = findFile(name, loc, includeSystem);
- if (!sourceFile)
- {
- sink->diagnose(loc, Diagnostics::cannotOpenFile, getText(name));
- return result;
- }
-
- // If the file has already been included, don't need to do anything further.
- if (auto existingFileDecl = module->getIncludedSourceFileMap().tryGetValue(sourceFile))
- {
- result.fileDecl = *existingFileDecl;
- result.isNew = false;
- return result;
- }
-
- if (isInLanguageServer())
- {
- // HACK: When in language server mode, we will always load the currently opend file as a
- // fresh module even if some previously opened file already references the current file via
- // `import` or `include`. see comments in `WorkspaceVersion::getOrLoadModule()` for the
- // reason behind this. An undesired outcome of this decision is that we could endup
- // including the currently opened file itself via chain of `__include`s because the
- // currently opened file will not have a true unique file system identity that allows it to
- // be deduplicated correct. Therefore we insert a hack logic here to detect re-inclusion by
- // just the file path. We can clean up this hack by making the language server truly support
- // incremental checking so we can reuse the previously loaded module instead of needing to
- // always start with a fresh copy.
- //
- for (auto file : translationUnit->getSourceFiles())
- {
- if (file->getPathInfo().hasFoundPath() &&
- Path::equals(file->getPathInfo().foundPath, sourceFile->getPathInfo().foundPath))
- return result;
- }
- }
-
- module->addFileDependency(sourceFile);
-
- // Create a transparent FileDecl to hold all children from the included file.
- auto fileDecl = module->getASTBuilder()->create<FileDecl>();
- fileDecl->nameAndLoc.name = name;
- fileDecl->parentDecl = module->getModuleDecl();
- module->getIncludedSourceFileMap().add(sourceFile, fileDecl);
-
- FrontEndPreprocessorHandler preprocessorHandler(
- module,
- module->getASTBuilder(),
- sink,
- translationUnit);
- auto combinedPreprocessorDefinitions = translationUnit->getCombinedPreprocessorDefinitions();
- SourceLanguage sourceLanguage = translationUnit->sourceLanguage;
- SlangLanguageVersion slangLanguageVersion = module->getModuleDecl()->languageVersion;
- auto tokens = preprocessSource(
- sourceFile,
- sink,
- &includeSystem,
- combinedPreprocessorDefinitions,
- this,
- sourceLanguage,
- slangLanguageVersion,
- &preprocessorHandler);
-
- if (sourceLanguage == SourceLanguage::Unknown)
- sourceLanguage = translationUnit->sourceLanguage;
-
- if (slangLanguageVersion != module->getModuleDecl()->languageVersion)
- {
- sink->diagnose(
- tokens.begin()->getLoc(),
- Diagnostics::languageVersionDiffersFromIncludingModule);
- }
-
- auto outerScope = module->getModuleDecl()->ownedScope;
- parseSourceFile(
- module->getASTBuilder(),
- translationUnit,
- sourceLanguage,
- tokens,
- sink,
- outerScope,
- fileDecl);
-
- module->getModuleDecl()->addMember(fileDecl);
-
- result.fileDecl = fileDecl;
- result.isNew = true;
- return result;
-}
-
-//
-// 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);
- }
-}
-
-//
-// Module
-//
-
-Module::Module(Linkage* linkage, ASTBuilder* astBuilder)
- : ComponentType(linkage), m_mangledExportPool(StringSlicePool::Style::Empty)
-{
- if (astBuilder)
- {
- m_astBuilder = astBuilder;
- }
- else
- {
- m_astBuilder = linkage->getASTBuilder();
- }
- getOptionSet() = linkage->m_optionSet;
- addModuleDependency(this);
-}
-
-ISlangUnknown* Module::getInterface(const Guid& guid)
-{
- if (guid == IModule::getTypeGuid())
- return asExternal(this);
- if (guid == IModulePrecompileService_Experimental::getTypeGuid())
- return static_cast<slang::IModulePrecompileService_Experimental*>(this);
- return Super::getInterface(guid);
-}
-
-void Module::buildHash(DigestBuilder<SHA1>& builder)
-{
- builder.append(computeDigest());
-}
-
-slang::DeclReflection* Module::getModuleReflection()
-{
- return (slang::DeclReflection*)m_moduleDecl;
-}
-
-SHA1::Digest Module::computeDigest()
-{
- if (m_digest == SHA1::Digest())
- {
- DigestBuilder<SHA1> digestBuilder;
- auto version = String(getBuildTagString());
- digestBuilder.append(version);
- getOptionSet().buildHash(digestBuilder);
-
- auto fileDependencies = getFileDependencies();
-
- for (auto file : fileDependencies)
- {
- digestBuilder.append(file->getDigest());
- }
- m_digest = digestBuilder.finalize();
- }
- return m_digest;
-}
-
-void Module::addModuleDependency(Module* module)
-{
- m_moduleDependencyList.addDependency(module);
- m_fileDependencyList.addDependency(module);
-}
-
-void Module::addFileDependency(SourceFile* sourceFile)
-{
- m_fileDependencyList.addDependency(sourceFile);
-}
-
-void Module::setModuleDecl(ModuleDecl* moduleDecl)
-{
- m_moduleDecl = moduleDecl;
- moduleDecl->module = this;
-}
-
-void Module::setName(String name)
-{
- m_name = getLinkage()->getNamePool()->getName(name);
-}
-
-
-RefPtr<EntryPoint> Module::findEntryPointByName(UnownedStringSlice const& name)
-{
- for (auto entryPoint : m_entryPoints)
- {
- if (entryPoint->getName()->text.getUnownedSlice() == name)
- return entryPoint;
- }
-
- return nullptr;
-}
-
-RefPtr<EntryPoint> Module::findAndCheckEntryPoint(
- UnownedStringSlice const& name,
- SlangStage stage,
- ISlangBlob** outDiagnostics)
-{
- // If there is already an entrypoint marked with the [shader] attribute,
- // we should just return that.
- //
- if (auto existingEntryPoint = findEntryPointByName(name))
- return existingEntryPoint;
-
- SLANG_AST_BUILDER_RAII(m_astBuilder);
-
- // If the function hasn't been marked as [shader], then it won't be discovered
- // by findEntryPointByName. We need to route this to the `findAndValidateEntryPoint`
- // function. To do that we need to setup a FrontEndCompileRequest and a
- // FrontEndEntryPointRequest.
- //
- DiagnosticSink sink(getLinkage()->getSourceManager(), DiagnosticSink::SourceLocationLexer());
- FrontEndCompileRequest frontEndRequest(getLinkage(), StdWriters::getSingleton(), &sink);
- RefPtr<TranslationUnitRequest> tuRequest = new TranslationUnitRequest(&frontEndRequest);
- tuRequest->module = this;
- tuRequest->moduleName = m_name;
- frontEndRequest.translationUnits.add(tuRequest);
- FrontEndEntryPointRequest entryPointRequest(
- &frontEndRequest,
- 0,
- getLinkage()->getNamePool()->getName(name),
- Profile((Stage)stage));
- auto result = findAndValidateEntryPoint(&entryPointRequest);
- if (outDiagnostics)
- {
- sink.getBlobIfNeeded(outDiagnostics);
- }
- return result;
-}
-
-void Module::_addEntryPoint(EntryPoint* entryPoint)
-{
- m_entryPoints.add(entryPoint);
-}
-
-static bool _canExportDeclSymbol(ASTNodeType type)
-{
- switch (type)
- {
- case ASTNodeType::EmptyDecl:
- {
- return false;
- }
- default:
- break;
- }
-
- return true;
-}
-
-static bool _canRecurseExportSymbol(Decl* decl)
-{
- if (as<FunctionDeclBase>(decl) || as<ScopeDecl>(decl))
- {
- return false;
- }
- return true;
-}
-
-void Module::_processFindDeclsExportSymbolsRec(Decl* decl)
-{
- if (_canExportDeclSymbol(decl->astNodeType))
- {
- // It's a reference to a declaration in another module, so first get the symbol name.
- String mangledName = getMangledName(getCurrentASTBuilder(), decl);
-
- Index index = Index(m_mangledExportPool.add(mangledName));
-
- // TODO(JS): It appears that more than one entity might have the same mangled name.
- // So for now we ignore and just take the first one.
- if (index == m_mangledExportSymbols.getCount())
- {
- m_mangledExportSymbols.add(decl);
- }
- }
-
- if (!_canRecurseExportSymbol(decl))
- {
- // We don't need to recurse any further into this
- return;
- }
-
- // If it's a container process it's children
- if (auto containerDecl = as<ContainerDecl>(decl))
- {
- for (auto child : containerDecl->getDirectMemberDecls())
- {
- _processFindDeclsExportSymbolsRec(child);
- }
- }
-
- // GenericDecl is also a container, so do subsequent test
- if (auto genericDecl = as<GenericDecl>(decl))
- {
- _processFindDeclsExportSymbolsRec(genericDecl->inner);
- }
-}
-
-Decl* Module::findExportedDeclByMangledName(const UnownedStringSlice& mangledName)
-{
- // If this module is a serialized module that is being
- // deserialized on-demand, then we want to use the
- // mangled name mapping that was baked into the serialized
- // data, rather than attempt to enumerate all of the declarations
- // in the module (as would be done if we proceeded to call
- // `ensureExportLookupAcceleratorBuilt()`).
- //
- if (this->m_moduleDecl->isUsingOnDemandDeserializationForExports())
- {
- return m_moduleDecl->_findSerializedDeclByMangledExportName(mangledName);
- }
-
- ensureExportLookupAcceleratorBuilt();
-
- const Index index = m_mangledExportPool.findIndex(mangledName);
- return (index >= 0) ? m_mangledExportSymbols[index] : nullptr;
-}
-
-void Module::ensureExportLookupAcceleratorBuilt()
-{
- // Will be non zero if has been previously attempted
- if (m_mangledExportSymbols.getCount() == 0)
- {
- // Build up the exported mangled name list
- _processFindDeclsExportSymbolsRec(getModuleDecl());
-
- // If nothing found, mark that we have tried looking by making
- // m_mangledExportSymbols.getCount() != 0
- if (m_mangledExportSymbols.getCount() == 0)
- {
- m_mangledExportSymbols.add(nullptr);
- }
- }
-}
-
-Count Module::getExportedDeclCount()
-{
- ensureExportLookupAcceleratorBuilt();
-
- return m_mangledExportPool.getSlicesCount();
-}
-
-Decl* Module::getExportedDecl(Index index)
-{
- ensureExportLookupAcceleratorBuilt();
- return m_mangledExportSymbols[index];
-}
-
-UnownedStringSlice Module::getExportedDeclMangledName(Index index)
-{
- ensureExportLookupAcceleratorBuilt();
- return m_mangledExportPool.getSlices()[index];
-}
-
-// 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;
-}
-
-//
-// CompositeComponentType
-//
-
-RefPtr<ComponentType> CompositeComponentType::create(
- Linkage* linkage,
- List<RefPtr<ComponentType>> const& childComponents)
-{
- // TODO: We should ideally be caching the results of
- // composition on the `linkage`, so that if we get
- // asked for the same composite again later we re-use
- // it rather than re-create it.
- //
- // Similarly, we might want to do some amount of
- // work to "canonicalize" the input for composition.
- // E.g., if the user does:
- //
- // X = compose(A,B);
- // Y = compose(C,D);
- // Z = compose(X,Y);
- //
- // W = compose(A, B, C, D);
- //
- // Then there is no observable difference between
- // Z and W, so we might prefer to have them be identical.
-
- // If there is only a single child, then we should
- // just return that child rather than create a dummy composite.
- //
- if (childComponents.getCount() == 1)
- {
- return childComponents[0];
- }
-
- return new CompositeComponentType(linkage, childComponents);
-}
-
-
-CompositeComponentType::CompositeComponentType(
- Linkage* linkage,
- List<RefPtr<ComponentType>> const& childComponents)
- : ComponentType(linkage), m_childComponents(childComponents)
-{
- HashSet<ComponentType*> requirementsSet;
- for (auto child : childComponents)
- {
- child->enumerateModules([&](Module* module) { requirementsSet.add(module); });
- }
-
- for (auto child : childComponents)
- {
- auto childEntryPointCount = child->getEntryPointCount();
- for (Index cc = 0; cc < childEntryPointCount; ++cc)
- {
- m_entryPoints.add(child->getEntryPoint(cc));
- m_entryPointMangledNames.add(child->getEntryPointMangledName(cc));
- m_entryPointNameOverrides.add(child->getEntryPointNameOverride(cc));
- }
-
- auto childShaderParamCount = child->getShaderParamCount();
- for (Index pp = 0; pp < childShaderParamCount; ++pp)
- {
- m_shaderParams.add(child->getShaderParam(pp));
- }
-
- auto childSpecializationParamCount = child->getSpecializationParamCount();
- for (Index pp = 0; pp < childSpecializationParamCount; ++pp)
- {
- m_specializationParams.add(child->getSpecializationParam(pp));
- }
-
- for (auto module : child->getModuleDependencies())
- {
- m_moduleDependencyList.addDependency(module);
- }
- for (auto sourceFile : child->getFileDependencies())
- {
- m_fileDependencyList.addDependency(sourceFile);
- }
-
- auto childRequirementCount = child->getRequirementCount();
- for (Index rr = 0; rr < childRequirementCount; ++rr)
- {
- auto childRequirement = child->getRequirement(rr);
- if (!requirementsSet.contains(childRequirement))
- {
- requirementsSet.add(childRequirement);
- m_requirements.add(childRequirement);
- }
- }
- }
-}
-
-void CompositeComponentType::buildHash(DigestBuilder<SHA1>& builder)
-{
- auto componentCount = getChildComponentCount();
-
- for (Index i = 0; i < componentCount; ++i)
- {
- getChildComponent(i)->buildHash(builder);
- }
-}
-
-Index CompositeComponentType::getEntryPointCount()
-{
- return m_entryPoints.getCount();
-}
-
-RefPtr<EntryPoint> CompositeComponentType::getEntryPoint(Index index)
-{
- return m_entryPoints[index];
-}
-
-String CompositeComponentType::getEntryPointMangledName(Index index)
-{
- return m_entryPointMangledNames[index];
-}
-
-String CompositeComponentType::getEntryPointNameOverride(Index index)
-{
- return m_entryPointNameOverrides[index];
-}
-
-Index CompositeComponentType::getShaderParamCount()
-{
- return m_shaderParams.getCount();
-}
-
-ShaderParamInfo CompositeComponentType::getShaderParam(Index index)
-{
- return m_shaderParams[index];
-}
-
-Index CompositeComponentType::getSpecializationParamCount()
-{
- return m_specializationParams.getCount();
-}
-
-SpecializationParam const& CompositeComponentType::getSpecializationParam(Index index)
-{
- return m_specializationParams[index];
-}
-
-Index CompositeComponentType::getRequirementCount()
-{
- return m_requirements.getCount();
-}
-
-RefPtr<ComponentType> CompositeComponentType::getRequirement(Index index)
-{
- return m_requirements[index];
-}
-
-List<Module*> const& CompositeComponentType::getModuleDependencies()
-{
- return m_moduleDependencyList.getModuleList();
-}
-
-List<SourceFile*> const& CompositeComponentType::getFileDependencies()
-{
- return m_fileDependencyList.getFileList();
-}
-
-void CompositeComponentType::acceptVisitor(
- ComponentTypeVisitor* visitor,
- SpecializationInfo* specializationInfo)
-{
- visitor->visitComposite(this, as<CompositeSpecializationInfo>(specializationInfo));
-}
-
-RefPtr<ComponentType::SpecializationInfo> CompositeComponentType::_validateSpecializationArgsImpl(
- SpecializationArg const* args,
- Index argCount,
- DiagnosticSink* sink)
-{
- SLANG_UNUSED(argCount);
-
- RefPtr<CompositeSpecializationInfo> specializationInfo = new CompositeSpecializationInfo();
-
- Index offset = 0;
- for (auto child : m_childComponents)
- {
- auto childParamCount = child->getSpecializationParamCount();
- SLANG_ASSERT(offset + childParamCount <= argCount);
-
- auto childInfo = child->_validateSpecializationArgs(args + offset, childParamCount, sink);
-
- specializationInfo->childInfos.add(childInfo);
-
- offset += childParamCount;
- }
- return specializationInfo;
-}
-
-//
-// SpecializedComponentType
-//
-
-/// Utility type for collecting modules references by types/declarations
-struct SpecializationArgModuleCollector : ComponentTypeVisitor
-{
- HashSet<Module*> m_modulesSet;
- List<Module*> m_modulesList;
-
- void addModule(Module* module)
- {
- m_modulesList.add(module);
- m_modulesSet.add(module);
- }
-
- void maybeAddModule(Module* module)
- {
- if (!module)
- return;
- if (m_modulesSet.contains(module))
- return;
-
- addModule(module);
- }
-
- void collectReferencedModules(Decl* decl)
- {
- auto module = getModule(decl);
- maybeAddModule(module);
- }
-
- void collectReferencedModules(SubstitutionSet substitutions)
- {
- substitutions.forEachGenericSubstitution(
- [this](GenericDecl*, Val::OperandView<Val> args)
- {
- for (auto arg : args)
- {
- collectReferencedModules(arg);
- }
- });
- }
-
- void collectReferencedModules(DeclRefBase* declRef)
- {
- collectReferencedModules(declRef->getDecl());
- collectReferencedModules(SubstitutionSet(declRef));
- }
-
- void collectReferencedModules(Type* type)
- {
- if (auto declRefType = as<DeclRefType>(type))
- {
- collectReferencedModules(declRefType->getDeclRef());
- }
-
- // TODO: Handle non-decl-ref composite type cases
- // (e.g., function types).
- }
-
- void collectReferencedModules(Val* val)
- {
- if (auto type = as<Type>(val))
- {
- collectReferencedModules(type);
- }
- else if (auto declRefVal = as<DeclRefIntVal>(val))
- {
- collectReferencedModules(declRefVal->getDeclRef());
- }
-
- // TODO: other cases of values that could reference
- // a declaration.
- }
-
- void collectReferencedModules(List<ExpandedSpecializationArg> const& args)
- {
- for (auto arg : args)
- {
- collectReferencedModules(arg.val);
- collectReferencedModules(arg.witness);
- }
- }
-
- //
- // ComponentTypeVisitor methods
- //
-
- void visitEntryPoint(
- EntryPoint* entryPoint,
- EntryPoint::EntryPointSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- SLANG_UNUSED(entryPoint);
-
- if (!specializationInfo)
- return;
-
- collectReferencedModules(specializationInfo->specializedFuncDeclRef);
- collectReferencedModules(specializationInfo->existentialSpecializationArgs);
- }
-
- void visitRenamedEntryPoint(
- RenamedEntryPointComponentType* entryPoint,
- EntryPoint::EntryPointSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- entryPoint->getBase()->acceptVisitor(this, specializationInfo);
- }
-
- void visitModule(Module* module, Module::ModuleSpecializationInfo* specializationInfo)
- SLANG_OVERRIDE
- {
- SLANG_UNUSED(module);
-
- if (!specializationInfo)
- return;
-
- for (auto arg : specializationInfo->genericArgs)
- {
- collectReferencedModules(arg.argVal);
- }
- collectReferencedModules(specializationInfo->existentialArgs);
- }
-
- 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);
- }
-};
-
-SpecializedComponentType::SpecializedComponentType(
- ComponentType* base,
- ComponentType::SpecializationInfo* specializationInfo,
- List<SpecializationArg> const& specializationArgs,
- DiagnosticSink* sink)
- : ComponentType(base->getLinkage())
- , m_base(base)
- , m_specializationInfo(specializationInfo)
- , m_specializationArgs(specializationArgs)
-{
- m_optionSet.overrideWith(base->getOptionSet());
-
- m_irModule = generateIRForSpecializedComponentType(this, sink);
-
- // We need to account for the fact that a specialized
- // entity like `myShader<SomeType>` needs to not only
- // depend on the module(s) that `myShader` depends on,
- // but also on any modules that `SomeType` depends on.
- //
- // We will set up a "collector" type that will be
- // used to build a list of these additional modules.
- //
- SpecializationArgModuleCollector moduleCollector;
-
- // We don't want to go adding additional requirements for
- // modules that the base component type already includes,
- // so we will add those to the set of modules in
- // the collector before we starting trying to add others.
- //
- base->enumerateModules([&](Module* module) { moduleCollector.m_modulesSet.add(module); });
-
- // In order to collect the additional modules, we need
- // to inspect the specialization arguments and see what
- // they depend on.
- //
- // Naively, it seems like we'd just want to iterate
- // over `specializationArgs`, which gives the specialization
- // arguments as the user supplied them. However, such
- // an approach would have a subtle problem.
- //
- // If we have a generic entry point like:
- //
- // // In module A
- // myShader<T : IThing>
- //
- //
- // And the type `SomeType` that is being used as an argument doesn't
- // directly conform to `IThing`:
- //
- // // In module B
- // struct SomeType { ... }
- //
- // and the conformance of `SomeType` to `IThing` is
- // coming from yet another module:
- //
- // // In module C
- // import B;
- // extension SomeType : IThing { ... }
- //
- // In this case, the specialized component for `myShader<SomeType>`
- // needs to depend on all of:
- //
- // * Module A, because it defines `myShader`
- // * Module B, because it defines `SomeType`
- // * Module C, because it defines the conformance `SomeType : IThing`
- //
- // We thus need to iterate over a form of the specialization
- // arguments that includes the "expanded" arguments like
- // interface conformance witnesses that got added during
- // semantic checking.
- //
- // The expanded arguments are being stored in the `specializationInfo`
- // today (for use by downstream code generation), and the easiest
- // way to walk that information and get to the leaf nodes where
- // the expanded arguments are stored is to apply a visitor to
- // the specialized component type we are in the middle of constructing.
- //
- moduleCollector.visitSpecialized(this);
-
- // Now that we've collected our additional information, we can
- // start to build up the final lists for the specialized component type.
- //
- // The starting point for our lists comes from the base component type.
- //
- m_moduleDependencies = base->getModuleDependencies();
- m_fileDependencies = base->getFileDependencies();
-
- Index baseRequirementCount = base->getRequirementCount();
- for (Index r = 0; r < baseRequirementCount; r++)
- {
- m_requirements.add(base->getRequirement(r));
- }
-
- // The specialized component type will need to have additional
- // dependencies and requirements based on the modules that
- // were collected when looking at the specialization arguments.
-
- // We want to avoid adding the same file dependency more than once.
- //
- HashSet<SourceFile*> fileDependencySet;
- for (SourceFile* sourceFile : m_fileDependencies)
- fileDependencySet.add(sourceFile);
-
- for (auto module : moduleCollector.m_modulesList)
- {
- // The specialized component type will have an open (unsatisfied)
- // requirement for each of the modules that its specialization
- // arguments need.
- //
- // Note: what this means in practice is that the component type
- // records that the given module(s) will need to be linked in
- // before final code can be generated, but it importantly
- // does not dictate the final placement of the parameters from
- // those modules in the layout.
- //
- m_requirements.add(module);
-
- // The speciialized component type will also have a dependency
- // on all the files that any of the modules involved in
- // it depend on (including those that are required but not
- // yet linked in).
- //
- // The file path information is what a client would need to
- // use to decide if kernel code is out of date compared to
- // source files, so we want to include anything that could
- // affect the validity of generated code.
- //
- for (SourceFile* sourceFile : module->getFileDependencies())
- {
- if (fileDependencySet.contains(sourceFile))
- continue;
- fileDependencySet.add(sourceFile);
- m_fileDependencies.add(sourceFile);
- }
-
- // Finalyl we also add the module for the specialization arguments
- // to the list of modules that would be used for legacy lookup
- // operations where we need an implicit/default scope to use
- // and want it to be expansive.
- //
- // TODO: This stuff really isn't worth keeping around long
- // term, and we should ditch the entire "legacy lookup" idea.
- //
- m_moduleDependencies.add(module);
- }
-
- // Because we are specializing shader code, the mangled entry
- // point names for this component type may be different than
- // for the base component type (e.g., the mangled name for `f<int>`
- // is different than that that of the generic `f` function
- // itself).
- //
- // We will compute the mangled names of all the entry points and
- // store them here, so that we don't have to do it on the fly.
- // Because the `ComponentType` structure is hierarchical, we
- // need to use a recursive visitor to compute the names,
- // and we will define that visitor locally:
- //
- struct EntryPointMangledNameCollector : ComponentTypeVisitor
- {
- List<String>* mangledEntryPointNames;
- List<String>* entryPointNameOverrides;
-
- void visitEntryPoint(
- EntryPoint* entryPoint,
- EntryPoint::EntryPointSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- auto funcDeclRef = entryPoint->getFuncDeclRef();
- if (specializationInfo)
- funcDeclRef = specializationInfo->specializedFuncDeclRef;
-
- (*mangledEntryPointNames).add(getMangledName(m_astBuilder, funcDeclRef));
- (*entryPointNameOverrides).add(entryPoint->getEntryPointNameOverride(0));
- }
-
- void visitRenamedEntryPoint(
- RenamedEntryPointComponentType* entryPoint,
- EntryPoint::EntryPointSpecializationInfo* specializationInfo) SLANG_OVERRIDE
- {
- entryPoint->getBase()->acceptVisitor(this, specializationInfo);
- (*entryPointNameOverrides).getLast() = entryPoint->getEntryPointNameOverride(0);
- }
-
- void visitModule(Module*, Module::ModuleSpecializationInfo*) SLANG_OVERRIDE {}
- 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);
- }
- EntryPointMangledNameCollector(ASTBuilder* astBuilder)
- : m_astBuilder(astBuilder)
- {
- }
- ASTBuilder* m_astBuilder;
- };
-
- // With the visitor defined, we apply it to ourself to compute
- // and collect the mangled entry point names.
- //
- EntryPointMangledNameCollector collector(getLinkage()->getASTBuilder());
- collector.mangledEntryPointNames = &m_entryPointMangledNames;
- collector.entryPointNameOverrides = &m_entryPointNameOverrides;
- collector.visitSpecialized(this);
-}
-
-void SpecializedComponentType::buildHash(DigestBuilder<SHA1>& builder)
-{
- auto specializationArgCount = getSpecializationArgCount();
- for (Index i = 0; i < specializationArgCount; ++i)
- {
- auto specializationArg = getSpecializationArg(i);
- auto argString = specializationArg.val->toString();
- builder.append(argString);
- }
-
- getBaseComponentType()->buildHash(builder);
-}
-
-void SpecializedComponentType::acceptVisitor(
- ComponentTypeVisitor* visitor,
- SpecializationInfo* specializationInfo)
-{
- SLANG_ASSERT(specializationInfo == nullptr);
- SLANG_UNUSED(specializationInfo);
- visitor->visitSpecialized(this);
-}
-
-Index SpecializedComponentType::getRequirementCount()
-{
- return m_requirements.getCount();
-}
-
-RefPtr<ComponentType> SpecializedComponentType::getRequirement(Index index)
-{
- return m_requirements[index];
-}
-
-String SpecializedComponentType::getEntryPointMangledName(Index index)
-{
- return m_entryPointMangledNames[index];
-}
-
-String SpecializedComponentType::getEntryPointNameOverride(Index index)
-{
- return m_entryPointNameOverrides[index];
-}
-
-// RenamedEntryPointComponentType
-
-RenamedEntryPointComponentType::RenamedEntryPointComponentType(ComponentType* base, String newName)
- : ComponentType(base->getLinkage()), m_base(base), m_entryPointNameOverride(newName)
-{
-}
-
-void RenamedEntryPointComponentType::acceptVisitor(
- ComponentTypeVisitor* visitor,
- SpecializationInfo* specializationInfo)
-{
- visitor->visitRenamedEntryPoint(
- this,
- as<EntryPoint::EntryPointSpecializationInfo>(specializationInfo));
-}
-
-void RenamedEntryPointComponentType::buildHash(DigestBuilder<SHA1>& builder)
-{
- SLANG_UNUSED(builder);
-}
-
-void ComponentTypeVisitor::visitChildren(
- CompositeComponentType* composite,
- CompositeComponentType::CompositeSpecializationInfo* specializationInfo)
-{
- auto childCount = composite->getChildComponentCount();
- for (Index ii = 0; ii < childCount; ++ii)
- {
- auto child = composite->getChildComponent(ii);
- auto childSpecializationInfo =
- specializationInfo ? specializationInfo->childInfos[ii] : nullptr;
-
- child->acceptVisitor(this, childSpecializationInfo);
- }
-}
-
-void ComponentTypeVisitor::visitChildren(SpecializedComponentType* specialized)
-{
- specialized->getBaseComponentType()->acceptVisitor(this, specialized->getSpecializationInfo());
-}
-
-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;
-}
-
-//
-// TargetProgram
-//
-
-TargetProgram::TargetProgram(ComponentType* componentType, TargetRequest* targetReq)
- : m_program(componentType), m_targetReq(targetReq)
-{
- m_entryPointResults.setCount(componentType->getEntryPointCount());
- m_optionSet.overrideWith(m_program->getOptionSet());
- m_optionSet.inheritFrom(targetReq->getOptionSet());
-}
-
-//
-
-Session* CompileRequestBase::getSession()
-{
- return getLinkage()->getSessionImpl();
-}
-
-void Linkage::setFileSystem(ISlangFileSystem* inFileSystem)
-{
- // Set the fileSystem
- m_fileSystem = inFileSystem;
-
- // Release what's there
- m_fileSystemExt.setNull();
-
- // If nullptr passed in set up default
- if (inFileSystem == nullptr)
- {
- m_fileSystemExt = new Slang::CacheFileSystem(Slang::OSFileSystem::getExtSingleton());
- }
- else
- {
- if (auto cacheFileSystem = as<CacheFileSystem>(inFileSystem))
- {
- m_fileSystemExt = cacheFileSystem;
- }
- else
- {
- if (m_requireCacheFileSystem)
- {
- m_fileSystemExt = new Slang::CacheFileSystem(inFileSystem);
- }
- else
- {
- // See if we have the full ISlangFileSystemExt interface, if we do just use it
- inFileSystem->queryInterface(SLANG_IID_PPV_ARGS(m_fileSystemExt.writeRef()));
-
- // If not wrap with CacheFileSystem that emulates ISlangFileSystemExt from the
- // ISlangFileSystem interface
- if (!m_fileSystemExt)
- {
- // Construct a wrapper to emulate the extended interface behavior
- m_fileSystemExt = new Slang::CacheFileSystem(m_fileSystem);
- }
- }
- }
- }
-
- // If requires a cache file system, check that it does have one
- SLANG_ASSERT(m_requireCacheFileSystem == false || as<CacheFileSystem>(m_fileSystemExt));
-
- // Set the file system used on the source manager
- getSourceManager()->setFileSystemExt(m_fileSystemExt);
-}
-
-SlangResult Linkage::loadSerializedModuleContents(
- Module* module,
- const PathInfo& moduleFilePathInfo,
- ISlangBlob* blobHoldingSerializedData,
- ModuleChunk const* moduleChunk,
- RIFF::ListChunk const* containerChunk,
- DiagnosticSink* sink)
-{
- // At this point we've dealt with basically all of
- // the formalities, and we just need to get down
- // to the real work of decoding the information
- // in the `moduleChunk`.
-
- //
- // TODO(tfoley): The fact that a separate `containerChunk` is getting
- // passed in here is entirely byproduct of the support for "module libraries"
- // that can (in principle) contain multiple serialized modules. When
- // things are serialized in the "container" representation used for
- // a module library, there is a single `DebugChunk` as a child of
- // the container, with all of the `ModuleChunk`s sharing that debug info.
- //
- // In contrast, the more typical kind of serialized module that the compiler
- // produces serializes a single `ModuleChunk`, and the `DebugChunk` is
- // one of its direct children. Thus there are currently two different
- // locations where debug information might be found.
- //
- // Prior to the change where we navigate the serialized RIFF hierarchy
- // in memory without copying it, this issue was addressed by having
- // the subroutine that looked for a `DebugChunk` start at the `ModuleChunk`
- // and work its way up through the hierarchy using parent pointers that
- // were created as part of RIFF loading. When navigating the RIFF in-place
- // we don't have such parent pointers.
- //
- // As a short-term solution, we should deprecate and remove the support
- // for "module libraries" so that the code doesn't have to handle two
- // different layouts.
- //
- // In the longer term, we should be making some conscious design decisions
- // around how we want to organize the top-level structure of our serialized
- // intermediate/output formats, since there's quite a mix of different
- // approaches currently in use.
- //
-
- auto sourceManager = getSourceManager();
- RefPtr<SerialSourceLocReader> sourceLocReader;
- if (auto debugChunk = DebugChunk::find(moduleChunk, containerChunk))
- {
- SLANG_RETURN_ON_FAIL(
- readSourceLocationsFromDebugChunk(debugChunk, sourceManager, sourceLocReader));
- }
-
- auto astChunk = moduleChunk->findAST();
- if (!astChunk)
- return SLANG_FAIL;
-
- auto irChunk = moduleChunk->findIR();
- if (!irChunk)
- return SLANG_FAIL;
-
- auto astBuilder = getASTBuilder();
- auto session = getSessionImpl();
-
- // For the purposes of any modules referenced
- // by the module we're about to decode, we will
- // construct a source location that represents
- // the module itself (if possible).
- //
- // TODO(tfoley): This logic seems like overkill, given
- // that many (most? all?) control-flow paths that can
- // reach this routine will have already found a `SourceFile`
- // to represent the module, as part of even getting the
- // `moduleFilePathInfo` to pass in
- //
- // The approach here is more or less exactly copied
- // from what the old `SerialContainerUtil::read` function
- // used to do, with the hopes that it will as many tests
- // passing as possible.
- //
- // Down the line somebody should scrutinize all of this
- // kind of logic in the compiler codebase, because there
- // is something that feels unclean about how paths are being handled.
- //
- SourceLoc serializedModuleLoc;
- {
- auto sourceFile =
- sourceManager->findSourceFileByPathRecursively(moduleFilePathInfo.foundPath);
- if (!sourceFile)
- {
- sourceFile = sourceManager->createSourceFileWithString(moduleFilePathInfo, String());
- sourceManager->addSourceFile(moduleFilePathInfo.getMostUniqueIdentity(), sourceFile);
- }
- auto sourceView =
- sourceManager->createSourceView(sourceFile, &moduleFilePathInfo, SourceLoc());
- serializedModuleLoc = sourceView->getRange().begin;
- }
-
- auto moduleDecl = readSerializedModuleAST(
- this,
- astBuilder,
- sink,
- blobHoldingSerializedData,
- astChunk,
- sourceLocReader,
- serializedModuleLoc);
- if (!moduleDecl)
- return SLANG_FAIL;
- module->setModuleDecl(moduleDecl);
-
- RefPtr<IRModule> irModule;
- SLANG_RETURN_ON_FAIL(readSerializedModuleIR(irChunk, session, sourceLocReader, irModule));
- module->setIRModule(irModule);
-
- // The handling of file dependencies is complicated, because of
- // the way that the encoding logic tried to make all of the
- // paths be relative to the primary source file for the module.
- //
- // We end up needing to undo some amount of that work here.
- //
-
- module->clearFileDependency();
- String moduleSourcePath = moduleFilePathInfo.foundPath;
- bool isFirst = true;
- for (auto depenencyFileChunk : moduleChunk->getFileDependencies())
- {
- auto encodedDependencyFilePath = depenencyFileChunk->getValue();
-
- auto sourceFile = loadSourceFile(moduleFilePathInfo.foundPath, encodedDependencyFilePath);
- if (isFirst)
- {
- // The first file is the source for the main module file.
- // We store the module path as the basis for finding the remaining
- // dependent files.
- if (sourceFile)
- moduleSourcePath = sourceFile->getPathInfo().foundPath;
- isFirst = false;
- }
- // If we cannot find the dependent file directly, try to find
- // it relative to the module source path.
- if (!sourceFile)
- {
- sourceFile = loadSourceFile(moduleSourcePath, encodedDependencyFilePath);
- }
- if (sourceFile)
- {
- module->addFileDependency(sourceFile);
- }
- }
- module->setPathInfo(moduleFilePathInfo);
- module->setDigest(moduleChunk->getDigest());
- module->_collectShaderParams();
- module->_discoverEntryPoints(sink, targets);
-
- // Hook up fileDecl's scope to module's scope.
- for (auto fileDecl : moduleDecl->getDirectMemberDeclsOfType<FileDecl>())
- {
- addSiblingScopeForContainerDecl(m_astBuilder, moduleDecl->ownedScope, fileDecl);
- }
-
- return SLANG_OK;
-}
-
-void Linkage::setRequireCacheFileSystem(bool requireCacheFileSystem)
-{
- if (requireCacheFileSystem == m_requireCacheFileSystem)
- {
- return;
- }
-
- ComPtr<ISlangFileSystem> scopeFileSystem(m_fileSystem);
- m_requireCacheFileSystem = requireCacheFileSystem;
-
- setFileSystem(scopeFileSystem);
-}
-
-RefPtr<Module> findOrImportModule(
- Linkage* linkage,
- Name* name,
- SourceLoc const& loc,
- DiagnosticSink* sink,
- const LoadedModuleDictionary* loadedModules)
-{
- return linkage->findOrImportModule(name, loc, sink, loadedModules);
-}
-
-void Session::addBuiltinSource(
- Scope* scope,
- String const& path,
- ISlangBlob* sourceBlob,
- Module*& outModule)
-{
- SourceManager* sourceManager = getBuiltinSourceManager();
-
- DiagnosticSink sink(sourceManager, Lexer::sourceLocationLexer);
-
- RefPtr<FrontEndCompileRequest> compileRequest =
- new FrontEndCompileRequest(m_builtinLinkage, nullptr, &sink);
- compileRequest->m_isCoreModuleCode = true;
-
- // Set the source manager on the sink
- sink.setSourceManager(sourceManager);
- // Make the linkage use the builtin source manager
- Linkage* linkage = compileRequest->getLinkage();
- linkage->setSourceManager(sourceManager);
-
- Name* moduleName = getNamePool()->getName(path);
- auto translationUnitIndex =
- compileRequest->addTranslationUnit(SourceLanguage::Slang, moduleName);
-
- compileRequest->addTranslationUnitSourceBlob(translationUnitIndex, path, sourceBlob);
-
- SlangResult res = compileRequest->executeActionsInner();
- if (SLANG_FAILED(res))
- {
- char const* diagnostics = sink.outputBuffer.getBuffer();
- fprintf(stderr, "%s", diagnostics);
-
- PlatformUtil::outputDebugMessage(diagnostics);
-
- SLANG_UNEXPECTED("error in Slang core module");
- }
-
- // Compiling the core module should not yield any warnings.
- SLANG_ASSERT(sink.outputBuffer.getLength() == 0);
-
- // Extract the AST for the code we just parsed
- auto module = compileRequest->translationUnits[translationUnitIndex]->getModule();
- auto moduleDecl = module->getModuleDecl();
-
- // Extact documentation markup.
- ASTMarkup markup;
- ASTMarkupUtil::extract(moduleDecl, sourceManager, &sink, &markup);
- markup.attachToAST();
-
- // Put in the loaded module map
- linkage->mapNameToLoadedModules.add(moduleName, module);
-
- // Add the resulting code to the appropriate scope
- if (!scope->containerDecl)
- {
- // We are the first chunk of code to be loaded for this scope
- scope->containerDecl = moduleDecl;
- }
- else
- {
- // We need to create a new scope to link into the whole thing
- auto subScope = module->getASTBuilder()->create<Scope>();
- subScope->containerDecl = moduleDecl;
- subScope->nextSibling = scope->nextSibling;
- scope->nextSibling = subScope;
- }
-
- outModule = module;
-}
-
-Session::~Session()
-{
- // This is necessary because this ASTBuilder uses the SharedASTBuilder also owned by the
- // session. If the SharedASTBuilder gets dtored before the globalASTBuilder it has a dangling
- // pointer, which is referenced in the ASTBuilder dtor (likely) causing a crash.
- //
- // By destroying first we know it is destroyed, before the SharedASTBuilder.
- globalAstBuilder.setNull();
-
- // destroy modules next
- coreModules = decltype(coreModules)();
-}
-
-} // namespace Slang
-
-
-/* !!!!!!!!!!!!!!!!!! EndToEndCompileRequestImpl !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-namespace Slang
-{
-
-void EndToEndCompileRequest::setFileSystem(ISlangFileSystem* fileSystem)
-{
- getLinkage()->setFileSystem(fileSystem);
-}
-
-void EndToEndCompileRequest::setCompileFlags(SlangCompileFlags flags)
-{
- if (flags & SLANG_COMPILE_FLAG_NO_MANGLING)
- getOptionSet().set(CompilerOptionName::NoMangle, true);
- if (flags & SLANG_COMPILE_FLAG_NO_CODEGEN)
- getOptionSet().set(CompilerOptionName::SkipCodeGen, true);
- if (flags & SLANG_COMPILE_FLAG_OBFUSCATE)
- getOptionSet().set(CompilerOptionName::Obfuscate, true);
-}
-
-SlangCompileFlags EndToEndCompileRequest::getCompileFlags()
-{
- SlangCompileFlags result = 0;
- if (getOptionSet().getBoolOption(CompilerOptionName::NoMangle))
- result |= SLANG_COMPILE_FLAG_NO_MANGLING;
- if (getOptionSet().getBoolOption(CompilerOptionName::SkipCodeGen))
- result |= SLANG_COMPILE_FLAG_NO_CODEGEN;
- if (getOptionSet().getBoolOption(CompilerOptionName::Obfuscate))
- result |= SLANG_COMPILE_FLAG_OBFUSCATE;
- return result;
-}
-
-void EndToEndCompileRequest::setDumpIntermediates(int enable)
-{
- getOptionSet().set(CompilerOptionName::DumpIntermediates, enable);
-}
-
-void EndToEndCompileRequest::setTrackLiveness(bool v)
-{
- getOptionSet().set(CompilerOptionName::TrackLiveness, v);
-}
-
-void EndToEndCompileRequest::setDumpIntermediatePrefix(const char* prefix)
-{
- getOptionSet().set(CompilerOptionName::DumpIntermediatePrefix, String(prefix));
-}
-
-void EndToEndCompileRequest::setLineDirectiveMode(SlangLineDirectiveMode mode)
-{
- getOptionSet().set(CompilerOptionName::LineDirectiveMode, mode);
-}
-
-void EndToEndCompileRequest::setCommandLineCompilerMode()
-{
- m_isCommandLineCompile = true;
-
- // legacy slangc tool defaults to column major layout.
- if (!getOptionSet().hasOption(CompilerOptionName::MatrixLayoutRow))
- getOptionSet().setMatrixLayoutMode(kMatrixLayoutMode_ColumnMajor);
-}
-
-void EndToEndCompileRequest::_completeTargetRequest(UInt targetIndex)
-{
- auto linkage = getLinkage();
-
- TargetRequest* targetRequest = linkage->targets[Index(targetIndex)];
-
- targetRequest->getOptionSet().inheritFrom(getLinkage()->m_optionSet);
- targetRequest->getOptionSet().inheritFrom(m_optionSetForDefaultTarget);
-}
-
-void EndToEndCompileRequest::setCodeGenTarget(SlangCompileTarget target)
-{
- auto linkage = getLinkage();
- linkage->targets.clear();
- const auto targetIndex = linkage->addTarget(CodeGenTarget(target));
- SLANG_ASSERT(targetIndex == 0);
- _completeTargetRequest(0);
-}
-
-int EndToEndCompileRequest::addCodeGenTarget(SlangCompileTarget target)
-{
- const auto targetIndex = getLinkage()->addTarget(CodeGenTarget(target));
- _completeTargetRequest(targetIndex);
- return int(targetIndex);
-}
-
-void EndToEndCompileRequest::setTargetProfile(int targetIndex, SlangProfileID profile)
-{
- getTargetOptionSet(targetIndex).setProfile(Profile(profile));
-}
-
-void EndToEndCompileRequest::setTargetFlags(int targetIndex, SlangTargetFlags flags)
-{
- getTargetOptionSet(targetIndex).setTargetFlags(flags);
-}
-
-void EndToEndCompileRequest::setTargetForceGLSLScalarBufferLayout(int targetIndex, bool value)
-{
- getTargetOptionSet(targetIndex).set(CompilerOptionName::GLSLForceScalarLayout, value);
-}
-
-void EndToEndCompileRequest::setTargetForceDXLayout(int targetIndex, bool value)
-{
- getTargetOptionSet(targetIndex).set(CompilerOptionName::ForceDXLayout, value);
-}
-
-void EndToEndCompileRequest::setTargetFloatingPointMode(
- int targetIndex,
- SlangFloatingPointMode mode)
-{
- getTargetOptionSet(targetIndex)
- .set(CompilerOptionName::FloatingPointMode, FloatingPointMode(mode));
-}
-
-void EndToEndCompileRequest::setMatrixLayoutMode(SlangMatrixLayoutMode mode)
-{
- getOptionSet().setMatrixLayoutMode((MatrixLayoutMode)mode);
-}
-
-void EndToEndCompileRequest::setTargetMatrixLayoutMode(int targetIndex, SlangMatrixLayoutMode mode)
-{
- getTargetOptionSet(targetIndex).setMatrixLayoutMode(MatrixLayoutMode(mode));
-}
-
-void EndToEndCompileRequest::setTargetGenerateWholeProgram(int targetIndex, bool value)
-{
- getTargetOptionSet(targetIndex).set(CompilerOptionName::GenerateWholeProgram, value);
-}
-
-void EndToEndCompileRequest::setTargetEmbedDownstreamIR(int targetIndex, bool value)
-{
- getTargetOptionSet(targetIndex).set(CompilerOptionName::EmbedDownstreamIR, value);
-}
-
-void EndToEndCompileRequest::setTargetLineDirectiveMode(
- SlangInt targetIndex,
- SlangLineDirectiveMode mode)
-{
- getTargetOptionSet(targetIndex)
- .set(CompilerOptionName::LineDirectiveMode, LineDirectiveMode(mode));
-}
-
-void EndToEndCompileRequest::overrideDiagnosticSeverity(
- SlangInt messageID,
- SlangSeverity overrideSeverity)
-{
- getSink()->overrideDiagnosticSeverity(int(messageID), Severity(overrideSeverity));
-}
-
-SlangDiagnosticFlags EndToEndCompileRequest::getDiagnosticFlags()
-{
- DiagnosticSink::Flags sinkFlags = getSink()->getFlags();
-
- SlangDiagnosticFlags flags = 0;
-
- if (sinkFlags & DiagnosticSink::Flag::VerbosePath)
- flags |= SLANG_DIAGNOSTIC_FLAG_VERBOSE_PATHS;
-
- if (sinkFlags & DiagnosticSink::Flag::TreatWarningsAsErrors)
- flags |= SLANG_DIAGNOSTIC_FLAG_TREAT_WARNINGS_AS_ERRORS;
-
- return flags;
-}
-
-void EndToEndCompileRequest::setDiagnosticFlags(SlangDiagnosticFlags flags)
-{
- DiagnosticSink::Flags sinkFlags = getSink()->getFlags();
-
- if (flags & SLANG_DIAGNOSTIC_FLAG_VERBOSE_PATHS)
- sinkFlags |= DiagnosticSink::Flag::VerbosePath;
- else
- sinkFlags &= ~DiagnosticSink::Flag::VerbosePath;
-
- if (flags & SLANG_DIAGNOSTIC_FLAG_TREAT_WARNINGS_AS_ERRORS)
- sinkFlags |= DiagnosticSink::Flag::TreatWarningsAsErrors;
- else
- sinkFlags &= ~DiagnosticSink::Flag::TreatWarningsAsErrors;
-
- getSink()->setFlags(sinkFlags);
-}
-
-SlangResult EndToEndCompileRequest::addTargetCapability(
- SlangInt targetIndex,
- SlangCapabilityID capability)
-{
- auto& targets = getLinkage()->targets;
- if (targetIndex < 0 || targetIndex >= targets.getCount())
- return SLANG_E_INVALID_ARG;
- getTargetOptionSet(targetIndex).addCapabilityAtom(CapabilityName(capability));
- return SLANG_OK;
-}
-
-void EndToEndCompileRequest::setDebugInfoLevel(SlangDebugInfoLevel level)
-{
- getOptionSet().set(CompilerOptionName::DebugInformation, DebugInfoLevel(level));
-}
-
-void EndToEndCompileRequest::setDebugInfoFormat(SlangDebugInfoFormat format)
-{
- getOptionSet().set(CompilerOptionName::DebugInformationFormat, DebugInfoFormat(format));
-}
-
-void EndToEndCompileRequest::setOptimizationLevel(SlangOptimizationLevel level)
-{
- getOptionSet().set(CompilerOptionName::Optimization, OptimizationLevel(level));
-}
-
-void EndToEndCompileRequest::setOutputContainerFormat(SlangContainerFormat format)
-{
- m_containerFormat = ContainerFormat(format);
-}
-
-void EndToEndCompileRequest::setPassThrough(SlangPassThrough inPassThrough)
-{
- m_passThrough = PassThroughMode(inPassThrough);
-}
-
-void EndToEndCompileRequest::setReportDownstreamTime(bool value)
-{
- getOptionSet().set(CompilerOptionName::ReportDownstreamTime, value);
-}
-
-void EndToEndCompileRequest::setReportPerfBenchmark(bool value)
-{
- getOptionSet().set(CompilerOptionName::ReportPerfBenchmark, value);
-}
-
-void EndToEndCompileRequest::setSkipSPIRVValidation(bool value)
-{
- getOptionSet().set(CompilerOptionName::SkipSPIRVValidation, value);
-}
-
-void EndToEndCompileRequest::setTargetUseMinimumSlangOptimization(int targetIndex, bool value)
-{
- getTargetOptionSet(targetIndex).set(CompilerOptionName::MinimumSlangOptimization, value);
-}
-
-void EndToEndCompileRequest::setIgnoreCapabilityCheck(bool value)
-{
- getOptionSet().set(CompilerOptionName::IgnoreCapabilities, value);
-}
-
-void EndToEndCompileRequest::setDiagnosticCallback(
- SlangDiagnosticCallback callback,
- void const* userData)
-{
- ComPtr<ISlangWriter> writer(new CallbackWriter(callback, userData, WriterFlag::IsConsole));
- setWriter(WriterChannel::Diagnostic, writer);
-}
-
-void EndToEndCompileRequest::setWriter(SlangWriterChannel chan, ISlangWriter* writer)
-{
- setWriter(WriterChannel(chan), writer);
-}
-
-ISlangWriter* EndToEndCompileRequest::getWriter(SlangWriterChannel chan)
-{
- return getWriter(WriterChannel(chan));
-}
-
-void EndToEndCompileRequest::addSearchPath(const char* path)
-{
- getOptionSet().addSearchPath(path);
-}
-
-void EndToEndCompileRequest::addPreprocessorDefine(const char* key, const char* value)
-{
- getOptionSet().addPreprocessorDefine(key, value);
-}
-
-void EndToEndCompileRequest::setEnableEffectAnnotations(bool value)
-{
- getOptionSet().set(CompilerOptionName::EnableEffectAnnotations, value);
-}
-
-char const* EndToEndCompileRequest::getDiagnosticOutput()
-{
- return m_diagnosticOutput.begin();
-}
-
-SlangResult EndToEndCompileRequest::getDiagnosticOutputBlob(ISlangBlob** outBlob)
-{
- if (!outBlob)
- return SLANG_E_INVALID_ARG;
-
- if (!m_diagnosticOutputBlob)
- {
- m_diagnosticOutputBlob = StringUtil::createStringBlob(m_diagnosticOutput);
- }
-
- ComPtr<ISlangBlob> resultBlob = m_diagnosticOutputBlob;
- *outBlob = resultBlob.detach();
- return SLANG_OK;
-}
-
-int EndToEndCompileRequest::addTranslationUnit(SlangSourceLanguage language, char const* inName)
-{
- auto frontEndReq = getFrontEndReq();
- NamePool* namePool = frontEndReq->getNamePool();
-
- // Work out a module name. Can be nullptr if so will generate a name
- Name* moduleName = inName ? namePool->getName(inName) : frontEndReq->m_defaultModuleName;
-
- // If moduleName is nullptr a name will be generated
- return frontEndReq->addTranslationUnit(Slang::SourceLanguage(language), moduleName);
-}
-
-void EndToEndCompileRequest::setDefaultModuleName(const char* defaultModuleName)
-{
- auto frontEndReq = getFrontEndReq();
- NamePool* namePool = frontEndReq->getNamePool();
- frontEndReq->m_defaultModuleName = namePool->getName(defaultModuleName);
-}
-
-SlangResult _addLibraryReference(
- EndToEndCompileRequest* req,
- ModuleLibrary* moduleLibrary,
- bool includeEntryPoint)
-{
- FrontEndCompileRequest* frontEndRequest = req->getFrontEndReq();
-
- if (includeEntryPoint)
- {
- frontEndRequest->m_extraEntryPoints.addRange(
- moduleLibrary->m_entryPoints.getBuffer(),
- moduleLibrary->m_entryPoints.getCount());
- }
-
- for (auto m : moduleLibrary->m_modules)
- {
- RefPtr<TranslationUnitRequest> tu = new TranslationUnitRequest(frontEndRequest, m);
- frontEndRequest->translationUnits.add(tu);
- // For modules loaded for EndToEndCompileRequest,
- // we don't need the automatically discovered entrypoints.
- if (!includeEntryPoint)
- m->getEntryPoints().clear();
- }
- return SLANG_OK;
-}
-
-SlangResult _addLibraryReference(
- EndToEndCompileRequest* req,
- String path,
- IArtifact* artifact,
- bool includeEntryPoint)
-{
- auto desc = artifact->getDesc();
-
- // TODO(JS):
- // This isn't perhaps the best way to handle this scenario, as IArtifact can
- // support lazy evaluation, with suitable hander.
- // For now we just read in and strip out the bits we want.
- if (isDerivedFrom(desc.kind, ArtifactKind::Container) &&
- isDerivedFrom(desc.payload, ArtifactPayload::CompileResults))
- {
- // We want to read as a file system
- ComPtr<IArtifact> container;
-
- SLANG_RETURN_ON_FAIL(ArtifactContainerUtil::readContainer(artifact, container));
-
- // Find the payload... It should be linkable
- if (!ArtifactDescUtil::isLinkable(container->getDesc()))
- {
- return SLANG_FAIL;
- }
-
- ComPtr<IModuleLibrary> libraryIntf;
- SLANG_RETURN_ON_FAIL(
- loadModuleLibrary(ArtifactKeep::Yes, container, path, req, libraryIntf));
-
- auto library = as<ModuleLibrary>(libraryIntf);
-
- // Look for source maps
- for (auto associated : container->getAssociated())
- {
- auto assocDesc = associated->getDesc();
-
- // If we find an obfuscated source map load it and associate
- if (isDerivedFrom(assocDesc.kind, ArtifactKind::Json) &&
- isDerivedFrom(assocDesc.payload, ArtifactPayload::SourceMap) &&
- isDerivedFrom(assocDesc.style, ArtifactStyle::Obfuscated))
- {
- ComPtr<ICastable> castable;
- SLANG_RETURN_ON_FAIL(associated->getOrCreateRepresentation(
- SourceMap::getTypeGuid(),
- ArtifactKeep::Yes,
- castable.writeRef()));
- auto sourceMapBox = asBoxValue<SourceMap>(castable);
- SLANG_ASSERT(sourceMapBox);
-
- // TODO(JS):
- // There is perhaps (?) a risk here that we might copy the obfuscated map
- // into some output container. Currently that only happens for source maps
- // that are from translation units.
- //
- // On the other hand using "import" is a way that such source maps *would* be
- // copied into the output, and that is something that could be a vector
- // for leaking.
- //
- // That isn't a risk from -r though because, it doesn't create a translation
- // unit(s).
- for (auto module : library->m_modules)
- {
- module->getIRModule()->setObfuscatedSourceMap(sourceMapBox);
- }
-
- // Look up the source file
- auto sourceManager = req->getSink()->getSourceManager();
-
- auto name = Path::getFileNameWithoutExt(associated->getName());
-
- if (name.getLength())
- {
- // Note(tfoley): There is a subtle requirement here, that any
- // source file `name` that might be searched for here *must*
- // have been added to the `sourceManager` already, as a
- // byproduct of debug source location information getting
- // deserialized as part of the call to `loadModuleLibrary()` above.
- //
- // The implicit dependency is frustrating, and could potentially
- // break if somehow the debug info chunk was stripped from a binary,
- // while the source map was left in (which should be valid, even if
- // it is unlikely to be what a user wants).
- //
- // Ideally the source map would either be made an integral part of
- // the debug source location chunk, so they are loaded together,
- // or the `SourceManager` would be adapted so that it can store
- // registered source maps independent of whether or not the
- // corresponding source file(s) have been loaded.
-
- auto sourceFile = sourceManager->findSourceFileByPathRecursively(name);
- SLANG_ASSERT(sourceFile);
- sourceFile->setSourceMap(sourceMapBox, SourceMapKind::Obfuscated);
- }
- }
- }
-
- SLANG_RETURN_ON_FAIL(_addLibraryReference(req, library, includeEntryPoint));
- return SLANG_OK;
- }
-
- if (desc.kind == ArtifactKind::Library && desc.payload == ArtifactPayload::SlangIR)
- {
- ComPtr<IModuleLibrary> libraryIntf;
-
- SLANG_RETURN_ON_FAIL(
- loadModuleLibrary(ArtifactKeep::Yes, artifact, path, req, libraryIntf));
-
- auto library = as<ModuleLibrary>(libraryIntf);
- if (!library)
- {
- return SLANG_FAIL;
- }
-
- SLANG_RETURN_ON_FAIL(_addLibraryReference(req, library, includeEntryPoint));
- return SLANG_OK;
- }
-
- // TODO(JS):
- // Do we want to check the path exists?
-
- // Add to the m_libModules
- auto linkage = req->getLinkage();
- linkage->m_libModules.add(ComPtr<IArtifact>(artifact));
-
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::addLibraryReference(
- const char* basePath,
- const void* libData,
- size_t libDataSize)
-{
- // We need to deserialize and add the modules
- ComPtr<IModuleLibrary> library;
-
- auto libBlob = RawBlob::create((const Byte*)libData, libDataSize);
-
- SLANG_RETURN_ON_FAIL(
- loadModuleLibrary(libBlob, (const Byte*)libData, libDataSize, basePath, this, library));
-
- // Create an artifact without any name (as one is not provided)
- auto artifact =
- Artifact::create(ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::SlangIR));
- artifact->addRepresentation(library);
-
- return _addLibraryReference(this, basePath, artifact, true);
-}
-
-void EndToEndCompileRequest::addTranslationUnitPreprocessorDefine(
- int translationUnitIndex,
- const char* key,
- const char* value)
-{
- getFrontEndReq()->translationUnits[translationUnitIndex]->preprocessorDefinitions[key] = value;
-}
-
-void EndToEndCompileRequest::addTranslationUnitSourceFile(
- int translationUnitIndex,
- char const* path)
-{
- auto frontEndReq = getFrontEndReq();
- if (!path)
- return;
- if (translationUnitIndex < 0)
- return;
- if (Index(translationUnitIndex) >= frontEndReq->translationUnits.getCount())
- return;
-
- frontEndReq->addTranslationUnitSourceFile(translationUnitIndex, path);
-}
-
-void EndToEndCompileRequest::addTranslationUnitSourceString(
- int translationUnitIndex,
- char const* path,
- char const* source)
-{
- if (!source)
- return;
- addTranslationUnitSourceStringSpan(translationUnitIndex, path, source, source + strlen(source));
-}
-
-void EndToEndCompileRequest::addTranslationUnitSourceStringSpan(
- int translationUnitIndex,
- char const* path,
- char const* sourceBegin,
- char const* sourceEnd)
-{
- auto frontEndReq = getFrontEndReq();
- if (!sourceBegin)
- return;
- if (translationUnitIndex < 0)
- return;
- if (Index(translationUnitIndex) >= frontEndReq->translationUnits.getCount())
- return;
-
- if (!path)
- path = "";
-
- const auto slice = UnownedStringSlice(sourceBegin, sourceEnd);
-
- auto blob = RawBlob::create(slice.begin(), slice.getLength());
-
- frontEndReq->addTranslationUnitSourceBlob(translationUnitIndex, path, blob);
-}
-
-void EndToEndCompileRequest::addTranslationUnitSourceBlob(
- int translationUnitIndex,
- char const* path,
- ISlangBlob* sourceBlob)
-{
- auto frontEndReq = getFrontEndReq();
- if (!sourceBlob)
- return;
- if (translationUnitIndex < 0)
- return;
- if (Slang::Index(translationUnitIndex) >= frontEndReq->translationUnits.getCount())
- return;
-
- if (!path)
- path = "";
-
- frontEndReq->addTranslationUnitSourceBlob(translationUnitIndex, path, sourceBlob);
-}
-
-
-int EndToEndCompileRequest::addEntryPoint(
- int translationUnitIndex,
- char const* name,
- SlangStage stage)
-{
- return addEntryPointEx(translationUnitIndex, name, stage, 0, nullptr);
-}
-
-int EndToEndCompileRequest::addEntryPointEx(
- int translationUnitIndex,
- char const* name,
- SlangStage stage,
- int genericParamTypeNameCount,
- char const** genericParamTypeNames)
-{
- auto frontEndReq = getFrontEndReq();
- if (!name)
- return -1;
- if (translationUnitIndex < 0)
- return -1;
- if (Index(translationUnitIndex) >= frontEndReq->translationUnits.getCount())
- return -1;
-
- List<String> typeNames;
- for (int i = 0; i < genericParamTypeNameCount; i++)
- typeNames.add(genericParamTypeNames[i]);
-
- return addEntryPoint(translationUnitIndex, name, Profile(Stage(stage)), typeNames);
-}
-
-SlangResult EndToEndCompileRequest::setGlobalGenericArgs(
- int genericArgCount,
- char const** genericArgs)
-{
- auto& argStrings = m_globalSpecializationArgStrings;
- argStrings.clear();
- for (int i = 0; i < genericArgCount; i++)
- argStrings.add(genericArgs[i]);
-
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::setTypeNameForGlobalExistentialTypeParam(
- int slotIndex,
- char const* typeName)
-{
- if (slotIndex < 0)
- return SLANG_FAIL;
- if (!typeName)
- return SLANG_FAIL;
-
- auto& typeArgStrings = m_globalSpecializationArgStrings;
- if (Index(slotIndex) >= typeArgStrings.getCount())
- typeArgStrings.setCount(slotIndex + 1);
- typeArgStrings[slotIndex] = String(typeName);
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::setTypeNameForEntryPointExistentialTypeParam(
- int entryPointIndex,
- int slotIndex,
- char const* typeName)
-{
- if (entryPointIndex < 0)
- return SLANG_FAIL;
- if (slotIndex < 0)
- return SLANG_FAIL;
- if (!typeName)
- return SLANG_FAIL;
-
- if (Index(entryPointIndex) >= m_entryPoints.getCount())
- return SLANG_FAIL;
-
- auto& entryPointInfo = m_entryPoints[entryPointIndex];
- auto& typeArgStrings = entryPointInfo.specializationArgStrings;
- if (Index(slotIndex) >= typeArgStrings.getCount())
- typeArgStrings.setCount(slotIndex + 1);
- typeArgStrings[slotIndex] = String(typeName);
- return SLANG_OK;
-}
-
-void EndToEndCompileRequest::setAllowGLSLInput(bool value)
-{
- getOptionSet().set(CompilerOptionName::AllowGLSL, value);
-}
-
-SlangResult EndToEndCompileRequest::compile()
-{
- SlangResult res = SLANG_FAIL;
- double downstreamStartTime = 0.0;
- double totalStartTime = 0.0;
-
- if (getOptionSet().getBoolOption(CompilerOptionName::ReportDownstreamTime))
- {
- getSession()->getCompilerElapsedTime(&totalStartTime, &downstreamStartTime);
- PerformanceProfiler::getProfiler()->clear();
- }
-#if !defined(SLANG_DEBUG_INTERNAL_ERROR)
- // By default we'd like to catch as many internal errors as possible,
- // and report them to the user nicely (rather than just crash their
- // application). Internally Slang currently uses exceptions for this.
- //
- // TODO: Consider using `setjmp()`-style escape so that we can work
- // with applications that disable exceptions.
- //
- // TODO: Consider supporting Windows "Structured Exception Handling"
- // so that we can also recover from a wider class of crashes.
-
- try
- {
- SLANG_PROFILE_SECTION(compileInner);
- res = executeActions();
- }
- catch (const AbortCompilationException& e)
- {
- // This situation indicates a fatal (but not necessarily internal) error
- // that forced compilation to terminate. There should already have been
- // a diagnostic produced, so we don't need to add one here.
- if (getSink()->getErrorCount() == 0)
- {
- // If for some reason we didn't output any diagnostic, something is
- // going wrong, but we want to make sure we at least output something.
- getSink()->diagnose(
- SourceLoc(),
- Diagnostics::compilationAbortedDueToException,
- typeid(e).name(),
- e.Message);
- }
- }
- catch (const Exception& e)
- {
- // The compiler failed due to an internal error that was detected.
- // We will print out information on the exception to help out the user
- // in either filing a bug, or locating what in their code created
- // a problem.
- getSink()->diagnose(
- SourceLoc(),
- Diagnostics::compilationAbortedDueToException,
- typeid(e).name(),
- e.Message);
- }
- catch (...)
- {
- // The compiler failed due to some exception that wasn't a sublass of
- // `Exception`, so something really fishy is going on. We want to
- // let the user know that we messed up, so they know to blame Slang
- // and not some other component in their system.
- getSink()->diagnose(SourceLoc(), Diagnostics::compilationAborted);
- }
- m_diagnosticOutput = getSink()->outputBuffer.produceString();
-
-#else
- // When debugging, we probably don't want to filter out any errors, since
- // we are probably trying to root-cause and *fix* those errors.
- {
- res = req->executeActions();
- }
-#endif
-
- if (getOptionSet().getBoolOption(CompilerOptionName::ReportDownstreamTime))
- {
- double downstreamEndTime = 0;
- double totalEndTime = 0;
- getSession()->getCompilerElapsedTime(&totalEndTime, &downstreamEndTime);
- double downstreamTime = downstreamEndTime - downstreamStartTime;
- String downstreamTimeStr = String(downstreamTime, "%.2f");
- getSink()->diagnose(SourceLoc(), Diagnostics::downstreamCompileTime, downstreamTimeStr);
- }
- if (getOptionSet().getBoolOption(CompilerOptionName::ReportPerfBenchmark))
- {
- StringBuilder perfResult;
- PerformanceProfiler::getProfiler()->getResult(perfResult);
- perfResult << "\nType Dictionary Size: " << getSession()->m_typeDictionarySize << "\n";
- getSink()->diagnose(
- SourceLoc(),
- Diagnostics::performanceBenchmarkResult,
- perfResult.produceString());
- }
-
- // Repro dump handling
- {
- auto dumpRepro = getOptionSet().getStringOption(CompilerOptionName::DumpRepro);
- auto dumpReproOnError = getOptionSet().getBoolOption(CompilerOptionName::DumpReproOnError);
-
- if (dumpRepro.getLength())
- {
- SlangResult saveRes = ReproUtil::saveState(this, dumpRepro);
- if (SLANG_FAILED(saveRes))
- {
- getSink()->diagnose(SourceLoc(), Diagnostics::unableToWriteReproFile, dumpRepro);
- return saveRes;
- }
- }
- else if (dumpReproOnError && SLANG_FAILED(res))
- {
- String reproFileName;
- SlangResult saveRes = SLANG_FAIL;
-
- RefPtr<Stream> stream;
- if (SLANG_SUCCEEDED(ReproUtil::findUniqueReproDumpStream(this, reproFileName, stream)))
- {
- saveRes = ReproUtil::saveState(this, stream);
- }
-
- if (SLANG_FAILED(saveRes))
- {
- getSink()->diagnose(
- SourceLoc(),
- Diagnostics::unableToWriteReproFile,
- reproFileName);
- }
- }
- }
-
- auto reflectionPath = getOptionSet().getStringOption(CompilerOptionName::EmitReflectionJSON);
- if (reflectionPath.getLength() != 0)
- {
- auto bufferWriter = PrettyWriter();
- emitReflectionJSON(this, this->getReflection(), bufferWriter);
- if (reflectionPath == "-")
- {
- auto builder = bufferWriter.getBuilder();
- StdWriters::getOut().write(builder.getBuffer(), builder.getLength());
- }
- else if (SLANG_FAILED(File::writeAllText(reflectionPath, bufferWriter.getBuilder())))
- {
- getSink()->diagnose(SourceLoc(), Diagnostics::unableToWriteFile, reflectionPath);
- }
- }
-
- return res;
-}
-
-int EndToEndCompileRequest::getDependencyFileCount()
-{
- auto frontEndReq = getFrontEndReq();
- auto program = frontEndReq->getGlobalAndEntryPointsComponentType();
- return (int)program->getFileDependencies().getCount();
-}
-
-char const* EndToEndCompileRequest::getDependencyFilePath(int index)
-{
- auto frontEndReq = getFrontEndReq();
- auto program = frontEndReq->getGlobalAndEntryPointsComponentType();
- SourceFile* sourceFile = program->getFileDependencies()[index];
- return sourceFile->getPathInfo().hasFoundPath()
- ? sourceFile->getPathInfo().getMostUniqueIdentity().getBuffer()
- : "unknown";
-}
-
-int EndToEndCompileRequest::getTranslationUnitCount()
-{
- return (int)getFrontEndReq()->translationUnits.getCount();
-}
-
-void const* EndToEndCompileRequest::getEntryPointCode(int entryPointIndex, size_t* outSize)
-{
- // Zero the size initially, in case need to return nullptr for error.
- if (outSize)
- {
- *outSize = 0;
- }
-
- auto linkage = getLinkage();
- auto program = getSpecializedGlobalAndEntryPointsComponentType();
-
- // TODO: We should really accept a target index in this API
- Index targetIndex = 0;
- auto targetCount = linkage->targets.getCount();
- if (targetIndex >= targetCount)
- return nullptr;
- auto targetReq = linkage->targets[targetIndex];
-
-
- if (entryPointIndex < 0)
- return nullptr;
- if (Index(entryPointIndex) >= program->getEntryPointCount())
- return nullptr;
- auto entryPoint = program->getEntryPoint(entryPointIndex);
-
- auto targetProgram = program->getTargetProgram(targetReq);
- if (!targetProgram)
- return nullptr;
- IArtifact* artifact = targetProgram->getExistingEntryPointResult(entryPointIndex);
- if (!artifact)
- {
- return nullptr;
- }
-
- ComPtr<ISlangBlob> blob;
- SLANG_RETURN_NULL_ON_FAIL(artifact->loadBlob(ArtifactKeep::Yes, blob.writeRef()));
-
- if (outSize)
- {
- *outSize = blob->getBufferSize();
- }
-
- return (void*)blob->getBufferPointer();
-}
-
-SlangResult EndToEndCompileRequest::getCompileTimeProfile(
- ISlangProfiler** compileTimeProfile,
- bool shouldClear)
-{
- if (compileTimeProfile == nullptr)
- {
- return SLANG_E_INVALID_ARG;
- }
-
- SlangProfiler* profiler = new SlangProfiler(PerformanceProfiler::getProfiler());
-
- if (shouldClear)
- {
- PerformanceProfiler::getProfiler()->clear();
- }
-
- ComPtr<ISlangProfiler> result(profiler);
- *compileTimeProfile = result.detach();
- return SLANG_OK;
-}
-
-static SlangResult _getEntryPointResult(
- EndToEndCompileRequest* req,
- int entryPointIndex,
- int targetIndex,
- ComPtr<IArtifact>& outArtifact)
-{
- auto linkage = req->getLinkage();
- auto program = req->getSpecializedGlobalAndEntryPointsComponentType();
-
- Index targetCount = linkage->targets.getCount();
- if ((targetIndex < 0) || (targetIndex >= targetCount))
- {
- return SLANG_E_INVALID_ARG;
- }
- auto targetReq = linkage->targets[targetIndex];
-
- // Get the entry point count on the program, rather than (say) req->m_entryPoints.getCount()
- // because
- // 1) The entry point is fetched from the program anyway so must be consistent
- // 2) The req may not have all entry points (for example when an entry point is in a module)
- const Index entryPointCount = program->getEntryPointCount();
-
- if ((entryPointIndex < 0) || (entryPointIndex >= entryPointCount))
- {
- return SLANG_E_INVALID_ARG;
- }
- auto entryPointReq = program->getEntryPoint(entryPointIndex);
-
- auto targetProgram = program->getTargetProgram(targetReq);
- if (!targetProgram)
- return SLANG_FAIL;
-
- outArtifact = targetProgram->getExistingEntryPointResult(entryPointIndex);
- return SLANG_OK;
-}
-
-static SlangResult _getWholeProgramResult(
- EndToEndCompileRequest* req,
- int targetIndex,
- ComPtr<IArtifact>& outArtifact)
-{
- auto linkage = req->getLinkage();
- auto program = req->getSpecializedGlobalAndEntryPointsComponentType();
-
- if (!program)
- {
- return SLANG_FAIL;
- }
-
- Index targetCount = linkage->targets.getCount();
- if ((targetIndex < 0) || (targetIndex >= targetCount))
- {
- return SLANG_E_INVALID_ARG;
- }
- auto targetReq = linkage->targets[targetIndex];
-
- auto targetProgram = program->getTargetProgram(targetReq);
- if (!targetProgram)
- return SLANG_FAIL;
- outArtifact = targetProgram->getExistingWholeProgramResult();
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::getEntryPointCodeBlob(
- int entryPointIndex,
- int targetIndex,
- ISlangBlob** outBlob)
-{
- if (!outBlob)
- return SLANG_E_INVALID_ARG;
- ComPtr<IArtifact> artifact;
- SLANG_RETURN_ON_FAIL(_getEntryPointResult(this, entryPointIndex, targetIndex, artifact));
- SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::Yes, outBlob));
-
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::getEntryPointHostCallable(
- int entryPointIndex,
- int targetIndex,
- ISlangSharedLibrary** outSharedLibrary)
-{
- if (!outSharedLibrary)
- return SLANG_E_INVALID_ARG;
- ComPtr<IArtifact> artifact;
- SLANG_RETURN_ON_FAIL(_getEntryPointResult(this, entryPointIndex, targetIndex, artifact));
- SLANG_RETURN_ON_FAIL(artifact->loadSharedLibrary(ArtifactKeep::Yes, outSharedLibrary));
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::getTargetCodeBlob(int targetIndex, ISlangBlob** outBlob)
-{
- if (!outBlob)
- return SLANG_E_INVALID_ARG;
-
- ComPtr<IArtifact> artifact;
- SLANG_RETURN_ON_FAIL(_getWholeProgramResult(this, targetIndex, artifact));
- SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::Yes, outBlob));
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::getTargetHostCallable(
- int targetIndex,
- ISlangSharedLibrary** outSharedLibrary)
-{
- if (!outSharedLibrary)
- return SLANG_E_INVALID_ARG;
-
- ComPtr<IArtifact> artifact;
- SLANG_RETURN_ON_FAIL(_getWholeProgramResult(this, targetIndex, artifact));
- SLANG_RETURN_ON_FAIL(artifact->loadSharedLibrary(ArtifactKeep::Yes, outSharedLibrary));
- return SLANG_OK;
-}
-
-char const* EndToEndCompileRequest::getEntryPointSource(int entryPointIndex)
-{
- return (char const*)getEntryPointCode(entryPointIndex, nullptr);
-}
-
-ISlangMutableFileSystem* EndToEndCompileRequest::getCompileRequestResultAsFileSystem()
-{
- if (!m_containerFileSystem)
- {
- if (m_containerArtifact)
- {
- ComPtr<ISlangMutableFileSystem> fileSystem(new MemoryFileSystem);
-
- // Filter the containerArtifact into things that can be written
- ComPtr<IArtifact> writeArtifact;
- if (SLANG_SUCCEEDED(
- ArtifactContainerUtil::filter(m_containerArtifact, writeArtifact)) &&
- writeArtifact)
- {
- if (SLANG_SUCCEEDED(
- ArtifactContainerUtil::writeContainer(writeArtifact, "", fileSystem)))
- {
- m_containerFileSystem.swap(fileSystem);
- }
- }
- }
- }
-
- return m_containerFileSystem;
-}
-
-void const* EndToEndCompileRequest::getCompileRequestCode(size_t* outSize)
-{
- if (m_containerArtifact)
- {
- ComPtr<ISlangBlob> containerBlob;
- if (SLANG_SUCCEEDED(
- m_containerArtifact->loadBlob(ArtifactKeep::Yes, containerBlob.writeRef())))
- {
- *outSize = containerBlob->getBufferSize();
- return containerBlob->getBufferPointer();
- }
- }
-
- // Container blob does not have any contents
- *outSize = 0;
- return nullptr;
-}
-
-SlangResult EndToEndCompileRequest::getContainerCode(ISlangBlob** outBlob)
-{
- if (m_containerArtifact)
- {
- ComPtr<ISlangBlob> containerBlob;
- if (SLANG_SUCCEEDED(
- m_containerArtifact->loadBlob(ArtifactKeep::Yes, containerBlob.writeRef())))
- {
- *outBlob = containerBlob.detach();
- return SLANG_OK;
- }
- }
- return SLANG_FAIL;
-}
-
-SlangResult EndToEndCompileRequest::loadRepro(
- ISlangFileSystem* fileSystem,
- const void* data,
- size_t size)
-{
- List<uint8_t> buffer;
- SLANG_RETURN_ON_FAIL(ReproUtil::loadState((const uint8_t*)data, size, getSink(), buffer));
-
- MemoryOffsetBase base;
- base.set(buffer.getBuffer(), buffer.getCount());
-
- ReproUtil::RequestState* requestState = ReproUtil::getRequest(buffer);
-
- SLANG_RETURN_ON_FAIL(ReproUtil::load(base, requestState, fileSystem, this));
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::saveRepro(ISlangBlob** outBlob)
-{
- OwnedMemoryStream stream(FileAccess::Write);
-
- SLANG_RETURN_ON_FAIL(ReproUtil::saveState(this, &stream));
-
- // Put the content of the stream in the blob
-
- List<uint8_t> data;
- stream.swapContents(data);
-
- *outBlob = ListBlob::moveCreate(data).detach();
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::enableReproCapture()
-{
- getLinkage()->setRequireCacheFileSystem(true);
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::processCommandLineArguments(
- char const* const* args,
- int argCount)
-{
- return parseOptions(this, argCount, args);
-}
-
-SlangReflection* EndToEndCompileRequest::getReflection()
-{
- auto linkage = getLinkage();
- auto program = getSpecializedGlobalAndEntryPointsComponentType();
-
- // Note(tfoley): The API signature doesn't let the client
- // specify which target they want to access reflection
- // information for, so for now we default to the first one.
- //
- // TODO: Add a new `spGetReflectionForTarget(req, targetIndex)`
- // so that we can do this better, and make it clear that
- // `spGetReflection()` is shorthand for `targetIndex == 0`.
- //
- Slang::Index targetIndex = 0;
- auto targetCount = linkage->targets.getCount();
- if (targetIndex >= targetCount)
- return nullptr;
-
- auto targetReq = linkage->targets[targetIndex];
- auto targetProgram = program->getTargetProgram(targetReq);
-
-
- DiagnosticSink sink(linkage->getSourceManager(), Lexer::sourceLocationLexer);
- auto programLayout = targetProgram->getOrCreateLayout(&sink);
-
- return (SlangReflection*)programLayout;
-}
-
-SlangResult EndToEndCompileRequest::getProgram(slang::IComponentType** outProgram)
-{
- auto program = getSpecializedGlobalComponentType();
- *outProgram = Slang::ComPtr<slang::IComponentType>(program).detach();
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::getProgramWithEntryPoints(slang::IComponentType** outProgram)
-{
- auto program = getSpecializedGlobalAndEntryPointsComponentType();
- *outProgram = Slang::ComPtr<slang::IComponentType>(program).detach();
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::getModule(
- SlangInt translationUnitIndex,
- slang::IModule** outModule)
-{
- auto module = getFrontEndReq()->getTranslationUnit(translationUnitIndex)->getModule();
-
- *outModule = Slang::ComPtr<slang::IModule>(module).detach();
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::getSession(slang::ISession** outSession)
-{
- auto session = getLinkage();
- *outSession = Slang::ComPtr<slang::ISession>(session).detach();
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::getEntryPoint(
- SlangInt entryPointIndex,
- slang::IComponentType** outEntryPoint)
-{
- auto entryPoint = getSpecializedEntryPointComponentType(entryPointIndex);
- *outEntryPoint = Slang::ComPtr<slang::IComponentType>(entryPoint).detach();
- return SLANG_OK;
-}
-
-SlangResult EndToEndCompileRequest::isParameterLocationUsed(
- Int entryPointIndex,
- Int targetIndex,
- SlangParameterCategory category,
- UInt spaceIndex,
- UInt registerIndex,
- bool& outUsed)
-{
- if (!ShaderBindingRange::isUsageTracked((slang::ParameterCategory)category))
- return SLANG_E_NOT_AVAILABLE;
-
- ComPtr<IArtifact> artifact;
- if (SLANG_FAILED(_getEntryPointResult(
- this,
- static_cast<int>(entryPointIndex),
- static_cast<int>(targetIndex),
- artifact)))
- return SLANG_E_INVALID_ARG;
-
- if (!artifact)
- return SLANG_E_NOT_AVAILABLE;
-
- // Find a rep
- auto metadata = findAssociatedRepresentation<IArtifactPostEmitMetadata>(artifact);
- if (!metadata)
- return SLANG_E_NOT_AVAILABLE;
-
- return metadata->isParameterLocationUsed(category, spaceIndex, registerIndex, outUsed);
-}
-
} // namespace Slang