diff options
| -rw-r--r-- | slang.h | 431 | ||||
| -rw-r--r-- | source/core/slang-com-ptr.h | 57 | ||||
| -rw-r--r-- | source/core/slang-defines.h | 171 | ||||
| -rw-r--r-- | source/core/slang-string.h | 12 | ||||
| -rw-r--r-- | source/slang/compiler.cpp | 27 | ||||
| -rw-r--r-- | source/slang/compiler.h | 38 | ||||
| -rw-r--r-- | source/slang/preprocessor.cpp | 6 | ||||
| -rw-r--r-- | source/slang/preprocessor.h | 2 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 320 | ||||
| -rw-r--r-- | source/slang/source-loc.cpp | 21 | ||||
| -rw-r--r-- | source/slang/source-loc.h | 14 |
11 files changed, 847 insertions, 252 deletions
@@ -1,6 +1,193 @@ #ifndef SLANG_H #define SLANG_H +/** \file slang.h + +The Slang API provides services to compile, reflect, and specialize code +written in the Slang shading language. +*/ + +/* +The following section attempts to detect the compiler and version in use. + +If an application defines `SLANG_COMPILER` before including this header, +they take responsibility for setting any compiler-dependent macros +used later in the file. + +Most applications should not need to touch this section. +*/ +#ifndef SLANG_COMPILER +# define SLANG_COMPILER + +/* +Compiler defines, see http://sourceforge.net/p/predef/wiki/Compilers/ +NOTE that SLANG_VC holds the compiler version - not just 1 or 0 +*/ +# if defined(_MSC_VER) +# if _MSC_VER >= 1900 +# define SLANG_VC 14 +# elif _MSC_VER >= 1800 +# define SLANG_VC 12 +# elif _MSC_VER >= 1700 +# define SLANG_VC 11 +# elif _MSC_VER >= 1600 +# define SLANG_VC 10 +# elif _MSC_VER >= 1500 +# define SLANG_VC 9 +# else +# error "unknown version of Visual C++ compiler" +# endif +# elif defined(__clang__) +# define SLANG_CLANG 1 +# elif defined(__SNC__) +# define SLANG_SNC 1 +# elif defined(__ghs__) +# define SLANG_GHS 1 +# elif defined(__GNUC__) /* note: __clang__, __SNC__, or __ghs__ imply __GNUC__ */ +# define SLANG_GCC 1 +# else +# error "unknown compiler" +# endif +/* +Any compilers not detected by the above logic are now now explicitly zeroed out. +*/ +# ifndef SLANG_VC +# define SLANG_VC 0 +# endif +# ifndef SLANG_CLANG +# define SLANG_CLANG 0 +# endif +# ifndef SLANG_SNC +# define SLANG_SNC 0 +# endif +# ifndef SLANG_GHS +# define SLANG_GHS 0 +# endif +# ifndef SLANG_GCC +# define SLANG_GCC 0 +# endif +#endif /* SLANG_COMPILER */ + +/* +The following section attempts to detect the target platform being compiled for. + +If an application defines `SLANG_PLATFORM` before including this header, +they take responsibility for setting any compiler-dependent macros +used later in the file. + +Most applications should not need to touch this section. +*/ +#ifndef SLANG_PLATFORM +# define SLANG_PLATFORM +/** +Operating system defines, see http://sourceforge.net/p/predef/wiki/OperatingSystems/ +*/ +# if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_PARTITION_APP +# define SLANG_WINRT 1 /* Windows Runtime, either on Windows RT or Windows 8 */ +# elif defined(XBOXONE) +# define SLANG_XBOXONE 1 +# elif defined(_WIN64) /* note: XBOXONE implies _WIN64 */ +# define SLANG_WIN64 1 +# elif defined(_M_PPC) +# define SLANG_X360 1 +# elif defined(_WIN32) /* note: _M_PPC implies _WIN32 */ +# define SLANG_WIN32 1 +# elif defined(__ANDROID__) +# define SLANG_ANDROID 1 +# elif defined(__linux__) || defined(__CYGWIN__) /* note: __ANDROID__ implies __linux__ */ +# define SLANG_LINUX 1 +# elif defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) +# define SLANG_IOS 1 +# elif defined(__APPLE__) +# define SLANG_OSX 1 +# elif defined(__CELLOS_LV2__) +# define SLANG_PS3 1 +# elif defined(__ORBIS__) +# define SLANG_PS4 1 +# elif defined(__SNC__) && defined(__arm__) +# define SLANG_PSP2 1 +# elif defined(__ghs__) +# define SLANG_WIIU 1 +# else +# error "unknown target platform" +# endif +/* +Any platforms not detected by the above logic are now now explicitly zeroed out. +*/ +# ifndef SLANG_WINRT +# define SLANG_WINRT 0 +# endif +# ifndef SLANG_XBOXONE +# define SLANG_XBOXONE 0 +# endif +# ifndef SLANG_WIN64 +# define SLANG_WIN64 0 +# endif +# ifndef SLANG_X360 +# define SLANG_X360 0 +# endif +# ifndef SLANG_WIN32 +# define SLANG_WIN32 0 +# endif +# ifndef SLANG_ANDROID +# define SLANG_ANDROID 0 +# endif +# ifndef SLANG_LINUX +# define SLANG_LINUX 0 +# endif +# ifndef SLANG_IOS +# define SLANG_IOS 0 +# endif +# ifndef SLANG_OSX +# define SLANG_OSX 0 +# endif +# ifndef SLANG_PS3 +# define SLANG_PS3 0 +# endif +# ifndef SLANG_PS4 +# define SLANG_PS4 0 +# endif +# ifndef SLANG_PSP2 +# define SLANG_PSP2 0 +# endif +# ifndef SLANG_WIIU +# define SLANG_WIIU 0 +# endif +#endif /* SLANG_PLATFORM */ + +/* Shorthands for "families" of compilers/platforms */ +#define SLANG_GCC_FAMILY (SLANG_CLANG || SLANG_SNC || SLANG_GHS || SLANG_GCC) +#define SLANG_WINDOWS_FAMILY (SLANG_WINRT || SLANG_WIN32 || SLANG_WIN64) +#define SLANG_MICROSOFT_FAMILY (SLANG_XBOXONE || SLANG_X360 || SLANG_WINDOWS_FAMILY) +#define SLANG_LINUX_FAMILY (SLANG_LINUX || SLANG_ANDROID) +#define SLANG_APPLE_FAMILY (SLANG_IOS || SLANG_OSX) /* equivalent to #if __APPLE__ */ +#define SLANG_UNIX_FAMILY (SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY) /* shortcut for unix/posix platforms */ + +/* Macro for declaring if a method is no throw. Should be set before the return parameter. */ +#ifndef SLANG_NO_THROW +# if SLANG_WINDOWS_FAMILY && !defined(SLANG_DISABLE_EXCEPTIONS) +# define SLANG_NO_THROW __declspec(nothrow) +# endif +#endif +#ifndef SLANG_NO_THROW +# define SLANG_NO_THROW +#endif + +/* The `SLANG_STDCALL` and `SLANG_MCALL` defines are used to set the calling +convention for interface methods. +*/ +#ifndef SLANG_STDCALL +# if SLANG_MICROSOFT_FAMILY +# define SLANG_STDCALL __stdcall +# else +# define SLANG_STDCALL +# endif +#endif +#ifndef SLANG_MCALL +# define SLANG_MCALL SLANG_STDCALL +#endif + + #if !defined(SLANG_STATIC) && !defined(SLANG_STATIC) #define SLANG_DYNAMIC #endif @@ -178,12 +365,95 @@ extern "C" SLANG_MATRIX_LAYOUT_COLUMN_MAJOR, }; -//#define SLANG_LAYOUT_UNIFORM 0 -//#define SLANG_LAYOUT_PACKED 1 -//#define SLANG_LAYOUT_STORAGE 2 + /** A result code for a Slang API operation. -#define SLANG_ERROR_INSUFFICIENT_BUFFER -1 -#define SLANG_ERROR_INVALID_PARAMETER -2 + This type is generally compatible with the Windows API + `HRESULT` type. In particular, negative values indicate + failure results, while zero or positive results indicate + success. + + In general, Slang APIs always return a zero result on + success, unless documented otherwise. + */ + typedef int32_t SlangResult; + + /** A "Universally Unique Identifier" (UUID) + + The Slang API uses UUIDs to identify interfaces when + using `queryInterface`. + + This type is compatible with the `GUID` type defined + by the Component Object Model (COM), but Slang is + not dependent on COM. + */ + struct SlangUUID + { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; + }; + + /** Base interface for components exchanged through the API. + + This interface definition is compatible with the COM `IUnknown`, + and uses the same UUID, but Slang does not require applications + to use or initialize COM. + */ + struct ISlangUnknown + { + public: + virtual SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) = 0; + virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() = 0; + virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() = 0; + + /* + Inline methods are provided to allow the above operations to be called + using their traditional COM names/signatures: + */ + SlangResult QueryInterface(struct _GUID const& uuid, void** outObject) { return queryInterface(*(SlangUUID const*)&uuid, outObject); } + uint32_t AddRef() { return addRef(); } + uint32_t Release() { return release(); } + }; + #define SLANG_UUID_ISlangUnknown { 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } + + /** A "blob" of binary data. + + This interface definition is compatible with the `ID3DBlob` and `ID3D10Blob` interfaces. + */ + struct ISlangBlob : public ISlangUnknown + { + public: + virtual SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() = 0; + virtual SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() = 0; + }; + #define SLANG_UUID_ISlangBlob { 0x8BA5FB08, 0x5195, 0x40e2, 0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02 } + + /** A (real or virtual) file system. + + Slang can make use of this interface whenever it would otherwise try to load files + from disk, allowing applications to hook and/or overide filesystem access from + the compiler. + */ + struct ISlangFileSystem : public ISlangUnknown + { + public: + /** Load a file from `path` and return a blob of its contents + + @param path The path to load from, as a nul-terminated UTF-8 string. + @param outBlob A destination pointer to receive the blob of the file contents. + @returns A `SlangResult` to indicate success or failure in loading the file. + + If load is successful, the implementation should create a blob to hold + the file's content, store it to `outBlob`, and return 0. + If the load fails, the implementation should return a failure status + (any negative value will do). + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile( + char const* path, + ISlangBlob** outBlob) = 0; + }; + #define SLANG_UUID_ISlangFileSystem { 0x003A09FC, 0x3A4D, 0x4BA0, 0xAD, 0x60, 0x1F, 0xD8, 0x63, 0xA9, 0x15, 0xAB } /*! @brief An instance of the Slang library. @@ -197,9 +467,8 @@ extern "C" /*! @brief Initialize an instance of the Slang library. - @param cacheDir The directory used to store cached compilation results. Pass NULL to disable caching. */ - SLANG_API SlangSession* spCreateSession(const char * cacheDir); + SLANG_API SlangSession* spCreateSession(const char* deprecated = 0); /*! @brief Clean up after an instance of the Slang library. @@ -228,6 +497,21 @@ extern "C" SLANG_API void spDestroyCompileRequest( SlangCompileRequest* request); + /** Set the filesystem hook to use for a compile request + + The provided `fileSystem` will be used to load any files that + need to be loaded during processing of the compile `request`. + This includes: + + - Source files loaded via `spAddTranslationUnitSourceFile` + - Files referenced via `#include` + - Files loaded to resolve `#import` operations + + */ + SLANG_API void spSetFileSystem( + SlangCompileRequest* request, + ISlangFileSystem* fileSystem); + /*! @brief Set flags to be used for compilation. @@ -355,16 +639,35 @@ extern "C" const char* value); - /** Add a source file to the given translation unit + /** Add a source file to the given translation unit. + + If a user-defined file system has been specified via + `spSetFileSystem`, then it will be used to load the + file at `path`. Otherwise, Slang will use the OS + file system. + + This function does *not* search for a file using + the registered search paths (`spAddSearchPath`), + and instead using the given `path` as-is. */ SLANG_API void spAddTranslationUnitSourceFile( SlangCompileRequest* request, int translationUnitIndex, char const* path); - /** Add a source string to the given translation unit + /** Add a source string to the given translation unit. + + @param request The comile request that owns the translation unit. + @param translationUnitIndex The index of the translation unit to add source to. + @param path The file-system path that should be assumed for the source code. + @param source A nul-terminated UTF-8 encoded string of source code. + + The implementation will make a copy of the source code data. + An application may free the buffer immediately after this call returns. - The `path` will be used in any diagnostic output. + The `path` will be used in any diagnostic output, as well + as to determine the base path when resolving relative + `#include`s. */ SLANG_API void spAddTranslationUnitSourceString( SlangCompileRequest* request, @@ -372,6 +675,49 @@ extern "C" char const* path, char const* source); + + /** Add a source string to the given translation unit. + + @param request The comile request that owns the translation unit. + @param translationUnitIndex The index of the translation unit to add source to. + @param path The file-system path that should be assumed for the source code. + @param sourceBegin A pointer to a buffer of UTF-8 encoded source code. + @param sourceEnd A pointer to to the end of the buffer specified in `sourceBegin` + + The implementation will make a copy of the source code data. + An application may free the buffer immediately after this call returns. + + The `path` will be used in any diagnostic output, as well + as to determine the base path when resolving relative + `#include`s. + */ + SLANG_API void spAddTranslationUnitSourceStringSpan( + SlangCompileRequest* request, + int translationUnitIndex, + char const* path, + char const* sourceBegin, + char const* sourceEnd); + + /** Add a blob of source code to the given translation unit. + + @param request The comile request that owns the translation unit. + @param translationUnitIndex The index of the translation unit to add source to. + @param path The file-system path that should be assumed for the source code. + @param sourceBlob A blob containing UTF-8 encoded source code. + @param sourceEnd A pointer to to the end of the buffer specified in `sourceBegin` + + The compile request will retain a reference to the blob. + + The `path` will be used in any diagnostic output, as well + as to determine the base path when resolving relative + `#include`s. + */ + SLANG_API void spAddTranslationUnitSourceBlob( + SlangCompileRequest* request, + int translationUnitIndex, + char const* path, + ISlangBlob* sourceBlob); + /** Look up a compilation profile by name. For example, one could look up the string `"ps_5_0"` to find the corresponding target ID. @@ -409,10 +755,28 @@ extern "C" /** Get any diagnostic messages reported by the compiler. + + @returns A nul-terminated UTF-8 encoded string of diagnostic messages. + + The returned pointer is only guaranteed to be valid + until `reqeust` is destroyed. Applications that wish to + hold on to the diagnostic output for longer should use + `spGetDiagnosticOutputBlob`. */ SLANG_API char const* spGetDiagnosticOutput( SlangCompileRequest* request); + /** Get diagnostic messages reported by the compiler. + + @param request The compile request to get output from. + @param outBlob A pointer to receive a blob holding a nul-terminated UTF-8 encoded string of diagnostic messages. + @returns A `SlangResult` indicating success or failure. + */ + SLANG_API SlangResult spGetDiagnosticOutputBlob( + SlangCompileRequest* request, + ISlangBlob** outBlob); + + /** Get the number of files that this compilation depended on. This includes both the explicit source files, as well as any @@ -436,14 +800,6 @@ extern "C" spGetTranslationUnitCount( SlangCompileRequest* request); - /** Get the output code associated with a specific translation unit. - - The lifetime of the output pointer is the same as `request`. - */ - SLANG_API char const* spGetTranslationUnitSource( - SlangCompileRequest* request, - int translationUnitIndex); - /** Get the output source code associated with a specific entry point. The lifetime of the output pointer is the same as `request`. @@ -461,6 +817,21 @@ extern "C" int entryPointIndex, size_t* outSize); + /** Get the output code associated with a specific entry point. + + @param entryPointIndex The index of the entry point to get code for. + @param targetIndex The index of the target to get code for (default: zero). + @param outBlob A pointer that will receive the blob of code + @returns A `SlangResult` to indicate success or failure. + + The lifetime of the output pointer is the same as `request`. + */ + SLANG_API SlangResult spGetEntryPointCodeBlob( + SlangCompileRequest* request, + int entryPointIndex, + int targetIndex, + ISlangBlob** outBlob); + /** Get the output bytecode associated with an entire compile request. The lifetime of the output pointer is the same as `request`. @@ -1278,4 +1649,28 @@ namespace slang #endif +/* DEPRECATED DEFINITIONS + +Everything below this point represents deprecated APIs/definition that are only +being kept around for source/binary compatibility with old client code. New +code should not use any of these declarations, and the Slang API will drop these +declarations over time. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SLANG_ERROR_INSUFFICIENT_BUFFER -1 +#define SLANG_ERROR_INVALID_PARAMETER -2 + +SLANG_API char const* spGetTranslationUnitSource( + SlangCompileRequest* request, + int translationUnitIndex); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/core/slang-com-ptr.h b/source/core/slang-com-ptr.h index 9f6651306..765edbee5 100644 --- a/source/core/slang-com-ptr.h +++ b/source/core/slang-com-ptr.h @@ -8,17 +8,17 @@ namespace Slang { -/*! \brief ComPtr is a simple smart pointer that manages types which implement COM based interfaces. +/*! \brief ComPtr is a simple smart pointer that manages types which implement COM based interfaces. \details A class that implements a COM, must derive from the IUnknown interface or a type that matches it's layout exactly (such as IForwardUnknown). Trying to use this template with a class that doesn't follow -these rules, will lead to undefined behavior. -This is a 'strong' pointer type, and will AddRef when a non null pointer is set and Release when the pointer -leaves scope. +these rules, will lead to undefined behavior. +This is a 'strong' pointer type, and will AddRef when a non null pointer is set and Release when the pointer +leaves scope. Using 'detach' allows a pointer to be removed from the management of the ComPtr. To set the smart pointer to null, there is the method setNull, or alternatively just assign SLANG_NULL/nullptr. One edge case using the template is that sometimes you want access as a pointer to a pointer. Sometimes this -is to write into the smart pointer, other times to pass as an array. To handle these different behaviors +is to write into the smart pointer, other times to pass as an array. To handle these different behaviors there are the methods readRef and writeRef, which are used instead of the & (ref) operator. For example \code @@ -31,7 +31,7 @@ ComPtr<ID3D12Resource> resources[3]; doSomething(resources[0].readRef(), SLANG_COUNT_OF(resource)); \endcode -A more common scenario writing to the pointer +A more common scenario writing to the pointer \code IUnknown* unk = ...; @@ -40,35 +40,29 @@ ComPtr<ID3D12Resource> resource; Result res = unk->QueryInterface(resource.writeRef()); \endcode */ - -struct Guid -{ - uint32_t data1; ///< Low field of the timestamp - uint16_t data2; ///< Middle field of the timestamp - uint16_t data3; ///< High field of the timestamp with multiplexed version number - uint8_t data4[8]; ///< 0, 1 = clock_seq_hi_and_reserved, clock_seq_low, followed by 'spatially unique node' (48 bits) -}; + +typedef SlangUUID Guid; SLANG_FORCE_INLINE bool operator==(const Guid& aIn, const Guid& bIn) { - // Use the largest type the honors the alignment of Guid - typedef uint32_t CmpType; - struct GuidCompare + // Use the largest type the honors the alignment of Guid + typedef uint32_t CmpType; + union GuidCompare { Guid guid; - CmpType data[sizeof(Guid) / sizeof(CmpType)]; + CmpType data[sizeof(Guid) / sizeof(CmpType)]; }; - // Type pun - so compiler can 'see' the pun and not break aliasing rules + // Type pun - so compiler can 'see' the pun and not break aliasing rules const CmpType* a = reinterpret_cast<const GuidCompare&>(aIn).data; const CmpType* b = reinterpret_cast<const GuidCompare&>(bIn).data; - // Make the guid comparison a single branch, by not using short circuit - return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]) | (a[3] ^ b[3])) == 0; -} + // Make the guid comparison a single branch, by not using short circuit + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]) | (a[3] ^ b[3])) == 0; +} SLANG_FORCE_INLINE bool operator!=(const Guid& a, const Guid& b) { return !(a == b); -} +} // Allows for defining of a GUID that works in C++ and C which defines in a format similar to microsofts INTERFACE style // MIDL_INTERFACE("00000000-0000-0000-C000-00 00 00 00 00 46") @@ -84,16 +78,9 @@ SLANG_FORCE_INLINE bool operator!=(const Guid& a, const Guid& b) // Compatible with Microsoft IUnknown static const Guid IID_IComUnknown = SLANG_MAKE_GUID(00000000, 0000, 0000, C000, 000000000046); -/// ! Must be kept in sync with IUnknown -class IComUnknown -{ -public: - virtual SLANG_NO_THROW Result SLANG_MCALL queryInterface(const Guid& iid, void* objOut) = 0; - virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() = 0; - virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() = 0; -}; +typedef ISlangUnknown IComUnknown; -// Enum to force initializing as an attach (without adding a reference) +// Enum to force initializing as an attach (without adding a reference) enum InitAttach { INIT_ATTACH @@ -139,7 +126,7 @@ public: /// For making method invocations through the smart pointer work through the dumb pointer SLANG_FORCE_INLINE T* operator->() const { return m_ptr; } - /// Assign + /// Assign SLANG_FORCE_INLINE const ThisType &operator=(const ThisType& rhs); /// Assign from dumb ptr SLANG_FORCE_INLINE T* operator=(T* in); @@ -202,7 +189,7 @@ T* ComPtr<T>::operator=(T* ptr) { if (ptr) ((Ptr)ptr)->addRef(); if (m_ptr) ((Ptr)m_ptr)->release(); - m_ptr = ptr; + m_ptr = ptr; return m_ptr; } //---------------------------------------------------------------------------- @@ -214,6 +201,6 @@ void ComPtr<T>::swap(ThisType& rhs) rhs.m_ptr = tmp; } -} // namespace Slang +} // namespace Slang #endif // SLANG_COM_PTR_H diff --git a/source/core/slang-defines.h b/source/core/slang-defines.h index 98993d662..580dd801c 100644 --- a/source/core/slang-defines.h +++ b/source/core/slang-defines.h @@ -2,140 +2,15 @@ #define SLANG_DEFINES_H /* -The following preprocessor identifiers specify compiler, OS, and architecture. -All definitions have a value of 1 or 0, use '#if' instead of '#ifdef'. +Some of our `#define`s are needed in the public API header as well, so +we will go ahead and include that here so that we can share the definitions. */ - -#ifndef SLANG_COMPILER -# define SLANG_COMPILER +#include "../../slang.h" /* -Compiler defines, see http://sourceforge.net/p/predef/wiki/Compilers/ -NOTE that SLANG_VC holds the compiler version - not just 1 or 0 -*/ -# if defined(_MSC_VER) -# if _MSC_VER >= 1900 -# define SLANG_VC 14 -# elif _MSC_VER >= 1800 -# define SLANG_VC 12 -# elif _MSC_VER >= 1700 -# define SLANG_VC 11 -# elif _MSC_VER >= 1600 -# define SLANG_VC 10 -# elif _MSC_VER >= 1500 -# define SLANG_VC 9 -# else -# error "Unknown VC version" -# endif -# elif defined(__clang__) -# define SLANG_CLANG 1 -# elif defined(__SNC__) -# define SLANG_SNC 1 -# elif defined(__ghs__) -# define SLANG_GHS 1 -# elif defined(__GNUC__) // note: __clang__, __SNC__, or __ghs__ imply __GNUC__ -# define SLANG_GCC 1 -# else -# error "Unknown compiler" -# endif - -// Zero unset -# ifndef SLANG_VC -# define SLANG_VC 0 -# endif -# ifndef SLANG_CLANG -# define SLANG_CLANG 0 -# endif -# ifndef SLANG_SNC -# define SLANG_SNC 0 -# endif -# ifndef SLANG_GHS -# define SLANG_GHS 0 -# endif -# ifndef SLANG_GCC -# define SLANG_GCC 0 -# endif - -#endif // SLANG_COMPILER - -#ifndef SLANG_PLATFORM -# define SLANG_PLATFORM - -/** -Operating system defines, see http://sourceforge.net/p/predef/wiki/OperatingSystems/ +The following preprocessor identifiers specify compiler, OS, and architecture. +All definitions have a value of 1 or 0, use '#if' instead of '#ifdef'. */ -# if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_PARTITION_APP -# define SLANG_WINRT 1 // Windows Runtime, either on Windows RT or Windows 8 -# elif defined(XBOXONE) -# define SLANG_XBOXONE 1 -# elif defined(_WIN64) // note: XBOXONE implies _WIN64 -# define SLANG_WIN64 1 -# elif defined(_M_PPC) -# define SLANG_X360 1 -# elif defined(_WIN32) // note: _M_PPC implies _WIN32 -# define SLANG_WIN32 1 -# elif defined(__ANDROID__) -# define SLANG_ANDROID 1 -# elif defined(__linux__) || defined(__CYGWIN__) // note: __ANDROID__ implies __linux__ -# define SLANG_LINUX 1 -# elif defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) -# define SLANG_IOS 1 -# elif defined(__APPLE__) -# define SLANG_OSX 1 -# elif defined(__CELLOS_LV2__) -# define SLANG_PS3 1 -# elif defined(__ORBIS__) -# define SLANG_PS4 1 -# elif defined(__SNC__) && defined(__arm__) -# define SLANG_PSP2 1 -# elif defined(__ghs__) -# define SLANG_WIIU 1 -# else -# error "Unknown operating system" -# endif - -// zero unset -# ifndef SLANG_WINRT -# define SLANG_WINRT 0 -# endif -# ifndef SLANG_XBOXONE -# define SLANG_XBOXONE 0 -# endif -# ifndef SLANG_WIN64 -# define SLANG_WIN64 0 -# endif -# ifndef SLANG_X360 -# define SLANG_X360 0 -# endif -# ifndef SLANG_WIN32 -# define SLANG_WIN32 0 -# endif -# ifndef SLANG_ANDROID -# define SLANG_ANDROID 0 -# endif -# ifndef SLANG_LINUX -# define SLANG_LINUX 0 -# endif -# ifndef SLANG_IOS -# define SLANG_IOS 0 -# endif -# ifndef SLANG_OSX -# define SLANG_OSX 0 -# endif -# ifndef SLANG_PS3 -# define SLANG_PS3 0 -# endif -# ifndef SLANG_PS4 -# define SLANG_PS4 0 -# endif -# ifndef SLANG_PSP2 -# define SLANG_PSP2 0 -# endif -# ifndef SLANG_WIIU -# define SLANG_WIIU 0 -# endif - -#endif // SLANG_PLATFORM #ifndef SLANG_PROCESSOR # define SLANG_PROCESSOR @@ -217,15 +92,6 @@ define anything not defined through the command line to 0 /** family shortcuts */ -// compiler -#define SLANG_GCC_FAMILY (SLANG_CLANG || SLANG_SNC || SLANG_GHS || SLANG_GCC) - -// os -#define SLANG_WINDOWS_FAMILY (SLANG_WINRT || SLANG_WIN32 || SLANG_WIN64) -#define SLANG_MICROSOFT_FAMILY (SLANG_XBOXONE || SLANG_X360 || SLANG_WINDOWS_FAMILY) -#define SLANG_LINUX_FAMILY (SLANG_LINUX || SLANG_ANDROID) -#define SLANG_APPLE_FAMILY (SLANG_IOS || SLANG_OSX) // equivalent to #if __APPLE__ -#define SLANG_UNIX_FAMILY (SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY) // shortcut for unix/posix platforms // architecture #define SLANG_INTEL_FAMILY (SLANG_X64 || SLANG_X86) // Intel x86 family #define SLANG_ARM_FAMILY (SLANG_ARM || SLANG_A64) @@ -233,9 +99,9 @@ family shortcuts #define SLANG_P64_FAMILY (SLANG_X64 || SLANG_A64) // shortcut for 64-bit architectures -// Use for getting the amount of members of a standard C array. +// Use for getting the amount of members of a standard C array. #define SLANG_COUNT_OF(x) (sizeof(x)/sizeof(x[0])) -/// SLANG_INLINE exists to have a way to inline consistent with SLANG_ALWAYS_INLINE +/// SLANG_INLINE exists to have a way to inline consistent with SLANG_ALWAYS_INLINE #define SLANG_INLINE inline // Other defines @@ -253,7 +119,7 @@ family shortcuts General defines */ -// GCC Specific +// GCC Specific #if SLANG_GCC_FAMILY # define SLANG_NO_INLINE __attribute__((noinline)) @@ -264,7 +130,7 @@ General defines # if !SLANG_SNC && !SLANG_GHS # define SLANG_OFFSET_OF(X, Y) __builtin_offsetof(X, Y) -# endif +# endif //# if !SLANG_LINUX // Workaround; Fedora Core 3 do not agree with force inline # define SLANG_FORCE_INLINE inline __attribute__((always_inline)) @@ -314,7 +180,6 @@ General defines # define SLANG_INT64(x) (x##i64) # define SLANG_UINT64(x) (x##ui64) -# define SLANG_STDCALL __stdcall # define SLANG_CALL_CONV __cdecl #endif // SLANG_MICROSOFT_FAMILY @@ -340,7 +205,7 @@ General defines #ifndef SLANG_FORCE_INLINE # define SLANG_FORCE_INLINE inline #endif -#ifndef SLANG_NO_INLINE +#ifndef SLANG_NO_INLINE # define SLANG_NO_INLINE #endif #ifndef SLANG_NO_ALIAS @@ -364,15 +229,12 @@ General defines # define SLANG_FUNCTION_SIG SLANG_FUNCTION_NAME #endif -#ifndef SLANG_STDCALL -# define SLANG_STDCALL -#endif #ifndef SLANG_CALL_CONV # define SLANG_CALL_CONV #endif //! casting the null ptr takes a special-case code path, which we don't want -#define SLANG_OFFSETOF_BASE 0x100 +#define SLANG_OFFSETOF_BASE 0x100 #define SLANG_OFFSET_OF_RT(Class, Member) \ (reinterpret_cast<size_t>(&reinterpret_cast<Class*>(SLANG_OFFSETOF_BASE)->Member) - size_t(SLANG_OFFSETOF_BASE)) @@ -404,18 +266,13 @@ General defines # define SLANG_HAS_ENUM_CLASS 1 # endif # if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 -# define SLANG_OVERRIDE override +# define SLANG_OVERRIDE override # endif # endif # endif // SLANG_GCC_FAMILY // Visual Studio -// Macro for declaring if a method is no throw. Should be set before the return parameter. -#if SLANG_WINDOWS_FAMILY && !defined(SLANG_DISABLE_EXCEPTIONS) -# define SLANG_NO_THROW __declspec(nothrow) -#endif - # if SLANG_VC // C4481: nonstandard extension used: override specifier 'override' # if _MSC_VER < 1700 @@ -434,7 +291,7 @@ General defines # if SLANG_CLANG # endif // SLANG_CLANG -// Set non set +// Set non set #ifndef SLANG_NO_THROW # define SLANG_NO_THROW @@ -449,8 +306,6 @@ General defines # define SLANG_HAS_MOVE_SEMANTICS 0 #endif -#define SLANG_MCALL SLANG_STDCALL - #include <new> // For placement new #endif // __cplusplus diff --git a/source/core/slang-string.h b/source/core/slang-string.h index 894776ca6..a67597360 100644 --- a/source/core/slang-string.h +++ b/source/core/slang-string.h @@ -172,7 +172,7 @@ namespace Slang { return i; } - } + } return -1; } @@ -412,6 +412,11 @@ namespace Slang append(slice); } + String(UnownedStringSlice const& slice) + { + append(slice); + } + ~String() { buffer = 0; @@ -741,6 +746,11 @@ namespace Slang Append(str); return *this; } + StringBuilder & operator << (UnownedStringSlice const& str) + { + append(str); + return *this; + } StringBuilder & operator << (const _EndLine) { Append('\n'); diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp index 66df01db0..9c1823f91 100644 --- a/source/slang/compiler.cpp +++ b/source/slang/compiler.cpp @@ -52,7 +52,7 @@ // Includes to allow us to control console // output when writing assembly dumps. -#include <fcntl.h> +#include <fcntl.h> #ifdef _WIN32 #include <io.h> #else @@ -97,6 +97,28 @@ namespace Slang } } + ComPtr<ISlangBlob> CompileResult::getBlob() + { + if(!blob) + { + switch(format) + { + case ResultFormat::None: + default: + break; + + case ResultFormat::Text: + blob = createStringBlob(outputString); + break; + + case ResultFormat::Binary: + blob = createRawBlob(outputBinary.Buffer(), outputBinary.Count()); + break; + } + } + return blob; + } + // EntryPointRequest TranslationUnitRequest* EntryPointRequest::getTranslationUnit() @@ -149,6 +171,7 @@ namespace Slang } } codeBuilder << "\"\n"; + codeBuilder << sourceFile->content << "\n"; } @@ -886,7 +909,7 @@ String dissassembleDXILUsingDXC( void emitEntryPoints( TargetRequest* /*targetReq*/) { - + } void generateOutputForTarget( diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 3a5f888fe..acbad9a7e 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -2,6 +2,7 @@ #define RASTER_SHADER_COMPILER_H #include "../core/basic.h" +#include "../core/slang-com-ptr.h" #include "diagnostics.h" #include "name.h" @@ -99,9 +100,13 @@ namespace Slang void append(CompileResult const& result); + ComPtr<ISlangBlob> getBlob(); + ResultFormat format = ResultFormat::None; String outputString; List<uint8_t> outputBinary; + + ComPtr<ISlangBlob> blob; }; // Describes an entry point that we've been requested to compile @@ -281,6 +286,14 @@ namespace Slang class Session; + /// Create a blob that will retain a string for its lifetime. + /// + ComPtr<ISlangBlob> createStringBlob(String const& string); + + /// Create a blob that will retain (a copy of) raw data. + /// + ComPtr<ISlangBlob> createRawBlob(void const* data, size_t size); + class CompileRequest : public RefObject { public: @@ -348,6 +361,9 @@ namespace Slang DiagnosticSink mSink; String mDiagnosticOutput; + /// A blob holding the diagnostic output + ComPtr<ISlangBlob> diagnosticOutputBlob; + // Files that compilation depended on List<String> mDependencyFilePaths; @@ -368,6 +384,21 @@ namespace Slang // The resulting specialized IR module for each entry point request List<RefPtr<IRModule>> compiledModules; + /// File system implementation to use when loading files from disk. + /// + /// If this member is `null`, a default implementation that tries + /// to use the native OS filesystem will be used instead. + /// + ComPtr<ISlangFileSystem> fileSystem; + + /// Load a file into memory using the configured file system. + /// + /// @param path The path to attempt to load from + /// @param outBlob A destination pointer to receive the loaded blob + /// @returns A `SlangResult` to indicate success or failure. + /// + SlangResult loadFile(String const& path, ISlangBlob** outBlob); + CompileRequest(Session* session); ~CompileRequest(); @@ -394,6 +425,11 @@ namespace Slang int translationUnitIndex, SourceFile* sourceFile); + void addTranslationUnitSourceBlob( + int translationUnitIndex, + String const& path, + ISlangBlob* sourceBlob); + void addTranslationUnitSourceString( int translationUnitIndex, String const& path, @@ -415,7 +451,7 @@ namespace Slang RefPtr<ModuleDecl> loadModule( Name* name, String const& path, - String const& source, + ISlangBlob* sourceBlob, SourceLoc const& loc); void loadParsedModule( diff --git a/source/slang/preprocessor.cpp b/source/slang/preprocessor.cpp index 301264632..3ec44fc28 100644 --- a/source/slang/preprocessor.cpp +++ b/source/slang/preprocessor.cpp @@ -1581,7 +1581,7 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context) auto expandedDirectiveLoc = context->preprocessor->translationUnit->compileRequest->getSourceManager()->expandSourceLoc(directiveLoc); String pathIncludedFrom = expandedDirectiveLoc.getSpellingPath(); String foundPath; - String foundSource; + ComPtr<ISlangBlob> foundSourceBlob; IncludeHandler* includeHandler = context->preprocessor->includeHandler; if (!includeHandler) @@ -1590,7 +1590,7 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context) GetSink(context)->diagnose(pathToken.loc, Diagnostics::noIncludeHandlerSpecified); return; } - auto includeResult = includeHandler->TryToFindIncludeFile(path, pathIncludedFrom, &foundPath, &foundSource); + auto includeResult = includeHandler->TryToFindIncludeFile(path, pathIncludedFrom, &foundPath, foundSourceBlob.writeRef()); switch (includeResult) { @@ -1611,7 +1611,7 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context) // Push the new file onto our stack of input streams // TODO(tfoley): check if we have made our include stack too deep - SourceFile* sourceFile = context->preprocessor->getCompileRequest()->getSourceManager()->allocateSourceFile(foundPath, foundSource); + SourceFile* sourceFile = context->preprocessor->getCompileRequest()->getSourceManager()->allocateSourceFile(foundPath, foundSourceBlob); PreprocessorInputStream* inputStream = CreateInputStreamForSource(context->preprocessor, sourceFile); inputStream->parent = context->preprocessor->inputStream; diff --git a/source/slang/preprocessor.h b/source/slang/preprocessor.h index 64591ef03..0e30038bf 100644 --- a/source/slang/preprocessor.h +++ b/source/slang/preprocessor.h @@ -26,7 +26,7 @@ struct IncludeHandler String const& pathToInclude, String const& pathIncludedFrom, String* outFoundPath, - String* outFoundSource) = 0; + ISlangBlob** outFoundSourceBlob) = 0; }; // Take a string of source code and preprocess it into a list of tokens. diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 2d3e9ee77..24dff88a8 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -81,32 +81,29 @@ struct IncludeHandlerImpl : IncludeHandler String const& pathToInclude, String const& pathIncludedFrom, String* outFoundPath, - String* outFoundSource) override + ISlangBlob** outFoundSourceBlob) override { String path = Path::Combine(Path::GetDirectoryName(pathIncludedFrom), pathToInclude); - if (File::Exists(path)) + + if(SLANG_SUCCEEDED(request->loadFile(path, outFoundSourceBlob))) { *outFoundPath = path; - *outFoundSource = File::ReadAllText(path); - request->mDependencyFilePaths.Add(path); - return IncludeResult::Found; } for (auto & dir : request->searchDirectories) { path = Path::Combine(dir.path, pathToInclude); - if (File::Exists(path)) + + if(SLANG_SUCCEEDED(request->loadFile(path, outFoundSourceBlob))) { *outFoundPath = path; - *outFoundSource = File::ReadAllText(path); - request->mDependencyFilePaths.Add(path); - return IncludeResult::Found; } } + return IncludeResult::NotFound; } }; @@ -205,11 +202,168 @@ CompileRequest::~CompileRequest() types = decltype(types)(); } +// Allocate static const storage for the various interface IDs that the Slang API needs to expose +static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown; +static const Guid IID_ISlangBlob = SLANG_UUID_ISlangBlob; + +/** Base class for simple blobs. +*/ +class BlobBase : public ISlangBlob +{ +public: + BlobBase() {} + virtual ~BlobBase() {} + + uint32_t referenceCount = 0; + + // ISlangUnknown + + SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE + { + if(uuid == IID_IComUnknown) + { + *(ISlangUnknown**)outObject = this; + addRef(); + return SLANG_OK; + } + else if(uuid == IID_ISlangBlob) + { + *(ISlangBlob**)outObject = this; + addRef(); + return SLANG_OK; + } + + return SLANG_FAIL; + } + + SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE + { + referenceCount++; + return 0; + } + + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE + { + if(--referenceCount == 0) + { + delete this; + } + return 0; + } + +}; + +/** A blob that uses a `String` for its storage. +*/ +class StringBlob : public BlobBase +{ +public: + String string; + + explicit StringBlob(String const& string) + : string(string) + {} + + // ISlangBlob + + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return string.Buffer(); + } + + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE + { + return string.Length(); + } +}; + +ComPtr<ISlangBlob> createStringBlob(String const& string) +{ + return ComPtr<ISlangBlob>(new StringBlob(string)); +} + +/** A blob that manages some raw data that it owns. +*/ +class RawBlob : public BlobBase +{ +public: + void* data; + size_t size; + + ~RawBlob() + { + free(data); + } + + // ISlangBlob + + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return data; + } + + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE + { + return size; + } +}; + + +ComPtr<ISlangBlob> createRawBlob(void const* inData, size_t size) +{ + void* dataCopy = malloc(size); + memcpy(dataCopy, inData, size); + + RawBlob* rawBlob = new RawBlob(); + rawBlob->data = dataCopy; + rawBlob->size = size; + + return ComPtr<ISlangBlob>(rawBlob); +} + + +SlangResult CompileRequest::loadFile(String const& path, ISlangBlob** outBlob) +{ + // If there is a used-defined filesystem, then use that to load files. + // + if(fileSystem) + { + return fileSystem->loadFile(path.Buffer(), outBlob); + } + + // Otherwise, fall back to a default implementation that uses the `core` + // libraries facilities for talking to the OS filesystem. + // + // TODO: we might want to conditionally compile these in, so that + // a user could create a build of Slang that doesn't include any OS + // filesystem calls. + // + + if (!File::Exists(path)) + { + return SLANG_FAIL; + } + + try + { + String sourceString = File::ReadAllText(path); + ComPtr<ISlangBlob> sourceBlob = createStringBlob(sourceString); + *outBlob = sourceBlob.detach(); + + return SLANG_OK; + } + catch(...) + { + } + return SLANG_FAIL; + +} + RefPtr<Expr> CompileRequest::parseTypeString(TranslationUnitRequest * translationUnit, String typeStr, RefPtr<Scope> scope) { Slang::SourceFile srcFile; - srcFile.content = typeStr; + srcFile.content = UnownedStringSlice(typeStr.begin(), typeStr.end()); DiagnosticSink sink; sink.sourceManager = sourceManager; auto tokens = preprocessSource( @@ -484,6 +638,16 @@ void CompileRequest::addTranslationUnitSourceFile( translationUnits[translationUnitIndex]->sourceFiles.Add(sourceFile); } +void CompileRequest::addTranslationUnitSourceBlob( + int translationUnitIndex, + String const& path, + ISlangBlob* sourceBlob) +{ + RefPtr<SourceFile> sourceFile = getSourceManager()->allocateSourceFile(path, sourceBlob); + + addTranslationUnitSourceFile(translationUnitIndex, sourceFile); +} + void CompileRequest::addTranslationUnitSourceString( int translationUnitIndex, String const& path, @@ -498,12 +662,17 @@ void CompileRequest::addTranslationUnitSourceFile( int translationUnitIndex, String const& path) { - String source; - try - { - source = File::ReadAllText(path); - } - catch (...) + // TODO: We need to consider whether a relative `path` should cause + // us to look things up using the registered search paths. + // + // This behavior wouldn't make sense for command-line invocations + // of `slangc`, but at least one API user wondered by the search + // paths were not taken into account by this function. + // + + ComPtr<ISlangBlob> sourceBlob; + SlangResult result = loadFile(path, sourceBlob.writeRef()); + if(SLANG_FAILED(result)) { // Emit a diagnostic! mSink.diagnose( @@ -513,10 +682,10 @@ void CompileRequest::addTranslationUnitSourceFile( return; } - addTranslationUnitSourceString( + addTranslationUnitSourceBlob( translationUnitIndex, path, - source); + sourceBlob); mDependencyFilePaths.Add(path); } @@ -590,7 +759,7 @@ void CompileRequest::loadParsedModule( RefPtr<ModuleDecl> CompileRequest::loadModule( Name* name, String const& path, - String const& source, + ISlangBlob* sourceBlob, SourceLoc const& srcLoc) { RefPtr<TranslationUnitRequest> translationUnit = new TranslationUnitRequest(); @@ -603,7 +772,7 @@ RefPtr<ModuleDecl> CompileRequest::loadModule( // TODO: decide which options, if any, should be inherited. translationUnit->compileFlags = 0; - RefPtr<SourceFile> sourceFile = getSourceManager()->allocateSourceFile(path, source); + RefPtr<SourceFile> sourceFile = getSourceManager()->allocateSourceFile(path, sourceBlob); translationUnit->sourceFiles.Add(sourceFile); @@ -687,8 +856,8 @@ RefPtr<ModuleDecl> CompileRequest::findOrImportModule( String pathIncludedFrom = expandedLoc.getSpellingPath(); String foundPath; - String foundSource; - IncludeResult includeResult = includeHandler.TryToFindIncludeFile(fileName, pathIncludedFrom, &foundPath, &foundSource); + ComPtr<ISlangBlob> foundSourceBlob; + IncludeResult includeResult = includeHandler.TryToFindIncludeFile(fileName, pathIncludedFrom, &foundPath, foundSourceBlob.writeRef()); switch( includeResult ) { case IncludeResult::NotFound: @@ -715,7 +884,7 @@ RefPtr<ModuleDecl> CompileRequest::findOrImportModule( return loadModule( name, foundPath, - foundSource, + foundSourceBlob, loc); } @@ -832,7 +1001,7 @@ Session::~Session() constExprRate = nullptr; destroyTypeCheckingCache(); - + builtinTypes = decltype(builtinTypes)(); // destroy modules next loadedModuleCode = decltype(loadedModuleCode)(); @@ -895,6 +1064,16 @@ SLANG_API void spDestroyCompileRequest( delete req; } +SLANG_API void spSetFileSystem( + SlangCompileRequest* request, + ISlangFileSystem* fileSystem) +{ + if(!request) return; + auto req = REQ(request); + req->fileSystem = fileSystem; +} + + SLANG_API void spSetCompileFlags( SlangCompileRequest* request, SlangCompileFlags flags) @@ -1021,6 +1200,25 @@ SLANG_API char const* spGetDiagnosticOutput( return req->mDiagnosticOutput.begin(); } +SLANG_API SlangResult spGetDiagnosticOutputBlob( + SlangCompileRequest* request, + ISlangBlob** outBlob) +{ + if(!request) return SLANG_ERROR_INVALID_PARAMETER; + if(!outBlob) return SLANG_ERROR_INVALID_PARAMETER; + + auto req = REQ(request); + + if(!req->diagnosticOutputBlob) + { + req->diagnosticOutputBlob = Slang::createStringBlob(req->mDiagnosticOutput); + } + + Slang::ComPtr<ISlangBlob> resultBlob = req->diagnosticOutputBlob; + *outBlob = resultBlob.detach(); + return SLANG_OK; +} + // New-fangled compilation API SLANG_API int spAddTranslationUnit( @@ -1063,16 +1261,31 @@ SLANG_API void spAddTranslationUnitSourceFile( path); } -// Add a source string to the given translation unit SLANG_API void spAddTranslationUnitSourceString( SlangCompileRequest* request, int translationUnitIndex, char const* path, char const* source) { + if(!source) return; + spAddTranslationUnitSourceStringSpan( + request, + translationUnitIndex, + path, + source, + source + strlen(source)); +} + +SLANG_API void spAddTranslationUnitSourceStringSpan( + SlangCompileRequest* request, + int translationUnitIndex, + char const* path, + char const* sourceBegin, + char const* sourceEnd) +{ if(!request) return; auto req = REQ(request); - if(!source) return; + if(!sourceBegin) return; if(translationUnitIndex < 0) return; if(Slang::UInt(translationUnitIndex) >= req->translationUnits.Count()) return; @@ -1081,10 +1294,34 @@ SLANG_API void spAddTranslationUnitSourceString( req->addTranslationUnitSourceString( translationUnitIndex, path, - source); + Slang::UnownedStringSlice(sourceBegin, sourceEnd)); +} +SLANG_API void spAddTranslationUnitSourceBlob( + SlangCompileRequest* request, + int translationUnitIndex, + char const* path, + ISlangBlob* sourceBlob) +{ + if(!request) return; + auto req = REQ(request); + if(!sourceBlob) return; + if(translationUnitIndex < 0) return; + if(Slang::UInt(translationUnitIndex) >= req->translationUnits.Count()) return; + + if(!path) path = ""; + + req->addTranslationUnitSourceBlob( + translationUnitIndex, + path, + sourceBlob); } + + + + + SLANG_API SlangProfileID spFindProfile( SlangSession*, char const* name) @@ -1267,6 +1504,35 @@ SLANG_API void const* spGetEntryPointCode( return data; } +SLANG_API SlangResult spGetEntryPointCodeBlob( + SlangCompileRequest* request, + int entryPointIndex, + int targetIndex, + ISlangBlob** outBlob) +{ + if(!request) return SLANG_ERROR_INVALID_PARAMETER; + if(!outBlob) return SLANG_ERROR_INVALID_PARAMETER; + + auto req = REQ(request); + + int targetCount = (int) req->targets.Count(); + if((targetIndex < 0) || (targetIndex >= targetCount)) + { + return SLANG_ERROR_INVALID_PARAMETER; + } + auto targetReq = req->targets[targetIndex]; + + int entryPointCount = (int) req->entryPoints.Count(); + if((entryPointIndex < 0) || (entryPointIndex >= entryPointCount)) + { + return SLANG_ERROR_INVALID_PARAMETER; + } + Slang::CompileResult& result = targetReq->entryPointResults[entryPointIndex]; + + *outBlob = result.getBlob().detach(); + return SLANG_OK; +} + SLANG_API char const* spGetEntryPointSource( SlangCompileRequest* request, int entryPointIndex) diff --git a/source/slang/source-loc.cpp b/source/slang/source-loc.cpp index 80556ac37..3042c3bd4 100644 --- a/source/slang/source-loc.cpp +++ b/source/slang/source-loc.cpp @@ -1,6 +1,8 @@ // source-loc.cpp #include "source-loc.h" +#include "compiler.h" + namespace Slang { String ExpandedSourceLoc::getPath() const @@ -70,15 +72,18 @@ SourceRange SourceManager::allocateSourceRange(UInt size) SourceFile* SourceManager::allocateSourceFile( String const& path, - String const& content) + ISlangBlob* contentBlob) { - UInt size = content.Length(); + char const* contentBegin = (char const*) contentBlob->getBufferPointer(); + UInt contentSize = contentBlob->getBufferSize(); + char const* contentEnd = contentBegin + contentSize; - SourceRange sourceRange = allocateSourceRange(size); + SourceRange sourceRange = allocateSourceRange(contentSize); SourceFile* sourceFile = new SourceFile(); sourceFile->path = path; - sourceFile->content = content; + sourceFile->contentBlob = contentBlob; + sourceFile->content = UnownedStringSlice(contentBegin, contentEnd); sourceFile->sourceRange = sourceRange; Entry entry; @@ -91,6 +96,14 @@ SourceFile* SourceManager::allocateSourceFile( return sourceFile; } +SourceFile* SourceManager::allocateSourceFile( + String const& path, + String const& content) +{ + ComPtr<ISlangBlob> contentBlob = createStringBlob(content); + return allocateSourceFile(path, contentBlob); +} + SourceLoc SourceManager::allocateSourceFileForLineDirective( SourceLoc const& directiveLoc, String const& path, diff --git a/source/slang/source-loc.h b/source/slang/source-loc.h index 83ad87633..88ec6b62a 100644 --- a/source/slang/source-loc.h +++ b/source/slang/source-loc.h @@ -3,6 +3,9 @@ #define SLANG_SOURCE_LOC_H_INCLUDED #include "../core/basic.h" +#include "../core/slang-com-ptr.h" + +#include "../../slang.h" namespace Slang { @@ -73,8 +76,11 @@ public: // The logical file path to report for locations inside this span. String path; - // The actual contents of the file. - String content; + /// A blob that owns the storage for the file contents + ComPtr<ISlangBlob> contentBlob; + + /// The actual contents of the file. + UnownedStringSlice content; // The range of source locations that the span covers SourceRange sourceRange; @@ -134,6 +140,10 @@ struct SourceManager SourceFile* allocateSourceFile( String const& path, + ISlangBlob* content); + + SourceFile* allocateSourceFile( + String const& path, String const& content); SourceLoc allocateSourceFileForLineDirective( |
