From 8922141f79a3e679e50a9b6947a61e8cae5fb29c Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Tue, 11 Nov 2025 20:29:33 +0200 Subject: [PATCH 01/21] Fix SLANG_ENABLE_ASAN CMake option Fixes #8646. --- cmake/CompilerFlags.cmake | 47 ++++++---- cmake/LLVM.cmake | 6 -- cmake/SlangTarget.cmake | 1 + include/slang.h | 2 +- .../slang-downstream-compiler.cpp | 88 +++++++++++++------ .../compiler-core/slang-gcc-compiler-util.cpp | 59 ++++++++++--- source/compiler-core/slang-lexer.cpp | 2 +- source/core/slang-blob.h | 8 +- source/core/slang-char-util.h | 5 +- source/core/slang-dictionary.h | 2 +- source/core/slang-hash.h | 2 +- source/core/slang-memory-arena.h | 23 +++++ source/core/slang-riff.cpp | 7 ++ source/core/slang-riff.h | 12 +-- source/core/slang-rtti-info.h | 5 +- source/core/slang-string.h | 6 +- source/core/slang-uint-set.cpp | 6 +- source/core/slang-zip-file-system.cpp | 13 +-- source/slang-glslang/CMakeLists.txt | 5 ++ source/slang-glslang/slang-glslang.cpp | 33 ++++--- source/slang-glslang/slang-glslang.h | 2 +- source/slang/slang-check-decl.cpp | 3 + source/slang/slang-check-expr.cpp | 24 +++-- source/slang/slang-check-impl.h | 2 +- source/slang/slang-compiler.cpp | 2 +- source/slang/slang-compiler.h | 2 +- source/slang/slang-emit-spirv.cpp | 10 ++- source/slang/slang-global-session.cpp | 8 ++ source/slang/slang-global-session.h | 2 + source/slang/slang-ir-sccp.cpp | 23 ++++- source/slang/slang-ir.cpp | 5 +- source/slang/slang-parser.cpp | 6 +- source/slang/slang-preprocessor.cpp | 5 +- source/slang/slang-reflection-json.cpp | 27 ++++-- source/slang/slang-serialize-ast.cpp | 2 +- source/slang/slang-serialize-ir.cpp | 2 +- source/slang/slang-type-layout.h | 2 +- source/slang/slang-vm-inst-impl.cpp | 14 ++- tools/gfx/renderer-shared.cpp | 51 ++++++----- tools/render-test/render-test-main.cpp | 17 ++-- tools/slang-fiddle/slang-fiddle-main.cpp | 3 +- tools/slang-test/slang-test-main.cpp | 25 +++--- .../unit-test-com-host-callable.cpp | 5 +- tools/slang-unit-test/unit-test-crypto.cpp | 10 --- .../unit-test-fcpw-compile.cpp | 17 ++-- .../unit-test-get-target-code.cpp | 13 +-- .../unit-test-persistent-cache.cpp | 7 +- 47 files changed, 416 insertions(+), 205 deletions(-) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index f9b4c86c7d7..3c4aec3a7e1 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -159,11 +159,17 @@ function(set_default_compile_options target) add_supported_cxx_linker_flags( ${target} PRIVATE - # Don't assume that symbols will be resolved at runtime - "-Wl,--no-undefined" # No reason not to do this? Useful when using split debug info "-Wl,--build-id" ) + if(NOT ${target} STREQUAL slang-llvm) + add_supported_cxx_linker_flags( + ${target} + PRIVATE + # Don't assume that symbols will be resolved at runtime + "-Wl,--no-undefined" + ) + endif() endif() set_target_properties( @@ -214,19 +220,30 @@ function(set_default_compile_options target) ) if(SLANG_ENABLE_ASAN) - add_supported_cxx_flags( - ${target} - PRIVATE - /fsanitize=address - -fsanitize=address - ) - add_supported_cxx_linker_flags( - ${target} - BEFORE - PUBLIC - /INCREMENTAL:NO - -fsanitize=address - ) + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # Clang defaults to statically linking the sanitizer runtime (except on macOS/Darwin), + # which is not compatible with -Wl,--no-undefined, so we need to use dynamic linking + # instead (-shared-libsan). + target_compile_options( + ${target} + PRIVATE -fsanitize=address,undefined -shared-libsan + ) + target_link_options( + ${target} + PUBLIC -fsanitize=address,undefined -shared-libsan + ) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options( + ${target} + PRIVATE -fsanitize=address,undefined + ) + target_link_options(${target} PUBLIC -fsanitize=address,undefined) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + target_compile_options(${target} PRIVATE /fsanitize=address) + target_link_options(${target} PRIVATE /INCREMENTAL:NO) + else() + message(WARNING "Not enabling sanitizers: unsupported C++ compiler") + endif() endif() if(SLANG_ENABLE_COVERAGE) diff --git a/cmake/LLVM.cmake b/cmake/LLVM.cmake index 9a9754684a8..3827a9b3e11 100644 --- a/cmake/LLVM.cmake +++ b/cmake/LLVM.cmake @@ -91,12 +91,6 @@ function(fetch_or_build_slang_llvm) target_compile_options(slang-llvm PRIVATE -wd4244 /Zc:preprocessor) endif() - if(NOT LLVM_ENABLE_RTTI) - # Make sure that we don't disable rtti if this library wasn't compiled with - # support - add_supported_cxx_flags(slang-llvm PRIVATE -fno-rtti /GR-) - endif() - # TODO: Put a check here that libslang-llvm.so doesn't have a 'NEEDED' # directive for libLLVM-21.so, it's almost certainly going to break at # runtime in surprising ways when linked alongside Mesa (or anything else diff --git a/cmake/SlangTarget.cmake b/cmake/SlangTarget.cmake index 6e2fc97b1f3..3aacb1ef7dc 100644 --- a/cmake/SlangTarget.cmake +++ b/cmake/SlangTarget.cmake @@ -348,6 +348,7 @@ function(slang_add_target dir type) VERBATIM ) else() + # NOTE(ncelik): I had disabled these, iirc it was because GDB/LLDB couldn't find some debug symbols. add_custom_command( TARGET ${target} POST_BUILD diff --git a/include/slang.h b/include/slang.h index f84dd599ed2..6aae9ace049 100644 --- a/include/slang.h +++ b/include/slang.h @@ -464,7 +464,7 @@ convention for interface methods. // Processor features #if SLANG_PROCESSOR_FAMILY_X86 #define SLANG_LITTLE_ENDIAN 1 - #define SLANG_UNALIGNED_ACCESS 1 + #define SLANG_UNALIGNED_ACCESS 0 #elif SLANG_PROCESSOR_FAMILY_ARM #if defined(__ARMEB__) #define SLANG_BIG_ENDIAN 1 diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index 190400f55ad..1f5ce551029 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -74,11 +74,7 @@ SlangResult CommandLineDownstreamCompiler::compile( CompileOptions options = getCompatibleVersion(&inOptions); - // Copy the command line options - CommandLine cmdLine(m_cmdLine); - - // Work out the ArtifactDesc - const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); + bool shouldSeparateCompileAndLink = options.targetType != SLANG_OBJECT_CODE; auto helper = DefaultArtifactHelper::getSingleton(); @@ -110,9 +106,61 @@ SlangResult CommandLineDownstreamCompiler::compile( options.modulePath = SliceUtil::asTerminatedCharSlice(modulePath); } - // Append command line args to the end of cmdLine using the target specific function for the - // specified options - SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); + // Compile stage: compile source to object code + ComPtr objectArtifact; + auto compileDiagnostics = ArtifactDiagnostics::create(); + + if (shouldSeparateCompileAndLink) + { + CompileOptions compileOptions = options; + compileOptions.targetType = SLANG_OBJECT_CODE; + + CommandLine compileCmdLine(m_cmdLine); + SLANG_RETURN_ON_FAIL(calcArgs(compileOptions, compileCmdLine)); + + List> compileArtifacts; + SLANG_RETURN_ON_FAIL(calcCompileProducts( + compileOptions, + DownstreamProductFlag::All, + lockFile, + compileArtifacts)); + + // There should only be one object file (.o/.obj) as artifact + SLANG_ASSERT(compileArtifacts.getCount() == 1); + SLANG_ASSERT(compileArtifacts[0]->getDesc().kind == ArtifactKind::ObjectCode); + objectArtifact = compileArtifacts[0]; + + ExecuteResult compileResult; + SLANG_RETURN_ON_FAIL(ProcessUtil::execute(compileCmdLine, compileResult)); + + SLANG_RETURN_ON_FAIL(parseOutput(compileResult, compileDiagnostics)); + + // If compilation failed, return the diagnostics + if (compileResult.resultCode != 0 || !objectArtifact->exists()) + { + auto artifact = ArtifactUtil::createArtifact( + ArtifactDescUtil::makeDescForCompileTarget(options.targetType)); + ArtifactUtil::addAssociated(artifact, compileDiagnostics); + *outArtifact = artifact.detach(); + return SLANG_OK; + } + } + + // Link stage (or single-stage compile for object code targets) + CommandLine cmdLine(m_cmdLine); + const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); + + if (shouldSeparateCompileAndLink) + { + // Build link command line + options.sourceArtifacts = makeSlice(objectArtifact.readRef(), 1); + SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); + } + else + { + // Single-stage compilation + SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); + } // The 'productArtifact' is the main product produced from the compilation - the // executable/sharedlibrary/object etc @@ -143,23 +191,8 @@ SlangResult CommandLineDownstreamCompiler::compile( } ExecuteResult exeRes; - -#if 0 - // Test - { - String line = ProcessUtil::getCommandLineString(cmdLine); - printf("%s", line.getBuffer()); - } -#endif - SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); -#if 0 - { - printf("stdout=\"%s\"\nstderr=\"%s\"\nret=%d\n", exeRes.standardOutput.getBuffer(), exeRes.standardError.getBuffer(), int(exeRes.resultCode)); - } -#endif - // Go through the list of artifacts in the artifactList and check if they exist. // // This is useful because `calcCompileProducts` is conservative and may produce artifacts for @@ -233,10 +266,11 @@ SlangResult CommandLineDownstreamCompiler::compile( { // Holds all of the artifacts that are relatated to the final artifact - such as debug // files, ancillary file and lock files - auto artifactContainer = ArtifactUtil::createArtifact(ArtifactDesc::make( - ArtifactKind::Container, - ArtifactPayload::Unknown, - ArtifactStyle::Unknown)); + auto artifactContainer = ArtifactUtil::createArtifact( + ArtifactDesc::make( + ArtifactKind::Container, + ArtifactPayload::Unknown, + ArtifactStyle::Unknown)); auto slice = SliceUtil::asSlice(artifactList); diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index cabb7799650..49db1383023 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -620,12 +620,34 @@ static SlangResult _parseGCCFamilyLine( { // Don't link, just produce object file cmdLine.addArg("-c"); + + if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind)) + { + // Position independent + cmdLine.addArg("-fPIC"); + } break; } default: break; } +#if defined(__has_feature) +#if __has_feature(address_sanitizer) + if (options.targetType != SLANG_OBJECT_CODE) + { +#if SLANG_CLANG || SLANG_GCC + // Assume ASan was enabled through the SLANG_ENABLE_ASAN CMake option, meaning UBSan was + // enabled as well. + cmdLine.addArg("-fsanitize=address,undefined"); +#endif +#if SLANG_CLANG + cmdLine.addArg("-shared-libsan"); +#endif + } +#endif +#endif + // Add defines for (const auto& define : options.defines) { @@ -678,14 +700,18 @@ static SlangResult _parseGCCFamilyLine( cmdLine.addArg(fileRep->getPath()); } - // Add the library paths - - if (options.libraryPaths.count && (options.targetType == SLANG_HOST_EXECUTABLE)) + // Add linker-specific options only when not compiling to object code + if (options.targetType != SLANG_OBJECT_CODE) { - if (PlatformUtil::isFamily(PlatformFamily::Apple, platformKind)) - cmdLine.addArg("-Wl,-rpath,@loader_path,-rpath,@loader_path/../lib"); - else - cmdLine.addArg("-Wl,-rpath,$ORIGIN,-rpath,$ORIGIN/../lib"); + // Add the library paths + + if (options.libraryPaths.count && (options.targetType == SLANG_HOST_EXECUTABLE)) + { + if (PlatformUtil::isFamily(PlatformFamily::Apple, platformKind)) + cmdLine.addArg("-Wl,-rpath,@loader_path,-rpath,@loader_path/../lib"); + else + cmdLine.addArg("-Wl,-rpath,$ORIGIN,-rpath,$ORIGIN/../lib"); + } } StringSlicePool libPathPool(StringSlicePool::Style::Default); @@ -711,13 +737,17 @@ static SlangResult _parseGCCFamilyLine( const UnownedStringSlice path(fileRep->getPath()); libPathPool.add(Path::getParentDirectory(path)); - cmdLine.addPrefixPathArg( - "-l", - ArtifactDescUtil::getBaseNameFromPath(artifact->getDesc(), path)); + if (options.targetType != SLANG_OBJECT_CODE) + { + cmdLine.addPrefixPathArg( + "-l", + ArtifactDescUtil::getBaseNameFromPath(artifact->getDesc(), path)); + } } } if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP && + options.targetType != SLANG_OBJECT_CODE && !PlatformUtil::isFamily(PlatformFamily::Windows, platformKind)) { // Make STD libs available @@ -728,9 +758,12 @@ static SlangResult _parseGCCFamilyLine( for (const auto& libPath : libPathPool.getAdded()) { - // Note that any escaping of the path is handled in the ProcessUtil:: - cmdLine.addArg("-L"); - cmdLine.addArg(libPath); + if (options.targetType != SLANG_OBJECT_CODE) + { + // Note that any escaping of the path is handled in the ProcessUtil:: + cmdLine.addArg("-L"); + cmdLine.addArg(libPath); + } cmdLine.addArg("-F"); cmdLine.addArg(libPath); } diff --git a/source/compiler-core/slang-lexer.cpp b/source/compiler-core/slang-lexer.cpp index e4c61bab7bd..fed8904856d 100644 --- a/source/compiler-core/slang-lexer.cpp +++ b/source/compiler-core/slang-lexer.cpp @@ -743,7 +743,7 @@ IntegerLiteralValue getIntegerLiteralValue( if (digit < 0) break; - value = value * base + digit; + value = static_cast(value) * base + digit; } if (outSuffix) diff --git a/source/core/slang-blob.h b/source/core/slang-blob.h index 5277ef0cd95..4c24645d396 100644 --- a/source/core/slang-blob.h +++ b/source/core/slang-blob.h @@ -280,7 +280,13 @@ class RawBlob : public BlobBase protected: // Ctor // NOTE! Takes a copy of the input data - RawBlob(const void* data, size_t size) { memcpy(m_data.allocateTerminated(size), data, size); } + RawBlob(const void* data, size_t size) + { + if (data) + { + memcpy(m_data.allocateTerminated(size), data, size); + } + } void* getObject(const Guid& guid); diff --git a/source/core/slang-char-util.h b/source/core/slang-char-util.h index 896eb69567b..0c95ba0e450 100644 --- a/source/core/slang-char-util.h +++ b/source/core/slang-char-util.h @@ -54,7 +54,10 @@ struct CharUtil SLANG_FORCE_INLINE static bool isOctalDigit(char c) { return c >= '0' && c <= '7'; } /// For a given character get the associated flags - SLANG_FORCE_INLINE static Flags getFlags(char c) { return g_charFlagMap.flags[size_t(c)]; } + SLANG_FORCE_INLINE static Flags getFlags(unsigned char c) + { + return g_charFlagMap.flags[size_t(c)]; + } /// Given a character return the lower case equivalent SLANG_FORCE_INLINE static char toLower(char c) diff --git a/source/core/slang-dictionary.h b/source/core/slang-dictionary.h index b3aa354d2bc..910957a13bf 100644 --- a/source/core/slang-dictionary.h +++ b/source/core/slang-dictionary.h @@ -473,7 +473,7 @@ class OrderedDictionary inline int getHashPos(T& key) const { const unsigned int hash = (unsigned int)getHashCode(key); - return ((unsigned int)(hash * 2654435761)) % m_bucketCountMinusOne; + return hash * 2654435761UL % m_bucketCountMinusOne; } template FindPositionResult findPosition(const T& key) const diff --git a/source/core/slang-hash.h b/source/core/slang-hash.h index 295f1c193ad..12b7fe4badd 100644 --- a/source/core/slang-hash.h +++ b/source/core/slang-hash.h @@ -188,7 +188,7 @@ auto combineHash(H1 n, H2 m, Hs... args) // unhashed integers in here along with proper hashes of objects. static_assert(std::is_convertible_v || std::is_convertible_v); static_assert(std::is_convertible_v || std::is_convertible_v); - return combineHash((n * 16777619) ^ m, args...); + return combineHash((n * 16777619U) ^ m, args...); } template diff --git a/source/core/slang-memory-arena.h b/source/core/slang-memory-arena.h index f08541ddb72..b2b3f769acf 100644 --- a/source/core/slang-memory-arena.h +++ b/source/core/slang-memory-arena.h @@ -256,6 +256,12 @@ SLANG_FORCE_INLINE bool MemoryArena::isValid(const void* data, size_t size) cons SLANG_FORCE_INLINE void* MemoryArena::allocateUnaligned(size_t sizeInBytes) { assert(sizeInBytes > 0); + + if (!m_current) + { + return _allocateAlignedFromNewBlock(sizeInBytes, kMinAlignment); + } + // Align with the minimum alignment uint8_t* mem = m_current; uint8_t* end = mem + sizeInBytes; @@ -291,6 +297,12 @@ SLANG_FORCE_INLINE void* MemoryArena::allocateCurrentUnaligned(size_t sizeInByte SLANG_FORCE_INLINE void* MemoryArena::allocate(size_t sizeInBytes) { assert(sizeInBytes > 0); + + if (!m_current) + { + return _allocateAlignedFromNewBlock(sizeInBytes, kMinAlignment); + } + // Align with the minimum alignment const size_t alignMask = kMinAlignment - 1; uint8_t* mem = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask); @@ -310,6 +322,12 @@ SLANG_FORCE_INLINE void* MemoryArena::allocate(size_t sizeInBytes) SLANG_FORCE_INLINE void* MemoryArena::allocateAndZero(size_t sizeInBytes) { assert(sizeInBytes > 0); + + if (!m_current) + { + return _allocateAlignedFromNewBlockAndZero(sizeInBytes, kMinAlignment); + } + // Align with the minimum alignment const size_t alignMask = kMinAlignment - 1; // Implement without calling ::allocate, because in most common case we don't need to test for @@ -335,6 +353,11 @@ SLANG_FORCE_INLINE void* MemoryArena::allocateAligned(size_t sizeInBytes, size_t // Alignment must be a power of 2 assert(((alignment - 1) & alignment) == 0); + if (!m_current) + { + return _allocateAlignedFromNewBlock(sizeInBytes, alignment); + } + // Align the pointer const size_t alignMask = alignment - 1; uint8_t* memory = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask); diff --git a/source/core/slang-riff.cpp b/source/core/slang-riff.cpp index be15497f350..d8be80bf362 100644 --- a/source/core/slang-riff.cpp +++ b/source/core/slang-riff.cpp @@ -220,6 +220,13 @@ BoundsCheckedChunkPtr ListChunk::getFirstChild() const if (availableSizeForChildren == 0) return nullptr; + // There will be padding after the `ListChunk::Header` to align the first child to 8 bytes. + // However, if the parent chunk has no children, then its total size will only be the size of + // `ListChunk::Header` without the padding. Thus, we can only align the child offset after the + // previous size checks. + firstChildOffset = _roundUpToChunkAlignment(firstChildOffset); + availableSizeForChildren = reportedParentSize - firstChildOffset; + // If the parent chunk has a non-zero size, then it should // have at least one child, and the available size had better // be big enough to at least hold the *header* of that first diff --git a/source/core/slang-riff.h b/source/core/slang-riff.h index 9459c8a5516..ce1803c05f1 100644 --- a/source/core/slang-riff.h +++ b/source/core/slang-riff.h @@ -119,15 +119,11 @@ struct Builder; struct Chunk { public: - // - // The starting offset of a chunk in a RIFF file - // is only guaranteed to be 2-byte aligned. - // Code that reads from a chunk must be cautious about - // the possibility of performing unaligned loads. - // - /// Required alignment for the starting offset of a chunk. - static const UInt32 kChunkAlignment = 2; + /// + /// We align chunks to 8 bytes instead of the traditional 2 bytes to avoid unaligned loads and + /// member calls on misaligned pointers, which are undefined behavior. + static const UInt32 kChunkAlignment = 8; // // Every chunk starts with a *header*, which includes diff --git a/source/core/slang-rtti-info.h b/source/core/slang-rtti-info.h index 9d4967cfebc..6def698f528 100644 --- a/source/core/slang-rtti-info.h +++ b/source/core/slang-rtti-info.h @@ -143,7 +143,10 @@ struct GetRttiTypeFuncsForZeroPod { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); - ::memcpy(dst, src, sizeof(T) * count); + if (src) + { + ::memcpy(dst, src, sizeof(T) * count); + } } static RttiTypeFuncs getFuncs() diff --git a/source/core/slang-string.h b/source/core/slang-string.h index 1a45f747bc9..c9ecc315714 100644 --- a/source/core/slang-string.h +++ b/source/core/slang-string.h @@ -467,7 +467,11 @@ class SLANG_RT_API String friend class StringBuilder; private: - char* getData() const { return m_buffer ? m_buffer->getData() : (char*)""; } + char* getData() const + { + static char empty[] = ""; + return m_buffer ? m_buffer->getData() : empty; + } void ensureUniqueStorageWithCapacity(Index capacity); diff --git a/source/core/slang-uint-set.cpp b/source/core/slang-uint-set.cpp index 1098db6d51a..45a48b2459e 100644 --- a/source/core/slang-uint-set.cpp +++ b/source/core/slang-uint-set.cpp @@ -65,7 +65,8 @@ void UIntSet::resize(UInt size) void UIntSet::clear() { - ::memset(m_buffer.getBuffer(), 0, m_buffer.getCount() * sizeof(Element)); + if (auto* buffer = m_buffer.getBuffer()) + ::memset(buffer, 0, m_buffer.getCount() * sizeof(Element)); } bool UIntSet::isEmpty() const @@ -102,6 +103,9 @@ bool UIntSet::operator==(const UIntSet& set) const const Index minCount = Math::Min(aCount, bCount); + if (!aElems || !bElems) + return aElems == bElems; + return ::memcmp(aElems, bElems, minCount * sizeof(Element)) == 0 && _areAllZero(aElems + minCount, aCount - minCount) && _areAllZero(bElems + minCount, bCount - minCount); diff --git a/source/core/slang-zip-file-system.cpp b/source/core/slang-zip-file-system.cpp index 0d3503222d1..40be850742d 100644 --- a/source/core/slang-zip-file-system.cpp +++ b/source/core/slang-zip-file-system.cpp @@ -99,8 +99,8 @@ class ZipFileSystemImpl : public ComBaseObject, void _rebuildMap(); - /// Returns true if the named item is at the index - UnownedStringSlice _getPathAtIndex(Index index); + /// Returns the path of the named item at the index, or an empty string on error + String _getPathAtIndex(Index index); void* getInterface(const Guid& guid); void* getObject(const Guid& guid); @@ -225,18 +225,21 @@ void ZipFileSystemImpl::_rebuildMap() } } -UnownedStringSlice ZipFileSystemImpl::_getPathAtIndex(Index index) +String ZipFileSystemImpl::_getPathAtIndex(Index index) { SLANG_ASSERT(m_mode != Mode::None); mz_zip_archive_file_stat fileStat; // Check it's added at the end + // TODO(ncelik): What does the comment above mean? if (!mz_zip_reader_file_stat(&m_archive, mz_uint(index), &fileStat)) { - return UnownedStringSlice(); + return String(); } - return UnownedStringSlice(fileStat.m_filename).trim('/'); + // AddressSanitizer: stack-use-after-return + // (/home/ncelik/projects/slang/source/core/slang-string.cpp:766:12) + return String(UnownedStringSlice(fileStat.m_filename).trim('/')); } void ZipFileSystemImpl::_initReadWrite(mz_zip_archive& outWriter) diff --git a/source/slang-glslang/CMakeLists.txt b/source/slang-glslang/CMakeLists.txt index e7af32234b2..57b753cfbea 100644 --- a/source/slang-glslang/CMakeLists.txt +++ b/source/slang-glslang/CMakeLists.txt @@ -31,6 +31,11 @@ if(SLANG_ENABLE_SLANG_GLSLANG) PROPERTIES OUTPUT_NAME slang-glslang-${SLANG_VERSION_NUMERIC} ) endif() + add_supported_cxx_flags( + slang-glslang + PRIVATE + -fno-rtti + ) add_supported_cxx_linker_flags( slang-glslang PRIVATE diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index 19e4b224c07..ab9491d1267 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -169,7 +169,8 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - bool glslang_validateSPIRV(const uint32_t* contents, int contentsSize) + bool + glslang_validateSPIRV(const uint32_t* contents, int contentsSize) { spv_target_env target_env = SPV_ENV_VULKAN_1_4; @@ -190,10 +191,8 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - bool glslang_disassembleSPIRVWithResult( - const uint32_t* contents, - int contentsSize, - char** outString) + bool + glslang_disassembleSPIRVWithResult(const uint32_t* contents, int contentsSize, char** outString) { static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; spv_text text; @@ -238,7 +237,8 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - bool glslang_disassembleSPIRV(const uint32_t* contents, int contentsSize) + bool + glslang_disassembleSPIRV(const uint32_t* contents, int contentsSize) { char* result = nullptr; auto succ = glslang_disassembleSPIRVWithResult(contents, contentsSize, &result); @@ -533,8 +533,13 @@ static int spirv_Optimize_1_2(const glslang_CompileRequest_1_2& request) std::vector diagnostics; std::vector spirvBuffer; size_t inputBlobSize = (char*)request.inputEnd - (char*)request.inputBegin; - spirvBuffer.resize(inputBlobSize / sizeof(uint32_t)); - memcpy(spirvBuffer.data(), request.inputBegin, inputBlobSize); + // TODO(ncelik): Are any diagnostics emitted in this case or should `inputBlobSize == 0` cause + // an early return? + if (inputBlobSize > 0) + { + spirvBuffer.resize(inputBlobSize / sizeof(uint32_t)); + memcpy(spirvBuffer.data(), request.inputBegin, inputBlobSize); + } glslang_optimizeSPIRV(SPV_ENV_UNIVERSAL_1_5, request, diagnostics, spirvBuffer); if (request.outputFunc) @@ -950,7 +955,8 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - int glslang_compile_1_2(glslang_CompileRequest_1_2* inRequest) + int + glslang_compile_1_2(glslang_CompileRequest_1_2* inRequest) { static ProcessInitializer g_processInitializer; if (!g_processInitializer.init()) @@ -989,7 +995,8 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - int glslang_compile_1_1(glslang_CompileRequest_1_1* inRequest) + int + glslang_compile_1_1(glslang_CompileRequest_1_1* inRequest) { glslang_CompileRequest_1_2 request; memset(&request, 0, sizeof(request)); @@ -1004,7 +1011,8 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - int glslang_compile(glslang_CompileRequest_1_0* inRequest) + int + glslang_compile(glslang_CompileRequest_1_0* inRequest) { glslang_CompileRequest_1_1 request; memset(&request, 0, sizeof(request)); @@ -1019,7 +1027,8 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - int glslang_linkSPIRV(glslang_LinkRequest* request) + int + glslang_linkSPIRV(glslang_LinkRequest* request) { if (!request || !request->modules || request->linkResult) return false; diff --git a/source/slang-glslang/slang-glslang.h b/source/slang-glslang/slang-glslang.h index 570bddfc3d5..e20cff8c2b5 100644 --- a/source/slang-glslang/slang-glslang.h +++ b/source/slang-glslang/slang-glslang.h @@ -171,5 +171,5 @@ typedef bool (*glslang_DisassembleSPIRVWithResultFunc)( const uint32_t* contents, int contentsSize, char** outString); -typedef bool (*glslang_LinkSPIRVFunc)(glslang_LinkRequest* request); +typedef int (*glslang_LinkSPIRVFunc)(glslang_LinkRequest* request); #endif diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 6fa916dca7c..e6308af2c17 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -12753,6 +12753,9 @@ void checkDerivativeAttributeImpl( DeclRef funcDeclRef = defaultFuncDeclRef.as(); auto funcThisType = getTypeForThisExpr(visitor, funcDeclRef); + if (!funcThisType) + return; + DeclRef calleeFuncDeclRef = calleeDeclRef->declRef.template as(); auto derivativeFuncThisType = getTypeForThisExpr(visitor, calleeFuncDeclRef); diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 7935ba96e73..9329e0ac281 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -2104,19 +2104,19 @@ IntVal* SemanticsVisitor::tryConstantFoldExpr( } // simple binary operators -#define CASE(OP) \ - else if (opName == getName(#OP)) do \ - { \ - if (argCount != 2) \ - return nullptr; \ - resultValue = constArgVals[0] OP constArgVals[1]; \ - } \ +#define CASE(OP) \ + else if (opName == getName(#OP)) do \ + { \ + if (argCount != 2) \ + return nullptr; \ + resultValue = \ + static_cast(constArgVals[0]) OP static_cast(constArgVals[1]); \ + } \ while (0) CASE(+); // TODO: this can also be unary... CASE(*); CASE(<<); - CASE(>>); CASE(&); CASE(|); CASE(^); @@ -2126,6 +2126,14 @@ IntVal* SemanticsVisitor::tryConstantFoldExpr( CASE(<=); CASE(<); CASE(>); + else if (opName == getName(">>")) + { + if (argCount != 2) + return nullptr; + resultValue = + static_cast(constArgVals[0]) >> + std::min(static_cast(constArgVals[1]), static_cast(64 - 1)); + } #undef CASE // binary operators with chance of divide-by-zero // TODO: issue a suitable error in that case diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 1705c9fb830..bf260657640 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -55,7 +55,7 @@ Type* getPointedToTypeIfCanImplicitDeref(Type* type); inline int getIntValueBitSize(IntegerLiteralValue val) { - uint64_t v = val > 0 ? (uint64_t)val : (uint64_t)-val; + uint64_t v = val > 0 ? (uint64_t)val : -(uint64_t)val; int result = 1; while (v >>= 1) { diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 4b689455b80..f2e1889a851 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -4,7 +4,7 @@ namespace Slang { -bool isValidSlangLanguageVersion(SlangLanguageVersion version) +bool isValidSlangLanguageVersion(int version) { switch (version) { diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 934f86096a8..0d95fecf01f 100644 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -249,7 +249,7 @@ bool maybeDiagnoseWarningOrError( } } -bool isValidSlangLanguageVersion(SlangLanguageVersion version); +bool isValidSlangLanguageVersion(int version); bool isValidGLSLVersion(int version); } // namespace Slang diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index b953426ad61..22483efad9d 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -8895,7 +8895,9 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex line, col, builder.getIntValue(builder.getUIntType(), offset * 8), - builder.getIntValue(builder.getUIntType(), sizeAlignment.size * 8), + builder.getIntValue( + builder.getUIntType(), + static_cast(sizeAlignment.size) * 8), builder.getIntValue(builder.getUIntType(), 0)); members.add(memberType); } @@ -9173,7 +9175,11 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex [this](SpvOp opcode, SpvInstParent* defaultParent) -> SpvInstParent* { const auto info = m_grammarInfo->opInfos.lookup(opcode); - SLANG_ASSERT(info.has_value()); + // TODO(ncelik): tests/spirv/unknown-opcode.slang results in this func being called + // with opcode=SpvOpMax (0x7fffffff). Release/RelWithDebInfo builds would just + // invoke UB (call a [noreturn] func that does in fact return) in this case. The + // best solution would be to emit a proper diagnostic here. + SLANG_RELEASE_ASSERT(info.has_value()); switch (info->class_) { case SPIRVCoreGrammarInfo::OpInfo::TypeDeclaration: diff --git a/source/slang/slang-global-session.cpp b/source/slang/slang-global-session.cpp index cf526bea835..26f009cdb91 100644 --- a/source/slang/slang-global-session.cpp +++ b/source/slang/slang-global-session.cpp @@ -63,6 +63,12 @@ void Session::init() auto rootASTBuilder = new RootASTBuilder(this); m_rootASTBuilder = rootASTBuilder; + // Set the root AST builder as current AST builder as a workaround for code that would get a + // null pointer from getCurrentASTBuilder() and call member functions on it, which is undefined + // behavior and is reported as such by UBSan. + m_previousASTBuilder = getCurrentASTBuilder(); + setCurrentASTBuilder(m_rootASTBuilder); + // Make sure our source manager is initialized builtinSourceManager.initialize(nullptr, nullptr); @@ -139,6 +145,8 @@ Session::~Session() // are still alive. // coreModules = decltype(coreModules)(); + + setCurrentASTBuilder(m_previousASTBuilder); } SharedASTBuilder* Session::getSharedASTBuilder() diff --git a/source/slang/slang-global-session.h b/source/slang/slang-global-session.h index 22cf8a0564e..232a80f390d 100644 --- a/source/slang/slang-global-session.h +++ b/source/slang/slang-global-session.h @@ -368,6 +368,8 @@ class Session : public RefObject, public slang::IGlobalSession /// The AST builder that will be used for builtin modules. /// RefPtr m_rootASTBuilder; + + ASTBuilder* m_previousASTBuilder; }; /* Returns SLANG_OK if pass through support is available */ diff --git a/source/slang/slang-ir-sccp.cpp b/source/slang/slang-ir-sccp.cpp index f1b647045b4..e0127a63d86 100644 --- a/source/slang/slang-ir-sccp.cpp +++ b/source/slang/slang-ir-sccp.cpp @@ -559,7 +559,10 @@ struct SCCPContext type, v0, v1, - [](IRIntegerValue c0, IRIntegerValue c1) { return c0 + c1; }, + [](IRIntegerValue c0, IRIntegerValue c1) { + return static_cast( + static_cast(c0) + static_cast(c1)); + }, [](IRFloatingPointValue c0, IRFloatingPointValue c1) { return c0 + c1; }); } LatticeVal evalSub(IRType* type, LatticeVal v0, LatticeVal v1) @@ -568,7 +571,10 @@ struct SCCPContext type, v0, v1, - [](IRIntegerValue c0, IRIntegerValue c1) { return c0 - c1; }, + [](IRIntegerValue c0, IRIntegerValue c1) { + return static_cast( + static_cast(c0) - static_cast(c1)); + }, [](IRFloatingPointValue c0, IRFloatingPointValue c1) { return c0 - c1; }); } LatticeVal evalMul(IRType* type, LatticeVal v0, LatticeVal v1) @@ -577,7 +583,10 @@ struct SCCPContext type, v0, v1, - [](IRIntegerValue c0, IRIntegerValue c1) { return c0 * c1; }, + [](IRIntegerValue c0, IRIntegerValue c1) { + return static_cast( + static_cast(c0) * static_cast(c1)); + }, [](IRFloatingPointValue c0, IRFloatingPointValue c1) { return c0 * c1; }); } LatticeVal evalDiv(IRType* type, LatticeVal v0, LatticeVal v1) @@ -726,7 +735,13 @@ struct SCCPContext type, v0, v1, - [](IRUnsignedIntegerValue c0, IRUnsignedIntegerValue c1) { return c0 >> c1; }); + [](IRUnsignedIntegerValue c0, IRUnsignedIntegerValue c1) + { + return c0 >> std::min( + c1, + static_cast( + std::numeric_limits::digits - 1)); + }); } return evalBinaryIntImpl( type, diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 2391bc25f63..0b513f4e351 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -2285,7 +2285,10 @@ IRConstant* IRBuilder::_findOrEmitConstant(IRConstant& keyInst) // Turn into pointer to avoid warning of array overrun char* dstChars = dstString.chars; // Copy the chars - memcpy(dstChars, slice.begin(), sliceSize); + if (sliceSize > 0) + { + memcpy(dstChars, slice.begin(), sliceSize); + } break; } diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index cc06e981222..5de9b31d2ab 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -8227,7 +8227,7 @@ static IRIntegerValue _foldIntegerPrefixOp(TokenType tokenType, IRIntegerValue v case TokenType::OpAdd: return value; case TokenType::OpSub: - return -value; + return -static_cast(value); default: { SLANG_ASSERT(!"Unexpected op"); @@ -8455,7 +8455,9 @@ static std::optional parseSPIRVAsmInst(Parser* parser) const auto& opcodeWord = spirvInfo->opcodes.lookup(ret.opcode.token.getContent()); const auto& opInfo = opcodeWord ? spirvInfo->opInfos.lookup(*opcodeWord) : std::nullopt; - ret.opcode.knownValue = opcodeWord.value_or(SpvOp(0xffffffff)); + // UBSan: load of value 4294967295, which is not a valid value for type 'const SpvOp' (aka + // 'const SpvOp_') + ret.opcode.knownValue = opcodeWord.value_or(SpvOpMax); // If we couldn't find any info, but used this assignment syntax, raise // an error diff --git a/source/slang/slang-preprocessor.cpp b/source/slang/slang-preprocessor.cpp index 39b1214d763..616b6b42822 100644 --- a/source/slang/slang-preprocessor.cpp +++ b/source/slang/slang-preprocessor.cpp @@ -4406,7 +4406,6 @@ static void HandleVersionDirective(PreprocessorDirectiveContext* context) Diagnostics::unknownLanguageVersion, version); } - context->m_preprocessor->languageVersion = (SlangLanguageVersion)version; } static void HandleLanguageDirective(PreprocessorDirectiveContext* context) @@ -4454,9 +4453,10 @@ static void HandleLanguageDirective(PreprocessorDirectiveContext* context) SkipToEndOfLine(context); - if (isValidSlangLanguageVersion((SlangLanguageVersion)version)) + if (isValidSlangLanguageVersion(version)) { context->m_preprocessor->language = SourceLanguage::Slang; + context->m_preprocessor->languageVersion = (SlangLanguageVersion)version; } else { @@ -4465,7 +4465,6 @@ static void HandleLanguageDirective(PreprocessorDirectiveContext* context) Diagnostics::unknownLanguageVersion, version); } - context->m_preprocessor->languageVersion = (SlangLanguageVersion)version; } // Handle an invalid directive diff --git a/source/slang/slang-reflection-json.cpp b/source/slang/slang-reflection-json.cpp index d21161a1232..9acbf075ac2 100644 --- a/source/slang/slang-reflection-json.cpp +++ b/source/slang/slang-reflection-json.cpp @@ -400,10 +400,13 @@ static void emitReflectionVarLayoutJSON(PrettyWriter& writer, slang::VariableLay CommaTrackerRAII commaTracker(writer); - if (auto name = var->getName()) + if (var->getVariable()) { - writer.maybeComma(); - emitReflectionNameInfoJSON(writer, name); + if (auto name = var->getName()) + { + writer.maybeComma(); + emitReflectionNameInfoJSON(writer, name); + } } writer.maybeComma(); @@ -417,7 +420,10 @@ static void emitReflectionVarLayoutJSON(PrettyWriter& writer, slang::VariableLay emitReflectionTypeLayoutJSON(writer, var->getTypeLayout()); } - emitReflectionModifierInfoJSON(writer, var->getVariable()); + if (var->getVariable()) + { + emitReflectionModifierInfoJSON(writer, var->getVariable()); + } emitReflectionVarBindingInfoJSON(writer, var); writer.dedent(); @@ -1028,13 +1034,16 @@ static void emitReflectionParamJSON(PrettyWriter& writer, slang::VariableLayoutR CommaTrackerRAII commaTracker(writer); - if (auto name = param->getName()) + if (param->getVariable()) { - writer.maybeComma(); - emitReflectionNameInfoJSON(writer, name); - } + if (auto name = param->getName()) + { + writer.maybeComma(); + emitReflectionNameInfoJSON(writer, name); + } - emitReflectionModifierInfoJSON(writer, param->getVariable()); + emitReflectionModifierInfoJSON(writer, param->getVariable()); + } emitReflectionVarBindingInfoJSON(writer, param); diff --git a/source/slang/slang-serialize-ast.cpp b/source/slang/slang-serialize-ast.cpp index 66b701ced83..2ebafb812ad 100644 --- a/source/slang/slang-serialize-ast.cpp +++ b/source/slang/slang-serialize-ast.cpp @@ -1899,8 +1899,8 @@ void writeSerializedModuleAST( // (which is more or less just a pair of pointers, to the two // values described above). // - Fossil::SerialWriter writer(blobBuilder); ASTSerialWriteContext context(moduleDecl, sourceLocWriter); + Fossil::SerialWriter writer(blobBuilder); ASTSerialWriteContext::ASTSerializer serializer(&writer, &context); // Once we have our `serializer`, we can finally invoke diff --git a/source/slang/slang-serialize-ir.cpp b/source/slang/slang-serialize-ir.cpp index 83955cc06cf..cd39057c2ea 100644 --- a/source/slang/slang-serialize-ir.cpp +++ b/source/slang/slang-serialize-ir.cpp @@ -735,8 +735,8 @@ void writeSerializedModuleIR( #else BlobBuilder blobBuilder; { - Fossil::SerialWriter writer(blobBuilder); IRSerialWriteContext context{sourceLocWriter}; + Fossil::SerialWriter writer(blobBuilder); IRWriteSerializer serializer(&writer, &context); serialize(serializer, moduleInfo); } diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h index 635d5de5777..54b15ce71e1 100644 --- a/source/slang/slang-type-layout.h +++ b/source/slang/slang-type-layout.h @@ -1364,7 +1364,7 @@ struct TypeLayoutContext TypeLayoutContext withSpecializationArgsOffsetBy(Int offset) const { TypeLayoutContext result = *this; - if (specializationArgCount > offset) + if (specializationArgCount > 0 && specializationArgCount > offset) { result.specializationArgCount = specializationArgCount - offset; result.specializationArgs = specializationArgs + offset; diff --git a/source/slang/slang-vm-inst-impl.cpp b/source/slang/slang-vm-inst-impl.cpp index 304ea09a858..7a050e7b9a4 100644 --- a/source/slang/slang-vm-inst-impl.cpp +++ b/source/slang/slang-vm-inst-impl.cpp @@ -17,7 +17,13 @@ ByteCodeInterpreter* convert(IByteCodeRunner* runner) template \ static void run(TR* dst, const T1* src1, const T2* src2) \ { \ - *dst = (*src1)op(*src2); \ + T1 tempSrc1; \ + ::memcpy((void*)&tempSrc1, (void*)src1, sizeof(T1)); \ + T2 tempSrc2; \ + ::memcpy((void*)&tempSrc2, (void*)src2, sizeof(T2)); \ + TR tempDst; \ + tempDst = (tempSrc1)op(tempSrc2); \ + ::memcpy((void*)dst, (void*)&tempDst, sizeof(TR)); \ } \ } @@ -708,7 +714,7 @@ void copyHandler16(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) SLANG_UNUSED(ctx); auto dst = (uint16_t*)inst->getOperand(0).getPtr(); auto src = (uint16_t*)inst->getOperand(1).getPtr(); - *dst = *src; + memcpy((void*)dst, (void*)src, sizeof(*dst)); } void copyHandler32(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) @@ -716,7 +722,7 @@ void copyHandler32(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) SLANG_UNUSED(ctx); auto dst = (uint32_t*)inst->getOperand(0).getPtr(); auto src = (uint32_t*)inst->getOperand(1).getPtr(); - *dst = *src; + memcpy((void*)dst, (void*)src, sizeof(*dst)); } void copyHandler64(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) @@ -724,7 +730,7 @@ void copyHandler64(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) SLANG_UNUSED(ctx); auto dst = (uint64_t*)inst->getOperand(0).getPtr(); auto src = (uint64_t*)inst->getOperand(1).getPtr(); - *dst = *src; + memcpy((void*)dst, (void*)src, sizeof(*dst)); } void generalCopyHandler(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp index d68ce4ee8b3..47f83a7eada 100644 --- a/tools/gfx/renderer-shared.cpp +++ b/tools/gfx/renderer-shared.cpp @@ -854,39 +854,42 @@ Result RendererBase::resetShaderCacheStats() ShaderComponentID ShaderCache::getComponentId(slang::TypeReflection* type) { ComponentKey key; - key.typeName = UnownedStringSlice(type->getName()); - switch (type->getKind()) + if (type) { - case slang::TypeReflection::Kind::Specialized: + key.typeName = UnownedStringSlice(type->getName()); + switch (type->getKind()) { - auto baseType = type->getElementType(); + case slang::TypeReflection::Kind::Specialized: + { + auto baseType = type->getElementType(); - StringBuilder builder; - builder.append(UnownedTerminatedStringSlice(baseType->getName())); + StringBuilder builder; + builder.append(UnownedTerminatedStringSlice(baseType->getName())); - auto rawType = (SlangReflectionType*)type; + auto rawType = (SlangReflectionType*)type; - builder.appendChar('<'); - SlangInt argCount = spReflectionType_getSpecializedTypeArgCount(rawType); - for (SlangInt a = 0; a < argCount; ++a) - { - if (a != 0) - builder.appendChar(','); - if (auto rawArgType = spReflectionType_getSpecializedTypeArgType(rawType, a)) + builder.appendChar('<'); + SlangInt argCount = spReflectionType_getSpecializedTypeArgCount(rawType); + for (SlangInt a = 0; a < argCount; ++a) { - auto argType = (slang::TypeReflection*)rawArgType; - builder.append(argType->getName()); + if (a != 0) + builder.appendChar(','); + if (auto rawArgType = spReflectionType_getSpecializedTypeArgType(rawType, a)) + { + auto argType = (slang::TypeReflection*)rawArgType; + builder.append(argType->getName()); + } } + builder.appendChar('>'); + key.typeName = builder.getUnownedSlice(); + key.updateHash(); + return getComponentId(key); } - builder.appendChar('>'); - key.typeName = builder.getUnownedSlice(); - key.updateHash(); - return getComponentId(key); + // TODO: collect specialization arguments and append them to `key`. + SLANG_UNIMPLEMENTED_X("specialized type"); + default: + break; } - // TODO: collect specialization arguments and append them to `key`. - SLANG_UNIMPLEMENTED_X("specialized type"); - default: - break; } key.updateHash(); return getComponentId(key); diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp index c6d1e5780ca..49895433b43 100644 --- a/tools/render-test/render-test-main.cpp +++ b/tools/render-test/render-test-main.cpp @@ -315,15 +315,18 @@ struct AssignValsFromLayoutContext const size_t bufferSize = srcVal->bufferData.getCount() * sizeof(uint32_t); ShaderCursor dataCursor = dstCursor; - switch (dataCursor.getTypeLayout()->getKind()) + if (auto* typeLayout = dataCursor.getTypeLayout()) { - case slang::TypeReflection::Kind::ConstantBuffer: - case slang::TypeReflection::Kind::ParameterBlock: - dataCursor = dataCursor.getDereferenced(); - break; + switch (typeLayout->getKind()) + { + case slang::TypeReflection::Kind::ConstantBuffer: + case slang::TypeReflection::Kind::ParameterBlock: + dataCursor = dataCursor.getDereferenced(); + break; - default: - break; + default: + break; + } } SLANG_RETURN_ON_FAIL(dataCursor.setData(srcVal->bufferData.getBuffer(), bufferSize)); diff --git a/tools/slang-fiddle/slang-fiddle-main.cpp b/tools/slang-fiddle/slang-fiddle-main.cpp index fea16dafe35..9caf44b34b2 100644 --- a/tools/slang-fiddle/slang-fiddle-main.cpp +++ b/tools/slang-fiddle/slang-fiddle-main.cpp @@ -407,7 +407,8 @@ int main(int argc, char const* const* argv) using namespace fiddle; using namespace Slang; - ComPtr writer(new FileWriter(stderr, WriterFlag::AutoFlush)); + ComPtr writer( + new FileWriter(stderr, WriterFlag::IsUnowned | WriterFlag::AutoFlush)); NamePool namePool; diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp index 2625119ac00..8a9c6e837ba 100644 --- a/tools/slang-test/slang-test-main.cpp +++ b/tools/slang-test/slang-test-main.cpp @@ -2625,9 +2625,10 @@ TestResult runSimpleLineTest(TestContext* context, TestInput& input) // Parse all the diagnostics so we can extract line numbers auto diagnostics = ArtifactDiagnostics::create(); - if (SLANG_FAILED(ParseDiagnosticUtil::parseDiagnostics( - exeRes.standardError.getUnownedSlice(), - diagnostics)) || + if (SLANG_FAILED( + ParseDiagnosticUtil::parseDiagnostics( + exeRes.standardError.getUnownedSlice(), + diagnostics)) || diagnostics->getCount() <= 0) { // Write out the diagnostics which couldn't be parsed. @@ -3937,7 +3938,8 @@ TestResult runComputeComparisonImpl( nullptr, ".expected.txt", actualOutputContent, - [](const auto& a, const auto& e) { + [](const auto& a, const auto& e) + { return SLANG_SUCCEEDED( _compareWithType(a.getUnownedSlice(), e.getUnownedSlice())); }); @@ -5353,13 +5355,14 @@ SlangResult innerMain(int argc, char** argv) context.setInnerMainFunc("slangi", &SlangITool::innerMain); } - SLANG_RETURN_ON_FAIL(Options::parse( - argc, - argv, - &categorySet, - StdWriters::getOut(), - StdWriters::getError(), - &context.options)); + SLANG_RETURN_ON_FAIL( + Options::parse( + argc, + argv, + &categorySet, + StdWriters::getOut(), + StdWriters::getError(), + &context.options)); Options& options = context.options; diff --git a/tools/slang-unit-test/unit-test-com-host-callable.cpp b/tools/slang-unit-test/unit-test-com-host-callable.cpp index 3d37247b7f8..c057cfc9e9f 100644 --- a/tools/slang-unit-test/unit-test-com-host-callable.cpp +++ b/tools/slang-unit-test/unit-test-com-host-callable.cpp @@ -132,8 +132,11 @@ struct ComTestContext { const SlangPassThrough cppCompilers[] = { SLANG_PASS_THROUGH_VISUAL_STUDIO, - SLANG_PASS_THROUGH_GCC, +#if SLANG_CLANG SLANG_PASS_THROUGH_CLANG, +#else + SLANG_PASS_THROUGH_GCC, +#endif }; // Do we have a C++ compiler for (const auto compiler : cppCompilers) diff --git a/tools/slang-unit-test/unit-test-crypto.cpp b/tools/slang-unit-test/unit-test-crypto.cpp index 5899f22c543..05ba080e138 100644 --- a/tools/slang-unit-test/unit-test-crypto.cpp +++ b/tools/slang-unit-test/unit-test-crypto.cpp @@ -67,16 +67,6 @@ SLANG_UNIT_TEST(crypto) SLANG_CHECK(digest.toString() == "87d3caecb0ab82faae84d60fde994aca"); } - // compute() - { - SLANG_CHECK(MD5::compute(nullptr, 0).toString() == "d41d8cd98f00b204e9800998ecf8427e"); - const String str("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " - "tempor incididunt ut labore et dolore magna aliqua."); - SLANG_CHECK( - MD5::compute(str.getBuffer(), str.getLength()).toString() == - "818c6e601a24f72750da0f6c9b8ebe28"); - } - // SHA1 // Empty string diff --git a/tools/slang-unit-test/unit-test-fcpw-compile.cpp b/tools/slang-unit-test/unit-test-fcpw-compile.cpp index 7ed1c8e1a2c..9d2717b4428 100644 --- a/tools/slang-unit-test/unit-test-fcpw-compile.cpp +++ b/tools/slang-unit-test/unit-test-fcpw-compile.cpp @@ -18,7 +18,8 @@ using namespace Slang; SLANG_UNIT_TEST(fcpwCompile) { ComPtr globalSession; - SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); + SLANG_CHECK_ABORT( + slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); slang::TargetDesc targetDesc = {}; targetDesc.format = SLANG_SPIRV; targetDesc.profile = globalSession->findProfile("spirv_1_5"); @@ -31,16 +32,16 @@ SLANG_UNIT_TEST(fcpwCompile) macroDesc.value = "2"; sessionDesc.preprocessorMacros = ¯oDesc; ComPtr session; - SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); + SLANG_CHECK_ABORT(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); ComPtr diagnosticBlob; auto module = session->loadModule("tests/fcpw/bvh-traversal.cs.slang", diagnosticBlob.writeRef()); - SLANG_CHECK(module != nullptr); + SLANG_CHECK_ABORT(module != nullptr); ComPtr entryPoint; module->findEntryPointByName("rayIntersection", entryPoint.writeRef()); - SLANG_CHECK(entryPoint != nullptr); + SLANG_CHECK_ABORT(entryPoint != nullptr); ComPtr compositeProgram; slang::IComponentType* components[] = {module, entryPoint.get()}; @@ -49,14 +50,14 @@ SLANG_UNIT_TEST(fcpwCompile) 2, compositeProgram.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK(compositeProgram != nullptr); + SLANG_CHECK_ABORT(compositeProgram != nullptr); ComPtr linkedProgram; compositeProgram->link(linkedProgram.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK(linkedProgram != nullptr); + SLANG_CHECK_ABORT(linkedProgram != nullptr); ComPtr code; linkedProgram->getEntryPointCode(0, 0, code.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK(code != nullptr); - SLANG_CHECK(code->getBufferSize() != 0); + SLANG_CHECK_ABORT(code != nullptr); + SLANG_CHECK_ABORT(code->getBufferSize() != 0); } diff --git a/tools/slang-unit-test/unit-test-get-target-code.cpp b/tools/slang-unit-test/unit-test-get-target-code.cpp index 6a9f6ca279b..d66b4385386 100644 --- a/tools/slang-unit-test/unit-test-get-target-code.cpp +++ b/tools/slang-unit-test/unit-test-get-target-code.cpp @@ -33,7 +33,8 @@ SLANG_UNIT_TEST(getTargetCode) String userSource = userSourceBody; ComPtr globalSession; - SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); + SLANG_CHECK_ABORT( + slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); slang::TargetDesc targetDesc = {}; // Request SPIR-V disassembly so we can check the content. targetDesc.format = SLANG_SPIRV_ASM; @@ -43,7 +44,7 @@ SLANG_UNIT_TEST(getTargetCode) sessionDesc.targets = &targetDesc; ComPtr session; - SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); + SLANG_CHECK_ABORT(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); ComPtr diagnosticBlob; auto module = session->loadModuleFromSourceString( @@ -51,17 +52,17 @@ SLANG_UNIT_TEST(getTargetCode) "m.slang", userSourceBody, diagnosticBlob.writeRef()); - SLANG_CHECK(module != nullptr); + SLANG_CHECK_ABORT(module != nullptr); ComPtr linkedProgram; module->link(linkedProgram.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK(linkedProgram != nullptr); + SLANG_CHECK_ABORT(linkedProgram != nullptr); ComPtr code; linkedProgram->getTargetCode(0, code.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK(code != nullptr); + SLANG_CHECK_ABORT(code != nullptr); - SLANG_CHECK(code->getBufferSize() != 0); + SLANG_CHECK_ABORT(code->getBufferSize() != 0); UnownedStringSlice resultStr = UnownedStringSlice((char*)code->getBufferPointer()); diff --git a/tools/slang-unit-test/unit-test-persistent-cache.cpp b/tools/slang-unit-test/unit-test-persistent-cache.cpp index 95c52c596a7..82283354306 100644 --- a/tools/slang-unit-test/unit-test-persistent-cache.cpp +++ b/tools/slang-unit-test/unit-test-persistent-cache.cpp @@ -27,8 +27,11 @@ inline ComPtr createRandomBlob(size_t size) inline bool isBlobEqual(ISlangBlob* a, ISlangBlob* b) { - return a->getBufferSize() == b->getBufferSize() && - ::memcmp(a->getBufferPointer(), b->getBufferPointer(), a->getBufferSize()) == 0; + if (!a->getBufferPointer() || !b->getBufferPointer()) + { + return a->getBufferSize() == b->getBufferSize(); + } + return ::memcmp(a->getBufferPointer(), b->getBufferPointer(), a->getBufferSize()) == 0; } class Barrier From 4dae658f4475cf776140ee3f8bc49a1a6d81e8f1 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Wed, 12 Nov 2025 16:27:01 +0200 Subject: [PATCH 02/21] Fix formatting --- .../slang-downstream-compiler.cpp | 9 +++---- source/slang-glslang/slang-glslang.cpp | 24 ++++++++---------- tools/slang-test/slang-test-main.cpp | 25 ++++++++----------- 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index 1f5ce551029..190a3854aeb 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -266,11 +266,10 @@ SlangResult CommandLineDownstreamCompiler::compile( { // Holds all of the artifacts that are relatated to the final artifact - such as debug // files, ancillary file and lock files - auto artifactContainer = ArtifactUtil::createArtifact( - ArtifactDesc::make( - ArtifactKind::Container, - ArtifactPayload::Unknown, - ArtifactStyle::Unknown)); + auto artifactContainer = ArtifactUtil::createArtifact(ArtifactDesc::make( + ArtifactKind::Container, + ArtifactPayload::Unknown, + ArtifactStyle::Unknown)); auto slice = SliceUtil::asSlice(artifactList); diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index ab9491d1267..a3c4039a193 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -169,8 +169,7 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - bool - glslang_validateSPIRV(const uint32_t* contents, int contentsSize) + bool glslang_validateSPIRV(const uint32_t* contents, int contentsSize) { spv_target_env target_env = SPV_ENV_VULKAN_1_4; @@ -191,8 +190,10 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - bool - glslang_disassembleSPIRVWithResult(const uint32_t* contents, int contentsSize, char** outString) + bool glslang_disassembleSPIRVWithResult( + const uint32_t* contents, + int contentsSize, + char** outString) { static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; spv_text text; @@ -237,8 +238,7 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - bool - glslang_disassembleSPIRV(const uint32_t* contents, int contentsSize) + bool glslang_disassembleSPIRV(const uint32_t* contents, int contentsSize) { char* result = nullptr; auto succ = glslang_disassembleSPIRVWithResult(contents, contentsSize, &result); @@ -955,8 +955,7 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - int - glslang_compile_1_2(glslang_CompileRequest_1_2* inRequest) + int glslang_compile_1_2(glslang_CompileRequest_1_2* inRequest) { static ProcessInitializer g_processInitializer; if (!g_processInitializer.init()) @@ -995,8 +994,7 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - int - glslang_compile_1_1(glslang_CompileRequest_1_1* inRequest) + int glslang_compile_1_1(glslang_CompileRequest_1_1* inRequest) { glslang_CompileRequest_1_2 request; memset(&request, 0, sizeof(request)); @@ -1011,8 +1009,7 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - int - glslang_compile(glslang_CompileRequest_1_0* inRequest) + int glslang_compile(glslang_CompileRequest_1_0* inRequest) { glslang_CompileRequest_1_1 request; memset(&request, 0, sizeof(request)); @@ -1027,8 +1024,7 @@ extern "C" #else __attribute__((__visibility__("default"))) #endif - int - glslang_linkSPIRV(glslang_LinkRequest* request) + int glslang_linkSPIRV(glslang_LinkRequest* request) { if (!request || !request->modules || request->linkResult) return false; diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp index 8a9c6e837ba..2625119ac00 100644 --- a/tools/slang-test/slang-test-main.cpp +++ b/tools/slang-test/slang-test-main.cpp @@ -2625,10 +2625,9 @@ TestResult runSimpleLineTest(TestContext* context, TestInput& input) // Parse all the diagnostics so we can extract line numbers auto diagnostics = ArtifactDiagnostics::create(); - if (SLANG_FAILED( - ParseDiagnosticUtil::parseDiagnostics( - exeRes.standardError.getUnownedSlice(), - diagnostics)) || + if (SLANG_FAILED(ParseDiagnosticUtil::parseDiagnostics( + exeRes.standardError.getUnownedSlice(), + diagnostics)) || diagnostics->getCount() <= 0) { // Write out the diagnostics which couldn't be parsed. @@ -3938,8 +3937,7 @@ TestResult runComputeComparisonImpl( nullptr, ".expected.txt", actualOutputContent, - [](const auto& a, const auto& e) - { + [](const auto& a, const auto& e) { return SLANG_SUCCEEDED( _compareWithType(a.getUnownedSlice(), e.getUnownedSlice())); }); @@ -5355,14 +5353,13 @@ SlangResult innerMain(int argc, char** argv) context.setInnerMainFunc("slangi", &SlangITool::innerMain); } - SLANG_RETURN_ON_FAIL( - Options::parse( - argc, - argv, - &categorySet, - StdWriters::getOut(), - StdWriters::getError(), - &context.options)); + SLANG_RETURN_ON_FAIL(Options::parse( + argc, + argv, + &categorySet, + StdWriters::getOut(), + StdWriters::getError(), + &context.options)); Options& options = context.options; From 7e8a478ac13a93d91a0e0a928ed7fd5448e5d7d6 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Wed, 12 Nov 2025 16:28:19 +0200 Subject: [PATCH 03/21] Fix GCC -Wstring-compare warning (which I couldn't write a minimal reproducible example for) --- source/core/slang-string.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/core/slang-string.h b/source/core/slang-string.h index c9ecc315714..aebecf74f5a 100644 --- a/source/core/slang-string.h +++ b/source/core/slang-string.h @@ -662,7 +662,11 @@ class SLANG_RT_API String #endif } } - bool operator==(const char* strbuffer) const { return (strcmp(begin(), strbuffer) == 0); } + bool operator==(const char* strbuffer) const + { + const char* volatile b = begin(); + return (strcmp(b, strbuffer) == 0); + } bool operator==(const String& str) const { return (strcmp(begin(), str.begin()) == 0); } bool operator!=(const char* strbuffer) const { return (strcmp(begin(), strbuffer) != 0); } From 53b5d33efd779517758becee4204fb265ebed432 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Wed, 12 Nov 2025 16:30:47 +0200 Subject: [PATCH 04/21] Fix MSVC warning --- source/core/slang-byte-encode-util.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/source/core/slang-byte-encode-util.cpp b/source/core/slang-byte-encode-util.cpp index f3f375c605b..ce63057283e 100644 --- a/source/core/slang-byte-encode-util.cpp +++ b/source/core/slang-byte-encode-util.cpp @@ -285,17 +285,19 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int { const int numBytesRemaining = b0 - kLiteCut2 + 2 - 1; - // For unaligned access, do not use unaligned access for the last two values, - // (3rd last is safe because this value will have at least 2 bytes, followed by at worst - // two 1-byte values) otherwise we can access outside the bounds of the encoded array - // This prevents memory validation tools from causing an exception here - if (SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS && i < numValues - 2) +// For unaligned access, do not use unaligned access for the last two values, +// (3rd last is safe because this value will have at least 2 bytes, followed by at worst +// two 1-byte values) otherwise we can access outside the bounds of the encoded array +// This prevents memory validation tools from causing an exception here +#if SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS + if (i < numValues - 2) { const uint32_t mask = s_unalignedUInt32Mask[numBytesRemaining]; // const uint32_t mask = ~(uint32_t(0xffffff00) << ((numBytesRemaining - 1) * 8)); valuesOut[i] = (*(const uint32_t*)encodeIn) & mask; } else +#endif { valuesOut[i] = _decodeLiteCut2UInt32(encodeIn, numBytesRemaining); } From ffd7a0e391b669f9c7d99a9aa6d8160a7db1fc56 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Wed, 12 Nov 2025 16:43:07 +0200 Subject: [PATCH 05/21] Maybe fix macOS ld error --- cmake/CompilerFlags.cmake | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index 3c4aec3a7e1..092fdaba592 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -162,7 +162,18 @@ function(set_default_compile_options target) # No reason not to do this? Useful when using split debug info "-Wl,--build-id" ) - if(NOT ${target} STREQUAL slang-llvm) + # Workaround for slang-llvm's own classes needing RTTI for UBSan's type checks but LLVM not + # supporting RTTI, meaning slang-llvm built with RTTI will fail to link due to undefined + # LLVM typeinfo symbols + if(${target} STREQUAL slang-llvm) + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + add_supported_cxx_linker_flags( + ${target} + PRIVATE + "-Wl,-undefined,suppress" + ) + endif() + else() add_supported_cxx_linker_flags( ${target} PRIVATE From 9fe3e0225f01e1dbbb57b9399d8217fc8b9d081e Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Wed, 12 Nov 2025 16:41:11 +0200 Subject: [PATCH 06/21] Remove own TODO/NOTE comments --- cmake/SlangTarget.cmake | 1 - source/core/slang-zip-file-system.cpp | 3 --- source/slang-glslang/slang-glslang.cpp | 2 -- source/slang/slang-emit-spirv.cpp | 4 ---- source/slang/slang-parser.cpp | 2 -- 5 files changed, 12 deletions(-) diff --git a/cmake/SlangTarget.cmake b/cmake/SlangTarget.cmake index 3aacb1ef7dc..6e2fc97b1f3 100644 --- a/cmake/SlangTarget.cmake +++ b/cmake/SlangTarget.cmake @@ -348,7 +348,6 @@ function(slang_add_target dir type) VERBATIM ) else() - # NOTE(ncelik): I had disabled these, iirc it was because GDB/LLDB couldn't find some debug symbols. add_custom_command( TARGET ${target} POST_BUILD diff --git a/source/core/slang-zip-file-system.cpp b/source/core/slang-zip-file-system.cpp index 40be850742d..6d312cae9d0 100644 --- a/source/core/slang-zip-file-system.cpp +++ b/source/core/slang-zip-file-system.cpp @@ -231,14 +231,11 @@ String ZipFileSystemImpl::_getPathAtIndex(Index index) mz_zip_archive_file_stat fileStat; // Check it's added at the end - // TODO(ncelik): What does the comment above mean? if (!mz_zip_reader_file_stat(&m_archive, mz_uint(index), &fileStat)) { return String(); } - // AddressSanitizer: stack-use-after-return - // (/home/ncelik/projects/slang/source/core/slang-string.cpp:766:12) return String(UnownedStringSlice(fileStat.m_filename).trim('/')); } diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index a3c4039a193..efbff1114ff 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -533,8 +533,6 @@ static int spirv_Optimize_1_2(const glslang_CompileRequest_1_2& request) std::vector diagnostics; std::vector spirvBuffer; size_t inputBlobSize = (char*)request.inputEnd - (char*)request.inputBegin; - // TODO(ncelik): Are any diagnostics emitted in this case or should `inputBlobSize == 0` cause - // an early return? if (inputBlobSize > 0) { spirvBuffer.resize(inputBlobSize / sizeof(uint32_t)); diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 22483efad9d..b5b1e19ba99 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -9175,10 +9175,6 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex [this](SpvOp opcode, SpvInstParent* defaultParent) -> SpvInstParent* { const auto info = m_grammarInfo->opInfos.lookup(opcode); - // TODO(ncelik): tests/spirv/unknown-opcode.slang results in this func being called - // with opcode=SpvOpMax (0x7fffffff). Release/RelWithDebInfo builds would just - // invoke UB (call a [noreturn] func that does in fact return) in this case. The - // best solution would be to emit a proper diagnostic here. SLANG_RELEASE_ASSERT(info.has_value()); switch (info->class_) { diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 5de9b31d2ab..cfc3a505bf6 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -8455,8 +8455,6 @@ static std::optional parseSPIRVAsmInst(Parser* parser) const auto& opcodeWord = spirvInfo->opcodes.lookup(ret.opcode.token.getContent()); const auto& opInfo = opcodeWord ? spirvInfo->opInfos.lookup(*opcodeWord) : std::nullopt; - // UBSan: load of value 4294967295, which is not a valid value for type 'const SpvOp' (aka - // 'const SpvOp_') ret.opcode.knownValue = opcodeWord.value_or(SpvOpMax); // If we couldn't find any info, but used this assignment syntax, raise From 506d45749cf511cf52eacf7a39aebf6056e96bae Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Wed, 12 Nov 2025 19:40:16 +0200 Subject: [PATCH 07/21] Fix Clang unused variable warning --- source/core/slang-byte-encode-util.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/core/slang-byte-encode-util.cpp b/source/core/slang-byte-encode-util.cpp index ce63057283e..33614b483ab 100644 --- a/source/core/slang-byte-encode-util.cpp +++ b/source/core/slang-byte-encode-util.cpp @@ -193,6 +193,7 @@ namespace Slang } } +#if SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS static const uint32_t s_unalignedUInt32Mask[5] = { 0x00000000, 0x000000ff, @@ -200,6 +201,7 @@ static const uint32_t s_unalignedUInt32Mask[5] = { 0x00ffffff, 0xffffffff, }; +#endif // Decode the >= kLiteCut2. // in is pointing past the first byte. From 817f6db8e4a69db42b1b7c62625a90dd65c0e329 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Wed, 12 Nov 2025 20:00:17 +0200 Subject: [PATCH 08/21] Fix MSVC warning --- source/slang/slang-check-impl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index bf260657640..eef8a765ad0 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -55,7 +55,8 @@ Type* getPointedToTypeIfCanImplicitDeref(Type* type); inline int getIntValueBitSize(IntegerLiteralValue val) { - uint64_t v = val > 0 ? (uint64_t)val : -(uint64_t)val; + // Absolute value of `val` without triggering MSVC warning C4146. + uint64_t v = val > 0 ? (uint64_t)val : (~(uint64_t)val + 1); int result = 1; while (v >>= 1) { From 0a30070e859bff0e3c8dc95472dfd76009b4eac3 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Mon, 17 Nov 2025 12:05:15 +0200 Subject: [PATCH 09/21] Revert `#if 0` cleanups --- .../compiler-core/slang-downstream-compiler.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index 190a3854aeb..ef0f5300056 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -191,8 +191,23 @@ SlangResult CommandLineDownstreamCompiler::compile( } ExecuteResult exeRes; + +#if 0 + // Test + { + String line = ProcessUtil::getCommandLineString(cmdLine); + printf("%s", line.getBuffer()); + } +#endif + SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); +#if 0 + { + printf("stdout=\"%s\"\nstderr=\"%s\"\nret=%d\n", exeRes.standardOutput.getBuffer(), exeRes.standardError.getBuffer(), int(exeRes.resultCode)); + } +#endif + // Go through the list of artifacts in the artifactList and check if they exist. // // This is useful because `calcCompileProducts` is conservative and may produce artifacts for From 3d46bc297a33395025eb7aa217f3756a5e815024 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Mon, 17 Nov 2025 14:11:04 +0200 Subject: [PATCH 10/21] Re-enable SLANG_UNALIGNED_ACCESS and fix slang-byte-encode-util.cpp UB --- include/slang.h | 2 +- source/core/slang-byte-encode-util.cpp | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/slang.h b/include/slang.h index 6aae9ace049..f84dd599ed2 100644 --- a/include/slang.h +++ b/include/slang.h @@ -464,7 +464,7 @@ convention for interface methods. // Processor features #if SLANG_PROCESSOR_FAMILY_X86 #define SLANG_LITTLE_ENDIAN 1 - #define SLANG_UNALIGNED_ACCESS 0 + #define SLANG_UNALIGNED_ACCESS 1 #elif SLANG_PROCESSOR_FAMILY_ARM #if defined(__ARMEB__) #define SLANG_BIG_ENDIAN 1 diff --git a/source/core/slang-byte-encode-util.cpp b/source/core/slang-byte-encode-util.cpp index 33614b483ab..b4b6aff829d 100644 --- a/source/core/slang-byte-encode-util.cpp +++ b/source/core/slang-byte-encode-util.cpp @@ -213,13 +213,9 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int switch (numBytesRemaining) { case 2: - value = *(const uint16_t*)in; - break; case 3: - value = (uint32_t(in[2]) << 16) | (uint32_t(in[1]) << 8) | uint32_t(in[0]); - break; case 4: - value = *(const uint32_t*)in; + memcpy(&value, in, numBytesRemaining); break; default: break; @@ -296,7 +292,9 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int { const uint32_t mask = s_unalignedUInt32Mask[numBytesRemaining]; // const uint32_t mask = ~(uint32_t(0xffffff00) << ((numBytesRemaining - 1) * 8)); - valuesOut[i] = (*(const uint32_t*)encodeIn) & mask; + uint32_t temp; + memcpy(&temp, encodeIn, sizeof(temp)); + valuesOut[i] = temp & mask; } else #endif From d688ef34024621d7b8a2c97fb39b703028a62aef Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Tue, 18 Nov 2025 16:54:04 +0200 Subject: [PATCH 11/21] Fix logical right shift being used instead of arithmetic right shift --- source/slang/slang-check-expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 9329e0ac281..05709178ebe 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -2131,7 +2131,7 @@ IntVal* SemanticsVisitor::tryConstantFoldExpr( if (argCount != 2) return nullptr; resultValue = - static_cast(constArgVals[0]) >> + constArgVals[0] >> std::min(static_cast(constArgVals[1]), static_cast(64 - 1)); } #undef CASE From bc306b751af31b769a6bdbf6606c72cba60e3372 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Tue, 18 Nov 2025 18:35:46 +0200 Subject: [PATCH 12/21] Fix UIntSet::clear() call sites instead of adding non-null buffer check --- source/core/slang-dictionary.h | 2 +- source/core/slang-uint-set.cpp | 3 +-- source/core/slang-zip-file-system.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/core/slang-dictionary.h b/source/core/slang-dictionary.h index 910957a13bf..65c08706fd6 100644 --- a/source/core/slang-dictionary.h +++ b/source/core/slang-dictionary.h @@ -621,7 +621,7 @@ class OrderedDictionary { m_count = 0; m_kvPairs.clear(); - m_marks.clear(); + m_marks.resize(0); } template bool containsKey(const T& key) const diff --git a/source/core/slang-uint-set.cpp b/source/core/slang-uint-set.cpp index 45a48b2459e..36ab4888e91 100644 --- a/source/core/slang-uint-set.cpp +++ b/source/core/slang-uint-set.cpp @@ -65,8 +65,7 @@ void UIntSet::resize(UInt size) void UIntSet::clear() { - if (auto* buffer = m_buffer.getBuffer()) - ::memset(buffer, 0, m_buffer.getCount() * sizeof(Element)); + ::memset(m_buffer.getBuffer(), 0, m_buffer.getCount() * sizeof(Element)); } bool UIntSet::isEmpty() const diff --git a/source/core/slang-zip-file-system.cpp b/source/core/slang-zip-file-system.cpp index 6d312cae9d0..55a73c7aaee 100644 --- a/source/core/slang-zip-file-system.cpp +++ b/source/core/slang-zip-file-system.cpp @@ -206,7 +206,7 @@ void ZipFileSystemImpl::_rebuildMap() const mz_uint entryCount = mz_zip_reader_get_num_files(&m_archive); - m_removedSet.resizeAndClear(0); + m_removedSet.resize(0); for (mz_uint i = 0; i < entryCount; ++i) { From 626101750a74c176ed0a328110518b72e5da6204 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Wed, 19 Nov 2025 16:50:20 +0200 Subject: [PATCH 13/21] Disable Clang optimizations for `Session::get*LibraryCode()` functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang was taking around 10 minutes to compile `slang-embedded-core-module-source.cpp` with optimizations. Disabling optimizations for these functions reduced the compilation time to about 12 seconds on my machine (Intel Core Ultra 7 165H), and had no noticeable impact on run-time performance. Run-time performance with optimizations: ``` $ hyperfine --shell=none './build/generators/Release/bin/slang-bootstrap -archive-type riff-lz4 -save-core-module-bin-source slang-core-module-generated.h -save-glsl-module-bin-source slang-glsl-module-generated.h' Benchmark 1: ./build/generators/Release/bin/slang-bootstrap -archive-type riff-lz4 -save-core-module-bin-source slang-core-module-generated.h -save-glsl-module-bin-source slang-glsl-module-generated.h Time (mean ± σ): 2.545 s ± 0.035 s [User: 2.333 s, System: 0.210 s] Range (min … max): 2.496 s … 2.620 s 10 runs ``` Run-time performance without optimizations: ``` $ hyperfine --shell=none './build/generators/Release/bin/slang-bootstrap -archive-type riff-lz4 -save-core-module-bin-source slang-core-module-generated.h -save-glsl-module-bin-source slang-glsl-module-generated.h' Benchmark 1: ./build/generators/Release/bin/slang-bootstrap -archive-type riff-lz4 -save-core-module-bin-source slang-core-module-generated.h -save-glsl-module-bin-source slang-glsl-module-generated.h Time (mean ± σ): 2.564 s ± 0.039 s [User: 2.350 s, System: 0.213 s] Range (min … max): 2.512 s … 2.614 s 10 runs ``` Disabling optimizations also makes `slang-embedded-core-module-source.cpp.o` slightly smaller: - 7.84 MiB with optimizations, - 7.37 MiB without optimizations. Fixes #9054. --- .../slang-embedded-core-module-source.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source/slang-core-module/slang-embedded-core-module-source.cpp b/source/slang-core-module/slang-embedded-core-module-source.cpp index 0e03716cad6..da37553558b 100644 --- a/source/slang-core-module/slang-embedded-core-module-source.cpp +++ b/source/slang-core-module/slang-embedded-core-module-source.cpp @@ -326,6 +326,13 @@ struct IntrinsicOpInfo #define EMIT_LINE_DIRECTIVE() sb << "#line " << (__LINE__ + 1) << " \"" << path << "\"\n" +#if SLANG_CLANG +// Clang takes around 10 minutes to compile this file with optimizations, with EarlyCSEPass taking +// ~95% of the execution time. Disabling optimizations here reduces the compilation time to seconds +// and has no noticeable impact on run-time performance. +#pragma clang optimize off +#endif + ComPtr Session::getCoreLibraryCode() { #if SLANG_EMBED_CORE_MODULE_SOURCE @@ -382,3 +389,7 @@ ComPtr Session::getGLSLLibraryCode() return glslLibraryCode; } } // namespace Slang + +#if SLANG_CLANG +#pragma clang optimize on +#endif From 39971df561c717a7fbbc19aa3dafb4e0ee525aef Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Wed, 19 Nov 2025 19:30:35 +0200 Subject: [PATCH 14/21] Fix CommandLineDownstreamCompiler::compile() --- .../slang-downstream-compiler.cpp | 102 ++++++++++++------ .../compiler-core/slang-gcc-compiler-util.cpp | 3 +- .../slang-visual-studio-compiler-util.cpp | 4 +- tools/slang-test/slang-test-main.cpp | 12 +-- 4 files changed, 73 insertions(+), 48 deletions(-) diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index ef0f5300056..382548a826d 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -69,11 +69,29 @@ SlangResult CommandLineDownstreamCompiler::compile( if (!isVersionCompatible(inOptions)) { // Not possible to compile with this version of the interface. + // TODO: Fix other `IDownstreamCompiler::compile` implementations not always writing to + // `outArtifact` when returning early. + const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(SLANG_TARGET_UNKNOWN); + auto artifact = ArtifactUtil::createArtifact(targetDesc); + *outArtifact = artifact.detach(); return SLANG_E_NOT_IMPLEMENTED; } CompileOptions options = getCompatibleVersion(&inOptions); + const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); + + // Create the result artifact + auto artifact = ArtifactUtil::createArtifact(targetDesc); + + // Create the diagnostics + auto diagnostics = ArtifactDiagnostics::create(); + ArtifactUtil::addAssociated(artifact, diagnostics); + // If Slang was built with Clang or GCC and sanitizers were enabled, the same `-fsanitize=...` + // flag must be passed when linking an executable or shared library with a Slang library, or + // linking will fail. We can't instrument C++ generated from Slang code with sanitizers as they + // might report errors that we can't fix, so we separate compilation and linking into two + // commands to enable sanitizers only during linking. bool shouldSeparateCompileAndLink = options.targetType != SLANG_OBJECT_CODE; auto helper = DefaultArtifactHelper::getSingleton(); @@ -91,8 +109,13 @@ SlangResult CommandLineDownstreamCompiler::compile( { // We could use the path to the source, or use the source name/paths as defined on the // artifact For now we just go with a lock file based on "slang-generated". - SLANG_RETURN_ON_FAIL( - helper->createLockFile(asCharSlice(toSlice("slang-generated")), lockFile.writeRef())); + if (SLANG_FAILED(helper->createLockFile( + asCharSlice(toSlice("slang-generated")), + lockFile.writeRef()))) + { + *outArtifact = artifact.detach(); + return SLANG_FAIL; + } auto lockArtifact = Artifact::create( ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::Lock, ArtifactStyle::None)); @@ -108,7 +131,6 @@ SlangResult CommandLineDownstreamCompiler::compile( // Compile stage: compile source to object code ComPtr objectArtifact; - auto compileDiagnostics = ArtifactDiagnostics::create(); if (shouldSeparateCompileAndLink) { @@ -116,14 +138,22 @@ SlangResult CommandLineDownstreamCompiler::compile( compileOptions.targetType = SLANG_OBJECT_CODE; CommandLine compileCmdLine(m_cmdLine); - SLANG_RETURN_ON_FAIL(calcArgs(compileOptions, compileCmdLine)); + if (SLANG_FAILED(calcArgs(compileOptions, compileCmdLine))) + { + *outArtifact = artifact.detach(); + return SLANG_FAIL; + } List> compileArtifacts; - SLANG_RETURN_ON_FAIL(calcCompileProducts( - compileOptions, - DownstreamProductFlag::All, - lockFile, - compileArtifacts)); + if (SLANG_FAILED(calcCompileProducts( + compileOptions, + DownstreamProductFlag::All, + lockFile, + compileArtifacts))) + { + *outArtifact = artifact.detach(); + return SLANG_FAIL; + } // There should only be one object file (.o/.obj) as artifact SLANG_ASSERT(compileArtifacts.getCount() == 1); @@ -131,35 +161,36 @@ SlangResult CommandLineDownstreamCompiler::compile( objectArtifact = compileArtifacts[0]; ExecuteResult compileResult; - SLANG_RETURN_ON_FAIL(ProcessUtil::execute(compileCmdLine, compileResult)); - - SLANG_RETURN_ON_FAIL(parseOutput(compileResult, compileDiagnostics)); + if (SLANG_FAILED(ProcessUtil::execute(compileCmdLine, compileResult)) || + SLANG_FAILED(parseOutput(compileResult, diagnostics))) + { + *outArtifact = artifact.detach(); + return SLANG_FAIL; + } // If compilation failed, return the diagnostics if (compileResult.resultCode != 0 || !objectArtifact->exists()) { - auto artifact = ArtifactUtil::createArtifact( - ArtifactDescUtil::makeDescForCompileTarget(options.targetType)); - ArtifactUtil::addAssociated(artifact, compileDiagnostics); *outArtifact = artifact.detach(); - return SLANG_OK; + return SLANG_FAIL; } } // Link stage (or single-stage compile for object code targets) CommandLine cmdLine(m_cmdLine); - const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); if (shouldSeparateCompileAndLink) { - // Build link command line + // Pass compiled object to linker options.sourceArtifacts = makeSlice(objectArtifact.readRef(), 1); - SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); } - else + + // Append command line args to the end of cmdLine using the target specific function for the + // specified options + if (SLANG_FAILED(calcArgs(options, cmdLine))) { - // Single-stage compilation - SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); + *outArtifact = artifact.detach(); + return SLANG_FAIL; } // The 'productArtifact' is the main product produced from the compilation - the @@ -167,8 +198,12 @@ SlangResult CommandLineDownstreamCompiler::compile( ComPtr productArtifact; { List> artifacts; - SLANG_RETURN_ON_FAIL( - calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts)); + if (SLANG_FAILED( + calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts))) + { + *outArtifact = artifact.detach(); + return SLANG_FAIL; + } for (IArtifact* artifact : artifacts) { @@ -187,6 +222,7 @@ SlangResult CommandLineDownstreamCompiler::compile( // Somethings gone wrong if we don't find the main artifact if (!productArtifact) { + *outArtifact = artifact.detach(); return SLANG_FAIL; } @@ -200,7 +236,13 @@ SlangResult CommandLineDownstreamCompiler::compile( } #endif - SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); + if (SLANG_FAILED(ProcessUtil::execute(cmdLine, exeRes)) || + SLANG_FAILED(parseOutput(exeRes, diagnostics))) + { + // If the process failed or the output parsing failed, return the diagnostics + *outArtifact = artifact.detach(); + return SLANG_FAIL; + } #if 0 { @@ -257,16 +299,6 @@ SlangResult CommandLineDownstreamCompiler::compile( } } - // Create the result artifact - auto artifact = ArtifactUtil::createArtifact(targetDesc); - - // Createa the diagnostics - auto diagnostics = ArtifactDiagnostics::create(); - - SLANG_RETURN_ON_FAIL(parseOutput(exeRes, diagnostics)); - - ArtifactUtil::addAssociated(artifact, diagnostics); - // Find the rep from the 'main' artifact, we'll just use the same representation on the output // artifact. Sharing is desirable, because the rep owns the file. if (auto fileRep = productArtifact diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index 49db1383023..26aee9ad025 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -375,8 +375,7 @@ static SlangResult _parseGCCFamilyLine( SliceAllocator allocator; - diagnostics->reset(); - diagnostics->setRaw(SliceUtil::asCharSlice(exeRes.standardError)); + diagnostics->appendRaw(SliceUtil::asCharSlice(exeRes.standardError)); // We hold in workDiagnostics so as it is more convenient to append to the last with a // continuation also means we don't hold the allocations of building up continuations, just the diff --git a/source/compiler-core/slang-visual-studio-compiler-util.cpp b/source/compiler-core/slang-visual-studio-compiler-util.cpp index a7da11333e5..1361f364c84 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.cpp +++ b/source/compiler-core/slang-visual-studio-compiler-util.cpp @@ -502,9 +502,7 @@ static SlangResult _parseVisualStudioLine( const ExecuteResult& exeRes, IArtifactDiagnostics* diagnostics) { - diagnostics->reset(); - - diagnostics->setRaw(SliceUtil::asTerminatedCharSlice(exeRes.standardOutput)); + diagnostics->appendRaw(SliceUtil::asTerminatedCharSlice(exeRes.standardOutput)); SliceAllocator allocator; diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp index 2625119ac00..939a8dba4ed 100644 --- a/tools/slang-test/slang-test-main.cpp +++ b/tools/slang-test/slang-test-main.cpp @@ -3009,10 +3009,8 @@ static TestResult runCPPCompilerSharedLibrary(TestContext* context, TestInput& i options.modulePath = SliceUtil::asTerminatedCharSlice(modulePath); ComPtr artifact; - if (SLANG_FAILED(compiler->compile(options, artifact.writeRef()))) - { - return TestResult::Fail; - } + // Not checking the result as some tests are supposed to make compilation or linking fail. + compiler->compile(options, artifact.writeRef()); auto diagnostics = findAssociatedRepresentation(artifact); @@ -3139,10 +3137,8 @@ static TestResult runCPPCompilerExecute(TestContext* context, TestInput& input) options.modulePath = SliceUtil::asTerminatedCharSlice(modulePath); ComPtr artifact; - if (SLANG_FAILED(compiler->compile(options, artifact.writeRef()))) - { - return TestResult::Fail; - } + // Not checking the result as some tests are supposed to make compilation or linking fail. + compiler->compile(options, artifact.writeRef()); String actualOutput; From b4a3193a11ece11a603a73c9ca03d826928d005a Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Fri, 21 Nov 2025 14:06:02 +0200 Subject: [PATCH 15/21] Fix MSVC shadowing warning --- .../slang-downstream-compiler.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index 382548a826d..6ad339a45c4 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -81,11 +81,11 @@ SlangResult CommandLineDownstreamCompiler::compile( const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); // Create the result artifact - auto artifact = ArtifactUtil::createArtifact(targetDesc); + auto resultArtifact = ArtifactUtil::createArtifact(targetDesc); // Create the diagnostics auto diagnostics = ArtifactDiagnostics::create(); - ArtifactUtil::addAssociated(artifact, diagnostics); + ArtifactUtil::addAssociated(resultArtifact, diagnostics); // If Slang was built with Clang or GCC and sanitizers were enabled, the same `-fsanitize=...` // flag must be passed when linking an executable or shared library with a Slang library, or @@ -113,7 +113,7 @@ SlangResult CommandLineDownstreamCompiler::compile( asCharSlice(toSlice("slang-generated")), lockFile.writeRef()))) { - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_FAIL; } @@ -140,7 +140,7 @@ SlangResult CommandLineDownstreamCompiler::compile( CommandLine compileCmdLine(m_cmdLine); if (SLANG_FAILED(calcArgs(compileOptions, compileCmdLine))) { - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_FAIL; } @@ -151,7 +151,7 @@ SlangResult CommandLineDownstreamCompiler::compile( lockFile, compileArtifacts))) { - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_FAIL; } @@ -164,14 +164,14 @@ SlangResult CommandLineDownstreamCompiler::compile( if (SLANG_FAILED(ProcessUtil::execute(compileCmdLine, compileResult)) || SLANG_FAILED(parseOutput(compileResult, diagnostics))) { - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_FAIL; } // If compilation failed, return the diagnostics if (compileResult.resultCode != 0 || !objectArtifact->exists()) { - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_FAIL; } } @@ -189,7 +189,7 @@ SlangResult CommandLineDownstreamCompiler::compile( // specified options if (SLANG_FAILED(calcArgs(options, cmdLine))) { - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_FAIL; } @@ -201,7 +201,7 @@ SlangResult CommandLineDownstreamCompiler::compile( if (SLANG_FAILED( calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts))) { - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_FAIL; } @@ -222,7 +222,7 @@ SlangResult CommandLineDownstreamCompiler::compile( // Somethings gone wrong if we don't find the main artifact if (!productArtifact) { - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_FAIL; } @@ -240,7 +240,7 @@ SlangResult CommandLineDownstreamCompiler::compile( SLANG_FAILED(parseOutput(exeRes, diagnostics))) { // If the process failed or the output parsing failed, return the diagnostics - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_FAIL; } @@ -305,7 +305,7 @@ SlangResult CommandLineDownstreamCompiler::compile( ? findRepresentation(productArtifact) : nullptr) { - artifact->addRepresentation(fileRep); + resultArtifact->addRepresentation(fileRep); } // Add the artifact list if there is anything in it @@ -322,10 +322,10 @@ SlangResult CommandLineDownstreamCompiler::compile( artifactContainer->setChildren(slice.data, slice.count); - artifact->addAssociated(artifactContainer); + resultArtifact->addAssociated(artifactContainer); } - *outArtifact = artifact.detach(); + *outArtifact = resultArtifact.detach(); return SLANG_OK; } From 5464944d07c519e8eb2bb15bf0109d1d9e2fbe08 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Fri, 21 Nov 2025 14:06:26 +0200 Subject: [PATCH 16/21] Silence MSVC warning: "unary minus operator applied to unsigned type, result still unsigned" --- source/slang/slang-parser.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index cfc3a505bf6..5d23c31d605 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -8227,7 +8227,14 @@ static IRIntegerValue _foldIntegerPrefixOp(TokenType tokenType, IRIntegerValue v case TokenType::OpAdd: return value; case TokenType::OpSub: +#if SLANG_VC +#pragma warning(push) +#pragma warning(disable : 4146) +#endif return -static_cast(value); +#if SLANG_VC +#pragma warning(pop) +#endif default: { SLANG_ASSERT(!"Unexpected op"); From 6076e54759ee0659075d2402ea696e2b46f7ecde Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Fri, 21 Nov 2025 14:19:37 +0200 Subject: [PATCH 17/21] Document that these functions are only called once --- .../slang-core-module/slang-embedded-core-module-source.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/slang-core-module/slang-embedded-core-module-source.cpp b/source/slang-core-module/slang-embedded-core-module-source.cpp index da37553558b..de79be46f30 100644 --- a/source/slang-core-module/slang-embedded-core-module-source.cpp +++ b/source/slang-core-module/slang-embedded-core-module-source.cpp @@ -329,7 +329,9 @@ struct IntrinsicOpInfo #if SLANG_CLANG // Clang takes around 10 minutes to compile this file with optimizations, with EarlyCSEPass taking // ~95% of the execution time. Disabling optimizations here reduces the compilation time to seconds -// and has no noticeable impact on run-time performance. +// and has no noticeable impact on run-time performance. These functions are only called once, +// either at build time by slang-bootstrap, or on the first run of the slang-compiler library, +// depending on the value of the SLANG_EMBED_CORE_MODULE CMake option. #pragma clang optimize off #endif From 03c725fe641c037e855c463ef4d697fd2e4afd37 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Mon, 24 Nov 2025 14:58:54 +0200 Subject: [PATCH 18/21] Fix `SLANG_ENABLE_ASAN` CMake option Fixes sanitizers silently not being enabled due to broken checks for compiler support of sanitizer flags. Fixes non-leak errors reported by ASan when running `slang-test -api cpu` on Linux. Fixes #9097. Fixes #9098. --- cmake/CompilerFlags.cmake | 32 +++--------- cmake/LLVM.cmake | 6 +++ .../compiler-core/slang-gcc-compiler-util.cpp | 4 +- source/compiler-core/slang-lexer.cpp | 2 +- source/core/slang-blob.h | 8 +-- source/core/slang-byte-encode-util.cpp | 24 ++++----- source/core/slang-char-util.h | 5 +- source/core/slang-dictionary.h | 4 +- source/core/slang-hash.h | 2 +- source/core/slang-memory-arena.h | 23 --------- source/core/slang-riff.cpp | 7 --- source/core/slang-riff.h | 12 +++-- source/core/slang-rtti-info.h | 5 +- source/core/slang-uint-set.cpp | 3 -- source/core/slang-zip-file-system.cpp | 2 +- source/slang-glslang/CMakeLists.txt | 5 -- source/slang-glslang/slang-glslang.cpp | 7 +-- source/slang-glslang/slang-glslang.h | 2 +- source/slang/slang-check-decl.cpp | 3 -- source/slang/slang-check-expr.cpp | 24 +++------ source/slang/slang-check-impl.h | 3 +- source/slang/slang-compiler.cpp | 2 +- source/slang/slang-compiler.h | 2 +- source/slang/slang-emit-spirv.cpp | 6 +-- source/slang/slang-global-session.cpp | 8 --- source/slang/slang-global-session.h | 2 - source/slang/slang-ir-sccp.cpp | 23 ++------- source/slang/slang-ir.cpp | 5 +- source/slang/slang-parser.cpp | 11 +--- source/slang/slang-preprocessor.cpp | 5 +- source/slang/slang-reflection-json.cpp | 27 ++++------ source/slang/slang-type-layout.h | 2 +- source/slang/slang-vm-inst-impl.cpp | 14 ++--- tools/gfx/renderer-shared.cpp | 51 +++++++++---------- tools/render-test/render-test-main.cpp | 17 +++---- tools/slang-unit-test/unit-test-crypto.cpp | 10 ++++ .../unit-test-fcpw-compile.cpp | 17 +++---- .../unit-test-persistent-cache.cpp | 7 +-- .../unit-test-separate-debug.cpp | 29 ++++++----- 39 files changed, 146 insertions(+), 275 deletions(-) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index 092fdaba592..d67834e89c1 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -159,28 +159,11 @@ function(set_default_compile_options target) add_supported_cxx_linker_flags( ${target} PRIVATE + # Don't assume that symbols will be resolved at runtime + "-Wl,--no-undefined" # No reason not to do this? Useful when using split debug info "-Wl,--build-id" ) - # Workaround for slang-llvm's own classes needing RTTI for UBSan's type checks but LLVM not - # supporting RTTI, meaning slang-llvm built with RTTI will fail to link due to undefined - # LLVM typeinfo symbols - if(${target} STREQUAL slang-llvm) - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - add_supported_cxx_linker_flags( - ${target} - PRIVATE - "-Wl,-undefined,suppress" - ) - endif() - else() - add_supported_cxx_linker_flags( - ${target} - PRIVATE - # Don't assume that symbols will be resolved at runtime - "-Wl,--no-undefined" - ) - endif() endif() set_target_properties( @@ -237,18 +220,15 @@ function(set_default_compile_options target) # instead (-shared-libsan). target_compile_options( ${target} - PRIVATE -fsanitize=address,undefined -shared-libsan + PRIVATE -fsanitize=address -shared-libsan ) target_link_options( ${target} - PUBLIC -fsanitize=address,undefined -shared-libsan + PUBLIC -fsanitize=address -shared-libsan ) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options( - ${target} - PRIVATE -fsanitize=address,undefined - ) - target_link_options(${target} PUBLIC -fsanitize=address,undefined) + target_compile_options(${target} PRIVATE -fsanitize=address) + target_link_options(${target} PUBLIC -fsanitize=address) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") target_compile_options(${target} PRIVATE /fsanitize=address) target_link_options(${target} PRIVATE /INCREMENTAL:NO) diff --git a/cmake/LLVM.cmake b/cmake/LLVM.cmake index 3827a9b3e11..9a9754684a8 100644 --- a/cmake/LLVM.cmake +++ b/cmake/LLVM.cmake @@ -91,6 +91,12 @@ function(fetch_or_build_slang_llvm) target_compile_options(slang-llvm PRIVATE -wd4244 /Zc:preprocessor) endif() + if(NOT LLVM_ENABLE_RTTI) + # Make sure that we don't disable rtti if this library wasn't compiled with + # support + add_supported_cxx_flags(slang-llvm PRIVATE -fno-rtti /GR-) + endif() + # TODO: Put a check here that libslang-llvm.so doesn't have a 'NEEDED' # directive for libLLVM-21.so, it's almost certainly going to break at # runtime in surprising ways when linked alongside Mesa (or anything else diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index 26aee9ad025..feb323bf4c1 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -636,9 +636,7 @@ static SlangResult _parseGCCFamilyLine( if (options.targetType != SLANG_OBJECT_CODE) { #if SLANG_CLANG || SLANG_GCC - // Assume ASan was enabled through the SLANG_ENABLE_ASAN CMake option, meaning UBSan was - // enabled as well. - cmdLine.addArg("-fsanitize=address,undefined"); + cmdLine.addArg("-fsanitize=address"); #endif #if SLANG_CLANG cmdLine.addArg("-shared-libsan"); diff --git a/source/compiler-core/slang-lexer.cpp b/source/compiler-core/slang-lexer.cpp index fed8904856d..e4c61bab7bd 100644 --- a/source/compiler-core/slang-lexer.cpp +++ b/source/compiler-core/slang-lexer.cpp @@ -743,7 +743,7 @@ IntegerLiteralValue getIntegerLiteralValue( if (digit < 0) break; - value = static_cast(value) * base + digit; + value = value * base + digit; } if (outSuffix) diff --git a/source/core/slang-blob.h b/source/core/slang-blob.h index 4c24645d396..5277ef0cd95 100644 --- a/source/core/slang-blob.h +++ b/source/core/slang-blob.h @@ -280,13 +280,7 @@ class RawBlob : public BlobBase protected: // Ctor // NOTE! Takes a copy of the input data - RawBlob(const void* data, size_t size) - { - if (data) - { - memcpy(m_data.allocateTerminated(size), data, size); - } - } + RawBlob(const void* data, size_t size) { memcpy(m_data.allocateTerminated(size), data, size); } void* getObject(const Guid& guid); diff --git a/source/core/slang-byte-encode-util.cpp b/source/core/slang-byte-encode-util.cpp index b4b6aff829d..f3f375c605b 100644 --- a/source/core/slang-byte-encode-util.cpp +++ b/source/core/slang-byte-encode-util.cpp @@ -193,7 +193,6 @@ namespace Slang } } -#if SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS static const uint32_t s_unalignedUInt32Mask[5] = { 0x00000000, 0x000000ff, @@ -201,7 +200,6 @@ static const uint32_t s_unalignedUInt32Mask[5] = { 0x00ffffff, 0xffffffff, }; -#endif // Decode the >= kLiteCut2. // in is pointing past the first byte. @@ -213,9 +211,13 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int switch (numBytesRemaining) { case 2: + value = *(const uint16_t*)in; + break; case 3: + value = (uint32_t(in[2]) << 16) | (uint32_t(in[1]) << 8) | uint32_t(in[0]); + break; case 4: - memcpy(&value, in, numBytesRemaining); + value = *(const uint32_t*)in; break; default: break; @@ -283,21 +285,17 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int { const int numBytesRemaining = b0 - kLiteCut2 + 2 - 1; -// For unaligned access, do not use unaligned access for the last two values, -// (3rd last is safe because this value will have at least 2 bytes, followed by at worst -// two 1-byte values) otherwise we can access outside the bounds of the encoded array -// This prevents memory validation tools from causing an exception here -#if SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS - if (i < numValues - 2) + // For unaligned access, do not use unaligned access for the last two values, + // (3rd last is safe because this value will have at least 2 bytes, followed by at worst + // two 1-byte values) otherwise we can access outside the bounds of the encoded array + // This prevents memory validation tools from causing an exception here + if (SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS && i < numValues - 2) { const uint32_t mask = s_unalignedUInt32Mask[numBytesRemaining]; // const uint32_t mask = ~(uint32_t(0xffffff00) << ((numBytesRemaining - 1) * 8)); - uint32_t temp; - memcpy(&temp, encodeIn, sizeof(temp)); - valuesOut[i] = temp & mask; + valuesOut[i] = (*(const uint32_t*)encodeIn) & mask; } else -#endif { valuesOut[i] = _decodeLiteCut2UInt32(encodeIn, numBytesRemaining); } diff --git a/source/core/slang-char-util.h b/source/core/slang-char-util.h index 0c95ba0e450..896eb69567b 100644 --- a/source/core/slang-char-util.h +++ b/source/core/slang-char-util.h @@ -54,10 +54,7 @@ struct CharUtil SLANG_FORCE_INLINE static bool isOctalDigit(char c) { return c >= '0' && c <= '7'; } /// For a given character get the associated flags - SLANG_FORCE_INLINE static Flags getFlags(unsigned char c) - { - return g_charFlagMap.flags[size_t(c)]; - } + SLANG_FORCE_INLINE static Flags getFlags(char c) { return g_charFlagMap.flags[size_t(c)]; } /// Given a character return the lower case equivalent SLANG_FORCE_INLINE static char toLower(char c) diff --git a/source/core/slang-dictionary.h b/source/core/slang-dictionary.h index 65c08706fd6..b3aa354d2bc 100644 --- a/source/core/slang-dictionary.h +++ b/source/core/slang-dictionary.h @@ -473,7 +473,7 @@ class OrderedDictionary inline int getHashPos(T& key) const { const unsigned int hash = (unsigned int)getHashCode(key); - return hash * 2654435761UL % m_bucketCountMinusOne; + return ((unsigned int)(hash * 2654435761)) % m_bucketCountMinusOne; } template FindPositionResult findPosition(const T& key) const @@ -621,7 +621,7 @@ class OrderedDictionary { m_count = 0; m_kvPairs.clear(); - m_marks.resize(0); + m_marks.clear(); } template bool containsKey(const T& key) const diff --git a/source/core/slang-hash.h b/source/core/slang-hash.h index 12b7fe4badd..295f1c193ad 100644 --- a/source/core/slang-hash.h +++ b/source/core/slang-hash.h @@ -188,7 +188,7 @@ auto combineHash(H1 n, H2 m, Hs... args) // unhashed integers in here along with proper hashes of objects. static_assert(std::is_convertible_v || std::is_convertible_v); static_assert(std::is_convertible_v || std::is_convertible_v); - return combineHash((n * 16777619U) ^ m, args...); + return combineHash((n * 16777619) ^ m, args...); } template diff --git a/source/core/slang-memory-arena.h b/source/core/slang-memory-arena.h index b2b3f769acf..f08541ddb72 100644 --- a/source/core/slang-memory-arena.h +++ b/source/core/slang-memory-arena.h @@ -256,12 +256,6 @@ SLANG_FORCE_INLINE bool MemoryArena::isValid(const void* data, size_t size) cons SLANG_FORCE_INLINE void* MemoryArena::allocateUnaligned(size_t sizeInBytes) { assert(sizeInBytes > 0); - - if (!m_current) - { - return _allocateAlignedFromNewBlock(sizeInBytes, kMinAlignment); - } - // Align with the minimum alignment uint8_t* mem = m_current; uint8_t* end = mem + sizeInBytes; @@ -297,12 +291,6 @@ SLANG_FORCE_INLINE void* MemoryArena::allocateCurrentUnaligned(size_t sizeInByte SLANG_FORCE_INLINE void* MemoryArena::allocate(size_t sizeInBytes) { assert(sizeInBytes > 0); - - if (!m_current) - { - return _allocateAlignedFromNewBlock(sizeInBytes, kMinAlignment); - } - // Align with the minimum alignment const size_t alignMask = kMinAlignment - 1; uint8_t* mem = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask); @@ -322,12 +310,6 @@ SLANG_FORCE_INLINE void* MemoryArena::allocate(size_t sizeInBytes) SLANG_FORCE_INLINE void* MemoryArena::allocateAndZero(size_t sizeInBytes) { assert(sizeInBytes > 0); - - if (!m_current) - { - return _allocateAlignedFromNewBlockAndZero(sizeInBytes, kMinAlignment); - } - // Align with the minimum alignment const size_t alignMask = kMinAlignment - 1; // Implement without calling ::allocate, because in most common case we don't need to test for @@ -353,11 +335,6 @@ SLANG_FORCE_INLINE void* MemoryArena::allocateAligned(size_t sizeInBytes, size_t // Alignment must be a power of 2 assert(((alignment - 1) & alignment) == 0); - if (!m_current) - { - return _allocateAlignedFromNewBlock(sizeInBytes, alignment); - } - // Align the pointer const size_t alignMask = alignment - 1; uint8_t* memory = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask); diff --git a/source/core/slang-riff.cpp b/source/core/slang-riff.cpp index d8be80bf362..be15497f350 100644 --- a/source/core/slang-riff.cpp +++ b/source/core/slang-riff.cpp @@ -220,13 +220,6 @@ BoundsCheckedChunkPtr ListChunk::getFirstChild() const if (availableSizeForChildren == 0) return nullptr; - // There will be padding after the `ListChunk::Header` to align the first child to 8 bytes. - // However, if the parent chunk has no children, then its total size will only be the size of - // `ListChunk::Header` without the padding. Thus, we can only align the child offset after the - // previous size checks. - firstChildOffset = _roundUpToChunkAlignment(firstChildOffset); - availableSizeForChildren = reportedParentSize - firstChildOffset; - // If the parent chunk has a non-zero size, then it should // have at least one child, and the available size had better // be big enough to at least hold the *header* of that first diff --git a/source/core/slang-riff.h b/source/core/slang-riff.h index ce1803c05f1..9459c8a5516 100644 --- a/source/core/slang-riff.h +++ b/source/core/slang-riff.h @@ -119,11 +119,15 @@ struct Builder; struct Chunk { public: + // + // The starting offset of a chunk in a RIFF file + // is only guaranteed to be 2-byte aligned. + // Code that reads from a chunk must be cautious about + // the possibility of performing unaligned loads. + // + /// Required alignment for the starting offset of a chunk. - /// - /// We align chunks to 8 bytes instead of the traditional 2 bytes to avoid unaligned loads and - /// member calls on misaligned pointers, which are undefined behavior. - static const UInt32 kChunkAlignment = 8; + static const UInt32 kChunkAlignment = 2; // // Every chunk starts with a *header*, which includes diff --git a/source/core/slang-rtti-info.h b/source/core/slang-rtti-info.h index 6def698f528..9d4967cfebc 100644 --- a/source/core/slang-rtti-info.h +++ b/source/core/slang-rtti-info.h @@ -143,10 +143,7 @@ struct GetRttiTypeFuncsForZeroPod { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); - if (src) - { - ::memcpy(dst, src, sizeof(T) * count); - } + ::memcpy(dst, src, sizeof(T) * count); } static RttiTypeFuncs getFuncs() diff --git a/source/core/slang-uint-set.cpp b/source/core/slang-uint-set.cpp index 36ab4888e91..1098db6d51a 100644 --- a/source/core/slang-uint-set.cpp +++ b/source/core/slang-uint-set.cpp @@ -102,9 +102,6 @@ bool UIntSet::operator==(const UIntSet& set) const const Index minCount = Math::Min(aCount, bCount); - if (!aElems || !bElems) - return aElems == bElems; - return ::memcmp(aElems, bElems, minCount * sizeof(Element)) == 0 && _areAllZero(aElems + minCount, aCount - minCount) && _areAllZero(bElems + minCount, bCount - minCount); diff --git a/source/core/slang-zip-file-system.cpp b/source/core/slang-zip-file-system.cpp index 55a73c7aaee..6d312cae9d0 100644 --- a/source/core/slang-zip-file-system.cpp +++ b/source/core/slang-zip-file-system.cpp @@ -206,7 +206,7 @@ void ZipFileSystemImpl::_rebuildMap() const mz_uint entryCount = mz_zip_reader_get_num_files(&m_archive); - m_removedSet.resize(0); + m_removedSet.resizeAndClear(0); for (mz_uint i = 0; i < entryCount; ++i) { diff --git a/source/slang-glslang/CMakeLists.txt b/source/slang-glslang/CMakeLists.txt index 57b753cfbea..e7af32234b2 100644 --- a/source/slang-glslang/CMakeLists.txt +++ b/source/slang-glslang/CMakeLists.txt @@ -31,11 +31,6 @@ if(SLANG_ENABLE_SLANG_GLSLANG) PROPERTIES OUTPUT_NAME slang-glslang-${SLANG_VERSION_NUMERIC} ) endif() - add_supported_cxx_flags( - slang-glslang - PRIVATE - -fno-rtti - ) add_supported_cxx_linker_flags( slang-glslang PRIVATE diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index efbff1114ff..19e4b224c07 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -533,11 +533,8 @@ static int spirv_Optimize_1_2(const glslang_CompileRequest_1_2& request) std::vector diagnostics; std::vector spirvBuffer; size_t inputBlobSize = (char*)request.inputEnd - (char*)request.inputBegin; - if (inputBlobSize > 0) - { - spirvBuffer.resize(inputBlobSize / sizeof(uint32_t)); - memcpy(spirvBuffer.data(), request.inputBegin, inputBlobSize); - } + spirvBuffer.resize(inputBlobSize / sizeof(uint32_t)); + memcpy(spirvBuffer.data(), request.inputBegin, inputBlobSize); glslang_optimizeSPIRV(SPV_ENV_UNIVERSAL_1_5, request, diagnostics, spirvBuffer); if (request.outputFunc) diff --git a/source/slang-glslang/slang-glslang.h b/source/slang-glslang/slang-glslang.h index e20cff8c2b5..570bddfc3d5 100644 --- a/source/slang-glslang/slang-glslang.h +++ b/source/slang-glslang/slang-glslang.h @@ -171,5 +171,5 @@ typedef bool (*glslang_DisassembleSPIRVWithResultFunc)( const uint32_t* contents, int contentsSize, char** outString); -typedef int (*glslang_LinkSPIRVFunc)(glslang_LinkRequest* request); +typedef bool (*glslang_LinkSPIRVFunc)(glslang_LinkRequest* request); #endif diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index d5d46be5a48..dbf5d6d4ea1 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -12747,9 +12747,6 @@ void checkDerivativeAttributeImpl( DeclRef funcDeclRef = defaultFuncDeclRef.as(); auto funcThisType = getTypeForThisExpr(visitor, funcDeclRef); - if (!funcThisType) - return; - DeclRef calleeFuncDeclRef = calleeDeclRef->declRef.template as(); auto derivativeFuncThisType = getTypeForThisExpr(visitor, calleeFuncDeclRef); diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 007fd759c7c..cb67c2d1c0d 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -2104,19 +2104,19 @@ IntVal* SemanticsVisitor::tryConstantFoldExpr( } // simple binary operators -#define CASE(OP) \ - else if (opName == getName(#OP)) do \ - { \ - if (argCount != 2) \ - return nullptr; \ - resultValue = \ - static_cast(constArgVals[0]) OP static_cast(constArgVals[1]); \ - } \ +#define CASE(OP) \ + else if (opName == getName(#OP)) do \ + { \ + if (argCount != 2) \ + return nullptr; \ + resultValue = constArgVals[0] OP constArgVals[1]; \ + } \ while (0) CASE(+); // TODO: this can also be unary... CASE(*); CASE(<<); + CASE(>>); CASE(&); CASE(|); CASE(^); @@ -2126,14 +2126,6 @@ IntVal* SemanticsVisitor::tryConstantFoldExpr( CASE(<=); CASE(<); CASE(>); - else if (opName == getName(">>")) - { - if (argCount != 2) - return nullptr; - resultValue = - constArgVals[0] >> - std::min(static_cast(constArgVals[1]), static_cast(64 - 1)); - } #undef CASE // binary operators with chance of divide-by-zero // TODO: issue a suitable error in that case diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index ad6b4fe5fa6..f7dc4d714fb 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -55,8 +55,7 @@ Type* getPointedToTypeIfCanImplicitDeref(Type* type); inline int getIntValueBitSize(IntegerLiteralValue val) { - // Absolute value of `val` without triggering MSVC warning C4146. - uint64_t v = val > 0 ? (uint64_t)val : (~(uint64_t)val + 1); + uint64_t v = val > 0 ? (uint64_t)val : (uint64_t)-val; int result = 1; while (v >>= 1) { diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index f2e1889a851..4b689455b80 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -4,7 +4,7 @@ namespace Slang { -bool isValidSlangLanguageVersion(int version) +bool isValidSlangLanguageVersion(SlangLanguageVersion version) { switch (version) { diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 0d95fecf01f..934f86096a8 100644 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -249,7 +249,7 @@ bool maybeDiagnoseWarningOrError( } } -bool isValidSlangLanguageVersion(int version); +bool isValidSlangLanguageVersion(SlangLanguageVersion version); bool isValidGLSLVersion(int version); } // namespace Slang diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 78623af0444..07aaf3d2708 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -8918,9 +8918,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex fieldLine, fieldCol, builder.getIntValue(builder.getUIntType(), offset * 8), - builder.getIntValue( - builder.getUIntType(), - static_cast(sizeAlignment.size) * 8), + builder.getIntValue(builder.getUIntType(), sizeAlignment.size * 8), builder.getIntValue(builder.getUIntType(), 0)); members.add(memberType); } @@ -9198,7 +9196,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex [this](SpvOp opcode, SpvInstParent* defaultParent) -> SpvInstParent* { const auto info = m_grammarInfo->opInfos.lookup(opcode); - SLANG_RELEASE_ASSERT(info.has_value()); + SLANG_ASSERT(info.has_value()); switch (info->class_) { case SPIRVCoreGrammarInfo::OpInfo::TypeDeclaration: diff --git a/source/slang/slang-global-session.cpp b/source/slang/slang-global-session.cpp index 23e7bec73be..e6025b8aa41 100644 --- a/source/slang/slang-global-session.cpp +++ b/source/slang/slang-global-session.cpp @@ -63,12 +63,6 @@ void Session::init() auto rootASTBuilder = new RootASTBuilder(this); m_rootASTBuilder = rootASTBuilder; - // Set the root AST builder as current AST builder as a workaround for code that would get a - // null pointer from getCurrentASTBuilder() and call member functions on it, which is undefined - // behavior and is reported as such by UBSan. - m_previousASTBuilder = getCurrentASTBuilder(); - setCurrentASTBuilder(m_rootASTBuilder); - // Make sure our source manager is initialized builtinSourceManager.initialize(nullptr, nullptr); @@ -145,8 +139,6 @@ Session::~Session() // are still alive. // coreModules = decltype(coreModules)(); - - setCurrentASTBuilder(m_previousASTBuilder); } SharedASTBuilder* Session::getSharedASTBuilder() diff --git a/source/slang/slang-global-session.h b/source/slang/slang-global-session.h index 232a80f390d..22cf8a0564e 100644 --- a/source/slang/slang-global-session.h +++ b/source/slang/slang-global-session.h @@ -368,8 +368,6 @@ class Session : public RefObject, public slang::IGlobalSession /// The AST builder that will be used for builtin modules. /// RefPtr m_rootASTBuilder; - - ASTBuilder* m_previousASTBuilder; }; /* Returns SLANG_OK if pass through support is available */ diff --git a/source/slang/slang-ir-sccp.cpp b/source/slang/slang-ir-sccp.cpp index e0127a63d86..f1b647045b4 100644 --- a/source/slang/slang-ir-sccp.cpp +++ b/source/slang/slang-ir-sccp.cpp @@ -559,10 +559,7 @@ struct SCCPContext type, v0, v1, - [](IRIntegerValue c0, IRIntegerValue c1) { - return static_cast( - static_cast(c0) + static_cast(c1)); - }, + [](IRIntegerValue c0, IRIntegerValue c1) { return c0 + c1; }, [](IRFloatingPointValue c0, IRFloatingPointValue c1) { return c0 + c1; }); } LatticeVal evalSub(IRType* type, LatticeVal v0, LatticeVal v1) @@ -571,10 +568,7 @@ struct SCCPContext type, v0, v1, - [](IRIntegerValue c0, IRIntegerValue c1) { - return static_cast( - static_cast(c0) - static_cast(c1)); - }, + [](IRIntegerValue c0, IRIntegerValue c1) { return c0 - c1; }, [](IRFloatingPointValue c0, IRFloatingPointValue c1) { return c0 - c1; }); } LatticeVal evalMul(IRType* type, LatticeVal v0, LatticeVal v1) @@ -583,10 +577,7 @@ struct SCCPContext type, v0, v1, - [](IRIntegerValue c0, IRIntegerValue c1) { - return static_cast( - static_cast(c0) * static_cast(c1)); - }, + [](IRIntegerValue c0, IRIntegerValue c1) { return c0 * c1; }, [](IRFloatingPointValue c0, IRFloatingPointValue c1) { return c0 * c1; }); } LatticeVal evalDiv(IRType* type, LatticeVal v0, LatticeVal v1) @@ -735,13 +726,7 @@ struct SCCPContext type, v0, v1, - [](IRUnsignedIntegerValue c0, IRUnsignedIntegerValue c1) - { - return c0 >> std::min( - c1, - static_cast( - std::numeric_limits::digits - 1)); - }); + [](IRUnsignedIntegerValue c0, IRUnsignedIntegerValue c1) { return c0 >> c1; }); } return evalBinaryIntImpl( type, diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 0b513f4e351..2391bc25f63 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -2285,10 +2285,7 @@ IRConstant* IRBuilder::_findOrEmitConstant(IRConstant& keyInst) // Turn into pointer to avoid warning of array overrun char* dstChars = dstString.chars; // Copy the chars - if (sliceSize > 0) - { - memcpy(dstChars, slice.begin(), sliceSize); - } + memcpy(dstChars, slice.begin(), sliceSize); break; } diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 5d23c31d605..cc06e981222 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -8227,14 +8227,7 @@ static IRIntegerValue _foldIntegerPrefixOp(TokenType tokenType, IRIntegerValue v case TokenType::OpAdd: return value; case TokenType::OpSub: -#if SLANG_VC -#pragma warning(push) -#pragma warning(disable : 4146) -#endif - return -static_cast(value); -#if SLANG_VC -#pragma warning(pop) -#endif + return -value; default: { SLANG_ASSERT(!"Unexpected op"); @@ -8462,7 +8455,7 @@ static std::optional parseSPIRVAsmInst(Parser* parser) const auto& opcodeWord = spirvInfo->opcodes.lookup(ret.opcode.token.getContent()); const auto& opInfo = opcodeWord ? spirvInfo->opInfos.lookup(*opcodeWord) : std::nullopt; - ret.opcode.knownValue = opcodeWord.value_or(SpvOpMax); + ret.opcode.knownValue = opcodeWord.value_or(SpvOp(0xffffffff)); // If we couldn't find any info, but used this assignment syntax, raise // an error diff --git a/source/slang/slang-preprocessor.cpp b/source/slang/slang-preprocessor.cpp index 616b6b42822..39b1214d763 100644 --- a/source/slang/slang-preprocessor.cpp +++ b/source/slang/slang-preprocessor.cpp @@ -4406,6 +4406,7 @@ static void HandleVersionDirective(PreprocessorDirectiveContext* context) Diagnostics::unknownLanguageVersion, version); } + context->m_preprocessor->languageVersion = (SlangLanguageVersion)version; } static void HandleLanguageDirective(PreprocessorDirectiveContext* context) @@ -4453,10 +4454,9 @@ static void HandleLanguageDirective(PreprocessorDirectiveContext* context) SkipToEndOfLine(context); - if (isValidSlangLanguageVersion(version)) + if (isValidSlangLanguageVersion((SlangLanguageVersion)version)) { context->m_preprocessor->language = SourceLanguage::Slang; - context->m_preprocessor->languageVersion = (SlangLanguageVersion)version; } else { @@ -4465,6 +4465,7 @@ static void HandleLanguageDirective(PreprocessorDirectiveContext* context) Diagnostics::unknownLanguageVersion, version); } + context->m_preprocessor->languageVersion = (SlangLanguageVersion)version; } // Handle an invalid directive diff --git a/source/slang/slang-reflection-json.cpp b/source/slang/slang-reflection-json.cpp index 9acbf075ac2..d21161a1232 100644 --- a/source/slang/slang-reflection-json.cpp +++ b/source/slang/slang-reflection-json.cpp @@ -400,13 +400,10 @@ static void emitReflectionVarLayoutJSON(PrettyWriter& writer, slang::VariableLay CommaTrackerRAII commaTracker(writer); - if (var->getVariable()) + if (auto name = var->getName()) { - if (auto name = var->getName()) - { - writer.maybeComma(); - emitReflectionNameInfoJSON(writer, name); - } + writer.maybeComma(); + emitReflectionNameInfoJSON(writer, name); } writer.maybeComma(); @@ -420,10 +417,7 @@ static void emitReflectionVarLayoutJSON(PrettyWriter& writer, slang::VariableLay emitReflectionTypeLayoutJSON(writer, var->getTypeLayout()); } - if (var->getVariable()) - { - emitReflectionModifierInfoJSON(writer, var->getVariable()); - } + emitReflectionModifierInfoJSON(writer, var->getVariable()); emitReflectionVarBindingInfoJSON(writer, var); writer.dedent(); @@ -1034,17 +1028,14 @@ static void emitReflectionParamJSON(PrettyWriter& writer, slang::VariableLayoutR CommaTrackerRAII commaTracker(writer); - if (param->getVariable()) + if (auto name = param->getName()) { - if (auto name = param->getName()) - { - writer.maybeComma(); - emitReflectionNameInfoJSON(writer, name); - } - - emitReflectionModifierInfoJSON(writer, param->getVariable()); + writer.maybeComma(); + emitReflectionNameInfoJSON(writer, name); } + emitReflectionModifierInfoJSON(writer, param->getVariable()); + emitReflectionVarBindingInfoJSON(writer, param); writer.maybeComma(); diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h index 54b15ce71e1..635d5de5777 100644 --- a/source/slang/slang-type-layout.h +++ b/source/slang/slang-type-layout.h @@ -1364,7 +1364,7 @@ struct TypeLayoutContext TypeLayoutContext withSpecializationArgsOffsetBy(Int offset) const { TypeLayoutContext result = *this; - if (specializationArgCount > 0 && specializationArgCount > offset) + if (specializationArgCount > offset) { result.specializationArgCount = specializationArgCount - offset; result.specializationArgs = specializationArgs + offset; diff --git a/source/slang/slang-vm-inst-impl.cpp b/source/slang/slang-vm-inst-impl.cpp index 7a050e7b9a4..304ea09a858 100644 --- a/source/slang/slang-vm-inst-impl.cpp +++ b/source/slang/slang-vm-inst-impl.cpp @@ -17,13 +17,7 @@ ByteCodeInterpreter* convert(IByteCodeRunner* runner) template \ static void run(TR* dst, const T1* src1, const T2* src2) \ { \ - T1 tempSrc1; \ - ::memcpy((void*)&tempSrc1, (void*)src1, sizeof(T1)); \ - T2 tempSrc2; \ - ::memcpy((void*)&tempSrc2, (void*)src2, sizeof(T2)); \ - TR tempDst; \ - tempDst = (tempSrc1)op(tempSrc2); \ - ::memcpy((void*)dst, (void*)&tempDst, sizeof(TR)); \ + *dst = (*src1)op(*src2); \ } \ } @@ -714,7 +708,7 @@ void copyHandler16(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) SLANG_UNUSED(ctx); auto dst = (uint16_t*)inst->getOperand(0).getPtr(); auto src = (uint16_t*)inst->getOperand(1).getPtr(); - memcpy((void*)dst, (void*)src, sizeof(*dst)); + *dst = *src; } void copyHandler32(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) @@ -722,7 +716,7 @@ void copyHandler32(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) SLANG_UNUSED(ctx); auto dst = (uint32_t*)inst->getOperand(0).getPtr(); auto src = (uint32_t*)inst->getOperand(1).getPtr(); - memcpy((void*)dst, (void*)src, sizeof(*dst)); + *dst = *src; } void copyHandler64(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) @@ -730,7 +724,7 @@ void copyHandler64(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) SLANG_UNUSED(ctx); auto dst = (uint64_t*)inst->getOperand(0).getPtr(); auto src = (uint64_t*)inst->getOperand(1).getPtr(); - memcpy((void*)dst, (void*)src, sizeof(*dst)); + *dst = *src; } void generalCopyHandler(IByteCodeRunner* ctx, VMExecInstHeader* inst, void*) diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp index 47f83a7eada..d68ce4ee8b3 100644 --- a/tools/gfx/renderer-shared.cpp +++ b/tools/gfx/renderer-shared.cpp @@ -854,42 +854,39 @@ Result RendererBase::resetShaderCacheStats() ShaderComponentID ShaderCache::getComponentId(slang::TypeReflection* type) { ComponentKey key; - if (type) + key.typeName = UnownedStringSlice(type->getName()); + switch (type->getKind()) { - key.typeName = UnownedStringSlice(type->getName()); - switch (type->getKind()) + case slang::TypeReflection::Kind::Specialized: { - case slang::TypeReflection::Kind::Specialized: - { - auto baseType = type->getElementType(); + auto baseType = type->getElementType(); - StringBuilder builder; - builder.append(UnownedTerminatedStringSlice(baseType->getName())); + StringBuilder builder; + builder.append(UnownedTerminatedStringSlice(baseType->getName())); - auto rawType = (SlangReflectionType*)type; + auto rawType = (SlangReflectionType*)type; - builder.appendChar('<'); - SlangInt argCount = spReflectionType_getSpecializedTypeArgCount(rawType); - for (SlangInt a = 0; a < argCount; ++a) + builder.appendChar('<'); + SlangInt argCount = spReflectionType_getSpecializedTypeArgCount(rawType); + for (SlangInt a = 0; a < argCount; ++a) + { + if (a != 0) + builder.appendChar(','); + if (auto rawArgType = spReflectionType_getSpecializedTypeArgType(rawType, a)) { - if (a != 0) - builder.appendChar(','); - if (auto rawArgType = spReflectionType_getSpecializedTypeArgType(rawType, a)) - { - auto argType = (slang::TypeReflection*)rawArgType; - builder.append(argType->getName()); - } + auto argType = (slang::TypeReflection*)rawArgType; + builder.append(argType->getName()); } - builder.appendChar('>'); - key.typeName = builder.getUnownedSlice(); - key.updateHash(); - return getComponentId(key); } - // TODO: collect specialization arguments and append them to `key`. - SLANG_UNIMPLEMENTED_X("specialized type"); - default: - break; + builder.appendChar('>'); + key.typeName = builder.getUnownedSlice(); + key.updateHash(); + return getComponentId(key); } + // TODO: collect specialization arguments and append them to `key`. + SLANG_UNIMPLEMENTED_X("specialized type"); + default: + break; } key.updateHash(); return getComponentId(key); diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp index 49895433b43..c6d1e5780ca 100644 --- a/tools/render-test/render-test-main.cpp +++ b/tools/render-test/render-test-main.cpp @@ -315,18 +315,15 @@ struct AssignValsFromLayoutContext const size_t bufferSize = srcVal->bufferData.getCount() * sizeof(uint32_t); ShaderCursor dataCursor = dstCursor; - if (auto* typeLayout = dataCursor.getTypeLayout()) + switch (dataCursor.getTypeLayout()->getKind()) { - switch (typeLayout->getKind()) - { - case slang::TypeReflection::Kind::ConstantBuffer: - case slang::TypeReflection::Kind::ParameterBlock: - dataCursor = dataCursor.getDereferenced(); - break; + case slang::TypeReflection::Kind::ConstantBuffer: + case slang::TypeReflection::Kind::ParameterBlock: + dataCursor = dataCursor.getDereferenced(); + break; - default: - break; - } + default: + break; } SLANG_RETURN_ON_FAIL(dataCursor.setData(srcVal->bufferData.getBuffer(), bufferSize)); diff --git a/tools/slang-unit-test/unit-test-crypto.cpp b/tools/slang-unit-test/unit-test-crypto.cpp index 05ba080e138..5899f22c543 100644 --- a/tools/slang-unit-test/unit-test-crypto.cpp +++ b/tools/slang-unit-test/unit-test-crypto.cpp @@ -67,6 +67,16 @@ SLANG_UNIT_TEST(crypto) SLANG_CHECK(digest.toString() == "87d3caecb0ab82faae84d60fde994aca"); } + // compute() + { + SLANG_CHECK(MD5::compute(nullptr, 0).toString() == "d41d8cd98f00b204e9800998ecf8427e"); + const String str("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " + "tempor incididunt ut labore et dolore magna aliqua."); + SLANG_CHECK( + MD5::compute(str.getBuffer(), str.getLength()).toString() == + "818c6e601a24f72750da0f6c9b8ebe28"); + } + // SHA1 // Empty string diff --git a/tools/slang-unit-test/unit-test-fcpw-compile.cpp b/tools/slang-unit-test/unit-test-fcpw-compile.cpp index 9d2717b4428..7ed1c8e1a2c 100644 --- a/tools/slang-unit-test/unit-test-fcpw-compile.cpp +++ b/tools/slang-unit-test/unit-test-fcpw-compile.cpp @@ -18,8 +18,7 @@ using namespace Slang; SLANG_UNIT_TEST(fcpwCompile) { ComPtr globalSession; - SLANG_CHECK_ABORT( - slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); + SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); slang::TargetDesc targetDesc = {}; targetDesc.format = SLANG_SPIRV; targetDesc.profile = globalSession->findProfile("spirv_1_5"); @@ -32,16 +31,16 @@ SLANG_UNIT_TEST(fcpwCompile) macroDesc.value = "2"; sessionDesc.preprocessorMacros = ¯oDesc; ComPtr session; - SLANG_CHECK_ABORT(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); + SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); ComPtr diagnosticBlob; auto module = session->loadModule("tests/fcpw/bvh-traversal.cs.slang", diagnosticBlob.writeRef()); - SLANG_CHECK_ABORT(module != nullptr); + SLANG_CHECK(module != nullptr); ComPtr entryPoint; module->findEntryPointByName("rayIntersection", entryPoint.writeRef()); - SLANG_CHECK_ABORT(entryPoint != nullptr); + SLANG_CHECK(entryPoint != nullptr); ComPtr compositeProgram; slang::IComponentType* components[] = {module, entryPoint.get()}; @@ -50,14 +49,14 @@ SLANG_UNIT_TEST(fcpwCompile) 2, compositeProgram.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK_ABORT(compositeProgram != nullptr); + SLANG_CHECK(compositeProgram != nullptr); ComPtr linkedProgram; compositeProgram->link(linkedProgram.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK_ABORT(linkedProgram != nullptr); + SLANG_CHECK(linkedProgram != nullptr); ComPtr code; linkedProgram->getEntryPointCode(0, 0, code.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK_ABORT(code != nullptr); - SLANG_CHECK_ABORT(code->getBufferSize() != 0); + SLANG_CHECK(code != nullptr); + SLANG_CHECK(code->getBufferSize() != 0); } diff --git a/tools/slang-unit-test/unit-test-persistent-cache.cpp b/tools/slang-unit-test/unit-test-persistent-cache.cpp index 82283354306..95c52c596a7 100644 --- a/tools/slang-unit-test/unit-test-persistent-cache.cpp +++ b/tools/slang-unit-test/unit-test-persistent-cache.cpp @@ -27,11 +27,8 @@ inline ComPtr createRandomBlob(size_t size) inline bool isBlobEqual(ISlangBlob* a, ISlangBlob* b) { - if (!a->getBufferPointer() || !b->getBufferPointer()) - { - return a->getBufferSize() == b->getBufferSize(); - } - return ::memcmp(a->getBufferPointer(), b->getBufferPointer(), a->getBufferSize()) == 0; + return a->getBufferSize() == b->getBufferSize() && + ::memcmp(a->getBufferPointer(), b->getBufferPointer(), a->getBufferSize()) == 0; } class Barrier diff --git a/tools/slang-unit-test/unit-test-separate-debug.cpp b/tools/slang-unit-test/unit-test-separate-debug.cpp index 6ce849b0d0a..49999867bcf 100644 --- a/tools/slang-unit-test/unit-test-separate-debug.cpp +++ b/tools/slang-unit-test/unit-test-separate-debug.cpp @@ -41,7 +41,8 @@ SLANG_UNIT_TEST(separateDebug) )"; String userSource = userSourceBody; ComPtr globalSession; - SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); + SLANG_CHECK_ABORT( + slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); // Setup the target descriptor. slang::TargetDesc targetDesc = {}; @@ -67,7 +68,7 @@ SLANG_UNIT_TEST(separateDebug) sessionDesc.compilerOptionEntryCount = 2; ComPtr session; - SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); + SLANG_CHECK_ABORT(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); // Compile the module. ComPtr diagnosticBlob; @@ -76,7 +77,7 @@ SLANG_UNIT_TEST(separateDebug) "m.slang", userSourceBody, diagnosticBlob.writeRef()); - SLANG_CHECK(module != nullptr); + SLANG_CHECK_ABORT(module != nullptr); ComPtr entryPoint; module->findAndCheckEntryPoint( @@ -84,7 +85,7 @@ SLANG_UNIT_TEST(separateDebug) SLANG_STAGE_COMPUTE, entryPoint.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK(entryPoint != nullptr); + SLANG_CHECK_ABORT(entryPoint != nullptr); ComPtr compositeProgram; slang::IComponentType* components[] = {module, entryPoint.get()}; @@ -93,11 +94,11 @@ SLANG_UNIT_TEST(separateDebug) 2, compositeProgram.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK(compositeProgram != nullptr); + SLANG_CHECK_ABORT(compositeProgram != nullptr); ComPtr linkedProgram; compositeProgram->link(linkedProgram.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK(linkedProgram != nullptr); + SLANG_CHECK_ABORT(linkedProgram != nullptr); // Use getEntryPointCompileResult to get the base and debug spirv, and metadata // containing the debug build identifier. @@ -110,22 +111,22 @@ SLANG_UNIT_TEST(separateDebug) // to query for it, and then use it to get the results. ComPtr compileResult; ComPtr linkedProgram2; - SLANG_CHECK( + SLANG_CHECK_ABORT( linkedProgram->queryInterface(SLANG_IID_PPV_ARGS(linkedProgram2.writeRef())) == SLANG_OK); auto result = linkedProgram2->getEntryPointCompileResult( 0, 0, compileResult.writeRef(), diagnosticBlob.writeRef()); - SLANG_CHECK(result == SLANG_OK); - SLANG_CHECK(compileResult != nullptr); - SLANG_CHECK(compileResult->getItemCount() == 2); - SLANG_CHECK(compileResult->getItemData(0, code.writeRef()) == SLANG_OK); - SLANG_CHECK(compileResult->getItemData(1, debugCode.writeRef()) == SLANG_OK); - SLANG_CHECK(compileResult->getMetadata(metadata.writeRef()) == SLANG_OK); + SLANG_CHECK_ABORT(result == SLANG_OK); + SLANG_CHECK_ABORT(compileResult != nullptr); + SLANG_CHECK_ABORT(compileResult->getItemCount() == 2); + SLANG_CHECK_ABORT(compileResult->getItemData(0, code.writeRef()) == SLANG_OK); + SLANG_CHECK_ABORT(compileResult->getItemData(1, debugCode.writeRef()) == SLANG_OK); + SLANG_CHECK_ABORT(compileResult->getMetadata(metadata.writeRef()) == SLANG_OK); debugBuildIdentifier = metadata->getDebugBuildIdentifier(); - SLANG_CHECK(debugBuildIdentifier != nullptr); + SLANG_CHECK_ABORT(debugBuildIdentifier != nullptr); // Get the data for the stripped SPIRV. // This is already verified by the separate-debug.slang test but we From f3630e28cf4fbcdbdd11db870f5d2cf17e3d9057 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Mon, 24 Nov 2025 15:42:25 +0200 Subject: [PATCH 19/21] Minor refactorings --- cmake/CompilerFlags.cmake | 4 +-- .../slang-downstream-compiler.cpp | 8 +++-- .../compiler-core/slang-gcc-compiler-util.cpp | 35 +++++++------------ 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index d67834e89c1..b5bf0bfe6ab 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -216,8 +216,8 @@ function(set_default_compile_options target) if(SLANG_ENABLE_ASAN) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # Clang defaults to statically linking the sanitizer runtime (except on macOS/Darwin), - # which is not compatible with -Wl,--no-undefined, so we need to use dynamic linking - # instead (-shared-libsan). + # which is not compatible with `-Wl,--no-undefined`, so we need to use dynamic linking + # instead (`-shared-libsan`). target_compile_options( ${target} PRIVATE -fsanitize=address -shared-libsan diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index 6ad339a45c4..ee38a067666 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -90,7 +90,7 @@ SlangResult CommandLineDownstreamCompiler::compile( // If Slang was built with Clang or GCC and sanitizers were enabled, the same `-fsanitize=...` // flag must be passed when linking an executable or shared library with a Slang library, or // linking will fail. We can't instrument C++ generated from Slang code with sanitizers as they - // might report errors that we can't fix, so we separate compilation and linking into two + // might report errors that can't be fixed, so we separate compilation and linking into two // commands to enable sanitizers only during linking. bool shouldSeparateCompileAndLink = options.targetType != SLANG_OBJECT_CODE; @@ -129,7 +129,8 @@ SlangResult CommandLineDownstreamCompiler::compile( options.modulePath = SliceUtil::asTerminatedCharSlice(modulePath); } - // Compile stage: compile source to object code + // Compile stage if executable or library target: compile source to object code + ComPtr objectArtifact; if (shouldSeparateCompileAndLink) @@ -176,7 +177,8 @@ SlangResult CommandLineDownstreamCompiler::compile( } } - // Link stage (or single-stage compile for object code targets) + // Link stage if executable or library target, or single-stage compile if object code target + CommandLine cmdLine(m_cmdLine); if (shouldSeparateCompileAndLink) diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index feb323bf4c1..319ada1dca3 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -602,12 +602,6 @@ static SlangResult _parseGCCFamilyLine( { // Shared library cmdLine.addArg("-shared"); - - if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind)) - { - // Position independent - cmdLine.addArg("-fPIC"); - } break; } case SLANG_HOST_EXECUTABLE: @@ -620,17 +614,18 @@ static SlangResult _parseGCCFamilyLine( // Don't link, just produce object file cmdLine.addArg("-c"); - if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind)) - { - // Position independent - cmdLine.addArg("-fPIC"); - } break; } default: break; } + if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind)) + { + // Position independent + cmdLine.addArg("-fPIC"); + } + #if defined(__has_feature) #if __has_feature(address_sanitizer) if (options.targetType != SLANG_OBJECT_CODE) @@ -697,18 +692,14 @@ static SlangResult _parseGCCFamilyLine( cmdLine.addArg(fileRep->getPath()); } - // Add linker-specific options only when not compiling to object code - if (options.targetType != SLANG_OBJECT_CODE) - { - // Add the library paths + // Add the library paths - if (options.libraryPaths.count && (options.targetType == SLANG_HOST_EXECUTABLE)) - { - if (PlatformUtil::isFamily(PlatformFamily::Apple, platformKind)) - cmdLine.addArg("-Wl,-rpath,@loader_path,-rpath,@loader_path/../lib"); - else - cmdLine.addArg("-Wl,-rpath,$ORIGIN,-rpath,$ORIGIN/../lib"); - } + if (options.libraryPaths.count && (options.targetType == SLANG_HOST_EXECUTABLE)) + { + if (PlatformUtil::isFamily(PlatformFamily::Apple, platformKind)) + cmdLine.addArg("-Wl,-rpath,@loader_path,-rpath,@loader_path/../lib"); + else + cmdLine.addArg("-Wl,-rpath,$ORIGIN,-rpath,$ORIGIN/../lib"); } StringSlicePool libPathPool(StringSlicePool::Style::Default); From d33b400381ddf84cff4a10976d4beed26f695bdd Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Mon, 24 Nov 2025 15:50:15 +0200 Subject: [PATCH 20/21] Emit CMake FATAL_ERROR instead of warning if the C++ compiler is unsupported --- cmake/CompilerFlags.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index b5bf0bfe6ab..cd01ffbdef9 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -233,7 +233,7 @@ function(set_default_compile_options target) target_compile_options(${target} PRIVATE /fsanitize=address) target_link_options(${target} PRIVATE /INCREMENTAL:NO) else() - message(WARNING "Not enabling sanitizers: unsupported C++ compiler") + message(FATAL_ERROR "SLANG_ENABLE_ASAN: unsupported C++ compiler") endif() endif() From 6647622e502aa1637a8b038f4f8357a1b9415663 Mon Sep 17 00:00:00 2001 From: Nicolas Celik Date: Mon, 1 Dec 2025 14:37:56 +0200 Subject: [PATCH 21/21] Fix macOS build and Metal errors * The `SLANG_ENABLE_ASAN` CMake option must support `AppleClang` as C++ compiler ID. * `-fsanitize=...` must not be passed to the Metal compiler which doesn't support it. * The Metal compiler should be run using `xcrun metal`, which sets the `SDKROOT` environment variable, instead of running the `metal` executable directly. * `-fPIC` must not be passed to the Metal compiler or we will get `Compiler encountered an internal error` at run time when calling `newComputePipelineState`. --- cmake/CompilerFlags.cmake | 6 +-- .../slang-downstream-compiler.cpp | 21 +++++--- .../compiler-core/slang-gcc-compiler-util.cpp | 53 ++++++++++++++----- .../compiler-core/slang-gcc-compiler-util.h | 4 ++ source/compiler-core/slang-metal-compiler.cpp | 37 ++++--------- 5 files changed, 71 insertions(+), 50 deletions(-) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index cd01ffbdef9..ecd4a4e7f16 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -214,7 +214,7 @@ function(set_default_compile_options target) ) if(SLANG_ENABLE_ASAN) - if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # Clang defaults to statically linking the sanitizer runtime (except on macOS/Darwin), # which is not compatible with `-Wl,--no-undefined`, so we need to use dynamic linking # instead (`-shared-libsan`). @@ -226,10 +226,10 @@ function(set_default_compile_options target) ${target} PUBLIC -fsanitize=address -shared-libsan ) - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") target_compile_options(${target} PRIVATE -fsanitize=address) target_link_options(${target} PUBLIC -fsanitize=address) - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") target_compile_options(${target} PRIVATE /fsanitize=address) target_link_options(${target} PRIVATE /INCREMENTAL:NO) else() diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index ee38a067666..d0d50e53d50 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -87,12 +87,21 @@ SlangResult CommandLineDownstreamCompiler::compile( auto diagnostics = ArtifactDiagnostics::create(); ArtifactUtil::addAssociated(resultArtifact, diagnostics); - // If Slang was built with Clang or GCC and sanitizers were enabled, the same `-fsanitize=...` - // flag must be passed when linking an executable or shared library with a Slang library, or - // linking will fail. We can't instrument C++ generated from Slang code with sanitizers as they - // might report errors that can't be fixed, so we separate compilation and linking into two - // commands to enable sanitizers only during linking. - bool shouldSeparateCompileAndLink = options.targetType != SLANG_OBJECT_CODE; + // If Slang was built using Clang or GCC and with sanitizers, the same `-fsanitize=...` flag + // must be used when linking an executable or shared library with a Slang library, or it will + // fail to link. We can't instrument Slang-generated C++ with sanitizers as they might report + // errors that can't be fixed, so we separate compilation and linking into two commands to + // enable sanitizers only during linking. + bool shouldSeparateCompileAndLink = false; + switch (options.targetType) + { + case SLANG_HOST_EXECUTABLE: + case SLANG_SHADER_SHARED_LIBRARY: + case SLANG_SHADER_HOST_CALLABLE: + case SLANG_HOST_SHARED_LIBRARY: + shouldSeparateCompileAndLink = true; + break; + } auto helper = DefaultArtifactHelper::getSingleton(); diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index 319ada1dca3..e41fc144725 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -101,6 +101,14 @@ SlangResult GCCDownstreamCompilerUtil::calcVersion( { CommandLine cmdLine; cmdLine.setExecutableLocation(exe); + + return calcVersion(cmdLine, outDesc); +} + +SlangResult GCCDownstreamCompilerUtil::calcVersion( + CommandLine cmdLine, + DownstreamCompilerDesc& outDesc) +{ cmdLine.addArg("-v"); ExecuteResult exeRes; @@ -620,25 +628,34 @@ static SlangResult _parseGCCFamilyLine( break; } - if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind)) + switch (options.targetType) { - // Position independent - cmdLine.addArg("-fPIC"); - } - + case SLANG_HOST_EXECUTABLE: + case SLANG_SHADER_SHARED_LIBRARY: + case SLANG_SHADER_HOST_CALLABLE: + case SLANG_HOST_SHARED_LIBRARY: + // If Slang was built using Clang or GCC and with sanitizers, the same `-fsanitize=...` flag + // used for Slang must also be used when linking executables and shared libraries that we + // might be trying to link with Slang libraries. #if defined(__has_feature) #if __has_feature(address_sanitizer) - if (options.targetType != SLANG_OBJECT_CODE) - { #if SLANG_CLANG || SLANG_GCC cmdLine.addArg("-fsanitize=address"); -#endif +#endif // SLANG_CLANG || SLANG_GCC #if SLANG_CLANG cmdLine.addArg("-shared-libsan"); -#endif +#endif // SLANG_CLANG +#endif // __has_feature(address_sanitizer) +#endif // defined(__has_feature) + [[fallthrough]]; + + case SLANG_OBJECT_CODE: + if (PlatformUtil::isFamily(PlatformFamily::Unix, platformKind)) + { + // Position independent + cmdLine.addArg("-fPIC"); + } } -#endif -#endif // Add defines for (const auto& define : options.defines) @@ -769,13 +786,23 @@ static SlangResult _parseGCCFamilyLine( /* static */ SlangResult GCCDownstreamCompilerUtil::createCompiler( const ExecutableLocation& exe, ComPtr& outCompiler) +{ + CommandLine cmdLine; + cmdLine.setExecutableLocation(exe); + + return createCompiler(cmdLine, outCompiler); +} + +/* static */ SlangResult GCCDownstreamCompilerUtil::createCompiler( + const CommandLine& cmdLine, + ComPtr& outCompiler) { DownstreamCompilerDesc desc; - SLANG_RETURN_ON_FAIL(GCCDownstreamCompilerUtil::calcVersion(exe, desc)); + SLANG_RETURN_ON_FAIL(GCCDownstreamCompilerUtil::calcVersion(cmdLine, desc)); auto compiler = new GCCDownstreamCompiler(desc); ComPtr compilerIntf(compiler); - compiler->m_cmdLine.setExecutableLocation(exe); + compiler->m_cmdLine = cmdLine; outCompiler.swap(compilerIntf); return SLANG_OK; diff --git a/source/compiler-core/slang-gcc-compiler-util.h b/source/compiler-core/slang-gcc-compiler-util.h index e15701f94a9..99ced53f36f 100644 --- a/source/compiler-core/slang-gcc-compiler-util.h +++ b/source/compiler-core/slang-gcc-compiler-util.h @@ -18,6 +18,7 @@ struct GCCDownstreamCompilerUtil : public DownstreamCompilerUtilBase /// Runs the exe, and extracts the version info into outDesc static SlangResult calcVersion(const ExecutableLocation& exe, DownstreamCompilerDesc& outDesc); + static SlangResult calcVersion(CommandLine exe, DownstreamCompilerDesc& outDesc); /// Calculate gcc family compilers (including clang) cmdLine arguments from options static SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine); @@ -37,6 +38,9 @@ struct GCCDownstreamCompilerUtil : public DownstreamCompilerUtilBase static SlangResult createCompiler( const ExecutableLocation& exe, ComPtr& outCompiler); + static SlangResult createCompiler( + const CommandLine& cmdLine, + ComPtr& outCompiler); /// Finds GCC compiler/s and adds them to the set static SlangResult locateGCCCompilers( diff --git a/source/compiler-core/slang-metal-compiler.cpp b/source/compiler-core/slang-metal-compiler.cpp index af455a0f7f8..5e901d5f40b 100644 --- a/source/compiler-core/slang-metal-compiler.cpp +++ b/source/compiler-core/slang-metal-compiler.cpp @@ -16,12 +16,9 @@ class MetalDownstreamCompiler : public DownstreamCompilerBase // to create the inner compiler and wrap it here. // ComPtr cppCompiler; - String executablePath; - MetalDownstreamCompiler(ComPtr& innerCompiler, String path) - : DownstreamCompilerBase(innerCompiler->getDesc()) - , cppCompiler(innerCompiler) - , executablePath(path) + MetalDownstreamCompiler(ComPtr& innerCompiler) + : DownstreamCompilerBase(innerCompiler->getDesc()), cppCompiler(innerCompiler) { } @@ -47,9 +44,10 @@ class MetalDownstreamCompiler : public DownstreamCompilerBase { // Use metal-objdump to disassemble the Metal IR. - ExecutableLocation exeLocation(executablePath, "metal-objdump"); + ExecutableLocation exeLocation("xcrun"); CommandLine cmdLine; cmdLine.setExecutableLocation(exeLocation); + cmdLine.addArg("metal-objdump"); cmdLine.addArg("--disassemble"); ComPtr srcFile; SLANG_RETURN_ON_FAIL(from->requireFile(IArtifact::Keep::No, srcFile.writeRef())); @@ -64,37 +62,19 @@ class MetalDownstreamCompiler : public DownstreamCompilerBase } }; -static SlangResult locateMetalCompiler(const String& path, DownstreamCompilerSet* set) +static SlangResult locateMetalCompiler(DownstreamCompilerSet* set) { ComPtr innerCppCompiler; - ExecutableLocation metalcLocation = ExecutableLocation(path, "metal"); - - String metalSDKPath = path; - -#if defined(SLANG_APPLE_FAMILY) - // Use xcrun command to find the metal compiler. CommandLine xcrunCmdLine; ExecutableLocation xcrunLocation("xcrun"); xcrunCmdLine.setExecutableLocation(xcrunLocation); - xcrunCmdLine.addArg("--sdk"); - xcrunCmdLine.addArg("macosx"); - xcrunCmdLine.addArg("--find"); xcrunCmdLine.addArg("metal"); - ExecuteResult exeRes; - if (SLANG_SUCCEEDED(ProcessUtil::execute(xcrunCmdLine, exeRes))) - { - String metalPath = exeRes.standardOutput.trim(); - metalcLocation = ExecutableLocation(ExecutableLocation::Type::Path, metalPath); - metalSDKPath = Path::getParentDirectory(metalcLocation.m_pathOrName); - } -#endif - SLANG_RETURN_ON_FAIL( - GCCDownstreamCompilerUtil::createCompiler(metalcLocation, innerCppCompiler)); + SLANG_RETURN_ON_FAIL(GCCDownstreamCompilerUtil::createCompiler(xcrunCmdLine, innerCppCompiler)); ComPtr compiler = - ComPtr(new MetalDownstreamCompiler(innerCppCompiler, metalSDKPath)); + ComPtr(new MetalDownstreamCompiler(innerCppCompiler)); set->addCompiler(compiler); return SLANG_OK; } @@ -104,8 +84,9 @@ SlangResult MetalDownstreamCompilerUtil::locateCompilers( ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) { + SLANG_UNUSED(path); SLANG_UNUSED(loader); - return locateMetalCompiler(path, set); + return locateMetalCompiler(set); } } // namespace Slang