summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2020-08-18 13:42:46 -0400
committerGitHub <noreply@github.com>2020-08-18 13:42:46 -0400
commit9abcb6ea24dbc7184c3a2ad9f4458f63f8901928 (patch)
tree155ae80bbd15efae88b5852b7bb24804a70af405
parent697e7fbbbb5dcb448c03a9887e6ef09e328505ef (diff)
Support for float atomics on RWByteAddressBuffer (#1502)
* Fix premake5.lua so it uses the new path needed for OpenCLDebugInfo100.h * Keep including the includes directory. * Added the spirv-tools-generated files. * We don't need to include the spirv/unified1 path because the files needed are actually in the spirv-tools-generated folder. * Put the build_info.h glslang generated files in external/glslang-generated. Alter premake5.lua to pick up that header. * First pass at documenting how to build glslang and spirv-tools. * Improved glsl/spir-v tools README.md * Added revision.h * Change how gResources is calculated. Update about revision.h * Update docs a little. * Split out spirv-tools into a separate project for building glslang. This was not necessary on linux, but *is* necessary on windows, because there is a file disassemble.cpp in spirv-tools and in glslang, and this leads to VS choosing only one. With the separate library, the problem is resolved. * Fix direct-spirv-emit output. * Update to latest version of spirv headers and spirv-tools. * Upgrade submodule version of glslang in external. * Add fPIC to build options of slang-spirv-tools * WIP adding support for InterlockedAddFp32 * Upgrade slang-binaries to have new glslang. * Fix issues with Windows slang-glslang binaries, via update of slang-binaries used. * WIP - atomicAdd. This solution can't work as we can't do (float*) in glsl. * WIP on atomic float ops. * Added checking for multiple decls that takes into account __target_intrinsic and __specialized_for_target. First pass impl of atomic add on float for glsl. * Split __atomicAdd so extensions are applied appropriately. * Made Dxc/Fxc support includes. Use HLSL prelude to pass the path to nvapi Added -nv-api-path * Refactor around IncludeHandler and impl of IncludeSystem * slang-include-handler -> slang-include-system Have IncludeHandler/Impl defined in slang-preprocessor * Small comment improvements. * Document atomic float add addition in target-compatibility.md. * CUDA float atomic support on RWByteAddressBuffer. * Add atomic-float-byte-address-buffer-cross.slang * Removed inappropriate-once.slang - the test is no longer valid when a file is loaded and has a unique identity by default. A test could be made, but would require an API call to create the file (so no unique id). Improved handling of loadFile - uses uniqueId if has one. * Work around for testing target overlaps - to avoid exceptions on adding targets. Simplify PathInfo setup. Modify single-target-intrinsic.slang - it no longer failed because there were no longer multiple definitions for the same target. Co-authored-by: Tim Foley <tfoleyNV@users.noreply.github.com>
-rw-r--r--docs/target-compatibility.md18
-rw-r--r--prelude/slang-cuda-prelude.h7
-rw-r--r--source/core/slang-test-tool-util.cpp45
-rw-r--r--source/core/slang-test-tool-util.h8
-rw-r--r--source/slang/hlsl.meta.slang62
-rw-r--r--source/slang/slang-check-decl.cpp91
-rwxr-xr-xsource/slang/slang-compiler.cpp109
-rwxr-xr-xsource/slang/slang-compiler.h41
-rwxr-xr-xsource/slang/slang-dxc-support.cpp80
-rw-r--r--source/slang/slang-include-system.cpp139
-rw-r--r--source/slang/slang-include-system.h62
-rw-r--r--source/slang/slang-ir-byte-address-legalize.cpp27
-rw-r--r--source/slang/slang-ir-inst-defs.h3
-rw-r--r--source/slang/slang-preprocessor.h28
-rw-r--r--source/slang/slang-source-loc.cpp29
-rw-r--r--source/slang/slang-source-loc.h5
-rw-r--r--source/slang/slang.cpp115
-rw-r--r--source/slang/slang.vcxproj2
-rw-r--r--source/slang/slang.vcxproj.filters6
-rw-r--r--tests/compute/byte-address-buffer.slang2
-rw-r--r--tests/diagnostics/single-target-intrinsic.slang3
-rw-r--r--tests/diagnostics/single-target-intrinsic.slang.expected4
-rw-r--r--tests/preprocessor/inappropriate-once.slang6
-rw-r--r--tests/preprocessor/inappropriate-once.slang.expected6
-rw-r--r--tests/slang-extension/atomic-float-byte-address-buffer-cross.slang27
-rw-r--r--tests/slang-extension/atomic-float-byte-address-buffer-cross.slang.glsl51
-rw-r--r--tests/slang-extension/atomic-float-byte-address-buffer.slang34
-rw-r--r--tests/slang-extension/atomic-float-byte-address-buffer.slang.expected.txt4
-rw-r--r--tools/slang-test/options.cpp10
-rw-r--r--tools/slang-test/options.h2
-rw-r--r--tools/slang-test/slang-test-main.cpp15
31 files changed, 776 insertions, 265 deletions
diff --git a/docs/target-compatibility.md b/docs/target-compatibility.md
index e4c4a8496..31ae06055 100644
--- a/docs/target-compatibility.md
+++ b/docs/target-compatibility.md
@@ -40,6 +40,7 @@ Items with ^ means there is some discussion about support later in the document
| Atomics | Yes | Yes | Yes | Yes | No +
| Atomics on RWBuffer | Yes | Yes | Yes | No | No +
| Sampler Feedback | No | Yes | No + | No | Yes ^
+| RWByteAddressBuffer Atomic | No | Yes ^ | Yes ^ | Yes | No +
## Half Type
@@ -179,3 +180,20 @@ There doesn't not appear to be a similar feature available in Vulkan yet, but wh
For CPU targets there is the IFeedbackTexture interface that requires an implemention for use. Slang does not currently include CPU implementations for texture types.
+## RWByteAddressBuffer Atomic
+
+Currently feature allows atomic float additions on RWByteAddressBuffer. A future update will broader types supported. There are methods on RWByteAddressBuffer...
+
+```
+void RWByteAddressBuffer::InterlockedAddFp32(uint byteAddress, float valueToAdd, out float originalValue);
+void RWByteAddressBuffer::InterlockedAddFp32(uint byteAddress, float valueToAdd);
+```
+
+On HLSL based targets this functionality is achieved using [nvAPI](https://developer.nvidia.com/nvapi) based functionality. Therefore for the feature to work you must have nvAPI installed on your system. Then the 'prelude' functionality allows via the API for an include (or the text) of the relevent files. To see how to do this in practice look at the function `setSessionDefaultPrelude`. This makes the prelude for HLSL hold an include to the *absolute* path to the required include file `nvHLSLExtns.h`. As an absolute path is used, it means other includes that includes, look in the correct place without having to set up special include paths.
+
+To use nvAPI it is nessary to specify a unordered access views (UAV) based 'u' register that will be used to communicate with nvAPI. Note! Slang does not do any special handling around this, it will be necessary for application code to ensure the UAV is either guarenteed to not collide with what Slang assigns, or it's specified (but not used) in the Slang source. The u register number has to be specified also to the nvAPI runtime library.
+
+On Vulkan, the [`GL_EXT_shader_atomic_float`](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_atomic_float.html) extension is required.
+
+
+
diff --git a/prelude/slang-cuda-prelude.h b/prelude/slang-cuda-prelude.h
index 8bbac9eff..feec1562a 100644
--- a/prelude/slang-cuda-prelude.h
+++ b/prelude/slang-cuda-prelude.h
@@ -472,6 +472,13 @@ struct RWByteAddressBuffer
*(T*)((char*)data + offset) = value;
}
+ /// Can be used in stdlib to gain access
+ SLANG_CUDA_CALL uint* _getPtrAt(size_t offset)
+ {
+ SLANG_PRELUDE_ASSERT(offset + sizeof(T) <= sizeInBytes && (offset & (alignof(T)-1)) == 0);
+ return (uint*)(((char*)data) + offset);
+ }
+
uint32_t* data;
size_t sizeInBytes; //< Must be multiple of 4
};
diff --git a/source/core/slang-test-tool-util.cpp b/source/core/slang-test-tool-util.cpp
index f8e163758..5e31dc4d7 100644
--- a/source/core/slang-test-tool-util.cpp
+++ b/source/core/slang-test-tool-util.cpp
@@ -75,29 +75,54 @@ static SlangResult _addCUDAPrelude(const String& parentPath, slang::IGlobalSessi
return SLANG_OK;
}
-/* static */SlangResult TestToolUtil::setSessionDefaultPrelude(const char* exePath, slang::IGlobalSession* session)
+/* static */SlangResult TestToolUtil::setSessionDefaultPrelude(const PreludeInfo& info, slang::IGlobalSession* session)
{
// Set the prelude to a path
- String canonicalPath;
- if (SLANG_SUCCEEDED(Path::getCanonical(exePath, canonicalPath)))
+ if (info.exePath)
{
- // Get the directory
- String parentPath = Path::getParentDirectory(canonicalPath);
+ String exePath(info.exePath);
- if (SLANG_FAILED(_addCPPPrelude(parentPath, session)))
+ String canonicalPath;
+ if (SLANG_SUCCEEDED(Path::getCanonical(exePath, canonicalPath)))
{
- SLANG_ASSERT(!"Couldn't find the C++ prelude relative to the executable");
+ // Get the directory
+ String parentPath = Path::getParentDirectory(canonicalPath);
+
+ if (SLANG_FAILED(_addCPPPrelude(parentPath, session)))
+ {
+ SLANG_ASSERT(!"Couldn't find the C++ prelude relative to the executable");
+ }
+
+ if (SLANG_FAILED(_addCUDAPrelude(parentPath, session)))
+ {
+ SLANG_ASSERT(!"Couldn't find the CUDA prelude relative to the executable");
+ }
}
-
- if (SLANG_FAILED(_addCUDAPrelude(parentPath, session)))
+ }
+ // If the nvAPI path is set, and we find nvHLSLExtns.h, put that in the HLSL prelude
+ if (info.nvAPIPath)
+ {
+ String includePath;
+ if (SLANG_SUCCEEDED(_calcIncludePath(info.nvAPIPath, "nvHLSLExtns.h", includePath)))
{
- SLANG_ASSERT(!"Couldn't find the CUDA prelude relative to the executable");
+ StringBuilder buf;
+
+ buf << "#include \"" << includePath << "\"\n";
+
+ session->setLanguagePrelude(SLANG_SOURCE_LANGUAGE_HLSL, buf.getBuffer());
+ return SLANG_OK;
}
}
return SLANG_OK;
}
+/* static */SlangResult TestToolUtil::setSessionDefaultPrelude(const char* exePath, slang::IGlobalSession* session)
+{
+ PreludeInfo info;
+ info.exePath = exePath;
+ return setSessionDefaultPrelude(info, session);
+}
}
diff --git a/source/core/slang-test-tool-util.h b/source/core/slang-test-tool-util.h
index 9df2a6d6a..43bd49c9d 100644
--- a/source/core/slang-test-tool-util.h
+++ b/source/core/slang-test-tool-util.h
@@ -36,6 +36,12 @@ enum class ToolReturnCodeSpan
/* Utility functions for 'test tools' */
struct TestToolUtil
{
+ struct PreludeInfo
+ {
+ const char* exePath = nullptr;
+ const char* nvAPIPath = nullptr;
+ };
+
typedef SlangResult(*InnerMainFunc)(Slang::StdWriters* stdWriters, SlangSession* session, int argc, const char*const* argv);
/// If the test failed to run or was ignored then we are done
@@ -48,6 +54,8 @@ struct TestToolUtil
static ToolReturnCode getReturnCode(SlangResult res);
/// Sets the default preludes on the session based on the executable path
+ static SlangResult setSessionDefaultPrelude(const PreludeInfo& preludeInfo, slang::IGlobalSession* session);
+
static SlangResult setSessionDefaultPrelude(const char* exePath, slang::IGlobalSession* session);
};
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 62a548555..329a73a33 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -48,6 +48,29 @@ struct ByteAddressBuffer
}
};
+
+// Make the GLSL atomicAdd available.
+// We have separate int/float implementations, as the float version requires some specific extensions
+// https://www.khronos.org/registry/OpenGL/extensions/NV/NV_shader_atomic_float.txt
+
+__target_intrinsic(glsl, "atomicAdd($0, $1)")
+__glsl_version(430)
+__glsl_extension(GL_EXT_shader_atomic_float)
+//__glsl_extension(GL_EXT_gpu_shader5)
+float __atomicAdd(__ref float value, float amount);
+
+// Int versions require glsl 4.30
+// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/atomicAdd.xhtml
+
+__target_intrinsic(glsl, "atomicAdd($0, $1)")
+__glsl_version(430)
+int __atomicAdd(__ref int value, int amount);
+
+__target_intrinsic(glsl, "atomicAdd($0, $1)")
+__glsl_version(430)
+uint __atomicAdd(__ref uint value, uint amount);
+
+
__intrinsic_op($(kIROp_ByteAddressBufferLoad))
T __byteAddressBufferLoad<T>(ByteAddressBuffer buffer, int offset);
@@ -159,6 +182,41 @@ struct $(item.name)
{
return __byteAddressBufferLoad<T>(this, location);
}
+${{{{
+ if (item.op == kIROp_HLSLRWByteAddressBufferType)
+ {
+}}}}
+
+ // float32 and int64 atomic support. This is a Slang specific extension, it uses
+ // GL_EXT_shader_atomic_float on vk
+ // NvAPI support on DX
+ // NOTE! To use this feature on HLSL, the shader needs to include 'nvHLSLExtns.h' from the NvAPI SDK
+ //
+ __target_intrinsic(hlsl, "($3 = NvInterlockedAddFp32($0, $1, $2))")
+ __target_intrinsic(cuda, "(*$3 = atomicAdd((float*)$0._getPtrAt($1), $2))")
+ void InterlockedAddFp32(uint byteAddress, float valueToAdd, out float originalValue);
+
+ __specialized_for_target(glsl)
+ void InterlockedAddFp32(uint byteAddress, float valueToAdd, out float originalValue)
+ {
+ RWStructuredBuffer<float> buf = __getEquivalentStructuredBuffer<float>(this);
+ originalValue = __atomicAdd(buf[byteAddress / 4], valueToAdd);
+ }
+
+ __target_intrinsic(hlsl, "(NvInterlockedAddFp32($0, $1, $2))")
+ __target_intrinsic(cuda, "atomicAdd((float*)$0._getPtrAt($1), $2)")
+ void InterlockedAddFp32(uint byteAddress, float valueToAdd);
+
+ __specialized_for_target(glsl)
+ void InterlockedAddFp32(uint byteAddress, float valueToAdd)
+ {
+ RWStructuredBuffer<float> buf = __getEquivalentStructuredBuffer<float>(this);
+ __atomicAdd(buf[byteAddress / 4], valueToAdd);
+ }
+
+${{{{
+ }
+}}}}
// Added operations:
@@ -1091,6 +1149,10 @@ T dot(vector<T, N> x, vector<T, N> y)
__generic<T : __BuiltinFloatingPointType> vector<T,4> dst(vector<T,4> x, vector<T,4> y);
+// Given a RWByteAddressBuffer allow it to be interpretted as a RWStructuredBuffer
+__intrinsic_op($(kIROp_GetEquivalentStructuredBuffer))
+RWStructuredBuffer<T> __getEquivalentStructuredBuffer<T>(RWByteAddressBuffer b);
+
// Error message
// void errorf( string format, ... );
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index f965f9759..13b818b26 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -3520,6 +3520,7 @@ namespace Slang
return subst;
}
+#if 0
// For simplicity we will make having a definition of a function include having a body or a target intrinsics defined.
// It may be useful to add other modifiers to mark as having body - for example perhaps
// any target intrinsic modifier (like SPIR-V version) should be included.
@@ -3536,6 +3537,40 @@ namespace Slang
{
return decl->body || decl->hasModifier<TargetIntrinsicModifier>();
}
+#endif
+
+ typedef Dictionary<Name*, CallableDecl*> TargetDeclDictionary;
+
+ static void _addTargetModifiers(CallableDecl* decl, TargetDeclDictionary& ioDict)
+ {
+ if (auto specializedModifier = decl->findModifier<SpecializedForTargetModifier>())
+ {
+ // If it's specialized for target it should have a body...
+ if (auto funcDecl = as<FunctionDeclBase>(decl))
+ {
+ SLANG_ASSERT(funcDecl->body);
+ }
+ Name* targetName = specializedModifier->targetToken.getName();
+
+ ioDict.AddIfNotExists(targetName, decl);
+ }
+ else
+ {
+ for (auto modifier : decl->getModifiersOfType<TargetIntrinsicModifier>())
+ {
+ Name* targetName = modifier->targetToken.getName();
+ ioDict.AddIfNotExists(targetName, decl);
+ }
+
+ auto funcDecl = as<FunctionDeclBase>(decl);
+ if (funcDecl && funcDecl->body)
+ {
+ // Should only be one body if it isn't specialized for target.
+ // Use nullptr for this scenario
+ ioDict.AddIfNotExists(nullptr, decl);
+ }
+ }
+ }
Result SemanticsVisitor::checkFuncRedeclaration(
FuncDecl* newDecl,
@@ -3701,23 +3736,55 @@ namespace Slang
// with the case where the two function declarations
// might represent different target-specific versions
// of a function.
- //
- // TODO: if the two declarations are specialized for
- // different targets, then skip the body checks below.
- //
- // ???: Why isn't this problem showing up in practice?
-
+
// If both of the declarations have a body, then there
// is trouble, because we wouldn't know which one to
// use during code generation.
- if (_isDefinition(newDecl) && _isDefinition(oldDecl))
+
+ // Here to cover the 'bodies'/target_intrinsics, we find all the targets that
+ // that are previously defined, and make sure the new definition
+ // doesn't try and define what is already defined.
{
- // Redefinition
- getSink()->diagnose(newDecl, Diagnostics::functionRedefinition, newDecl->getName());
- getSink()->diagnose(oldDecl, Diagnostics::seePreviousDefinitionOf, newDecl->getName());
+ TargetDeclDictionary currentTargets;
+ {
+ CallableDecl* curDecl = newDecl->primaryDecl;
+ while (curDecl)
+ {
+ if (curDecl != newDecl)
+ {
+ _addTargetModifiers(curDecl, currentTargets);
+ }
+ curDecl = curDecl->nextDecl;
+ }
+ }
- // Don't bother emitting other errors
- return SLANG_FAIL;
+ // Add the targets for this new decl
+ TargetDeclDictionary newTargets;
+ _addTargetModifiers(newDecl, newTargets);
+
+ bool hasConflict = false;
+ for (auto& pair : newTargets)
+ {
+ Name* target = pair.Key;
+ auto found = currentTargets.TryGetValue(target);
+ if (found)
+ {
+ // Redefinition
+ if (!hasConflict)
+ {
+ getSink()->diagnose(newDecl, Diagnostics::functionRedefinition, newDecl->getName());
+ hasConflict = true;
+ }
+
+ auto prevDecl = *found;
+ getSink()->diagnose(prevDecl, Diagnostics::seePreviousDefinitionOf, prevDecl->getName());
+ }
+ }
+
+ if (hasConflict)
+ {
+ return SLANG_FAIL;
+ }
}
// At this point we've processed the redeclaration and
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index c643f825a..72cf2dfbe 100755
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -8,7 +8,6 @@
#include "../core/slang-riff.h"
#include "../core/slang-type-text-util.h"
-
#include "slang-check.h"
#include "slang-compiler.h"
#include "slang-lexer.h"
@@ -841,83 +840,39 @@ namespace Slang
return UnownedStringSlice();
}
- /// Read a file in the context of handling a preprocessor directive
- static SlangResult readFile(
- Linkage* linkage,
- String const& path,
- ISlangBlob** outBlob)
- {
- // The actual file loading will be handled by the file system
- // associated with the parent linkage.
- //
- auto fileSystemExt = linkage->getFileSystemExt();
- SLANG_RETURN_ON_FAIL(fileSystemExt->loadFile(path.getBuffer(), outBlob));
-
- return SLANG_OK;
- }
-
struct FxcIncludeHandler : ID3DInclude
{
- Linkage* linkage;
- DiagnosticSink* sink;
- IncludeHandler* includeHandler;
- PathInfo rootPathInfo;
-
- STDMETHOD(Open)(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) override
+
+ STDMETHOD(Open)(D3D_INCLUDE_TYPE includeType, LPCSTR fileName, LPCVOID parentData, LPCVOID* outData, UINT* outSize) override
{
- SLANG_UNUSED(IncludeType);
- SLANG_UNUSED(pParentData);
-
- String path(pFileName);
+ SLANG_UNUSED(includeType);
+ // NOTE! The pParentData means the *text* of any previous include.
+ // In order to work out what *path* that came from, we need to seach which source file it came from, and
+ // use it's path
- SourceLoc loc;
+ // Assume the root pathInfo initially
+ PathInfo includedFromPathInfo = m_rootPathInfo;
- PathInfo includedFromPathInfo = rootPathInfo;
-
- if (!includeHandler)
+ // Lets try and find the parent source if there is any
+ if (parentData)
{
- return SLANG_E_NOT_IMPLEMENTED;
- }
-
- // Find the path relative to the foundPath
- PathInfo filePathInfo;
- if (SLANG_FAILED(includeHandler->findFile(path, includedFromPathInfo.foundPath, filePathInfo)))
- {
- return SLANG_E_CANNOT_OPEN;
- }
-
- // We must have a uniqueIdentity to be compare
- if (!filePathInfo.hasUniqueIdentity())
- {
- return SLANG_E_ABORT;
- }
-
- // Simplify the path
- filePathInfo.foundPath = includeHandler->simplifyPath(filePathInfo.foundPath);
-
- // See if this an already loaded source file
- auto sourceManager = linkage->getSourceManager();
- SourceFile* sourceFile = sourceManager->findSourceFileRecursively(filePathInfo.uniqueIdentity);
-
- // If not create a new one, and add to the list of known source files
- if (!sourceFile)
- {
- ComPtr<ISlangBlob> foundSourceBlob;
- if (SLANG_FAILED(readFile(linkage, filePathInfo.foundPath, foundSourceBlob.writeRef())))
+ SourceFile* foundSourceFile = m_system.getSourceManager()->findSourceFileByContentRecursively((const char*)parentData);
+ if (foundSourceFile)
{
- return SLANG_E_CANNOT_OPEN;
+ includedFromPathInfo = foundSourceFile->getPathInfo();
}
-
- sourceFile = sourceManager->createSourceFileWithBlob(filePathInfo, foundSourceBlob);
- sourceManager->addSourceFile(filePathInfo.uniqueIdentity, sourceFile);
}
- // This is a new parse (even if it's a pre-existing source file), so create a new SourceUnit
- SourceView* sourceView = sourceManager->createSourceView(sourceFile, &filePathInfo);
+ String path(fileName);
+ PathInfo pathInfo;
+ ComPtr<ISlangBlob> blob;
- *ppData = sourceView->getContent().begin();
- *pBytes = (UINT) sourceView->getContentSize();
+ SLANG_RETURN_ON_FAIL(m_system.findAndLoadFile(path, includedFromPathInfo.foundPath, pathInfo, blob));
+ // Return the data
+ *outData = blob->getBufferPointer();
+ *outSize = (UINT) blob->getBufferSize();
+
return S_OK;
}
@@ -926,6 +881,13 @@ namespace Slang
SLANG_UNUSED(pData);
return S_OK;
}
+ FxcIncludeHandler(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager):
+ m_system(searchDirectories, fileSystemExt, sourceManager)
+ {
+ }
+
+ PathInfo m_rootPathInfo;
+ IncludeSystem m_system;
};
SlangResult emitDXBytecodeForEntryPoint(
@@ -967,13 +929,9 @@ namespace Slang
List<D3D_SHADER_MACRO> dxMacrosStorage;
D3D_SHADER_MACRO const* dxMacros = nullptr;
- IncludeHandlerImpl includeHandler;
- includeHandler.linkage = linkage;
- includeHandler.searchDirectories = &linkage->searchDirectories;
-
- FxcIncludeHandler fxcIncludeHandlerStorage;
- FxcIncludeHandler* fxcIncludeHandler = nullptr;
-
+ FxcIncludeHandler fxcIncludeHandlerStorage(&linkage->searchDirectories, linkage->getFileSystemExt(), sink->getSourceManager());
+ FxcIncludeHandler* fxcIncludeHandler = &fxcIncludeHandlerStorage;
+
if(auto translationUnit = findPassThroughTranslationUnit(endToEndReq, entryPointIndex))
{
for( auto& define : translationUnit->compileRequest->preprocessorDefinitions )
@@ -996,10 +954,7 @@ namespace Slang
dxMacros = dxMacrosStorage.getBuffer();
fxcIncludeHandler = &fxcIncludeHandlerStorage;
- fxcIncludeHandler->linkage = linkage;
- fxcIncludeHandler->sink = compileRequest->getSink();
- fxcIncludeHandler->includeHandler = &includeHandler;
- fxcIncludeHandler->rootPathInfo = translationUnit->m_sourceFiles[0]->getPathInfo();
+ fxcIncludeHandlerStorage.m_rootPathInfo = translationUnit->m_sourceFiles[0]->getPathInfo();
}
DWORD flags = 0;
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 19f56031d..8996f5512 100755
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -16,6 +16,8 @@
#include "slang-file-system.h"
+#include "slang-include-system.h"
+
#include "slang-ir-serialize-types.h"
#include "../../slang.h"
@@ -1169,28 +1171,6 @@ namespace Slang
Profile getEffectiveProfile(EntryPoint* entryPoint, TargetRequest* target);
- // A directory to be searched when looking for files (e.g., `#include`)
- struct SearchDirectory
- {
- SearchDirectory() = default;
- SearchDirectory(SearchDirectory const& other) = default;
- SearchDirectory(String const& path)
- : path(path)
- {}
-
- String path;
- };
-
- /// A list of directories to search for files (e.g., `#include`)
- struct SearchDirectoryList
- {
- // A parent list that should also be searched
- SearchDirectoryList* parent = nullptr;
-
- // Directories to be searched
- List<SearchDirectory> searchDirectories;
- };
-
/// Given a target returns the required downstream compiler
PassThroughMode getDownstreamCompilerRequiredForTarget(CodeGenTarget target);
/// Given a target returns a downstream compiler the prelude should be taken from.
@@ -2163,23 +2143,6 @@ namespace Slang
PassThroughMode m_defaultDownstreamCompilers[int(SourceLanguage::CountOf)];
};
-struct IncludeHandlerImpl : IncludeHandler
-{
- Linkage* linkage;
- SearchDirectoryList* searchDirectories;
-
- ISlangFileSystemExt* _getFileSystemExt();
-
- SlangResult _findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& pathInfoOut);
-
- virtual SlangResult findFile(
- String const& pathToInclude,
- String const& pathIncludedFrom,
- PathInfo& pathInfoOut) override;
-
- virtual String simplifyPath(const String& path) override;
-};
-
//
// The following functions are utilties to convert between
diff --git a/source/slang/slang-dxc-support.cpp b/source/slang/slang-dxc-support.cpp
index 6f8151921..b0938ed12 100755
--- a/source/slang/slang-dxc-support.cpp
+++ b/source/slang/slang-dxc-support.cpp
@@ -45,6 +45,82 @@ namespace Slang
return UnownedStringSlice();
}
+ // IDxcIncludeHandler
+ // 7f61fc7d-950d-467f-b3e3-3c02fb49187c
+ static const Guid IID_IDxcIncludeHandler = { 0x7f61fc7d, 0x950d, 0x467f, { 0x3c, 0x02, 0xfb, 0x49, 0x18, 0x7c } };
+ static const Guid IID_IUnknown = SLANG_UUID_ISlangUnknown;
+
+ class DxcIncludeHandler : public IDxcIncludeHandler, public RefObject
+ {
+ public:
+ // Implement IUnknown
+ SLANG_NO_THROW HRESULT SLANG_MCALL QueryInterface(const IID& uuid, void** out)
+ {
+ ISlangUnknown* intf = getInterface(reinterpret_cast<const Guid&>(uuid));
+ if (intf)
+ {
+ addReference();
+ *out = intf;
+ return SLANG_OK;
+ }
+ return SLANG_E_NO_INTERFACE;
+ }
+ SLANG_NO_THROW ULONG SLANG_MCALL AddRef() SLANG_OVERRIDE { return (uint32_t)addReference(); }
+ SLANG_NO_THROW ULONG SLANG_MCALL Release() SLANG_OVERRIDE { return (uint32_t)releaseReference(); }
+
+ // Implement IDxcIncludeHandler
+ virtual HRESULT SLANG_MCALL LoadSource(LPCWSTR inFilename, IDxcBlob** outSource) SLANG_OVERRIDE
+ {
+ // Hmm DXC does something a bit odd - when it sees a path, it just passes that in with ./ in front!!
+ // NOTE! It doesn't make any difference if it is "" or <> quoted.
+
+ // So we just do a work around where we strip if we see a path starting with ./
+ String filePath = String::fromWString(inFilename);
+
+ // If it starts with ./ then attempt to strip it
+ if (filePath.startsWith("./"))
+ {
+ String remaining(filePath.subString(2, filePath.getLength() - 2));
+
+ // Okay if we strip ./ and what we have is absolute, then it's the absolute path that we care about,
+ // otherwise we just leave as is.
+ if (Path::isAbsolute(remaining))
+ {
+ filePath = remaining;
+ }
+ }
+
+ ComPtr<ISlangBlob> blob;
+ PathInfo pathInfo;
+ SlangResult res = m_system.findAndLoadFile(filePath, String(), pathInfo, blob);
+
+ // NOTE! This only works because ISlangBlob is *binary compatible* with IDxcBlob, if either
+ // change things could go boom
+ *outSource = (IDxcBlob*)blob.detach();
+ return res;
+ }
+
+ DxcIncludeHandler(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager = nullptr) :
+ m_system(searchDirectories, fileSystemExt, sourceManager)
+ {
+ }
+
+ protected:
+
+ // Used by QueryInterface for casting
+ ISlangUnknown* getInterface(const Guid& guid)
+ {
+ if (guid == IID_IUnknown || guid == IID_IDxcIncludeHandler)
+ {
+ return (ISlangUnknown*)(static_cast<IDxcIncludeHandler*>(this));
+ }
+ return nullptr;
+ }
+
+ IncludeSystem m_system;
+ };
+
+
SlangResult emitDXILForEntryPointUsingDXC(
ComponentType* program,
BackEndCompileRequest* compileRequest,
@@ -194,6 +270,8 @@ namespace Slang
const String sourcePath = calcSourcePathForEntryPoint(endToEndReq, entryPointIndex);
+ ComPtr<DxcIncludeHandler> includeHandler(new DxcIncludeHandler(&linkage->searchDirectories, linkage->getFileSystemExt()));
+
ComPtr<IDxcOperationResult> dxcResult;
SLANG_RETURN_ON_FAIL(dxcCompiler->Compile(dxcSourceBlob,
sourcePath.toWString().begin(),
@@ -203,7 +281,7 @@ namespace Slang
argCount,
nullptr, // `#define`s
0, // `#define` count
- nullptr, // `#include` handler
+ includeHandler, // `#include` handler
dxcResult.writeRef()));
// Retrieve result.
diff --git a/source/slang/slang-include-system.cpp b/source/slang/slang-include-system.cpp
new file mode 100644
index 000000000..66aeb3f67
--- /dev/null
+++ b/source/slang/slang-include-system.cpp
@@ -0,0 +1,139 @@
+// slang-include-system.cpp
+#include "slang-include-system.h"
+
+#include "../core/slang-io.h"
+#include "../core/slang-string-util.h"
+
+namespace Slang
+{
+
+SlangResult IncludeSystem::findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& outPathInfo)
+{
+ // Get relative path
+ ComPtr<ISlangBlob> combinedPathBlob;
+ SLANG_RETURN_ON_FAIL(m_fileSystemExt->calcCombinedPath(fromPathType, fromPath.begin(), path.begin(), combinedPathBlob.writeRef()));
+ String combinedPath(StringUtil::getString(combinedPathBlob));
+ if (combinedPath.getLength() <= 0)
+ {
+ return SLANG_FAIL;
+ }
+
+ SlangPathType pathType;
+ SLANG_RETURN_ON_FAIL(m_fileSystemExt->getPathType(combinedPath.begin(), &pathType));
+ if (pathType != SLANG_PATH_TYPE_FILE)
+ {
+ return SLANG_E_NOT_FOUND;
+ }
+
+ // Get the uniqueIdentity
+ ComPtr<ISlangBlob> uniqueIdentityBlob;
+ SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity(combinedPath.begin(), uniqueIdentityBlob.writeRef()));
+
+ // If the rel path exists -> a uniqueIdentity MUST exists too
+ String uniqueIdentity(StringUtil::getString(uniqueIdentityBlob));
+ if (uniqueIdentity.getLength() <= 0)
+ {
+ // Unique identity can't be empty
+ return SLANG_FAIL;
+ }
+
+ outPathInfo = PathInfo::makeNormal(combinedPath, uniqueIdentity);
+ return SLANG_OK;
+}
+
+String IncludeSystem::simplifyPath(const String& path)
+{
+ ComPtr<ISlangBlob> simplifiedPath;
+ if (SLANG_FAILED(m_fileSystemExt->getSimplifiedPath(path.getBuffer(), simplifiedPath.writeRef())))
+ {
+ return path;
+ }
+ return StringUtil::getString(simplifiedPath);
+}
+
+SlangResult IncludeSystem::findFile(String const& pathToInclude, String const& pathIncludedFrom, PathInfo& outPathInfo)
+{
+ outPathInfo.type = PathInfo::Type::Unknown;
+
+ // Try just relative to current path
+ {
+ SlangResult res = findFile(SLANG_PATH_TYPE_FILE, pathIncludedFrom, pathToInclude, outPathInfo);
+ // It either succeeded or wasn't found, anything else is a failure passed back
+ if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND)
+ {
+ return res;
+ }
+ }
+
+ // Search all the searchDirectories
+ for (auto sd = m_searchDirectories; sd; sd = sd->parent)
+ {
+ for (auto& dir : sd->searchDirectories)
+ {
+ SlangResult res = findFile(SLANG_PATH_TYPE_DIRECTORY, dir.path, pathToInclude, outPathInfo);
+ if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND)
+ {
+ return res;
+ }
+ }
+ }
+
+ return SLANG_E_NOT_FOUND;
+}
+
+SlangResult IncludeSystem::loadFile(const PathInfo& pathInfo, ComPtr<ISlangBlob>& outBlob)
+{
+ if (m_sourceManager)
+ {
+ // See if this an already loaded source file
+ SourceFile* sourceFile = m_sourceManager->findSourceFileRecursively(pathInfo.uniqueIdentity);
+
+ // If not create a new one, and add to the list of known source files
+ if (!sourceFile)
+ {
+ ComPtr<ISlangBlob> foundSourceBlob;
+ if (SLANG_FAILED(m_fileSystemExt->loadFile(pathInfo.foundPath.getBuffer(), foundSourceBlob.writeRef())))
+ {
+ return SLANG_E_CANNOT_OPEN;
+ }
+
+ sourceFile = m_sourceManager->createSourceFileWithBlob(pathInfo, foundSourceBlob);
+ m_sourceManager->addSourceFile(pathInfo.uniqueIdentity, sourceFile);
+
+ outBlob = foundSourceBlob;
+ return SLANG_OK;
+ }
+ else
+ {
+ if (sourceFile->getContentBlob())
+ {
+ outBlob = sourceFile->getContentBlob();
+ return SLANG_OK;
+ }
+
+ ComPtr<ISlangBlob> foundSourceBlob;
+ if (SLANG_FAILED(m_fileSystemExt->loadFile(pathInfo.foundPath.getBuffer(), foundSourceBlob.writeRef())))
+ {
+ return SLANG_E_CANNOT_OPEN;
+ }
+
+ sourceFile->setContents(foundSourceBlob);
+ outBlob = foundSourceBlob;
+ return SLANG_OK;
+ }
+ }
+ else
+ {
+ // If we don't have the source manager, just load
+ return m_fileSystemExt->loadFile(pathInfo.foundPath.getBuffer(), outBlob.writeRef());
+ }
+}
+
+SlangResult IncludeSystem::findAndLoadFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo, ComPtr<ISlangBlob>& outBlob)
+{
+ SLANG_RETURN_ON_FAIL(findFile(pathToInclude, pathIncludedFrom, outPathInfo));
+ SLANG_RETURN_ON_FAIL(loadFile(outPathInfo, outBlob));
+ return SLANG_OK;
+}
+
+} // namespace Slang
diff --git a/source/slang/slang-include-system.h b/source/slang/slang-include-system.h
new file mode 100644
index 000000000..3b368b70d
--- /dev/null
+++ b/source/slang/slang-include-system.h
@@ -0,0 +1,62 @@
+#ifndef SLANG_INCLUDE_SYSTEM_H
+#define SLANG_INCLUDE_SYSTEM_H
+// slang-include-system.h
+
+#include "slang-source-loc.h"
+
+namespace Slang
+{
+
+// A directory to be searched when looking for files (e.g., `#include`)
+struct SearchDirectory
+{
+ SearchDirectory() = default;
+ SearchDirectory(SearchDirectory const& other) = default;
+ SearchDirectory(String const& path)
+ : path(path)
+ {}
+
+ String path;
+};
+
+/// A list of directories to search for files (e.g., `#include`)
+struct SearchDirectoryList
+{
+ // A parent list that should also be searched
+ SearchDirectoryList* parent = nullptr;
+
+ // Directories to be searched
+ List<SearchDirectory> searchDirectories;
+};
+
+/* A helper class that builds basic include handling on top of searchDirectories/fileSystemExt and optionally a sourceManager */
+struct IncludeSystem
+{
+ IncludeSystem(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager = nullptr) :
+ m_searchDirectories(searchDirectories),
+ m_fileSystemExt(fileSystemExt),
+ m_sourceManager(sourceManager)
+ {
+ }
+
+ SlangResult findFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo);
+ SlangResult findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& outPathInfo);
+ String simplifyPath(const String& path);
+ SlangResult loadFile(const PathInfo& pathInfo, ComPtr<ISlangBlob>& outBlob);
+
+ SlangResult findAndLoadFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo, ComPtr<ISlangBlob>& outBlob);
+
+ SearchDirectoryList* getSearchDirectoryList() const { return m_searchDirectories; }
+ ISlangFileSystemExt* getFileSystem() const { return m_fileSystemExt; }
+ SourceManager* getSourceManager() const { return m_sourceManager; }
+
+protected:
+
+ SearchDirectoryList* m_searchDirectories;
+ ISlangFileSystemExt* m_fileSystemExt;
+ SourceManager* m_sourceManager; ///< If not set, will not look up the content in the source manager
+};
+
+}
+
+#endif // SLANG_INCLUDE_HANDLER_H
diff --git a/source/slang/slang-ir-byte-address-legalize.cpp b/source/slang/slang-ir-byte-address-legalize.cpp
index e33408855..ed54a3ef6 100644
--- a/source/slang/slang-ir-byte-address-legalize.cpp
+++ b/source/slang/slang-ir-byte-address-legalize.cpp
@@ -61,8 +61,13 @@ struct ByteAddressBufferLegalizationContext
case kIROp_ByteAddressBufferStore:
processStore(inst);
break;
+
+ case kIROp_GetEquivalentStructuredBuffer:
+ processGetEquivalentStructuredBuffer(inst);
+ break;
}
+
IRInst* nextChild = nullptr;
for( IRInst* child = inst->getFirstChild(); child; child = nextChild )
{
@@ -71,6 +76,28 @@ struct ByteAddressBufferLegalizationContext
}
}
+ void processGetEquivalentStructuredBuffer(IRInst* inst)
+ {
+ // We need to see what type it is to be interpreted as.
+ auto type = inst->getDataType();
+
+ // We want to determine the element type
+ auto structuredBufferType = as<IRHLSLStructuredBufferTypeBase>(type);
+ auto elementType = structuredBufferType->getElementType();
+
+ // The buffer is operand 0
+ auto buffer = inst->getOperand(0);
+
+ // Get the equivalent structured buffer for the buffer.
+ if( auto structuredBuffer = getEquivalentStructuredBuffer(elementType, buffer) )
+ {
+ // We want to replace the the inst, with the equivalent structured buffer reference
+ inst->replaceUsesWith(structuredBuffer);
+ // Once replaced we don't need anymore
+ inst->removeAndDeallocate();
+ }
+ }
+
// The logic for both the load and store cases is similar,
// so we will present the entire load case first and then
// move on to stores.
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 74bd15531..f60f84a9e 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -590,6 +590,9 @@ INST(ExtractTaggedUnionPayload, extractTaggedUnionPayload, 1, 0)
INST(BitCast, bitCast, 1, 0)
+// Converts other resources (such as ByteAddressBuffer) to the equivalent StructuredBuffer
+INST(GetEquivalentStructuredBuffer, getEquivalentStructuredBuffer, 1, 0)
+
/* Layout */
INST(VarLayout, varLayout, 1, 0)
diff --git a/source/slang/slang-preprocessor.h b/source/slang/slang-preprocessor.h
index 191adce88..0e7509a27 100644
--- a/source/slang/slang-preprocessor.h
+++ b/source/slang/slang-preprocessor.h
@@ -3,7 +3,10 @@
#define SLANG_PREPROCESSOR_H_INCLUDED
#include "../core/slang-basic.h"
-#include "../slang/slang-lexer.h"
+
+#include "slang-lexer.h"
+
+#include "slang-include-system.h"
namespace Slang {
@@ -16,14 +19,27 @@ class ModuleDecl;
// for files in `#include` directives.
struct IncludeHandler
{
-
- virtual SlangResult findFile(const String& pathToInclude,
- const String& pathIncludedFrom,
- PathInfo& pathInfoOut) = 0;
-
+ virtual SlangResult findFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo) = 0;
virtual String simplifyPath(const String& path) = 0;
};
+// A default implementation that uses IncludeSystem to implement functionality
+struct IncludeHandlerImpl : IncludeHandler
+{
+ virtual SlangResult findFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo) override
+ {
+ return m_system.findFile(pathToInclude, pathIncludedFrom, outPathInfo);
+ }
+ virtual String simplifyPath(const String& path) override { return m_system.simplifyPath(path); }
+
+ IncludeHandlerImpl(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager = nullptr) :
+ m_system(searchDirectories, fileSystemExt, sourceManager)
+ {
+ }
+protected:
+ IncludeSystem m_system;
+};
+
// Take a string of source code and preprocess it into a list of tokens.
TokenList preprocessSource(
SourceFile* file,
diff --git a/source/slang/slang-source-loc.cpp b/source/slang/slang-source-loc.cpp
index eb2ea6b1b..7eca23d8d 100644
--- a/source/slang/slang-source-loc.cpp
+++ b/source/slang/slang-source-loc.cpp
@@ -521,6 +521,35 @@ SourceFile* SourceManager::findSourceFileRecursively(const String& uniqueIdentit
return nullptr;
}
+SourceFile* SourceManager::findSourceFileByContentRecursively(const char* text)
+{
+ const SourceManager* manager = this;
+ do
+ {
+ SourceFile* sourceFile = manager->findSourceFileByContent(text);
+ if (sourceFile)
+ {
+ return sourceFile;
+ }
+ manager = manager->m_parent;
+ } while (manager);
+ return nullptr;
+}
+
+SourceFile* SourceManager::findSourceFileByContent(const char* text) const
+{
+ for (SourceFile* sourceFile : getSourceFiles())
+ {
+ auto content = sourceFile->getContent();
+
+ if (text >= content.begin() && text <= content.end())
+ {
+ return sourceFile;
+ }
+ }
+ return nullptr;
+}
+
void SourceManager::addSourceFile(const String& uniqueIdentity, SourceFile* sourceFile)
{
SLANG_ASSERT(!findSourceFileRecursively(uniqueIdentity));
diff --git a/source/slang/slang-source-loc.h b/source/slang/slang-source-loc.h
index 51d826108..c00120476 100644
--- a/source/slang/slang-source-loc.h
+++ b/source/slang/slang-source-loc.h
@@ -350,6 +350,11 @@ struct SourceManager
/// Find if the source file is defined on this manager.
SourceFile* findSourceFile(const String& uniqueIdentity) const;
+ /// Searches this manager, and then the parent to see if can find a match
+ SourceFile* findSourceFileByContentRecursively(const char* text);
+ /// Find the source file that contains *the memory* text points to.
+ SourceFile* findSourceFileByContent(const char* text) const;
+
/// Get the file system associated with this source manager
ISlangFileSystemExt* getFileSystemExt() const { return m_fileSystemExt; }
/// Get the file system associated with this source manager
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 8523a445d..aed38547d 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -329,96 +329,6 @@ DownstreamCompiler* Session::getDefaultDownstreamCompiler(SourceLanguage sourceL
return getOrLoadDownstreamCompiler(m_defaultDownstreamCompilers[int(sourceLanguage)], nullptr);
}
-ISlangFileSystemExt* IncludeHandlerImpl::_getFileSystemExt()
-{
- return linkage->getFileSystemExt();
-}
-
-SlangResult IncludeHandlerImpl::_findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& pathInfoOut)
-{
- ISlangFileSystemExt* fileSystemExt = _getFileSystemExt();
-
- // Get relative path
- ComPtr<ISlangBlob> combinedPathBlob;
- SLANG_RETURN_ON_FAIL(fileSystemExt->calcCombinedPath(fromPathType, fromPath.begin(), path.begin(), combinedPathBlob.writeRef()));
- String combinedPath(StringUtil::getString(combinedPathBlob));
- if (combinedPath.getLength() <= 0)
- {
- return SLANG_FAIL;
- }
-
- SlangPathType pathType;
- SLANG_RETURN_ON_FAIL(fileSystemExt->getPathType(combinedPath.begin(), &pathType));
- if (pathType != SLANG_PATH_TYPE_FILE)
- {
- return SLANG_E_NOT_FOUND;
- }
-
- // Get the uniqueIdentity
- ComPtr<ISlangBlob> uniqueIdentityBlob;
- SLANG_RETURN_ON_FAIL(fileSystemExt->getFileUniqueIdentity(combinedPath.begin(), uniqueIdentityBlob.writeRef()));
-
- // If the rel path exists -> a uniqueIdentity MUST exists too
- String uniqueIdentity(StringUtil::getString(uniqueIdentityBlob));
- if (uniqueIdentity.getLength() <= 0)
- {
- // Unique identity can't be empty
- return SLANG_FAIL;
- }
-
- pathInfoOut.type = PathInfo::Type::Normal;
- pathInfoOut.foundPath = combinedPath;
- pathInfoOut.uniqueIdentity = uniqueIdentity;
- return SLANG_OK;
-}
-
-SlangResult IncludeHandlerImpl::findFile(
- String const& pathToInclude,
- String const& pathIncludedFrom,
- PathInfo& pathInfoOut)
-{
- pathInfoOut.type = PathInfo::Type::Unknown;
-
- // Try just relative to current path
- {
- SlangResult res = _findFile(SLANG_PATH_TYPE_FILE, pathIncludedFrom, pathToInclude, pathInfoOut);
- // It either succeeded or wasn't found, anything else is a failure passed back
- if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND)
- {
- return res;
- }
- }
-
- // Search all the searchDirectories
- for(auto sd = searchDirectories; sd; sd = sd->parent)
- {
- for(auto& dir : sd->searchDirectories)
- {
- SlangResult res = _findFile(SLANG_PATH_TYPE_DIRECTORY, dir.path, pathToInclude, pathInfoOut);
- if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND)
- {
- return res;
- }
- }
- }
-
- return SLANG_E_NOT_FOUND;
-}
-
-String IncludeHandlerImpl::simplifyPath(const String& path)
-{
- ISlangFileSystemExt* fileSystemExt = _getFileSystemExt();
- ComPtr<ISlangBlob> simplifiedPath;
- if (SLANG_FAILED(fileSystemExt->getSimplifiedPath(path.getBuffer(), simplifiedPath.writeRef())))
- {
- return path;
- }
- return StringUtil::getString(simplifiedPath);
-}
-
-//
-
-
Profile getEffectiveProfile(EntryPoint* entryPoint, TargetRequest* target)
{
auto entryPointProfile = entryPoint->getProfile();
@@ -866,12 +776,16 @@ SlangResult Linkage::loadFile(String const& path, PathInfo& outPathInfo, ISlangB
ComPtr<ISlangBlob> uniqueIdentity;
// Get the unique identity
- SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity(path.getBuffer(), uniqueIdentity.writeRef()));
-
- outPathInfo.foundPath = path;
- outPathInfo.type = PathInfo::Type::FoundPath;
- outPathInfo.uniqueIdentity = StringUtil::getString(uniqueIdentity);
-
+ if (SLANG_FAILED(m_fileSystemExt->getFileUniqueIdentity(path.getBuffer(), uniqueIdentity.writeRef())))
+ {
+ // We didn't get a unique identity, so go with just a found path
+ outPathInfo.type = PathInfo::Type::FoundPath;
+ outPathInfo.foundPath = path;
+ }
+ else
+ {
+ outPathInfo = PathInfo::makeNormal(path, StringUtil::getString(uniqueIdentity));
+ }
return SLANG_OK;
}
@@ -975,8 +889,6 @@ FrontEndCompileRequest::FrontEndCompileRequest(
void FrontEndCompileRequest::parseTranslationUnit(
TranslationUnitRequest* translationUnit)
{
- IncludeHandlerImpl includeHandler;
-
auto linkage = getLinkage();
// TODO(JS): NOTE! Here we are using the searchDirectories on the linkage. This is because
@@ -986,8 +898,7 @@ void FrontEndCompileRequest::parseTranslationUnit(
// If searchDirectories.parent pointed to the one in the Linkage would mean linkage paths
// would be checked too (after those on the FrontEndCompileRequest).
- includeHandler.linkage = linkage;
- includeHandler.searchDirectories = &linkage->searchDirectories;
+ IncludeHandlerImpl includeHandler(&linkage->searchDirectories, linkage->getFileSystemExt());
RefPtr<Scope> languageScope;
switch (translationUnit->sourceLanguage)
@@ -1740,9 +1651,7 @@ RefPtr<Module> Linkage::findOrImportModule(
// Next, try to find the file of the given name,
// using our ordinary include-handling logic.
- IncludeHandlerImpl includeHandler;
- includeHandler.linkage = this;
- includeHandler.searchDirectories = &searchDirectories;
+ IncludeHandlerImpl includeHandler(&searchDirectories, getFileSystemExt());
// Get the original path info
PathInfo pathIncludedFromInfo = getSourceManager()->getPathInfo(loc, SourceLocType::Actual);
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index 8861413c9..82e575ef9 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -221,6 +221,7 @@
<ClInclude Include="slang-glsl-extension-tracker.h" />
<ClInclude Include="slang-hlsl-intrinsic-set.h" />
<ClInclude Include="slang-image-format-defs.h" />
+ <ClInclude Include="slang-include-system.h" />
<ClInclude Include="slang-ir-any-value-marshalling.h" />
<ClInclude Include="slang-ir-bind-existentials.h" />
<ClInclude Include="slang-ir-byte-address-legalize.h" />
@@ -326,6 +327,7 @@
<ClCompile Include="slang-file-system.cpp" />
<ClCompile Include="slang-glsl-extension-tracker.cpp" />
<ClCompile Include="slang-hlsl-intrinsic-set.cpp" />
+ <ClCompile Include="slang-include-system.cpp" />
<ClCompile Include="slang-ir-any-value-marshalling.cpp" />
<ClCompile Include="slang-ir-bind-existentials.cpp" />
<ClCompile Include="slang-ir-byte-address-legalize.cpp" />
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index a556b5b03..3484a1638 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -114,6 +114,9 @@
<ClInclude Include="slang-image-format-defs.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="slang-include-system.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="slang-ir-any-value-marshalling.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -425,6 +428,9 @@
<ClCompile Include="slang-hlsl-intrinsic-set.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="slang-include-system.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="slang-ir-any-value-marshalling.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/tests/compute/byte-address-buffer.slang b/tests/compute/byte-address-buffer.slang
index f2078b52d..96e100ae8 100644
--- a/tests/compute/byte-address-buffer.slang
+++ b/tests/compute/byte-address-buffer.slang
@@ -3,7 +3,7 @@
//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
-//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-d3d12 -compute
+//TEST(compute):COMPARE_COMPUTE_EX:-d3d12 -compute
// Confirm cross-compilation of `(RW)ByteAddressBuffer`
//
diff --git a/tests/diagnostics/single-target-intrinsic.slang b/tests/diagnostics/single-target-intrinsic.slang
index e8ff0ed1a..94e1a2bae 100644
--- a/tests/diagnostics/single-target-intrinsic.slang
+++ b/tests/diagnostics/single-target-intrinsic.slang
@@ -9,6 +9,9 @@ T doThing<T>(T in)
__target_intrinsic(hlsl, "doSomethingIntrinsically($0)")
T doThing<T>(T in);
+__target_intrinsic(hlsl, "letsRedefineIt($0)")
+T doThing<T>(T in);
+
void test()
{
int a = 5;
diff --git a/tests/diagnostics/single-target-intrinsic.slang.expected b/tests/diagnostics/single-target-intrinsic.slang.expected
index 82068f17d..544cd2d3b 100644
--- a/tests/diagnostics/single-target-intrinsic.slang.expected
+++ b/tests/diagnostics/single-target-intrinsic.slang.expected
@@ -1,7 +1,7 @@
result code = -1
standard error = {
-tests/diagnostics/single-target-intrinsic.slang(10): error 30201: function 'doThing' already has a body
-tests/diagnostics/single-target-intrinsic.slang(4): note: see previous definition of 'doThing'
+tests/diagnostics/single-target-intrinsic.slang(13): error 30201: function 'doThing' already has a body
+tests/diagnostics/single-target-intrinsic.slang(10): note: see previous definition of 'doThing'
}
standard output = {
}
diff --git a/tests/preprocessor/inappropriate-once.slang b/tests/preprocessor/inappropriate-once.slang
deleted file mode 100644
index 6b750ec77..000000000
--- a/tests/preprocessor/inappropriate-once.slang
+++ /dev/null
@@ -1,6 +0,0 @@
-//TEST:SIMPLE:
-// #include support
-
-#pragma once
-
-int foo() { return 0; } \ No newline at end of file
diff --git a/tests/preprocessor/inappropriate-once.slang.expected b/tests/preprocessor/inappropriate-once.slang.expected
deleted file mode 100644
index 04d7f7834..000000000
--- a/tests/preprocessor/inappropriate-once.slang.expected
+++ /dev/null
@@ -1,6 +0,0 @@
-result code = 0
-standard error = {
-tests/preprocessor/inappropriate-once.slang(4): warning 15602: pragma once was ignored - this is typically because is not placed in an include
-}
-standard output = {
-}
diff --git a/tests/slang-extension/atomic-float-byte-address-buffer-cross.slang b/tests/slang-extension/atomic-float-byte-address-buffer-cross.slang
new file mode 100644
index 000000000..e99494d5f
--- /dev/null
+++ b/tests/slang-extension/atomic-float-byte-address-buffer-cross.slang
@@ -0,0 +1,27 @@
+// atomic-float-byte-address-buffer-cross.slang
+
+//TEST:CROSS_COMPILE: -profile cs_6_5 -entry computeMain -target spirv-assembly
+// We can't do this test, because it relies on nvAPI
+//DISABLE_TEST:CROSS_COMPILE: -profile cs_6_5 -entry computeMain -target dxil
+
+//TEST_INPUT:ubuffer(data=[0.1 0.2 0.3 0.4]):out,name=outputBuffer
+RWByteAddressBuffer outputBuffer;
+
+//TEST_INPUT:ubuffer(data=[0.7 0.5 0.2 0.6]):name=anotherBuffer
+RWStructuredBuffer<float> anotherBuffer;
+
+[numthreads(16, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ uint tid = dispatchThreadID.x;
+ int idx = (tid & 3) ^ (tid >> 2);
+
+ const float delta = anotherBuffer[idx & 3];
+
+ float previousValue = 0;
+ outputBuffer.InterlockedAddFp32((idx << 2), 1.0f, previousValue);
+
+ // The sum of values in anotherBuffer should also be added
+ int anotherIdx = tid >> 2;
+ outputBuffer.InterlockedAddFp32(anotherIdx << 2, delta);
+} \ No newline at end of file
diff --git a/tests/slang-extension/atomic-float-byte-address-buffer-cross.slang.glsl b/tests/slang-extension/atomic-float-byte-address-buffer-cross.slang.glsl
new file mode 100644
index 000000000..9fd2f18f9
--- /dev/null
+++ b/tests/slang-extension/atomic-float-byte-address-buffer-cross.slang.glsl
@@ -0,0 +1,51 @@
+#version 450
+#extension GL_EXT_shader_atomic_float : require
+layout(row_major) uniform;
+layout(row_major) buffer;
+
+#line 10 "tests/slang-extension/atomic-float-byte-address-buffer-cross.slang"
+layout(std430, binding = 1) buffer _S1 {
+ float _data[];
+} anotherBuffer_0;
+
+#line 60 "hlsl"
+layout(std430, binding = 0) buffer _S2 {
+ float _data[];
+} _S3;
+
+#line 18 "tests/slang-extension/atomic-float-byte-address-buffer-cross.slang"
+void RWByteAddressBuffer_InterlockedAddFp32_0(uint _S4, float _S5, out float _S6)
+{
+ uint _S7 = _S4 / uint(4);
+ float _S8 = (atomicAdd((((_S3)._data[(_S7)])), (_S5)));
+ _S6 = _S8;
+ return;
+}
+
+void RWByteAddressBuffer_InterlockedAddFp32_1(uint _S9, float _S10)
+{
+ uint _S11 = _S9 / uint(4);
+ float _S12 = (atomicAdd((((_S3)._data[(_S11)])), (_S10)));
+ return;
+}
+
+
+#line 13
+layout(local_size_x = 16, local_size_y = 1, local_size_z = 1) in;void main()
+{
+ uint tid_0 = gl_GlobalInvocationID.x;
+ int idx_0 = int(tid_0 & uint(3) ^ tid_0 >> 2);
+
+ float delta_0 = ((anotherBuffer_0)._data[(uint(idx_0 & 3))]);
+
+
+ uint _S13 = uint(idx_0 << 2);
+
+#line 21
+ float _S14;
+ RWByteAddressBuffer_InterlockedAddFp32_0(_S13, 1.00000000000000000000, _S14);
+ RWByteAddressBuffer_InterlockedAddFp32_1(uint(int(tid_0 >> 2) << 2), delta_0);
+
+#line 13
+ return;
+} \ No newline at end of file
diff --git a/tests/slang-extension/atomic-float-byte-address-buffer.slang b/tests/slang-extension/atomic-float-byte-address-buffer.slang
new file mode 100644
index 000000000..e6e2268ff
--- /dev/null
+++ b/tests/slang-extension/atomic-float-byte-address-buffer.slang
@@ -0,0 +1,34 @@
+// byte-address-buffer.slang
+
+//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
+//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
+// Disabled because crashes currently on vulkan
+//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
+// Disabled because requires nvapi to work
+// Note for this feature we require dxc and we can force that with -use-dxil
+//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-d3d12 -compute -use-dxil
+//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -use-dxil
+
+//TEST_INPUT:ubuffer(data=[0.1 0.2 0.3 0.4]):out,name=outputBuffer
+RWByteAddressBuffer outputBuffer;
+
+//TEST_INPUT:ubuffer(data=[0.7 0.5 0.2 0.6]):name=anotherBuffer
+RWStructuredBuffer<float> anotherBuffer;
+
+[numthreads(16, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ uint tid = dispatchThreadID.x;
+ int idx = (tid & 3) ^ (tid >> 2);
+
+ //const float delta = anotherBuffer[idx & 3];
+ const float delta = 0.0f;
+
+ float previousValue = 0;
+ outputBuffer.InterlockedAddFp32((idx << 2), 1.0f, previousValue);
+ //outputBuffer.InterlockedAddFp32((idx ^ 2) << 2, 2.0f + delta);
+
+ // The sum of values in anotherBuffer should also be added
+ //int anotherIdx = tid >> 2;
+ //outputBuffer.InterlockedAddFp32(anotherIdx << 2, delta);
+} \ No newline at end of file
diff --git a/tests/slang-extension/atomic-float-byte-address-buffer.slang.expected.txt b/tests/slang-extension/atomic-float-byte-address-buffer.slang.expected.txt
new file mode 100644
index 000000000..4affc7d87
--- /dev/null
+++ b/tests/slang-extension/atomic-float-byte-address-buffer.slang.expected.txt
@@ -0,0 +1,4 @@
+40833333
+40866666
+4089999A
+408CCCCD
diff --git a/tools/slang-test/options.cpp b/tools/slang-test/options.cpp
index 27b759a0e..875f9ef0b 100644
--- a/tools/slang-test/options.cpp
+++ b/tools/slang-test/options.cpp
@@ -266,6 +266,16 @@ static bool _isSubCommand(const char* arg)
return res;
}
}
+ else if (strcmp(arg, "-nv-api-path") == 0)
+ {
+ if (argCursor == argEnd)
+ {
+ stdError.print("error: expected operand for '%s'\n", arg);
+ return SLANG_FAIL;
+ }
+
+ optionsOut->nvAPIPath = *argCursor++;
+ }
else
{
stdError.print("unknown option '%s'\n", arg);
diff --git a/tools/slang-test/options.h b/tools/slang-test/options.h
index a8c2e3852..ddd905e64 100644
--- a/tools/slang-test/options.h
+++ b/tools/slang-test/options.h
@@ -98,6 +98,8 @@ struct Options
// The adapter to use. If empty will match first found adapter.
Slang::String adapter;
+ Slang::String nvAPIPath;
+
/// Parse the args, report any errors into stdError, and write the results into optionsOut
static SlangResult parse(int argc, char** argv, TestCategorySet* categorySet, Slang::WriterHelper stdError, Options* optionsOut);
};
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index 9ef013aad..c6562ed86 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -3191,8 +3191,6 @@ SlangResult innerMain(int argc, char** argv)
TestContext context;
SLANG_RETURN_ON_FAIL(SLANG_FAILED(context.init()))
- TestToolUtil::setSessionDefaultPrelude(argv[0], context.getSession());
-
auto& categorySet = context.categorySet;
// Set up our test categories here
@@ -3272,6 +3270,19 @@ SlangResult innerMain(int argc, char** argv)
Options& options = context.options;
+ // Set up the prelude
+ {
+ TestToolUtil::PreludeInfo info;
+ info.exePath = argv[0];
+
+ if (options.nvAPIPath.getLength())
+ {
+ info.nvAPIPath = options.nvAPIPath.getBuffer();
+ }
+
+ TestToolUtil::setSessionDefaultPrelude(info, context.getSession());
+ }
+
if (options.outputMode == TestOutputMode::TeamCity)
{
// On TeamCity CI there is an issue with unix/linux targets where test system may be different from the build system