diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2022-06-02 14:13:35 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-02 14:13:35 -0400 |
| commit | b39c99661b3ad482bbd419c24991ed325b5738a9 (patch) | |
| tree | 0f90fecdae10e704b2c1135c48ca5eeafa60b780 | |
| parent | bc6bc56db51d06b92dc63ef9c9e0def6c9760c9e (diff) | |
COM interfaces with host callable (#2258)
* #include an absolute path didn't work - because paths were taken to always be relative.
* Use TerminatedUnownedStringSlice for literals in output C++.
* Remove Escape/Unescape functions used in slang-token-reader.cpp
Add target type of 'host-cpp' etc to map to the target types.
* Fix some corner cases around string encoding.
* Added unit test for string escaping.
Fixed some assorted escaping bugs.
* Updated test output.
* Added decode test.
* Stop using hex output, to get around 'greedy' aspect. Use octal instead.
* Added HostHostCallable
Small changes to use ArtifactDesc/Info instead of large switches.
* Fix C++ emit to handle arbitrary function export.
* Add options handling for callable without an output being specified.
* Can compile with COM interface. Added example using com interface.
* Use the IR Ptr type instead of hack in C++ emit for interfaces.
* Fix issue with outputting the COM call when ptr is used.
* Fix crash issue on compilation failure.
27 files changed, 770 insertions, 108 deletions
diff --git a/build/visual-studio/cpu-com-example/cpu-com-example.vcxproj b/build/visual-studio/cpu-com-example/cpu-com-example.vcxproj new file mode 100644 index 000000000..d5f326bfe --- /dev/null +++ b/build/visual-studio/cpu-com-example/cpu-com-example.vcxproj @@ -0,0 +1,293 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug aarch64|Win32"> + <Configuration>Debug aarch64</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug aarch64|x64"> + <Configuration>Debug aarch64</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug aarch64|ARM"> + <Configuration>Debug aarch64</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release aarch64|Win32"> + <Configuration>Release aarch64</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release aarch64|x64"> + <Configuration>Release aarch64</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release aarch64|ARM"> + <Configuration>Release aarch64</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{0996B38F-F512-A7D2-1E90-A7E60A6C4366}</ProjectGuid> + <IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename> + <Keyword>Win32Proj</Keyword> + <RootNamespace>cpu-com-example</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v142</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v142</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug aarch64|ARM'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v142</PlatformToolset> + <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v142</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v142</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release aarch64|ARM'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v142</PlatformToolset> + <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug aarch64|ARM'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release aarch64|ARM'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>..\..\..\bin\windows-x86\debug\</OutDir> + <IntDir>..\..\..\intermediate\windows-x86\debug\cpu-com-example\</IntDir> + <TargetName>cpu-com-example</TargetName> + <TargetExt>.exe</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>..\..\..\bin\windows-x64\debug\</OutDir> + <IntDir>..\..\..\intermediate\windows-x64\debug\cpu-com-example\</IntDir> + <TargetName>cpu-com-example</TargetName> + <TargetExt>.exe</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug aarch64|ARM'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>..\..\..\bin\windows-aarch64\debug\</OutDir> + <IntDir>..\..\..\intermediate\windows-aarch64\debug\cpu-com-example\</IntDir> + <TargetName>cpu-com-example</TargetName> + <TargetExt>.exe</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>..\..\..\bin\windows-x86\release\</OutDir> + <IntDir>..\..\..\intermediate\windows-x86\release\cpu-com-example\</IntDir> + <TargetName>cpu-com-example</TargetName> + <TargetExt>.exe</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>..\..\..\bin\windows-x64\release\</OutDir> + <IntDir>..\..\..\intermediate\windows-x64\release\cpu-com-example\</IntDir> + <TargetName>cpu-com-example</TargetName> + <TargetExt>.exe</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release aarch64|ARM'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>..\..\..\bin\windows-aarch64\release\</OutDir> + <IntDir>..\..\..\intermediate\windows-aarch64\release\cpu-com-example\</IntDir> + <TargetName>cpu-com-example</TargetName> + <TargetExt>.exe</TargetExt> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\..;..\..\..\tools;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\..;..\..\..\tools;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug aarch64|ARM'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\..;..\..\..\tools;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\..;..\..\..\tools;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Optimization>Full</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <MinimalRebuild>false</MinimalRebuild> + <StringPooling>true</StringPooling> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\..;..\..\..\tools;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Optimization>Full</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <MinimalRebuild>false</MinimalRebuild> + <StringPooling>true</StringPooling> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release aarch64|ARM'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\..;..\..\..\tools;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Optimization>Full</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <MinimalRebuild>false</MinimalRebuild> + <StringPooling>true</StringPooling> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\..\..\examples\cpu-com-example\main.cpp" /> + </ItemGroup> + <ItemGroup> + <None Include="..\..\..\examples\cpu-com-example\shader.slang" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\example-base\example-base.vcxproj"> + <Project>{37BED5B5-23FA-D81F-8C0C-F1167867813A}</Project> + </ProjectReference> + <ProjectReference Include="..\slang\slang.vcxproj"> + <Project>{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}</Project> + </ProjectReference> + <ProjectReference Include="..\gfx\gfx.vcxproj"> + <Project>{222F7498-B40C-4F3F-A704-DDEB91A4484A}</Project> + </ProjectReference> + <ProjectReference Include="..\gfx-util\gfx-util.vcxproj"> + <Project>{F5ADB74E-02A7-44FB-AA3B-FC02F8AC7A4B}</Project> + </ProjectReference> + <ProjectReference Include="..\platform\platform.vcxproj"> + <Project>{3565FE5E-4FA3-11EB-AE93-0242AC130002}</Project> + </ProjectReference> + <ProjectReference Include="..\core\core.vcxproj"> + <Project>{F9BE7957-8399-899E-0C49-E714FDDD4B65}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/build/visual-studio/cpu-com-example/cpu-com-example.vcxproj.filters b/build/visual-studio/cpu-com-example/cpu-com-example.vcxproj.filters new file mode 100644 index 000000000..ad9cb293f --- /dev/null +++ b/build/visual-studio/cpu-com-example/cpu-com-example.vcxproj.filters @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{E9C7FDCE-D52A-8D73-7EB0-C5296AF258F6}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\..\examples\cpu-com-example\main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="..\..\..\examples\cpu-com-example\shader.slang"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/examples/cpu-com-example/README.md b/examples/cpu-com-example/README.md new file mode 100644 index 000000000..a5e234d15 --- /dev/null +++ b/examples/cpu-com-example/README.md @@ -0,0 +1,8 @@ +Slang COM Example +================= + +The goal of this example is to demonstrate Slang generating CPU code that can be communicated with via Common Object Model (COM) style interfaces. + +The `shader.slang` file contains Slang code that uses COM interfaces. + +The `main.cpp` file contains the C++ application code, showing how to use the Slang API to load and compile the shader code and communicate via interfaces. diff --git a/examples/cpu-com-example/main.cpp b/examples/cpu-com-example/main.cpp new file mode 100644 index 000000000..2e9eeed79 --- /dev/null +++ b/examples/cpu-com-example/main.cpp @@ -0,0 +1,135 @@ +// main.cpp + +#include <stdio.h> + +#include <slang.h> + +#include <slang-com-ptr.h> +#include <slang-com-helper.h> + + +// This includes a useful small function for setting up the prelude (described more further below). +#include "../../source/core/slang-test-tool-util.h" + +// Slang namespace is used for elements support code (like core) which we use here +// for ComPtr<> and TestToolUtil +using namespace Slang; + +// For the moment we have to explicitly write the Slang COM interface in C++ code. It *MUST* match +// the interface in the slang source +// As it stands all interfaces need to derive from ISlangUnknown (or IUnknown). +class IDoThings : public ISlangUnknown +{ +public: + virtual int SLANG_MCALL doThing(int a, int b) = 0; + virtual int SLANG_MCALL calcHash(const char* in) = 0; +}; + +static int _calcHash(const char* in) +{ + int hash = 0; + for (; *in; ++in) + { + // A very poor hash function + hash = hash * 13 + *in; + } + return hash; +} + +class DoThings :public IDoThings +{ +public: + // We don't need queryInterface for this impl, or ref counting + virtual SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE { return SLANG_E_NOT_IMPLEMENTED; } + virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } + virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } + + // IDoThings + virtual int SLANG_MCALL doThing(int a, int b) SLANG_OVERRIDE { return a + b + 1; } + virtual int SLANG_MCALL calcHash(const char* in) SLANG_OVERRIDE { return (int)_calcHash(in); } +}; + +static SlangResult _innerMain(int argc, char** argv) +{ + // Create the session + ComPtr<slang::IGlobalSession> slangSession; + slangSession.attach(spCreateSession(NULL)); + + // Set up the prelude + TestToolUtil::setSessionDefaultPreludeFromExePath(argv[0], slangSession); + + // Create a compile request + Slang::ComPtr<slang::ICompileRequest> request; + SLANG_RETURN_ON_FAIL(slangSession->createCompileRequest(request.writeRef())); + + // We want to compile to 'HOST_CALLABLE' here such that we can execute the Slang code. + // + // Note that it is possible to use HOST_HOST_CALLABLE, but this currently only works with 'regular' C++ compilers + // not with `slang-llvm`. + const int targetIndex = request->addCodeGenTarget(SLANG_SHADER_HOST_CALLABLE); + + // Set the target flag to indicate that we want to compile all into a library. + request->setTargetFlags(targetIndex, SLANG_TARGET_FLAG_GENERATE_WHOLE_PROGRAM); + + // Add the translation unit + const int translationUnitIndex = request->addTranslationUnit(SLANG_SOURCE_LANGUAGE_SLANG, nullptr); + + // Set the source file for the translation unit + request->addTranslationUnitSourceFile(translationUnitIndex, "shader.slang"); + + const SlangResult compileRes = request->compile(); + + // Even if there were no errors that forced compilation to fail, the + // compiler may have produced "diagnostic" output such as warnings. + // We will go ahead and print that output here. + // + if(auto diagnostics = request->getDiagnosticOutput()) + { + printf("%s", diagnostics); + } + + // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a shared library + // it's just an interface to executable code). + ComPtr<ISlangSharedLibrary> sharedLibrary; + SLANG_RETURN_ON_FAIL(request->getTargetHostCallable(0, sharedLibrary.writeRef())); + + { + typedef const char* (*Func)(const char*); + Func func = (Func)sharedLibrary->findFuncByName("getString"); + + if (!func) + { + return SLANG_FAIL; + } + + String text = "Hello World!"; + String returnedText = func(text.getBuffer()); + + SLANG_ASSERT(text == returnedText); + } + { + typedef int (*Func)(const char* text, IDoThings* doThings); + + Func func = (Func)sharedLibrary->findFuncByName("calcHash"); + + if (!func) + { + return SLANG_FAIL; + } + + DoThings doThings; + + String text("Hello"); + + const int hash = func(text.getBuffer(), &doThings); + + SLANG_ASSERT(hash == _calcHash(text.getBuffer())); + } + + return SLANG_OK; +} + +int main(int argc, char** argv) +{ + return SLANG_SUCCEEDED(_innerMain(argc, argv)) ? 0 : -1; +} diff --git a/examples/cpu-com-example/shader.slang b/examples/cpu-com-example/shader.slang new file mode 100644 index 000000000..b0fe259be --- /dev/null +++ b/examples/cpu-com-example/shader.slang @@ -0,0 +1,21 @@ +// shader.slang + +// Example of using 'NativeString' + +public __extern_cpp NativeString getString(NativeString in) +{ + return in; +} + +[COM] +interface IDoThings +{ + int doThing(int a, int b); + int calcHash(NativeString in); +} + +public __extern_cpp int calcHash(NativeString text, IDoThings doThings) +{ + return doThings.calcHash(text); +} + diff --git a/prelude/slang-cpp-prelude.h b/prelude/slang-cpp-prelude.h index 612f9ec9f..db83222a6 100644 --- a/prelude/slang-cpp-prelude.h +++ b/prelude/slang-cpp-prelude.h @@ -120,6 +120,52 @@ Any compilers not detected by the above logic are now now explicitly zeroed out. # define SLANG_OFFSET_OF(X, Y) offsetof(X, Y) #endif +// If slang.h has been included we don't need any of these definitions +#ifndef SLANG_H + +/* 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 + +struct SlangUUID +{ + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +}; + +typedef int32_t SlangResult; + +struct ISlangUnknown +{ + 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; +}; + +#endif // SLANG_H + #include "slang-cpp-types.h" #include "slang-cpp-scalar-intrinsics.h" diff --git a/premake5.lua b/premake5.lua index 8b4348cfa..75d093612 100644 --- a/premake5.lua +++ b/premake5.lua @@ -692,6 +692,9 @@ newoption { example "shader-object" kind "ConsoleApp" + example "cpu-com-example" + kind "ConsoleApp" + example "cpu-hello-world" kind "ConsoleApp" if enableExperimental then @@ -570,6 +570,7 @@ extern "C" SLANG_PTX, ///< PTX SLANG_OBJECT_CODE, ///< Object code that can be used for later linking SLANG_HOST_CPP_SOURCE, ///< C++ code for host library or executable. + SLANG_HOST_HOST_CALLABLE, ///< SLANG_TARGET_COUNT_OF, }; @@ -29,6 +29,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "build\visual-studio EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpu-com-example", "build\visual-studio\cpu-com-example\cpu-com-example.vcxproj", "{0996B38F-F512-A7D2-1E90-A7E60A6C4366}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpu-hello-world", "build\visual-studio\cpu-hello-world\cpu-hello-world.vcxproj", "{4B47A364-37C4-96A7-6041-97BB4C1D333B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example-base", "build\visual-studio\example-base\example-base.vcxproj", "{37BED5B5-23FA-D81F-8C0C-F1167867813A}"
@@ -235,6 +237,18 @@ Global {F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|Win32.Build.0 = Release|Win32
{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|x64.ActiveCfg = Release|x64
{F9BE7957-8399-899E-0C49-E714FDDD4B65}.Release|x64.Build.0 = Release|x64
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Debug|aarch64.ActiveCfg = Debug aarch64|ARM
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Debug|aarch64.Build.0 = Debug aarch64|ARM
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Debug|Win32.Build.0 = Debug|Win32
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Debug|x64.ActiveCfg = Debug|x64
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Debug|x64.Build.0 = Debug|x64
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Release|aarch64.ActiveCfg = Release aarch64|ARM
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Release|aarch64.Build.0 = Release aarch64|ARM
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Release|Win32.ActiveCfg = Release|Win32
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Release|Win32.Build.0 = Release|Win32
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Release|x64.ActiveCfg = Release|x64
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366}.Release|x64.Build.0 = Release|x64
{4B47A364-37C4-96A7-6041-97BB4C1D333B}.Debug|aarch64.ActiveCfg = Debug aarch64|ARM
{4B47A364-37C4-96A7-6041-97BB4C1D333B}.Debug|aarch64.Build.0 = Debug aarch64|ARM
{4B47A364-37C4-96A7-6041-97BB4C1D333B}.Debug|Win32.ActiveCfg = Debug|Win32
@@ -490,6 +504,7 @@ Global {B2D63B45-92B0-40F7-B242-CCA4DFD64341} = {FD47AE19-69FD-260F-F2F1-20E65EA61D13}
{BE412850-4BB9-429A-877C-BFBC4B34186C} = {FD47AE19-69FD-260F-F2F1-20E65EA61D13}
{23149706-C12F-4329-B6AA-8266407C32D3} = {FD47AE19-69FD-260F-F2F1-20E65EA61D13}
+ {0996B38F-F512-A7D2-1E90-A7E60A6C4366} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231}
{4B47A364-37C4-96A7-6041-97BB4C1D333B} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231}
{37BED5B5-23FA-D81F-8C0C-F1167867813A} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231}
{57C81DD3-4304-213D-AC16-39349871C957} = {EB5FC2C6-D72D-B6CC-C0C1-26F3AC2E9231}
diff --git a/source/compiler-core/slang-artifact-info.cpp b/source/compiler-core/slang-artifact-info.cpp index 1b9209516..b67adb666 100644 --- a/source/compiler-core/slang-artifact-info.cpp +++ b/source/compiler-core/slang-artifact-info.cpp @@ -152,6 +152,12 @@ static const KindExtension g_cpuKindExts[] = return info.isSet(ArtifactPayloadInfo::Flag::IsGpuNative) && info.flavor == ArtifactPayloadInfo::Flavor::Binary; } +/* static */bool ArtifactInfoUtil::isPayloadCpuTarget(Payload payload) +{ + return isPayloadCpuBinary(payload) || + (payload == Payload::C || payload == Payload::CPP); +} + /* static */UnownedStringSlice ArtifactInfoUtil::getDefaultExtensionForPayload(Payload payload) { switch (payload) diff --git a/source/compiler-core/slang-artifact-info.h b/source/compiler-core/slang-artifact-info.h index 1db3712dc..e63349937 100644 --- a/source/compiler-core/slang-artifact-info.h +++ b/source/compiler-core/slang-artifact-info.h @@ -67,6 +67,12 @@ struct ArtifactInfoUtil /// Returns true if the payload type is applicable to the GPU static bool isPayloadGpuBinary(Payload payload); + /// True if is a CPU target + static bool isPayloadCpuTarget(Payload payload); + + /// True if is a CPU target - either + static bool isCpuTarget(const ArtifactDesc& desc) { return isPayloadCpuTarget(desc.payload); } + /// True if is a CPU binary static bool isCpuBinary(const ArtifactDesc& desc) { return isPayloadCpuBinary(desc.payload); } /// True if is a GPU binary diff --git a/source/compiler-core/slang-artifact.cpp b/source/compiler-core/slang-artifact.cpp index dfa9e645b..5e5b93578 100644 --- a/source/compiler-core/slang-artifact.cpp +++ b/source/compiler-core/slang-artifact.cpp @@ -38,6 +38,7 @@ namespace Slang { case SLANG_CUDA_SOURCE: return make(Kind::Text, Payload::CUDA, Style::Kernel, 0); case SLANG_PTX: return make(Kind::Executable, Payload::PTX, Style::Kernel, 0); case SLANG_OBJECT_CODE: return make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0); + case SLANG_HOST_HOST_CALLABLE: return make(Kind::Callable, Payload::HostCPU, Style::Host, 0); default: break; } diff --git a/source/core/slang-type-text-util.cpp b/source/core/slang-type-text-util.cpp index 454ca4258..9985b8b23 100644 --- a/source/core/slang-type-text-util.cpp +++ b/source/core/slang-type-text-util.cpp @@ -75,6 +75,8 @@ static const CompileTargetInfo s_compileTargetInfos[] = { SLANG_PTX, "ptx", "ptx" }, { SLANG_SHADER_HOST_CALLABLE, "", "host-callable,callable" }, { SLANG_OBJECT_CODE, "obj,o", "object-code" }, + { SLANG_HOST_HOST_CALLABLE, "", "host-host-callable" }, + }; diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 74162d2ef..bcf857fc8 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -13,6 +13,7 @@ #include "slang-compiler.h" #include "../compiler-core/slang-lexer.h" +#include "../compiler-core/slang-artifact.h" #include "slang-lower-to-ir.h" #include "slang-mangle.h" @@ -56,14 +57,7 @@ namespace Slang bool isHeterogeneousTarget(CodeGenTarget target) { - switch (target) - { - case CodeGenTarget::HostCPPSource: - case CodeGenTarget::HostExecutable: - return true; - default: - return false; - } + return ArtifactDesc::makeFromCompileTarget(asExternal(target)).style == ArtifactStyle::Host; } void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) @@ -592,6 +586,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::ShaderSharedLibrary: case CodeGenTarget::HostExecutable: + case CodeGenTarget::HostHostCallable: { // We need some C/C++ compiler return PassThroughMode::GenericCCpp; @@ -983,9 +978,14 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) { case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::ShaderSharedLibrary: + { return CodeGenTarget::CPPSource; + } + case CodeGenTarget::HostHostCallable: case CodeGenTarget::HostExecutable: + { return CodeGenTarget::HostCPPSource; + } case CodeGenTarget::PTX: return CodeGenTarget::CUDASource; case CodeGenTarget::DXBytecode: return CodeGenTarget::HLSL; case CodeGenTarget::DXIL: return CodeGenTarget::HLSL; @@ -997,14 +997,8 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) static bool _isCPUHostTarget(CodeGenTarget target) { - switch (target) - { - case CodeGenTarget::HostCPPSource: - case CodeGenTarget::HostExecutable: - return true; - default: - return false; - } + auto desc = ArtifactDesc::makeFromCompileTarget(asExternal(target)); + return desc.style == ArtifactStyle::Host; } SlangResult CodeGenContext::emitWithDownstreamForEntryPoints( @@ -1299,7 +1293,8 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } // If we aren't using LLVM 'host callable', we want downstream compile to produce a shared library - if (compilerType != PassThroughMode::LLVM && target == CodeGenTarget::ShaderHostCallable) + if (compilerType != PassThroughMode::LLVM && + ArtifactDesc::makeFromCompileTarget(asExternal(target)).kind == ArtifactKind::Callable) { target = CodeGenTarget::ShaderSharedLibrary; } @@ -1586,6 +1581,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::ShaderSharedLibrary: case CodeGenTarget::HostExecutable: + case CodeGenTarget::HostHostCallable: SLANG_RETURN_ON_FAIL(emitWithDownstreamForEntryPoints(outDownstreamResult, outMetadata)); return SLANG_OK; @@ -1611,6 +1607,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) case CodeGenTarget::DXIL: case CodeGenTarget::DXBytecode: case CodeGenTarget::PTX: + case CodeGenTarget::HostHostCallable: case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::ShaderSharedLibrary: case CodeGenTarget::HostExecutable: @@ -1794,7 +1791,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) ComPtr<ISlangBlob> blob; if (SLANG_FAILED(result.getBlob(blob))) { - if (targetReq->getTarget() == CodeGenTarget::ShaderHostCallable) + if (ArtifactDesc::makeFromCompileTarget(asExternal(targetReq->getTarget())).kind == ArtifactKind::Callable) { // Some HostCallable are not directly representable as a 'binary'. // So here, we just ignore if that appears the case, and don't output an unexpected error. @@ -1838,6 +1835,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) case CodeGenTarget::PTX: // For now we just dump PTX out as hex + case CodeGenTarget::HostHostCallable: case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::ShaderSharedLibrary: case CodeGenTarget::HostExecutable: @@ -2411,11 +2409,19 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) case CodeGenTarget::CUDASource: return ".cu"; case CodeGenTarget::CPPSource: return ".cpp"; case CodeGenTarget::HostCPPSource: return ".cpp"; - // What these should be called is target specific, but just use these exts to make clear for now - // for now - case CodeGenTarget::HostExecutable: return ".exe"; + + // What these should be called is target specific, but just use these exts to make clear for now + // for now + case CodeGenTarget::HostExecutable: + { + return ".exe"; + } + case CodeGenTarget::HostHostCallable: case CodeGenTarget::ShaderHostCallable: - case CodeGenTarget::ShaderSharedLibrary: return ".shared-lib"; + case CodeGenTarget::ShaderSharedLibrary: + { + return ".shared-lib"; + } default: break; } return nullptr; @@ -2429,22 +2435,16 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return; auto target = getTargetFormat(); - switch (target) - { - case CodeGenTarget::CPPSource: - case CodeGenTarget::HostCPPSource: - case CodeGenTarget::CUDASource: - case CodeGenTarget::CSource: - case CodeGenTarget::DXILAssembly: - case CodeGenTarget::DXBytecodeAssembly: - case CodeGenTarget::SPIRVAssembly: - case CodeGenTarget::GLSL: - case CodeGenTarget::HLSL: - { - dumpIntermediateText(data, size, _getTargetExtension(target)); - break; - } + const auto desc = ArtifactDesc::makeFromCompileTarget(asExternal(target)); + if (desc.kind == ArtifactKind::Text) + { + dumpIntermediateText(data, size, _getTargetExtension(target)); + return; + } + + switch (target) + { #if 0 case CodeGenTarget::SlangIRAssembly: { @@ -2452,7 +2452,6 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) break; } #endif - case CodeGenTarget::DXIL: case CodeGenTarget::DXBytecode: case CodeGenTarget::SPIRV: @@ -2471,6 +2470,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) break; } + case CodeGenTarget::HostHostCallable: case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::ShaderSharedLibrary: case CodeGenTarget::HostExecutable: diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index e0152566c..683e1f7f1 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -79,6 +79,7 @@ namespace Slang CUDASource = SLANG_CUDA_SOURCE, PTX = SLANG_PTX, ObjectCode = SLANG_OBJECT_CODE, + HostHostCallable = SLANG_HOST_HOST_CALLABLE, CountOf = SLANG_TARGET_COUNT_OF, }; @@ -3136,6 +3137,8 @@ SLANG_FORCE_INLINE EndToEndCompileRequest* asInternal(SlangCompileRequest* reque return endToEndRequest; } +SLANG_FORCE_INLINE SlangCompileTarget asExternal(CodeGenTarget target) { return (SlangCompileTarget)target; } + } #endif diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 6b6d462b9..e0b1a44f2 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -1540,11 +1540,15 @@ void CLikeSourceEmitter::emitCallExpr(IRCall* inst, EmitOpInfo outerPrec) handleRequiredCapabilities(funcValue); // Detect if this is a call into a COM interface method. - if (funcValue->getOp() == kIROp_lookup_interface_method && - funcValue->getOperand(0)->getDataType()->getOp() == kIROp_ComPtrType) + if (funcValue->getOp() == kIROp_lookup_interface_method) { - emitComInterfaceCallExpr(inst, outerPrec); - return; + const auto operand0TypeOp = funcValue->getOperand(0)->getDataType()->getOp(); + + if (operand0TypeOp == kIROp_ComPtrType || operand0TypeOp == kIROp_PtrType) + { + emitComInterfaceCallExpr(inst, outerPrec); + return; + } } // We want to detect any call to an intrinsic operation, diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index 482ada394..ddc8b24ed 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -544,9 +544,10 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S } case kIROp_ComPtrType: { - out << "ComPtr<"; auto comPtrType = static_cast<IRComPtrType*>(type); auto baseType = cast<IRType>(comPtrType->getOperand(0)); + + out << "ComPtr<"; SLANG_RETURN_ON_FAIL(calcTypeName(baseType, target, out)); out << ">"; return SLANG_OK; @@ -1635,6 +1636,12 @@ CPPSourceEmitter::CPPSourceEmitter(const Desc& desc): { m_semanticUsedFlags = 0; //m_semanticUsedFlags = SemanticUsedFlag::GroupID | SemanticUsedFlag::GroupThreadID | SemanticUsedFlag::DispatchThreadID; + + + const auto artifactDesc = ArtifactDesc::makeFromCompileTarget(asExternal(getTarget())); + + // If we have runtime library we can convert to a terminated string slice + m_hasString = (artifactDesc.style == ArtifactStyle::Host); } void CPPSourceEmitter::emitParamTypeImpl(IRType* type, String const& name) @@ -1945,6 +1952,9 @@ void CPPSourceEmitter::emitEntryPointAttributesImpl(IRFunc* irFunc, IREntryPoint void CPPSourceEmitter::emitSimpleFuncImpl(IRFunc* func) { + // Emit function decorations + emitFuncDecorations(func); + auto resultType = func->getResultType(); auto name = getName(func); @@ -1952,7 +1962,6 @@ void CPPSourceEmitter::emitSimpleFuncImpl(IRFunc* func) // Deal with decorations that need // to be emitted as attributes - // We start by emitting the result type and function name. // if (IREntryPointDecoration* entryPointDecor = func->findDecoration<IREntryPointDecoration>()) @@ -2416,16 +2425,23 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOut } case kIROp_StringLit: { - m_writer->emit("toTerminatedSlice("); - auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp); - + StringBuilder buf; const auto slice = as<IRStringLit>(inst)->getStringSlice(); StringEscapeUtil::appendQuoted(handler, slice, buf); - m_writer->emit(buf); + + if (m_hasString) + { + m_writer->emit("toTerminatedSlice("); + m_writer->emit(buf); + m_writer->emit(")"); + } + else + { + m_writer->emit(buf); + } - m_writer->emit(")"); return true; } case kIROp_PtrLit: @@ -2475,12 +2491,17 @@ void CPPSourceEmitter::emitPreModuleImpl() { if (m_target == CodeGenTarget::CPPSource) { - // NOTE, that this opens an anonymous scope. + // TODO(JS): Previously this opened an anonymous scope for all generated functions + // Unfortunately this is a problem if we are just emitting code that is externally available + // and is not only accessible through entry points. So for now we disable + + // that this opens an anonymous scope. // The scope is closed in `emitModuleImpl` + //m_writer->emit("namespace { // anonymous \n\n"); + // When generating kernel code in C++, put all into an anonymous namespace // This includes any generated types, and generated intrinsics. - m_writer->emit("namespace { // anonymous \n\n"); m_writer->emit("#ifdef SLANG_PRELUDE_NAMESPACE\n"); m_writer->emit("using namespace SLANG_PRELUDE_NAMESPACE;\n"); m_writer->emit("#endif\n\n"); @@ -2526,6 +2547,45 @@ void CPPSourceEmitter::emitPreModuleImpl() } } +/* virtual */void CPPSourceEmitter::emitFuncDecorationsImpl(IRFunc* func) +{ + // Specially handle export, as we don't want to emit it multiple times + if (getTargetReq()->isWholeProgramRequest()) + { + bool isExternC = false; + bool isExported = false; + + // If public/export made it externally visible + for (auto decoration : func->getDecorations()) + { + const auto op = decoration->getOp(); + if (op == kIROp_ExternCppDecoration) + { + isExternC = true; + } + else if (op == kIROp_PublicDecoration || + op == kIROp_HLSLExportDecoration) + { + isExported = true; + } + } + + // TODO(JS): Currently export *also* implies it's extern "C" and we can't list twice + if (isExported) + { + m_writer->emit("SLANG_PRELUDE_EXPORT\n"); + } + else if (isExternC) + { + // It's name is not manged. + m_writer->emit("extern \"C\"\n"); + } + } + + // Use the default for others + Super::emitFuncDecorationsImpl(func); +} + void CPPSourceEmitter::emitOperandImpl(IRInst* inst, EmitOpInfo const& outerPrec) { if (shouldFoldInstIntoUseSites(inst)) @@ -2792,11 +2852,16 @@ void CPPSourceEmitter::emitModuleImpl(IRModule* module, DiagnosticSink* sink) // Emit all witness table definitions. _emitWitnessTableDefinitions(); - if (m_target == CodeGenTarget::CPPSource) - { + // TODO(JS): + // Previously output code was placed in an anonymous namespace + // Now that we can have any function available externally (not just entry points) + // this doesn't work. + + //if (m_target == CodeGenTarget::CPPSource) + //{ // Need to close the anonymous namespace when outputting for C++ kernel. - m_writer->emit("} // anonymous\n\n"); - } + //m_writer->emit("} // anonymous\n\n"); + //} // Finally we need to output dll entry points diff --git a/source/slang/slang-emit-cpp.h b/source/slang/slang-emit-cpp.h index 0d9327b9e..f5ba35933 100644 --- a/source/slang/slang-emit-cpp.h +++ b/source/slang/slang-emit-cpp.h @@ -74,7 +74,8 @@ protected: virtual bool tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* varType) SLANG_OVERRIDE; virtual void emitIntrinsicCallExprImpl(IRCall* inst, IRTargetIntrinsicDecoration* targetIntrinsic, EmitOpInfo const& inOuterPrec) SLANG_OVERRIDE; virtual void emitLoopControlDecorationImpl(IRLoopControlDecoration* decl) SLANG_OVERRIDE; - + virtual void emitFuncDecorationsImpl(IRFunc* func) SLANG_OVERRIDE; + virtual const UnownedStringSlice* getVectorElementNames(BaseType elemType, Index elemCount); // Replaceable for classes derived from CPPSourceEmitter @@ -153,6 +154,8 @@ protected: // They must be emitted last, after the entire `Context` class so those member functions defined // in `Context` may be referenced. List<IRWitnessTable*> pendingWitnessTableDefinitions; + + bool m_hasString = false; }; } diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 72ad80873..0bb1d73e5 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -177,6 +177,8 @@ Result linkAndOptimizeIR( auto target = codeGenContext->getTargetFormat(); auto targetRequest = codeGenContext->getTargetReq(); + // Get the artifact desc for the target + const auto artifactDesc = ArtifactDesc::makeFromCompileTarget(asExternal(target)); // We start out by performing "linking" at the level of the IR. // This step will create a fresh IR module to be used for @@ -203,12 +205,20 @@ Result linkAndOptimizeIR( switch (target) { - default: - break; - case CodeGenTarget::HostCPPSource: - lowerComInterfaces(irModule, sink); - generateDllImportFuncs(irModule, sink); - break; + case CodeGenTarget::CPPSource: + { + // TODO(JS): + // We want the interface transformation to take place for 'regular' CPPSource for now too. + lowerComInterfaces(irModule, artifactDesc.style, sink); + break; + } + case CodeGenTarget::HostCPPSource: + { + lowerComInterfaces(irModule, artifactDesc.style, sink); + generateDllImportFuncs(irModule, sink); + break; + } + default: break; } // Lower `Result<T,E>` types into ordinary struct types. diff --git a/source/slang/slang-ir-com-interface.cpp b/source/slang/slang-ir-com-interface.cpp index 1bcf3d2b6..009d2314d 100644 --- a/source/slang/slang-ir-com-interface.cpp +++ b/source/slang/slang-ir-com-interface.cpp @@ -12,9 +12,9 @@ struct ComInterfaceLoweringContext IRModule* module; DiagnosticSink* diagnosticSink; - SharedIRBuilder sharedBuilder; + ArtifactStyle artifactStyle; - Dictionary<IRInterfaceType*, IRComPtrType*> comPtrTypes; + SharedIRBuilder sharedBuilder; void replaceTypeUses(IRInst* inst, IRInst* newValue) { @@ -33,6 +33,7 @@ struct ComInterfaceLoweringContext case kIROp_RTTIPointerType: case kIROp_RTTIHandleType: case kIROp_ComPtrType: + case kIROp_PtrType: continue; default: break; @@ -41,19 +42,17 @@ struct ComInterfaceLoweringContext } } - IRComPtrType* processInterfaceType(IRInterfaceType* type) + IRType* processInterfaceType(IRInterfaceType* type) { if (!type->findDecoration<IRComInterfaceDecoration>()) return nullptr; - - IRComPtrType* result = nullptr; - - if (comPtrTypes.TryGetValue(type, result)) - return result; - + IRBuilder builder(sharedBuilder); builder.setInsertInto(module->getModuleInst()); - result = builder.getComPtrType(type); + + IRType* result = (artifactStyle == ArtifactStyle::Kernel) ? + static_cast<IRType*>(builder.getPtrType(type)) : + static_cast<IRType*>(builder.getComPtrType(type)); replaceTypeUses(type, result); return result; @@ -86,11 +85,12 @@ struct ComInterfaceLoweringContext } }; -void lowerComInterfaces(IRModule* module, DiagnosticSink* sink) +void lowerComInterfaces(IRModule* module, ArtifactStyle artifactStyle, DiagnosticSink* sink) { ComInterfaceLoweringContext context; context.module = module; context.diagnosticSink = sink; + context.artifactStyle = artifactStyle; context.sharedBuilder.init(module); return context.processModule(); } diff --git a/source/slang/slang-ir-com-interface.h b/source/slang/slang-ir-com-interface.h index 0f6737880..2fffc90fd 100644 --- a/source/slang/slang-ir-com-interface.h +++ b/source/slang/slang-ir-com-interface.h @@ -1,6 +1,8 @@ // slang-ir-com-interface.cpp #pragma once +#include "../compiler-core/slang-artifact.h" + namespace Slang { @@ -10,6 +12,6 @@ class DiagnosticSink; /// Lower com interface types. /// A use of `IRInterfaceType` with `IRComInterfaceDecoration` will be translated into a `IRComPtr` type. /// A use of `IRThisType` with a COM interface will also be translated into a `IRComPtr` type. -void lowerComInterfaces(IRModule* module, DiagnosticSink* sink); +void lowerComInterfaces(IRModule* module, ArtifactStyle artifactStyle, DiagnosticSink* sink); } diff --git a/source/slang/slang-ir-generics-lowering-context.cpp b/source/slang/slang-ir-generics-lowering-context.cpp index bf3b8d855..e20b8b680 100644 --- a/source/slang/slang-ir-generics-lowering-context.cpp +++ b/source/slang/slang-ir-generics-lowering-context.cpp @@ -38,8 +38,21 @@ namespace Slang bool isComInterfaceType(IRType* type) { - return type->findDecoration<IRComInterfaceDecoration>() != nullptr || - type->getOp() == kIROp_ComPtrType; + if (type->findDecoration<IRComInterfaceDecoration>() || + type->getOp() == kIROp_ComPtrType) + { + return true; + } + + // TODO(JS): Perhaps it should do IRPtrTypeBase, or some more expansive set of 'PtrType's + // but for now test for PtrType + if (auto ptrType = as<IRPtrType>(type)) + { + auto valueType = ptrType->getValueType(); + return valueType->findDecoration<IRComInterfaceDecoration>() != nullptr; + } + + return false; } bool isTypeValue(IRInst* typeInst) diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index 875f18980..9825e4e23 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -2032,6 +2032,18 @@ struct OptionsParser } } + // If we don't have any raw outputs but do have a raw target, + // and output type is callable, add an empty' rawOutput. + if (rawOutputs.getCount() == 0 && + rawTargets.getCount() == 1 && + ArtifactDesc::makeFromCompileTarget(asExternal(rawTargets[0].format)).kind == ArtifactKind::Callable) + { + RawOutput rawOutput; + rawOutput.impliedFormat = rawTargets[0].format; + rawOutput.targetIndex = 0; + rawOutputs.add(rawOutput); + } + // Consider the output files specified via `-o` and try to figure // out how to deal with them. // @@ -2083,6 +2095,8 @@ struct OptionsParser case CodeGenTarget::CPPSource: case CodeGenTarget::PTX: case CodeGenTarget::CUDASource: + + case CodeGenTarget::HostHostCallable: case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::HostExecutable: case CodeGenTarget::ShaderSharedLibrary: @@ -2099,6 +2113,7 @@ struct OptionsParser } } + // Now that we've diagnosed the output paths, we can add them // to the compile request at the appropriate locations. // diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index 7bff7118e..d0b12b19b 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -5,6 +5,8 @@ #include "slang-compiler.h" #include "slang-type-layout.h" +#include "../compiler-core/slang-artifact-info.h" + #include "slang-ir-string-hash.h" #include "../../slang.h" @@ -3029,18 +3031,8 @@ static int _calcTotalNumUsedRegistersForLayoutResourceKind(ParameterBindingConte static bool _isCPUTarget(CodeGenTarget target) { - switch (target) - { - case CodeGenTarget::CPPSource: - case CodeGenTarget::CSource: - case CodeGenTarget::HostExecutable: - case CodeGenTarget::ShaderSharedLibrary: - case CodeGenTarget::ShaderHostCallable: - { - return true; - } - default: return false; - } + const auto desc = ArtifactDesc::makeFromCompileTarget(asExternal(target)); + return ArtifactInfoUtil::isCpuTarget(desc); } static bool _isPTXTarget(CodeGenTarget target) diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index cd81c6173..09a21fb6f 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -4,6 +4,8 @@ #include "slang-syntax.h" #include "slang-ir-insts.h" +#include "../compiler-core/slang-artifact-info.h" + #include <assert.h> namespace Slang { @@ -1403,6 +1405,7 @@ LayoutRulesFamilyImpl* getDefaultLayoutRulesFamilyForTarget(TargetRequest* targe case CodeGenTarget::SPIRVAssembly: return &kGLSLLayoutRulesFamilyImpl; + case CodeGenTarget::HostHostCallable: case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::HostExecutable: case CodeGenTarget::ShaderSharedLibrary: @@ -1603,18 +1606,7 @@ bool isKhronosTarget(TargetRequest* targetReq) bool isCPUTarget(TargetRequest* targetReq) { - switch( targetReq->getTarget() ) - { - default: - return false; - - case CodeGenTarget::CPPSource: - case CodeGenTarget::CSource: - case CodeGenTarget::ShaderHostCallable: - case CodeGenTarget::HostExecutable: - case CodeGenTarget::ShaderSharedLibrary: - return true; - } + return ArtifactInfoUtil::isCpuTarget(ArtifactDesc::makeFromCompileTarget(asExternal(targetReq->getTarget()))); } bool isCUDATarget(TargetRequest* targetReq) diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 7b22d04de..9379f3b03 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -670,17 +670,17 @@ SlangPassThrough Session::getDownstreamCompilerForTransition(SlangCompileTarget return (SlangPassThrough)m_codeGenTransitionMap.getTransition(source, target); } + const auto desc = ArtifactDesc::makeFromCompileTarget(inTarget); + // Special case host-callable - if (target == CodeGenTarget::ShaderHostCallable) + if ((desc.kind == ArtifactKind::Callable) && + (source == CodeGenTarget::CSource || source == CodeGenTarget::CPPSource)) { - if (source == CodeGenTarget::CSource || source == CodeGenTarget::CPPSource) + // We prefer LLVM if it's available + DownstreamCompiler* llvm = getOrLoadDownstreamCompiler(PassThroughMode::LLVM, nullptr); + if (llvm) { - // We prefer LLVM if it's available - DownstreamCompiler* llvm = getOrLoadDownstreamCompiler(PassThroughMode::LLVM, nullptr); - if (llvm) - { - return SLANG_PASS_THROUGH_LLVM; - } + return SLANG_PASS_THROUGH_LLVM; } } @@ -1334,6 +1334,7 @@ CapabilitySet TargetRequest::getTargetCaps() case CodeGenTarget::CPPSource: case CodeGenTarget::HostExecutable: case CodeGenTarget::ShaderSharedLibrary: + case CodeGenTarget::HostHostCallable: case CodeGenTarget::ShaderHostCallable: atoms.add(CapabilityAtom::CPP); break; @@ -4711,6 +4712,11 @@ static SlangResult _getWholeProgramResult( auto linkage = req->getLinkage(); auto program = req->getSpecializedGlobalAndEntryPointsComponentType(); + if (!program) + { + return SLANG_FAIL; + } + Index targetCount = linkage->targets.getCount(); if ((targetIndex < 0) || (targetIndex >= targetCount)) { diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp index d5f4408ed..f0d92b810 100644 --- a/tools/slang-test/slang-test-main.cpp +++ b/tools/slang-test/slang-test-main.cpp @@ -781,6 +781,8 @@ static PassThroughFlags _getPassThroughFlagsForTarget(SlangCompileTarget target) } case SLANG_SHADER_HOST_CALLABLE: + case SLANG_HOST_HOST_CALLABLE: + case SLANG_HOST_EXECUTABLE: case SLANG_SHADER_SHARED_LIBRARY: { |
