├── .gitmodules
├── source
└── thusc
│ ├── LLVMSpecificProperties-Release.props
│ ├── LLVMSpecificProperties-Debug.props
│ ├── ClangHelperFunctions.h
│ ├── thusc.vcxproj.filters
│ ├── TypeHelpers.h
│ ├── LLVMSpecificProperties.props
│ ├── ThuscShaderIR.cpp
│ ├── ThuscBackendUE4.h
│ ├── ThuscCppToHLSLTranslator.h
│ ├── ThuscCommon.h
│ ├── ThuscBackend.h
│ ├── ThuscBackendHLSL.h
│ ├── ThuscFrontendAction.h
│ ├── ThuscCppToHLSLTranslator.cpp
│ ├── thusc.vcxproj
│ ├── thusc.cpp
│ ├── ThuscShaderIR.h
│ ├── ThuscBackendHLSL.cpp
│ ├── ThuscBackendUE4.cpp
│ └── ThuscFrontendAction.cpp
├── thusc.sln
├── CITATION.cff
├── LICENSE.txt
├── README.md
├── include
└── thusc.h
└── .gitignore
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "external/hlslpp"]
2 | path = external/hlslpp
3 | url = git@github.com:kseitz/hlslpp.git
4 |
--------------------------------------------------------------------------------
/source/thusc/LLVMSpecificProperties-Release.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | $(LLVMBuildDir)\Release\lib;
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/source/thusc/LLVMSpecificProperties-Debug.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | $(LLVMBuildDir)\RelWithDebInfo\lib;
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/thusc.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30320.27
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thusc", "source\thusc\thusc.vcxproj", "{9988EB8D-EB65-4BAB-AECA-845341448507}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {9988EB8D-EB65-4BAB-AECA-845341448507}.Debug|x64.ActiveCfg = Debug|x64
17 | {9988EB8D-EB65-4BAB-AECA-845341448507}.Debug|x64.Build.0 = Debug|x64
18 | {9988EB8D-EB65-4BAB-AECA-845341448507}.Debug|x86.ActiveCfg = Debug|Win32
19 | {9988EB8D-EB65-4BAB-AECA-845341448507}.Debug|x86.Build.0 = Debug|Win32
20 | {9988EB8D-EB65-4BAB-AECA-845341448507}.Release|x64.ActiveCfg = Release|x64
21 | {9988EB8D-EB65-4BAB-AECA-845341448507}.Release|x64.Build.0 = Release|x64
22 | {9988EB8D-EB65-4BAB-AECA-845341448507}.Release|x86.ActiveCfg = Release|Win32
23 | {9988EB8D-EB65-4BAB-AECA-845341448507}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {9144C82C-C073-40A6-BC4A-5EDB143DBDAD}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/source/thusc/ClangHelperFunctions.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | DISABLE_WARNINGS_LLVM
32 | #include "clang/Basic/Diagnostic.h"
33 | ENABLE_WARNINGS_LLVM
34 |
35 | template
36 | constexpr void diagError(clang::DiagnosticsEngine& diagEngine, clang::SourceLocation loc, const char(&msg)[N]) {
37 | const unsigned diagID = diagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error, msg);
38 | diagEngine.Report(loc, diagID);
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.2.0
2 | message: "If you use this software, please cite the associated technical paper from the preferred-citation."
3 | title: "Supporting Unified Shader Specialization by Co-opting C++ Features"
4 | authors:
5 | - given-names: "Kerry A."
6 | family-names: "Seitz"
7 | name-suffix: "Jr."
8 | email: "kaseitz@ucdavis.edu"
9 | affiliation: "University of California, Davis"
10 | orcid: "https://orcid.org/0000-0003-2424-9495"
11 | - given-names: "Theresa"
12 | family-names: "Foley"
13 | email: "tfoley@nvidia.com"
14 | affiliation: "NVIDIA"
15 | orcid: "https://orcid.org/0000-0002-2381-3544"
16 | - given-names: "Serban D."
17 | family-names: "Porumbescu"
18 | email: "sdporumbescu@ucdavis.edu"
19 | affiliation: "University of California, Davis"
20 | orcid: "https://orcid.org/0000-0003-1523-9199"
21 | - given-names: "John D."
22 | family-names: "Owens"
23 | email: "jowens@ece.ucdavis.edu"
24 | affiliation: "University of California, Davis"
25 | orcid: "https://orcid.org/0000-0001-6582-8237"
26 | repository-code: "https://github.com/owensgroup/UnifiedShaderSpecialization"
27 | preferred-citation:
28 | type: article
29 | title: "Supporting Unified Shader Specialization by Co-opting C++ Features"
30 | authors:
31 | - given-names: "Kerry A."
32 | family-names: "Seitz"
33 | name-suffix: "Jr."
34 | email: "kaseitz@ucdavis.edu"
35 | affiliation: "University of California, Davis"
36 | orcid: "https://orcid.org/0000-0003-2424-9495"
37 | - given-names: "Theresa"
38 | family-names: "Foley"
39 | email: "tfoley@nvidia.com"
40 | affiliation: "NVIDIA"
41 | orcid: "https://orcid.org/0000-0002-2381-3544"
42 | - given-names: "Serban D."
43 | family-names: "Porumbescu"
44 | email: "sdporumbescu@ucdavis.edu"
45 | affiliation: "University of California, Davis"
46 | orcid: "https://orcid.org/0000-0003-1523-9199"
47 | - given-names: "John D."
48 | family-names: "Owens"
49 | email: "jowens@ece.ucdavis.edu"
50 | affiliation: "University of California, Davis"
51 | orcid: "https://orcid.org/0000-0001-6582-8237"
52 | journal: "Proceedings of the ACM on Computer Graphics and Interactive Techniques"
53 | year: 2022
54 | volume: 5
55 | issue: 3
56 | start: "25:1"
57 | end: "25:17"
58 | month: 7
59 | doi: 10.1145/3543866
60 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Excluding the "external" directory, this code is licensed under
2 | the 3-clause BSD license as follows:
3 |
4 | Copyright (c) 2022, The Regents of the University of California,
5 | Davis campus. All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions
9 | are met:
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither any name of The Regents of the University of California nor
16 | the names of its contributors may be used to endorse or promote
17 | products derived from this software without specific prior written
18 | permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
21 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
32 |
33 | For code contained in the "external" directory and its subdirectories,
34 | please refer to the specific copyright and licensing information
35 | contained therein.
36 |
37 | This code relies on LLVM and Clang (distributed separately). LLVM and
38 | Clang are subject to their own terms and conditions that can be found
39 | at llvm.org.
40 |
41 | The output generated from this code interfaces with Unreal Engine 4.
42 | Unreal Engine 4 is not owned by The Regents of the University of
43 | California, and it requires a separate license. Users of this code
44 | are responsible for obtaining their own licenses to use Unreal Engine 4.
45 |
--------------------------------------------------------------------------------
/source/thusc/thusc.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 | Source Files
35 |
36 |
37 |
38 |
39 | Header Files
40 |
41 |
42 | Header Files
43 |
44 |
45 | Header Files
46 |
47 |
48 | Header Files
49 |
50 |
51 | Header Files
52 |
53 |
54 | Header Files
55 |
56 |
57 | Header Files
58 |
59 |
60 | Header Files
61 |
62 |
63 | Header Files
64 |
65 |
66 | Header Files
67 |
68 |
69 |
--------------------------------------------------------------------------------
/source/thusc/TypeHelpers.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | #include "ThuscCommon.h"
32 |
33 | DISABLE_WARNINGS_LLVM
34 | #include "clang/AST/ASTContext.h"
35 | #include "clang/AST/Type.h"
36 | #include "llvm/ADT/StringRef.h"
37 | ENABLE_WARNINGS_LLVM
38 |
39 | #include
40 | #include
41 |
42 | inline
43 | bool isPrimitiveType(const llvm::StringRef typeName) {
44 | const std::string typeNames[]{
45 | "float", "float2", "float3", "float4",
46 | "int", "int2", "int3", "int4",
47 | // TODO add others
48 | };
49 |
50 | for (const auto& name : typeNames) {
51 | if (name == typeName)
52 | return true;
53 | }
54 |
55 | return false;
56 | }
57 |
58 | // Map from UE4 types to HLSL types
59 | inline
60 | std::string getGpuTypeName(const clang::QualType& type, const clang::ASTContext& context) {
61 | std::pair typeNames[] = {
62 | std::make_pair("FVector2D", "float2"),
63 | std::make_pair("FVector4", "float4"),
64 | std::make_pair("FIntPoint", "int2"),
65 | std::make_pair("thusc::Texture2DBase", "Texture2D"),
66 | // TODO add others
67 | };
68 |
69 | std::string typeName = type.getDesugaredType(context).getAsString(context.getLangOpts());
70 |
71 | for (const auto& namePair : typeNames) {
72 | if (typeName == namePair.first)
73 | return namePair.second;
74 | }
75 |
76 | return typeName;
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/source/thusc/LLVMSpecificProperties.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $(SolutionDir)\..\llvm\
6 | $(LLVMDir)\llvm-project
7 | $(LLVMDir)\build-11.0.0
8 |
9 |
10 | <_PropertySheetDisplayName>LLVMSpecificProperties
11 |
12 |
13 |
14 | LLVMXRay.lib;LLVMWindowsManifest.lib;LLVMTestingSupport.lib;LLVMTableGen.lib;LLVMSymbolize.lib;LLVMDebugInfoPDB.lib;LLVMOrcJIT.lib;LLVMOrcError.lib;LLVMJITLink.lib;LLVMObjectYAML.lib;LLVMMCA.lib;LLVMLTO.lib;LLVMPasses.lib;LLVMObjCARCOpts.lib;LLVMExtensions.lib;LLVMLineEditor.lib;LLVMLibDriver.lib;LLVMInterpreter.lib;gtest_main.lib;gtest.lib;LLVMFuzzMutate.lib;LLVMFrontendOpenMP.lib;LLVMMCJIT.lib;LLVMExecutionEngine.lib;LLVMDWARFLinker.lib;LLVMDlltoolDriver.lib;LLVMOption.lib;LLVMDebugInfoGSYM.lib;LLVMCoverage.lib;LLVMCoroutines.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMMIRParser.lib;LLVMipo.lib;LLVMInstrumentation.lib;LLVMVectorize.lib;LLVMLinker.lib;LLVMIRReader.lib;LLVMAsmParser.lib;LLVMMCDisassembler.lib;LLVMCFGuard.lib;LLVMGlobalISel.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMDebugInfoDWARF.lib;LLVMCodeGen.lib;LLVMTarget.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMAggressiveInstCombine.lib;LLVMTransformUtils.lib;LLVMBitWriter.lib;LLVMAnalysis.lib;LLVMProfileData.lib;LLVMObject.lib;LLVMTextAPI.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMRemarks.lib;LLVMBitstreamReader.lib;LLVMMCParser.lib;LLVMMC.lib;LLVMDebugInfoCodeView.lib;LLVMDebugInfoMSF.lib;LLVMBinaryFormat.lib;LLVMSupport.lib;LLVMDemangle.lib;clangAnalysis.lib;clangARCMigrate.lib;clangAST.lib;clangASTMatchers.lib;clangBasic.lib;clangCodeGen.lib;clangCrossTU.lib;clangDependencyScanning.lib;clangDirectoryWatcher.lib;clangDriver.lib;clangDynamicASTMatchers.lib;clangEdit.lib;clangFormat.lib;clangFrontend.lib;clangFrontendTool.lib;clangHandleCXX.lib;clangHandleLLVM.lib;clangIndex.lib;clangLex.lib;clangParse.lib;clangRewrite.lib;clangRewriteFrontend.lib;clangSema.lib;clangSerialization.lib;clangStaticAnalyzerCheckers.lib;clangStaticAnalyzerCore.lib;clangStaticAnalyzerFrontend.lib;clangTooling.lib;clangToolingASTDiff.lib;clangToolingCore.lib;clangToolingInclusions.lib;clangToolingRefactoring.lib;clangToolingSyntax.lib;clangTransformer.lib;Version.lib;%(AdditionalDependencies)
15 |
16 |
17 | $(LLVMSrcDir)\clang\include;$(LLVMSrcDir)\llvm\include;$(LLVMBuildDir)\include;$(LLVMBuildDir)\tools\clang\include;
18 |
19 |
20 |
21 |
22 | $(LLVMDir)
23 |
24 |
25 | $(LLVMSrcDir)
26 | true
27 |
28 |
29 | $(LLVMBuildDir)
30 | true
31 |
32 |
33 |
--------------------------------------------------------------------------------
/source/thusc/ThuscShaderIR.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #include "ThuscShaderIR.h"
30 |
31 | using namespace clang;
32 | using namespace llvm;
33 | using namespace thusc;
34 |
35 | const char* thusc::shaderImplClassPrefix = "ThuscImpl_";
36 |
37 | // PermutationShaderClass
38 | PermutationShaderClass::PermutationShaderClass(const clang::FieldDecl* fieldDecl, llvm::StringRef name,
39 | const ShaderClass* shaderClassType, const ShaderIR* shaderIR)
40 | : fieldDecl(fieldDecl)
41 | , name(name)
42 | , shaderClassType(shaderClassType)
43 | {
44 | validShaderClasses.push_back(shaderClassType);
45 |
46 | for (const auto& shaderClass : shaderIR->getShaderClasses()) {
47 | const ShaderClass* baseShaderClass = shaderClass->baseShaderClass;
48 | while (baseShaderClass) {
49 | if (baseShaderClass == shaderClassType) {
50 | validShaderClasses.push_back(shaderClass.get());
51 | break;
52 | }
53 | baseShaderClass = baseShaderClass->baseShaderClass;
54 | }
55 | }
56 | }
57 |
58 | // ImplClass
59 | std::string ImplClass::generateImplClassName(const ShaderClass* parent, const std::vector& selections) {
60 | std::string name = (shaderImplClassPrefix + parent->getName()).str();
61 | for (const auto& s : selections) {
62 | name += "_" + s.implClass->getName().str();
63 | }
64 | return name;
65 | }
66 |
67 |
68 | // ShaderClass
69 | void ShaderClass::addGPUMethod(std::unique_ptr gpuFunc) {
70 | // If this function overrides a function that's already in the ShaderClass,
71 | // then remove the overridden functions
72 | if (const auto* methodDecl = dyn_cast(gpuFunc->getFunctionDecl())) {
73 | for (const auto* overriddenMethod : methodDecl->overridden_methods()) {
74 | gpuMethods.erase(std::remove_if(gpuMethods.begin(), gpuMethods.end(),
75 | [overriddenMethod](std::unique_ptr& f) {
76 | return (f->getFunctionDecl() == overriddenMethod);
77 | }), gpuMethods.end());
78 | }
79 | }
80 |
81 | gpuMethods.push_back(std::move(gpuFunc));
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/source/thusc/ThuscBackendUE4.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | #include "ThuscBackend.h"
32 | #include "ThuscBackendHLSL.h"
33 | #include "ThuscShaderIR.h"
34 |
35 | class ThuscBackendUE4Host : public ThuscBackendHost {
36 | public:
37 | ThuscBackendUE4Host(const thusc::ShaderIR& shaderIR, clang::Rewriter& rewriter, llvm::StringRef gpuOutputDirectory)
38 | : ThuscBackendHost(shaderIR, rewriter, gpuOutputDirectory)
39 | {}
40 |
41 | virtual bool Output(const clang::FileID currentFileID) override;
42 |
43 | private:
44 | bool OutputShaderClass(const thusc::ShaderClass* shaderClss);
45 | bool OutputGPUFunction(const thusc::GPUFunction* gpuFunc);
46 |
47 | void OutputUniformFieldStruct(const thusc::UniformField* uniform, llvm::raw_ostream& stream) const;
48 | void OutputUniformField(const thusc::UniformField* uniform, llvm::raw_ostream& stream) const;
49 | void OutputUniformFields(const thusc::ShaderClass* shaderClass, const thusc::ImplClass* implClass, llvm::raw_ostream& stream) const;
50 |
51 | void OutputPermutationErrorChecking(const thusc::PermutationField& perm, llvm::raw_ostream& stream) const;
52 | void OutputPermutationFields(const thusc::ShaderClass* shaderClass, const thusc::ImplClass* implClass, llvm::raw_ostream& stream) const;
53 |
54 | void OutputComputeShaderEntry(const thusc::ComputeEntryPoint* entryPoint, const thusc::ShaderClass* shaderClass, llvm::raw_ostream& stream) const;
55 |
56 | bool OutputImplClass(const thusc::ShaderClass* shaderClass, const thusc::ImplClass* implClass, llvm::raw_ostream& stream) const;
57 |
58 |
59 | const char* permutationClassPrefix = "ThuscPermutationClass_";
60 | const char* thuscTypeIDPrefix = "Thusc_getTypeID_";
61 | const char* thuscgetImplClassIDFunctionName = "Thusc_getImplClassID";
62 | };
63 |
64 | class ThuscBackendUE4 : public ThuscBackend {
65 | public:
66 | ThuscBackendUE4(const thusc::ShaderIR& shaderIR, clang::Rewriter& rewriter,
67 | llvm::StringRef gpuOutputDirectory, llvm::StringRef gpuOutputDirectoryVirtual)
68 | : ThuscBackend(shaderIR, rewriter, gpuOutputDirectory, gpuOutputDirectoryVirtual)
69 | {}
70 | };
71 |
72 |
--------------------------------------------------------------------------------
/source/thusc/ThuscCppToHLSLTranslator.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | #include "ThuscCommon.h"
32 | #include "ThuscShaderIR.h"
33 |
34 | DISABLE_WARNINGS_LLVM
35 | #include "clang/AST/RecursiveASTVisitor.h"
36 | #include "clang/Basic/Diagnostic.h"
37 | #include "clang/Basic/SourceManager.h"
38 | #include "clang/Rewrite/Core/Rewriter.h"
39 | ENABLE_WARNINGS_LLVM
40 |
41 | #include
42 |
43 | namespace thusc {
44 |
45 | class CppToHLSLVisitor : public clang::RecursiveASTVisitor {
46 | public:
47 | CppToHLSLVisitor(const llvm::DenseMap& clangFuncToThuscFunc,
48 | const ShaderClass* shaderClass,
49 | clang::Rewriter& rewriter)
50 | : clangFuncToThuscFunc(clangFuncToThuscFunc)
51 | , shaderClass(shaderClass)
52 | , context(shaderClass->classDecl->getASTContext())
53 | , rewriter(rewriter)
54 | , diagEngine(rewriter.getSourceMgr().getDiagnostics())
55 | {}
56 |
57 | bool VisitStmt(clang::Stmt* stmt);
58 | bool VisitDeclRefExpr(clang::DeclRefExpr* declRefExpr);
59 | bool VisitCallExpr(clang::CallExpr* callExpr);
60 | bool VisitMemberExpr(clang::MemberExpr* memberExpr);
61 |
62 | void pushNestedShaderClass(const ShaderClass* shaderClassParam, llvm::StringRef prefix) {
63 | shaderClassStack.push_back(std::make_pair(shaderClass, implicitThisOverride));
64 | shaderClass = shaderClassParam;
65 | implicitThisOverride = prefix.str();
66 | }
67 |
68 | void popNestedShaderClass() {
69 | shaderClass = shaderClassStack.back().first;
70 | implicitThisOverride = shaderClassStack.back().second;
71 | shaderClassStack.pop_back();
72 | }
73 |
74 | void undoRewrites();
75 |
76 | private:
77 | // Helper methods
78 | void replaceTextWithUndo(llvm::StringRef newText, std::function f);
79 | bool rewriteUniformMemberAccess(const clang::MemberExpr* memberExpr);
80 |
81 | const llvm::DenseMap& clangFuncToThuscFunc;
82 | const ShaderClass* shaderClass;
83 | const clang::ASTContext& context;
84 | clang::Rewriter& rewriter;
85 | clang::DiagnosticsEngine& diagEngine;
86 |
87 | std::vector> shaderClassStack;
88 | std::string implicitThisOverride = "";
89 |
90 | std::stack, unsigned, std::string>> undoStack;
91 | };
92 |
93 | }; // namespace thusc
94 |
--------------------------------------------------------------------------------
/source/thusc/ThuscCommon.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | #define DISABLE_WARNINGS_LLVM \
32 | __pragma(warning(push, 0)) /* Disable all warnings before including LLVM/Clang headers */ \
33 | __pragma(warning(disable : 4146)) /* Disable this specific warning too (which is reported as an error) */
34 |
35 | #define ENABLE_WARNINGS_LLVM \
36 | __pragma(warning(pop)) /* Reenable warnings */
37 |
38 | #define THUSC_H_PATH "G:\\workspace\\thusc\\include\\thusc.h"
39 |
40 | #define THUSC_FOWRARDING_FUNCTION(functionName) "template static auto " functionName "(Args&&... args) -> decltype(thusc::" functionName "(Forward(args)...)) { return " functionName "(Forward(args)...); }"
41 |
42 | #define HLSLPP_FOWRARDING_FUNCTION(functionName) "template static auto " functionName "(Args&&... args) -> decltype(hlslpp::" functionName "(Forward(args)...)) { return " functionName "(Forward(args)...); }"
43 |
44 | #define THUSC_TYPE_ADAPTERS \
45 | THUSC_FOWRARDING_FUNCTION("sincos") \
46 | THUSC_FOWRARDING_FUNCTION("max") \
47 | THUSC_FOWRARDING_FUNCTION("min") \
48 | HLSLPP_FOWRARDING_FUNCTION("all") \
49 | HLSLPP_FOWRARDING_FUNCTION("any") \
50 | ""
51 |
52 | #define THUSC_SHADER_SPELLING "ThuscShader"
53 |
54 | #define THUSC_UNIFORM_PREFIX "ThuscUniform-"
55 | #define THUSC_UNIFORM_SPELLING THUSC_UNIFORM_PREFIX
56 |
57 | #define THUSC_PERMUTATION_PREFIX "ThuscPermutation-"
58 | #define THUSC_PERMUTATION_ENUM_SPELLING THUSC_PERMUTATION_PREFIX "Enum"
59 | #define THUSC_PERMUTATION_BOOL_SPELLING THUSC_PERMUTATION_PREFIX "Bool"
60 | #define THUSC_PERMUTATION_INT_SPELLING THUSC_PERMUTATION_PREFIX "Int"
61 | #define THUSC_PERMUTATION_SPARSE_INT_SPELLING THUSC_PERMUTATION_PREFIX "SparseInt"
62 | #define THUSC_PERMUTATION_SHADERCLASS_SPELLING THUSC_PERMUTATION_PREFIX "ShaderClass"
63 |
64 | #define THUSC_HLSL_SEMANTIC_PREFIX "ThuscHLSLSemantic-"
65 |
66 | #define THUSC_HLSL_SEMANTIC_COMPUTESHADER_PREFIX THUSC_HLSL_SEMANTIC_PREFIX "ComputeShader-"
67 | #define THUSC_SV_DISPATCH_THREAD_ID_SPELLING THUSC_HLSL_SEMANTIC_COMPUTESHADER_PREFIX "SV_DispatchThreadID"
68 | #define THUSC_SV_GROUP_THREAD_ID_SPELLING THUSC_HLSL_SEMANTIC_COMPUTESHADER_PREFIX "SV_GroupThreadID"
69 | #define THUSC_SV_GROUP_ID_SPELLING THUSC_HLSL_SEMANTIC_COMPUTESHADER_PREFIX "SV_GroupID"
70 | #define THUSC_SV_GROUP_INDEX_SPELLING THUSC_HLSL_SEMANTIC_COMPUTESHADER_PREFIX "SV_GroupIndex"
71 |
72 | #define THUSC_SHADER_ENTRY_PREFIX "ThuscShaderEntry-"
73 | #define THUSC_ENTRY_COMPUTE_SPELLING THUSC_SHADER_ENTRY_PREFIX "Compute"
74 | #define THUSC_ENTRY_PIXEL_SPELLING THUSC_SHADER_ENTRY_PREFIX "Pixel"
75 |
76 | #define THUSC_GPU_FN_SPELLING "Thusc-GPU"
77 | #define THUSC_HLSL_PRECODE_SPELLING "Thusc-PrecodeHLSL"
78 | #define THUSC_HLSL_POSTCODE_SPELLING "Thusc-PostcodeHLSL"
79 | #define THUSC_HLSL_INOUT_SPELLING "Thusc-inout"
80 |
81 |
--------------------------------------------------------------------------------
/source/thusc/ThuscBackend.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | #include "ThuscCommon.h"
32 | #include "ThuscShaderIR.h"
33 |
34 | DISABLE_WARNINGS_LLVM
35 | #include "clang/AST/DeclCXX.h"
36 | #include "clang/Basic/Diagnostic.h"
37 | #include "clang/Basic/LangOptions.h"
38 | #include "clang/Basic/SourceManager.h"
39 | #include "clang/Rewrite/Core/Rewriter.h"
40 |
41 | #include "llvm/Support/MemoryBuffer.h"
42 | ENABLE_WARNINGS_LLVM
43 |
44 | #define WRITELN(X) X << ((X.empty()) ? "" : "\n")
45 |
46 | class ThuscBackendBase {
47 | public:
48 | ThuscBackendBase(const thusc::ShaderIR& shaderIR, clang::Rewriter& rewriter)
49 | : shaderIR(shaderIR)
50 | , sourceMgr(rewriter.getSourceMgr())
51 | , langOpts(rewriter.getLangOpts())
52 | , diagEngine(rewriter.getSourceMgr().getDiagnostics())
53 | , rewriter(rewriter)
54 | {}
55 |
56 | virtual bool Output(const clang::FileID currentFileID) = 0;
57 |
58 | protected:
59 | const thusc::ShaderIR& shaderIR;
60 | const clang::SourceManager& sourceMgr;
61 | const clang::LangOptions& langOpts;
62 | clang::DiagnosticsEngine& diagEngine;
63 | clang::Rewriter& rewriter;
64 | };
65 |
66 | class ThuscBackendHost : public ThuscBackendBase {
67 | public:
68 | ThuscBackendHost(const thusc::ShaderIR& shaderIR, clang::Rewriter& rewriter, llvm::StringRef gpuOutputDirectory)
69 | : ThuscBackendBase(shaderIR, rewriter)
70 | , gpuOutputDir(gpuOutputDirectory)
71 | {}
72 |
73 | protected:
74 | std::string gpuOutputDir;
75 | };
76 |
77 | class ThuscBackendGPU : public ThuscBackendBase {
78 | public:
79 | ThuscBackendGPU(const thusc::ShaderIR& shaderIR, clang::Rewriter& rewriter, llvm::StringRef gpuOutputDirectory)
80 | : ThuscBackendBase(shaderIR, rewriter)
81 | , gpuOutputDir(gpuOutputDirectory)
82 | {}
83 |
84 | protected:
85 | std::string gpuOutputDir;
86 | };
87 |
88 | template
89 | class ThuscBackend: public ThuscBackendBase {
90 | public:
91 | ThuscBackend(const thusc::ShaderIR& shaderIR, clang::Rewriter& rewriter,
92 | llvm::StringRef gpuOutputDirectory, llvm::StringRef gpuOutputDirectoryVirtual)
93 | : ThuscBackendBase(shaderIR, rewriter)
94 | , hostBackend(shaderIR, rewriter, gpuOutputDirectoryVirtual)
95 | , gpuBackend(shaderIR, rewriter, gpuOutputDirectory)
96 | {}
97 |
98 | virtual bool Output(const clang::FileID currentFileID) override {
99 | // GPU backend function must be called first
100 | // The host backend rewrites the source code, including deleting functions,
101 | // so the GPU backend must be called first so it has the chance to use the unaltered code
102 | return gpuBackend.Output(currentFileID) && hostBackend.Output(currentFileID);
103 | }
104 |
105 | protected:
106 | HostBackendType hostBackend;
107 | GPUBackendType gpuBackend;
108 | };
109 |
110 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # thusc
2 | Translator for Heterogeneous Unified Shaders in C++
3 |
4 | This repository contains source code supporting the High Performance Graphics 2022 paper:
5 |
6 | **Supporting Unified Shader Specialization by Co-opting C++ Features**\
7 | [Kerry A. Seitz, Jr.](https://seitz.tech/), Theresa Foley, [Serban D. Porumbescu](http://graphics.cs.ucdavis.edu/~porumbes), and [John D. Owens](https://www.ece.ucdavis.edu/~jowens/)\
8 | Proceedings of the ACM on Computer Graphics and Interactive Techniques (PACMCGIT)\
9 | Volume 5 Issue 3, July 2022\
10 | Article No. 25
11 |
12 | DOI: [https://doi.org/10.1145/3543866](https://doi.org/10.1145/3543866)\
13 | Code: [https://github.com/owensgroup/UnifiedShaderSpecialization](https://github.com/owensgroup/UnifiedShaderSpecialization)
14 |
15 |
16 | Getting Started
17 | ===============
18 |
19 | **Note:** This code is currently tested only on 64-bit Windows.
20 |
21 | Required Software
22 | =================
23 |
24 | 1) Microsoft Visual Studio 2019: [https://visualstudio.microsoft.com/vs/older-downloads/](https://visualstudio.microsoft.com/vs/older-downloads/)
25 |
26 | **Note:** Also known as Microsoft Visual Studio 16.0
27 |
28 | 2) LLVM and Clang version 11.0.0: [https://llvm.org/](https://llvm.org/)
29 |
30 | **Note:** We recommend building LLVM 11 from source with the following CMake arguments:
31 |
32 | * `-DLLVM_ENABLE_PROJECTS=clang`
33 | * `-DLLVM_TARGETS_TO_BUILD=X86`
34 | * `-DLLVM_USE_CRT_RELWITHDEBINFO=MDd`
35 | * `-DMSVC_DIA_SDK_DIR=C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/DIA SDK`
36 | * (Modify path appropriately for your install of Visual Studio 2019)
37 |
38 | **Note 2:** We recommend building the `Release` and `RelWithDebInfo` builds of LLVM and Clang, which are used with thusc's `Release` and `Debug` builds, respectively. However, you can change this by modifying `$THSUC/source/thusc/LLVMSpecificProperties-Release.props` and `$THUSC/source/thusc/LLVMSpecificProperties-Debug.props` to build against different LLVM build types.
39 |
40 |
41 | Building
42 | ========
43 |
44 | 1) Clone the thusc repository. We'll call the directory into which you cloned the repository: `$THUSC`
45 |
46 | ```Shell
47 | # Make sure to clone with --recursive
48 | git clone --recursive https://github.com/owensgroup/UnifiedShaderSpecialization.git
49 | ```
50 |
51 | **Note:** If you didn't clone with the `--recursive` flag, then you need to manually clone the submodules:
52 |
53 | ```Shell
54 | cd $THUSC
55 | git submodule update --init --recursive
56 | ```
57 |
58 | 2) Modify `$THUSC/source/thusc/ThuscCommon.h` as follows:
59 |
60 | * Modify line 38 `#define THUSC_H_PATH "G:\\workspace\\thusc\\include\\thusc.h"` to point to your cloned copy of the `$THUSC/include/thusc.h` file.
61 |
62 | 3) Modify `$THUSC/source/thusc/LLVMSpecificProperties.props` as follows:
63 |
64 | * (Optional) Modify line 5 `$(SolutionDir)\..\llvm\` to point to the location of the parent directory to your LLVM source and build directories.
65 | * Modify line 6 `$(LLVMDir)\llvm-project` to point to the location of your LLVM top-level source directory. This directory should contain subdirectories for `llvm` and `clang`.
66 | * Modify line 7 `$(LLVMDir)\build-11.0.0` to point to the location of your LLVM build directory.
67 |
68 | 4) Build thusc by opening `thusc.sln` and building via Visual Studio 2019. The solution provides both `Debug` and `Release` builds.
69 |
70 | 5) You should now be able to run the translator tool. Run with `-h` to see the command-line arguments.
71 |
72 |
73 | Tips for use with Unreal Engine 4 (UE4)
74 | =======================================
75 |
76 | In the paper, the C++ attribute `[[ShaderClass]]` is used to denote a ShaderClass. However, UE4 uses this identifier already. Instead, use `[[ThuscShader]]` to denote a ShaderClass.
77 |
78 |
79 | If you are writing code that `#includes` UE4 header files, we recommend generating a [Clang Compilation Database](https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) from UE4. The Unreal Build Tool can generate this database for you:
80 |
81 | 1) Unreal Build Tool expects LLVM and Clang to be installed at `C:\Program Files\LLVM` (it searches for `bin\clang-cl.exe` at that location). If you did not install LLVM and Clang to this location, you can symbolically link `C:\Program Files\LLVM` to your build.
82 |
83 | 2) You can then generate the compilation database by running this command:
84 |
85 | ```Shell
86 | UnrealEngine\Engine\Build\BatchFiles\Build.bat -mode=GenerateClangDatabase -Target="UE4Editor Win64 Development" -WaitMutex
87 | ```
88 |
89 | 3) This generated file is very large, and the translator tool takes a long time to parse it. We recommend making a copy and editing it to contain just the portions you need.
90 |
--------------------------------------------------------------------------------
/source/thusc/ThuscBackendHLSL.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | #include "ThuscBackend.h"
32 |
33 | #include "ThuscCppToHLSLTranslator.h"
34 |
35 | DISABLE_WARNINGS_LLVM
36 | #include "clang/AST/RecursiveASTVisitor.h"
37 | ENABLE_WARNINGS_LLVM
38 |
39 | namespace thusc {
40 |
41 | // TODO Fix this hack. It's a quick-and-dirty way to get the corresponding command line option to this file
42 | extern bool outputAllGPUFuncs;
43 |
44 | } // namespace thusc
45 |
46 | class ThuscBackendHLSL : public ThuscBackendGPU {
47 | public:
48 | ThuscBackendHLSL(const thusc::ShaderIR& shaderIR, clang::Rewriter& rewriter, llvm::StringRef gpuOutputDirectory)
49 | : ThuscBackendGPU(shaderIR, rewriter, gpuOutputDirectory)
50 | {
51 | for (const auto& gpuFunc : shaderIR.gpuFunctions) {
52 | clangFuncToThuscFunc.insert(std::make_pair(gpuFunc->getFunctionDecl(), gpuFunc.get()));
53 | }
54 |
55 | for (const auto& shaderClass : shaderIR.getShaderClasses()) {
56 | for (const auto& gpuMethod : shaderClass->getGPUMethods()) {
57 | clangFuncToThuscFunc.insert(std::make_pair(gpuMethod->getFunctionDecl(), gpuMethod.get()));
58 | }
59 | }
60 | }
61 |
62 | virtual bool Output(const clang::FileID currentFileID) override;
63 |
64 | private:
65 | bool OutputShaderClass(const thusc::ShaderClass* shaderClass);
66 |
67 | void OutputPermutationShaderClassFields(const thusc::ShaderClass* shaderClass, llvm::raw_ostream& stream) const;
68 | void OutputPermutationFields(const thusc::ShaderClass* shaderClass, llvm::raw_ostream& stream) const;
69 | void OutputUniformFields(const thusc::ShaderClass*, llvm::raw_ostream& stream, llvm::StringRef prefix = "") const;
70 |
71 | void OutputSelection(const thusc::PermutationShaderClassSelection& selection, llvm::raw_ostream& stream, llvm::StringRef prevPrefix = "" ) const;
72 |
73 | void OutputUniformFieldSimple(const thusc::UniformField* uniform, llvm::raw_ostream& stream, const llvm::Twine& prefix) const;
74 | void OutputFlattenedUniformStruct(const clang::CXXRecordDecl* classDecl, llvm::raw_ostream& stream, const llvm::Twine& prefix) const;
75 | void OutputUniformFieldStruct(const thusc::UniformField* uniform, llvm::raw_ostream& stream, const llvm::Twine& prefix) const;
76 | void OutputUniformField(const thusc::UniformField* uniform, llvm::raw_ostream& stream, const llvm::Twine& prefix) const;
77 |
78 | void OutputFunctionDeclaration(const thusc::GPUFunctionBase* gpuFunc, llvm::raw_ostream& stream, bool shouldOutputSemantics, llvm::StringRef prefix = "") const;
79 | void OutputFunctionBody(const clang::FunctionDecl* funcDecl, llvm::raw_ostream& stream) const;
80 |
81 | void OutputGPUFunction(const thusc::GPUFunction* gpuFunc, llvm::raw_ostream& stream, llvm::StringRef prefix = "") const;
82 |
83 | void OutputShaderEntryCommon(const thusc::EntryPoint* entryPoint, llvm::raw_ostream& stream) const;
84 | void OutputComputeShaderEntry(const thusc::ComputeEntryPoint* entryPoint, llvm::raw_ostream& stream) const;
85 |
86 | llvm::DenseMap clangFuncToThuscFunc;
87 | std::unique_ptr translator = nullptr;
88 | };
89 |
90 |
--------------------------------------------------------------------------------
/include/thusc.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | #include
32 |
33 | #include "RenderGraphResources.h"
34 |
35 | __pragma(warning(push, 0))
36 | __pragma(warning(disable : 4582))
37 | __pragma(warning(disable : 4668))
38 | #define HLSLPP_SCALAR
39 | #include "../external/hlslpp/include/hlsl++.h"
40 | __pragma(warning(pop))
41 |
42 | #define BRANCH
43 | #define UNROLL
44 |
45 |
46 | namespace thusc {
47 | template
48 | T1 max(T1 f1, T2 f2) { return (f2 > f1) ? f2 : f1; }
49 |
50 | template
51 | T1 min(T1 f1, T2 f2) { return (f2 < f1) ? f2 : f1; }
52 |
53 | template
54 | T rcp(T f) { return hlslpp::rcp(f); }
55 |
56 | template
57 | void sincos(const hlslpp::float1& f, hlslpp::swizzle1& s, hlslpp::swizzle1& c) {
58 | hlslpp::float1 sinFloat = s;
59 | hlslpp::float1 cosFloat = c;
60 | hlslpp::sincos(f, sinFloat, cosFloat);
61 | s = sinFloat;
62 | c = cosFloat;
63 | }
64 |
65 | template
66 | void sincos(const T& f, T& s, T& c) { hlslpp::sincos(f, s, c); }
67 |
68 | class SamplerState {
69 | public:
70 | SamplerState operator=(FRHISamplerState* rhs) {
71 | data = rhs;
72 | return *this;
73 | }
74 |
75 | operator FRHISamplerState*() const {
76 | return data;
77 | }
78 |
79 | private:
80 | FRHISamplerState* data;
81 | };
82 |
83 | template
84 | class Texture2DBase {
85 | public:
86 | Texture2DBase& operator=(const UE4Type& rhs) {
87 | data = rhs;
88 | return *this;
89 | }
90 |
91 | operator UE4Type() const {
92 | return data;
93 | }
94 |
95 | // GPU-only functions
96 | #ifndef THUSC_HOST
97 | T SampleLevel(SamplerState samplerState, hlslpp::float2 location, float lod, hlslpp::int2 offset = hlslpp::int2(0)) const {
98 | return T(0);
99 | }
100 |
101 | T Load(hlslpp::int3 in) const {
102 | return T(0);
103 | }
104 | #endif // ndef THUSC_HOST
105 |
106 | private:
107 | UE4Type data;
108 | };
109 |
110 | template
111 | class RWTexture2D {
112 | public:
113 | RWTexture2D& operator=(const FRDGTextureUAVRef& rhs) {
114 | data = rhs;
115 | return *this;
116 | }
117 |
118 | operator FRDGTextureUAVRef() const {
119 | return data;
120 | }
121 |
122 | // GPU-only functions
123 | #ifndef THUSC_HOST
124 | T operator[](const hlslpp::uint2 pos) const {
125 | return T();
126 | }
127 | #endif // ndef THUSC_HOST
128 |
129 |
130 | private:
131 | FRDGTextureUAVRef data;
132 | };
133 |
134 | template
135 | #ifdef THUSC_HOST
136 | class GlobalUniformBuffer {
137 | #else
138 | class GlobalUniformBuffer : public T {
139 | #endif // THUSC_HOST
140 | public:
141 | GlobalUniformBuffer& operator=(const TUniformBufferRef& rhs) {
142 | data = rhs;
143 | return *this;
144 | }
145 |
146 | operator TUniformBufferRef() const {
147 | return data;
148 | }
149 |
150 | private:
151 | TUniformBufferRef data;
152 | };
153 | } // namespace thusc
154 |
155 | using float2 = hlslpp::float2;
156 | using float3 = hlslpp::float3;
157 | using float4 = hlslpp::float4;
158 | using int1 = hlslpp::int1;
159 | using int2 = hlslpp::int2;
160 | using int3 = hlslpp::int3;
161 | using int4 = hlslpp::int4;
162 | using uint = unsigned int;
163 | using uint2 = hlslpp::uint2;
164 | using uint3 = hlslpp::uint3;
165 | using uint4 = hlslpp::uint4;
166 | using bool2 = hlslpp::uint2;
167 |
168 | #define THUSC_FOWRARDING_FUNCTION(functionName) template static auto functionName (Args&&... args) -> decltype(thusc:: functionName (Forward(args)...)) { return functionName (Forward(args)...); }
169 |
170 | #define HLSLPP_FOWRARDING_FUNCTION(functionName) template static auto functionName (Args&&... args) -> decltype(hlslpp:: functionName (Forward(args)...)) { return functionName (Forward(args)...); }
171 |
172 | THUSC_FOWRARDING_FUNCTION(sincos)
173 | THUSC_FOWRARDING_FUNCTION(max)
174 | THUSC_FOWRARDING_FUNCTION(min)
175 | THUSC_FOWRARDING_FUNCTION(rcp)
176 | //HLSLPP_FOWRARDING_FUNCTION(all)
177 | //HLSLPP_FOWRARDING_FUNCTION(any)
178 |
179 | //template
180 | //using min = thusc::min;
181 | //
182 | //template
183 | //using max = thusc::max;
184 |
185 | using SamplerState = thusc::SamplerState;
186 |
187 | using Texture2D = thusc::Texture2DBase;
188 |
189 | template
190 | using Texture2DSRV = thusc::Texture2DBase;
191 |
192 | template
193 | using RWTexture2D = thusc::RWTexture2D;
194 |
195 | template
196 | using GlobalUniformBuffer = thusc::GlobalUniformBuffer;
197 |
198 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | [Bb]uild/
2 |
3 | ## Ignore Visual Studio temporary files, build results, and
4 | ## files generated by popular Visual Studio add-ons.
5 | ##
6 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
7 |
8 | # User-specific files
9 | *.rsuser
10 | *.suo
11 | *.user
12 | *.userosscache
13 | *.sln.docstates
14 |
15 | # User-specific files (MonoDevelop/Xamarin Studio)
16 | *.userprefs
17 |
18 | # Mono auto generated files
19 | mono_crash.*
20 |
21 | # Build results
22 | [Dd]ebug/
23 | [Dd]ebugPublic/
24 | [Rr]elease/
25 | [Rr]eleases/
26 | x64/
27 | x86/
28 | [Aa][Rr][Mm]/
29 | [Aa][Rr][Mm]64/
30 | bld/
31 | [Bb]in/
32 | [Oo]bj/
33 | [Ll]og/
34 | [Ll]ogs/
35 |
36 | # Visual Studio 2015/2017 cache/options directory
37 | .vs/
38 | # Uncomment if you have tasks that create the project's static files in wwwroot
39 | #wwwroot/
40 |
41 | # Visual Studio 2017 auto generated files
42 | Generated\ Files/
43 |
44 | # MSTest test Results
45 | [Tt]est[Rr]esult*/
46 | [Bb]uild[Ll]og.*
47 |
48 | # NUnit
49 | *.VisualState.xml
50 | TestResult.xml
51 | nunit-*.xml
52 |
53 | # Build Results of an ATL Project
54 | [Dd]ebugPS/
55 | [Rr]eleasePS/
56 | dlldata.c
57 |
58 | # Benchmark Results
59 | BenchmarkDotNet.Artifacts/
60 |
61 | # .NET Core
62 | project.lock.json
63 | project.fragment.lock.json
64 | artifacts/
65 |
66 | # StyleCop
67 | StyleCopReport.xml
68 |
69 | # Files built by Visual Studio
70 | *_i.c
71 | *_p.c
72 | *_h.h
73 | *.ilk
74 | *.meta
75 | *.obj
76 | *.iobj
77 | *.pch
78 | *.pdb
79 | *.ipdb
80 | *.pgc
81 | *.pgd
82 | *.rsp
83 | *.sbr
84 | *.tlb
85 | *.tli
86 | *.tlh
87 | *.tmp
88 | *.tmp_proj
89 | *_wpftmp.csproj
90 | *.log
91 | *.vspscc
92 | *.vssscc
93 | .builds
94 | *.pidb
95 | *.svclog
96 | *.scc
97 |
98 | # Chutzpah Test files
99 | _Chutzpah*
100 |
101 | # Visual C++ cache files
102 | ipch/
103 | *.aps
104 | *.ncb
105 | *.opendb
106 | *.opensdf
107 | *.sdf
108 | *.cachefile
109 | *.VC.db
110 | *.VC.VC.opendb
111 |
112 | # Visual Studio profiler
113 | *.psess
114 | *.vsp
115 | *.vspx
116 | *.sap
117 |
118 | # Visual Studio Trace Files
119 | *.e2e
120 |
121 | # TFS 2012 Local Workspace
122 | $tf/
123 |
124 | # Guidance Automation Toolkit
125 | *.gpState
126 |
127 | # ReSharper is a .NET coding add-in
128 | _ReSharper*/
129 | *.[Rr]e[Ss]harper
130 | *.DotSettings.user
131 |
132 | # TeamCity is a build add-in
133 | _TeamCity*
134 |
135 | # DotCover is a Code Coverage Tool
136 | *.dotCover
137 |
138 | # AxoCover is a Code Coverage Tool
139 | .axoCover/*
140 | !.axoCover/settings.json
141 |
142 | # Visual Studio code coverage results
143 | *.coverage
144 | *.coveragexml
145 |
146 | # NCrunch
147 | _NCrunch_*
148 | .*crunch*.local.xml
149 | nCrunchTemp_*
150 |
151 | # MightyMoose
152 | *.mm.*
153 | AutoTest.Net/
154 |
155 | # Web workbench (sass)
156 | .sass-cache/
157 |
158 | # Installshield output folder
159 | [Ee]xpress/
160 |
161 | # DocProject is a documentation generator add-in
162 | DocProject/buildhelp/
163 | DocProject/Help/*.HxT
164 | DocProject/Help/*.HxC
165 | DocProject/Help/*.hhc
166 | DocProject/Help/*.hhk
167 | DocProject/Help/*.hhp
168 | DocProject/Help/Html2
169 | DocProject/Help/html
170 |
171 | # Click-Once directory
172 | publish/
173 |
174 | # Publish Web Output
175 | *.[Pp]ublish.xml
176 | *.azurePubxml
177 | # Note: Comment the next line if you want to checkin your web deploy settings,
178 | # but database connection strings (with potential passwords) will be unencrypted
179 | *.pubxml
180 | *.publishproj
181 |
182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
183 | # checkin your Azure Web App publish settings, but sensitive information contained
184 | # in these scripts will be unencrypted
185 | PublishScripts/
186 |
187 | # NuGet Packages
188 | *.nupkg
189 | # NuGet Symbol Packages
190 | *.snupkg
191 | # The packages folder can be ignored because of Package Restore
192 | **/[Pp]ackages/*
193 | # except build/, which is used as an MSBuild target.
194 | !**/[Pp]ackages/build/
195 | # Uncomment if necessary however generally it will be regenerated when needed
196 | #!**/[Pp]ackages/repositories.config
197 | # NuGet v3's project.json files produces more ignorable files
198 | *.nuget.props
199 | *.nuget.targets
200 |
201 | # Microsoft Azure Build Output
202 | csx/
203 | *.build.csdef
204 |
205 | # Microsoft Azure Emulator
206 | ecf/
207 | rcf/
208 |
209 | # Windows Store app package directories and files
210 | AppPackages/
211 | BundleArtifacts/
212 | Package.StoreAssociation.xml
213 | _pkginfo.txt
214 | *.appx
215 | *.appxbundle
216 | *.appxupload
217 |
218 | # Visual Studio cache files
219 | # files ending in .cache can be ignored
220 | *.[Cc]ache
221 | # but keep track of directories ending in .cache
222 | !?*.[Cc]ache/
223 |
224 | # Others
225 | ClientBin/
226 | ~$*
227 | *~
228 | *.dbmdl
229 | *.dbproj.schemaview
230 | *.jfm
231 | *.pfx
232 | *.publishsettings
233 | orleans.codegen.cs
234 |
235 | # Including strong name files can present a security risk
236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
237 | #*.snk
238 |
239 | # Since there are multiple workflows, uncomment next line to ignore bower_components
240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
241 | #bower_components/
242 |
243 | # RIA/Silverlight projects
244 | Generated_Code/
245 |
246 | # Backup & report files from converting an old project file
247 | # to a newer Visual Studio version. Backup files are not needed,
248 | # because we have git ;-)
249 | _UpgradeReport_Files/
250 | Backup*/
251 | UpgradeLog*.XML
252 | UpgradeLog*.htm
253 | ServiceFabricBackup/
254 | *.rptproj.bak
255 |
256 | # SQL Server files
257 | *.mdf
258 | *.ldf
259 | *.ndf
260 |
261 | # Business Intelligence projects
262 | *.rdl.data
263 | *.bim.layout
264 | *.bim_*.settings
265 | *.rptproj.rsuser
266 | *- [Bb]ackup.rdl
267 | *- [Bb]ackup ([0-9]).rdl
268 | *- [Bb]ackup ([0-9][0-9]).rdl
269 |
270 | # Microsoft Fakes
271 | FakesAssemblies/
272 |
273 | # GhostDoc plugin setting file
274 | *.GhostDoc.xml
275 |
276 | # Node.js Tools for Visual Studio
277 | .ntvs_analysis.dat
278 | node_modules/
279 |
280 | # Visual Studio 6 build log
281 | *.plg
282 |
283 | # Visual Studio 6 workspace options file
284 | *.opt
285 |
286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
287 | *.vbw
288 |
289 | # Visual Studio LightSwitch build output
290 | **/*.HTMLClient/GeneratedArtifacts
291 | **/*.DesktopClient/GeneratedArtifacts
292 | **/*.DesktopClient/ModelManifest.xml
293 | **/*.Server/GeneratedArtifacts
294 | **/*.Server/ModelManifest.xml
295 | _Pvt_Extensions
296 |
297 | # Paket dependency manager
298 | .paket/paket.exe
299 | paket-files/
300 |
301 | # FAKE - F# Make
302 | .fake/
303 |
304 | # CodeRush personal settings
305 | .cr/personal
306 |
307 | # Python Tools for Visual Studio (PTVS)
308 | __pycache__/
309 | *.pyc
310 |
311 | # Cake - Uncomment if you are using it
312 | # tools/**
313 | # !tools/packages.config
314 |
315 | # Tabs Studio
316 | *.tss
317 |
318 | # Telerik's JustMock configuration file
319 | *.jmconfig
320 |
321 | # BizTalk build output
322 | *.btp.cs
323 | *.btm.cs
324 | *.odx.cs
325 | *.xsd.cs
326 |
327 | # OpenCover UI analysis results
328 | OpenCover/
329 |
330 | # Azure Stream Analytics local run output
331 | ASALocalRun/
332 |
333 | # MSBuild Binary and Structured Log
334 | *.binlog
335 |
336 | # NVidia Nsight GPU debugger configuration file
337 | *.nvuser
338 |
339 | # MFractors (Xamarin productivity tool) working folder
340 | .mfractor/
341 |
342 | # Local History for Visual Studio
343 | .localhistory/
344 |
345 | # BeatPulse healthcheck temp database
346 | healthchecksdb
347 |
348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
349 | MigrationBackup/
350 |
351 | # Ionide (cross platform F# VS Code tools) working folder
352 | .ionide/
353 |
--------------------------------------------------------------------------------
/source/thusc/ThuscFrontendAction.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | #include "ThuscBackend.h"
32 | #include "ThuscCommon.h"
33 | #include "ThuscShaderIR.h"
34 |
35 | DISABLE_WARNINGS_LLVM
36 | #include "clang/AST/ASTContext.h"
37 | #include "clang/AST/DeclCXX.h"
38 | #include "clang/AST/RecursiveASTVisitor.h"
39 | #include "clang/Frontend/ASTConsumers.h"
40 | #include "clang/Frontend/CompilerInstance.h"
41 | #include "clang/Frontend/FrontendAction.h"
42 | #include "clang/Rewrite/Core/Rewriter.h"
43 | #include "clang/Tooling/Tooling.h"
44 |
45 | #include "llvm/ADT/StringRef.h"
46 | ENABLE_WARNINGS_LLVM
47 |
48 | class ThuscASTVisitor : public clang::RecursiveASTVisitor {
49 | public:
50 | ThuscASTVisitor(clang::Rewriter& r)
51 | : rewriter(r)
52 | , sourceMgr(r.getSourceMgr())
53 | , langOpts(r.getLangOpts())
54 | , diagEngine(r.getSourceMgr().getDiagnostics())
55 | , printingPolicy(langOpts)
56 | {
57 | printingPolicy.SuppressUnwrittenScope = 1;
58 | }
59 |
60 | void setShaderIR(thusc::ShaderIR* IR) {
61 | shaderIR = IR;
62 | }
63 |
64 | bool VisitCXXRecordDecl(clang::CXXRecordDecl* classDecl);
65 | bool VisitFunctionDecl(clang::FunctionDecl* funcDecl);
66 | bool VisitDecl(clang::Decl* Decl);
67 |
68 | private:
69 | bool HandleUniformFields(clang::CXXRecordDecl* shaderClassDecl, thusc::ShaderClass* shaderClass);
70 | bool HandlePermutationFields(clang::CXXRecordDecl* shaderClassDecl, thusc::ShaderClass* shaderClass);
71 | bool HandleShaderEntryFunctions(const clang::CXXRecordDecl* shaderClassDecl, thusc::ShaderClass* shaderClass);
72 |
73 | bool HandleOtherGPUDecls(const clang::CXXRecordDecl* shaderClassDecl, thusc::ShaderClass* shaderClass);
74 | bool HandleGPUMethods(const clang::CXXRecordDecl* shaderClassDecl, thusc::ShaderClass* shaderClass);
75 | bool HandleHLSLPrecodePostcode(const clang::CXXRecordDecl* shaderClassDecl, thusc::ShaderClass* shaderClass);
76 |
77 | // Helper functions
78 | std::unique_ptr CreateGPUFunctionIR(const clang::FunctionDecl* funcDecl);
79 | thusc::ShaderParameterSemanticKind getComputeEntryParameterSemantic(const clang::ParmVarDecl* param,
80 | const clang::CXXRecordDecl* shaderClassDecl) const;
81 |
82 | clang::Rewriter& rewriter;
83 | thusc::ShaderIR* shaderIR = nullptr;
84 |
85 | const clang::SourceManager& sourceMgr;
86 | const clang::LangOptions& langOpts;
87 | clang::DiagnosticsEngine& diagEngine;
88 | clang::PrintingPolicy printingPolicy;
89 | };
90 |
91 | template
92 | class ThuscASTConsumer : public clang::ASTConsumer {
93 | public:
94 | ThuscASTConsumer(clang::Rewriter& r, llvm::StringRef gpuOutputDirectory, llvm::StringRef gpuOutputDirectoryVirtual)
95 | : visitor(r)
96 | , rewriter(r)
97 | , gpuOutputDir(gpuOutputDirectory)
98 | , gpuOutputDirVirtual(gpuOutputDirectoryVirtual)
99 | {}
100 |
101 | virtual void HandleTranslationUnit(clang::ASTContext& context) override {
102 | thusc::ShaderIR shaderIR;
103 | visitor.setShaderIR(&shaderIR);
104 |
105 | visitor.TraverseDecl(context.getTranslationUnitDecl());
106 |
107 | BackendType backend(shaderIR, rewriter, gpuOutputDir, gpuOutputDirVirtual);
108 | backend.Output(rewriter.getSourceMgr().getMainFileID());
109 | }
110 |
111 | private:
112 | ThuscASTVisitor visitor;
113 | clang::Rewriter& rewriter;
114 | llvm::StringRef gpuOutputDir;
115 | llvm::StringRef gpuOutputDirVirtual;
116 | };
117 |
118 | template
119 | class ThuscFrontendAction : public clang::ASTFrontendAction {
120 | public:
121 | ThuscFrontendAction(llvm::raw_ostream& outputStream, llvm::StringRef gpuOutputDirectory, llvm::StringRef gpuOutputDirectoryVirtual)
122 | : outstream(outputStream), gpuOutputDir(gpuOutputDirectory), gpuOutputDirVirtual(gpuOutputDirectoryVirtual) {}
123 |
124 | void EndSourceFileAction() override {
125 | clang::SourceManager& sourceMgr = rewriter.getSourceMgr();
126 | const clang::FileID fileID = sourceMgr.getMainFileID();
127 | const clang::FileEntry* fileEntry = sourceMgr.getFileEntryForID(sourceMgr.getMainFileID());
128 |
129 | outstream << "// Generated from " << fileEntry->getName() << "\n\n";
130 | outstream << "#define THUSC_HOST\n";
131 | outstream << "#include \"" THUSC_H_PATH "\"\n";
132 | outstream << "#undef THUSC_HOST\n\n";
133 | rewriter.getEditBuffer(fileID).write(outstream);
134 | }
135 |
136 | std::unique_ptr CreateASTConsumer(
137 | clang::CompilerInstance& compilerInstance, llvm::StringRef inFile) override {
138 |
139 | rewriter.setSourceMgr(compilerInstance.getSourceManager(), compilerInstance.getLangOpts());
140 |
141 | return std::make_unique>(rewriter, gpuOutputDir, gpuOutputDirVirtual);
142 | }
143 |
144 | private:
145 | llvm::raw_ostream& outstream;
146 | llvm::StringRef gpuOutputDir;
147 | llvm::StringRef gpuOutputDirVirtual;
148 |
149 | clang::Rewriter rewriter;
150 | };
151 |
152 | template
153 | class ThuscFrontendActionFactory : public clang::tooling::FrontendActionFactory {
154 | public:
155 | ThuscFrontendActionFactory(llvm::raw_ostream& outputStream, llvm::StringRef gpuOutputDirectory, llvm::StringRef gpuOutputDirectoryVirtual)
156 | : outstream(outputStream), gpuOutputDir(gpuOutputDirectory), gpuOutputDirVirtual(gpuOutputDirectoryVirtual) {}
157 |
158 | std::unique_ptr create() override {
159 | // TODO Clang tools are often meant to be run on multiple files simultaneously,
160 | // so using the same output stream for each instance of the FrontendAction created
161 | // is probably a bad idea. However, it's fine for now, since thusc.cpp's main()
162 | // guarantees that only one source file will be processed per invocation of main().
163 | return std::make_unique< ThuscFrontendAction >(outstream, gpuOutputDir, gpuOutputDirVirtual);
164 | }
165 |
166 | private:
167 | llvm::raw_ostream& outstream;
168 | llvm::StringRef gpuOutputDir;
169 | llvm::StringRef gpuOutputDirVirtual;
170 | };
171 |
172 |
--------------------------------------------------------------------------------
/source/thusc/ThuscCppToHLSLTranslator.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #include "ThuscCppToHLSLTranslator.h"
30 |
31 | #include "ClangHelperFunctions.h"
32 |
33 | using namespace clang;
34 | using namespace llvm;
35 | using namespace thusc;
36 |
37 | // CppToHLSLVisitor methods
38 |
39 | void CppToHLSLVisitor::replaceTextWithUndo(StringRef newText, std::function f) {
40 | std::string origText = rewriter.getRewrittenText(f());
41 | undoStack.push(std::make_tuple(f, unsigned(newText.size()), origText));
42 |
43 | rewriter.ReplaceText(f(), newText);
44 | }
45 |
46 | void CppToHLSLVisitor::undoRewrites() {
47 | while (!undoStack.empty()) {
48 | auto elem = undoStack.top();
49 | undoStack.pop();
50 |
51 | rewriter.ReplaceText(std::get<0>(elem)().getBegin(), std::get<1>(elem), std::get<2>(elem));
52 | }
53 | }
54 |
55 | bool CppToHLSLVisitor::VisitStmt(Stmt* stmt) {
56 | //llvm::errs() << "============================================\n";
57 | //stmt->dump();
58 | //stmt->dumpPretty(context);
59 |
60 | return true;
61 | }
62 |
63 | bool CppToHLSLVisitor::VisitDeclRefExpr(DeclRefExpr* declRefExpr) {
64 | // Replace references to enum values (Foo::Bar) with the underscore version used in the output HLSL (Foo_Bar)
65 | // Currently only operates on enums that were used as permutation fields
66 | // TODO Make this work for non-permutation enums
67 | if (const auto* enumConstantDecl = dyn_cast(declRefExpr->getDecl())) {
68 | const auto* enumDecl = cast(enumConstantDecl->getDeclContext());
69 |
70 | for (const auto& perm : shaderClass->permutationFields) {
71 | if (const auto* enumType = dyn_cast(perm.fieldDecl->getType())) {
72 | if (enumType->getDecl() == enumDecl) {
73 | replaceTextWithUndo(perm.type + "_" + declRefExpr->getDecl()->getNameAsString(), [declRefExpr]() { return declRefExpr->getSourceRange(); });
74 | return true;
75 | }
76 | }
77 | }
78 |
79 | diagError(diagEngine, declRefExpr->getLocation(), "References to enum values must correspond to an enum used as a permutation parameter");
80 | return true;
81 | }
82 |
83 | return true;
84 | }
85 |
86 | bool CppToHLSLVisitor::VisitCallExpr(CallExpr* callExpr) {
87 | const FunctionDecl* funcDecl = callExpr->getDirectCallee();
88 | if (funcDecl == nullptr)
89 | return true;
90 |
91 | // TODO Rather than just searching for calls to known GPU functions,
92 | // we should also search for calls to builtin functions.
93 | // Then, if we find a CallExpr that calls a non-GPU and non-builtin
94 | // function, we can report an error.
95 |
96 | const auto funcMapEntry = clangFuncToThuscFunc.find(funcDecl);
97 | if (funcMapEntry != clangFuncToThuscFunc.end()) {
98 | const GPUFunction* gpuFunc = funcMapEntry->second;
99 |
100 | std::string argString = "(";
101 | if (callExpr->getNumArgs() == 0) {
102 | argString.append(")");
103 | }
104 | else {
105 | const SourceRange argRange(callExpr->getArg(0)->getBeginLoc(), callExpr->getRParenLoc());
106 | argString.append(rewriter.getRewrittenText(argRange));
107 | }
108 |
109 | std::string newText = (gpuFunc->getMangledName() + argString).str();
110 |
111 | // Replace function call with a call to the name-mangled version
112 | if (const auto* cxxMemberCallExpr = dyn_cast(callExpr)) {
113 | replaceTextWithUndo(newText, [cxxMemberCallExpr]() { return SourceRange(cxxMemberCallExpr->getExprLoc(), cxxMemberCallExpr->getRParenLoc()); });
114 | }
115 | else {
116 | replaceTextWithUndo(newText, [callExpr]() { return callExpr->getSourceRange(); });
117 | }
118 |
119 | }
120 |
121 | return true;
122 | }
123 |
124 | bool CppToHLSLVisitor::VisitMemberExpr(MemberExpr* memberExpr) {
125 | bool shouldContinue = rewriteUniformMemberAccess(memberExpr);
126 |
127 | const auto* base = memberExpr->getBase()->IgnoreImpCasts();
128 |
129 | // For implicit this expressions, replace with the implicitThisOverride prior to the access
130 | if (const auto* thisExpr = dyn_cast(base)) {
131 | bool isPermutationFieldOrOtherGPUDecl =
132 | shaderClass->isPermutationField(memberExpr->getMemberDecl()) || shaderClass->isOtherGPUDecl(memberExpr->getMemberDecl());
133 |
134 | if (!(isPermutationFieldOrOtherGPUDecl || implicitThisOverride.empty())) {
135 | std::string memberExprString = rewriter.getRewrittenText(memberExpr->getSourceRange());
136 | replaceTextWithUndo(implicitThisOverride + memberExprString, [memberExpr]() { return memberExpr->getSourceRange(); });
137 | }
138 | }
139 | // For accesses to member of ShaderClass permutation fields, change -> to _
140 | else if (const auto* baseMemberExpr = dyn_cast(base)) {
141 | if (shaderClass->isPermutationShaderClassField(baseMemberExpr->getMemberDecl())) {
142 | replaceTextWithUndo("_", [memberExpr]() { return SourceRange(memberExpr->getOperatorLoc(), memberExpr->getOperatorLoc()); });
143 | }
144 | }
145 |
146 | return shouldContinue;
147 | }
148 |
149 |
150 | // CppToHLSLVisitor helper methods
151 |
152 | // In UE4, struct uniform variables are flattened into individual uniforms.
153 | // So, if the MemberExpr has a base (somewhere up the chain) that is a
154 | // uniform, replace the MemberExpr with an access to the flattened uniform.
155 | bool CppToHLSLVisitor::rewriteUniformMemberAccess(const MemberExpr* memberExpr) {
156 | const Expr* base = memberExpr->getBase()->IgnoreCasts();
157 |
158 | bool foundUniformStruct = false;
159 | while (const auto* baseMemberExpr = dyn_cast(base)) {
160 | if (baseMemberExpr->getBase()->isImplicitCXXThis()) {
161 | if (const auto* fieldDecl = dyn_cast(baseMemberExpr->getMemberDecl())) {
162 | foundUniformStruct = shaderClass->isUniformField(fieldDecl, UniformField::Kind::Struct);
163 | }
164 | break;
165 | }
166 |
167 | base = baseMemberExpr->getBase()->IgnoreCasts();
168 | }
169 |
170 | if (!foundUniformStruct) {
171 | return true;
172 | }
173 |
174 | assert(!memberExpr->isArrow() && "Access to uniform parameter using arrow syntax (->) is not supported");
175 |
176 | // Replace the member access dot operator with an underscore
177 | replaceTextWithUndo("_", [memberExpr]() { return SourceRange(memberExpr->getOperatorLoc(), memberExpr->getOperatorLoc()); });
178 |
179 | return true;
180 | }
181 |
182 |
--------------------------------------------------------------------------------
/source/thusc/thusc.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {9988eb8d-eb65-4bab-aeca-845341448507}
25 | thusc
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | true
79 | $(SolutionDir)\build\bin\$(Platform)\$(Configuration)\
80 | $(SolutionDir)\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\
81 |
82 |
83 | false
84 | $(SolutionDir)\build\bin\$(Platform)\$(Configuration)\
85 | $(SolutionDir)\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\
86 |
87 |
88 | true
89 | $(SolutionDir)\build\bin\$(Platform)\$(Configuration)\
90 | $(SolutionDir)\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\
91 |
92 |
93 | false
94 | $(SolutionDir)\build\bin\$(Platform)\$(Configuration)\
95 | $(SolutionDir)\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\
96 |
97 |
98 |
99 | Level3
100 | true
101 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
102 | true
103 |
104 |
105 | Console
106 | true
107 |
108 |
109 |
110 |
111 | Level3
112 | true
113 | true
114 | true
115 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
116 | true
117 |
118 |
119 | Console
120 | true
121 | true
122 | true
123 |
124 |
125 |
126 |
127 | Level3
128 | true
129 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
130 | true
131 | true
132 |
133 |
134 | Console
135 | true
136 | %(AdditionalDependencies)
137 |
138 |
139 |
140 |
141 | Level3
142 | true
143 | true
144 | true
145 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
146 | true
147 | true
148 |
149 |
150 | Console
151 | true
152 | true
153 | true
154 | %(AdditionalDependencies)
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
--------------------------------------------------------------------------------
/source/thusc/thusc.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | // thusc.cpp
30 |
31 | #include "ThuscBackendUE4.h"
32 | #include "ThuscCommon.h"
33 | #include "ThuscFrontendAction.h"
34 |
35 | #include
36 | #include
37 |
38 | DISABLE_WARNINGS_LLVM
39 | #include "clang/Tooling/CommonOptionsParser.h"
40 | #include "clang/Tooling/CompilationDatabase.h"
41 | #include "clang/Tooling/Tooling.h"
42 |
43 | #include "llvm/Support/CommandLine.h"
44 | #include "llvm/Support/FileSystem.h"
45 | #include "llvm/Support/raw_ostream.h"
46 | #include "llvm/Support/ToolOutputFile.h"
47 | ENABLE_WARNINGS_LLVM
48 |
49 | using namespace clang::tooling;
50 | using namespace llvm;
51 |
52 | static cl::OptionCategory thuscOptionsCategory("thusc options");
53 |
54 | static cl::opt hostOutputFilename("o", cl::desc("Output filename for Host code"), cl::value_desc("filename"),
55 | cl::cat(thuscOptionsCategory), cl::Required);
56 |
57 | static cl::opt gpuOutputDirectory("gpuOutDir", cl::desc("Output directory for GPU code"), cl::value_desc("directory"),
58 | cl::cat(thuscOptionsCategory), cl::Required);
59 |
60 | static cl::opt gpuOutputDirectoryVirtual("gpuOutDirVirtual", cl::desc("Corresponding virtual path for directory specified in gpuOutDir (UE4 backend only)"), cl::value_desc("directory"),
61 | cl::cat(thuscOptionsCategory), cl::Required);
62 |
63 | static cl::opt disableNameManglingOpt("disableNameMangling", cl::desc("Disables name mangling of GPU functions"), cl::cat(thuscOptionsCategory));
64 | bool thusc::disableNameMangling = false;
65 |
66 | static cl::opt outputAllGPUFuncsOpt("outputAllGPUFuncs", cl::desc("Output all GPU functions to the HLSL file, whether or not they are used"), cl::cat(thuscOptionsCategory));
67 | bool thusc::outputAllGPUFuncs = false;
68 |
69 | static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
70 |
71 | #define ADD_ANNOTATION_OPTION(macroName, spelling, extraArgs) \
72 | "--extra-arg=-D" macroName "=clang::annotate(\"" spelling "\"" extraArgs ")"
73 |
74 | void addExtraClangArgs(std::vector* args) {
75 | // TODO These extra arguments probably be specified alongside the files to compile and parsed in,
76 | // rather than be hardcoded here.
77 | static const char* extraArgs[] = {
78 | "--extra-arg=-DUNREAL_CODE_ANALYZER=1",
79 | "--extra-arg=-Wno-nonportable-include-path",
80 | "--extra-arg=-Wno-inconsistent-missing-override",
81 | "--extra-arg=-Wno-microsoft-unqualified-friend",
82 | "--extra-arg=-Wno-gnu-string-literal-operator-template",
83 | "--extra-arg=-Wno-ignored-attributes",
84 | "--extra-arg=-Wno-switch",
85 | "--extra-arg=-Wno-tautological-undefined-compare",
86 | "--extra-arg=-Wno-invalid-offsetof",
87 |
88 | // TODO This path is hardcoded. Figure out how to get this path in a more portable way.
89 | "--extra-arg=-include" THUSC_H_PATH,
90 |
91 | // Thusc-specific #defines
92 | ADD_ANNOTATION_OPTION("ThuscShader", THUSC_SHADER_SPELLING, ""),
93 |
94 | // Uniforms
95 | ADD_ANNOTATION_OPTION("uniform", THUSC_UNIFORM_SPELLING, ""),
96 |
97 | // Permutations / Specializations
98 | ADD_ANNOTATION_OPTION("permutation_enum", THUSC_PERMUTATION_ENUM_SPELLING, ""),
99 | ADD_ANNOTATION_OPTION("permutation_bool", THUSC_PERMUTATION_BOOL_SPELLING, ""),
100 | ADD_ANNOTATION_OPTION("permutation_int(x)", THUSC_PERMUTATION_INT_SPELLING, " #x"),
101 | ADD_ANNOTATION_OPTION("permutation_sparseInt(...)", THUSC_PERMUTATION_SPARSE_INT_SPELLING, " #__VA_ARGS__"),
102 | ADD_ANNOTATION_OPTION("permutation_ShaderClass", THUSC_PERMUTATION_SHADERCLASS_SPELLING, ""),
103 |
104 | ADD_ANNOTATION_OPTION("specialization_Enum", THUSC_PERMUTATION_ENUM_SPELLING, ""),
105 | ADD_ANNOTATION_OPTION("specialization_Bool", THUSC_PERMUTATION_BOOL_SPELLING, ""),
106 | ADD_ANNOTATION_OPTION("specialization_Int(x)", THUSC_PERMUTATION_INT_SPELLING, " #x"),
107 | ADD_ANNOTATION_OPTION("specialization_SparseInt(...)", THUSC_PERMUTATION_SPARSE_INT_SPELLING, " #__VA_ARGS__"),
108 | ADD_ANNOTATION_OPTION("specialization_ShaderClass", THUSC_PERMUTATION_SHADERCLASS_SPELLING, ""),
109 |
110 | // Function parameters
111 | ADD_ANNOTATION_OPTION("SV_DispatchThreadID", THUSC_SV_DISPATCH_THREAD_ID_SPELLING, ""),
112 | ADD_ANNOTATION_OPTION("SV_GroupThreadID", THUSC_SV_GROUP_THREAD_ID_SPELLING, ""),
113 | ADD_ANNOTATION_OPTION("SV_GroupID", THUSC_SV_GROUP_ID_SPELLING, ""),
114 | ADD_ANNOTATION_OPTION("SV_GroupIndex", THUSC_SV_GROUP_INDEX_SPELLING, ""),
115 | ADD_ANNOTATION_OPTION("inout", THUSC_HLSL_INOUT_SPELLING, ""),
116 |
117 | // Shader entry functions
118 | ADD_ANNOTATION_OPTION("entry_ComputeShader(x, y, z)", THUSC_ENTRY_COMPUTE_SPELLING, " #x \",\" #y \",\" #z"),
119 | ADD_ANNOTATION_OPTION("entry_PixelShader", THUSC_ENTRY_PIXEL_SPELLING, ""),
120 |
121 | // GPU functions
122 | ADD_ANNOTATION_OPTION("gpu", THUSC_GPU_FN_SPELLING, ""),
123 | ADD_ANNOTATION_OPTION("PrecodeHLSL", THUSC_HLSL_PRECODE_SPELLING, ""),
124 | ADD_ANNOTATION_OPTION("PostcodeHLSL", THUSC_HLSL_POSTCODE_SPELLING, ""),
125 |
126 | // Backend-specific #defines
127 | // TODO move these to a backend-specific file
128 | "--extra-arg=-DTHUSC_SHADER(TY, SUPERTYPE)="
129 | "void ThuscShaderStubFunc() {};"
130 | "void AddComputePass(FRDGBuilder& GraphBuilder, FRDGEventName&& PassName, const FGlobalShaderMap* ShaderMap, FIntVector GroupCount) { }"
131 | THUSC_TYPE_ADAPTERS
132 | };
133 |
134 | args->insert(args->end(), std::begin(extraArgs), std::end(extraArgs));
135 | }
136 |
137 | // Returns false if the arguments did not produce a valid source path and corresponding compile command
138 | // Returns true otherwise
139 | bool validateArguments(CommonOptionsParser& optionsParser) {
140 | if (optionsParser.getSourcePathList().size() == 0) {
141 | // If no input soruce file is found, report an error
142 | llvm::errs() << "Error: No source file found for the specified arguments.\n";
143 | return false;
144 | }
145 | else if (optionsParser.getSourcePathList().size() != 1) {
146 | // thusc should be run on one input file at a time, to produce one source-to-source translation of that file.
147 | // The translation will be written to the output file specified by -o (or stdout by default).
148 | // If multiple source paths are found, report an error.
149 | llvm::errs() << "Error: Multiple source files found for the specified arguments.\n";
150 | return false;
151 | }
152 |
153 | const std::string sourcePath = optionsParser.getSourcePathList()[0];
154 | const std::vector commands = optionsParser.getCompilations().getCompileCommands(sourcePath);
155 |
156 | if (commands.size() == 0) {
157 | // If there are no valid compile commands for the input file, report an error.
158 | llvm::errs() << "Error: No compile command found for input file <" << sourcePath << ">.\n";
159 | return false;
160 | }
161 | else if (commands.size() != 1) {
162 | // Since thusc produces one source-to-source translation per input file, it cannot handle the case where
163 | // there are mutliple entries found for that file in the compilation database. So report an error.
164 | // (This may change later.)
165 | llvm::errs() << "Error: Multiple compile commands found for input file <" << sourcePath << ">. "
166 | "(The compilation database may contain multiple entries for this file, which is currently unsupported.)\n";
167 | return false;
168 | }
169 | else {
170 | CompileCommand cc = commands[0];
171 |
172 | if (cc.Heuristic != std::string("")) {
173 | // The heuristic used to determine compile commands when an exact match isn't found in the compilation database
174 | // does not seem to do a great job. For now, report an error if a heuristic was used to find the compile command.
175 | llvm::errs() << "Error: The compile command was determined by a heuristic, "
176 | "which might mean that the exact input file could not be found in the compilation database. "
177 | "The reported heuristic is: " << cc.Heuristic << "\n";
178 | return false;
179 | }
180 | }
181 |
182 | // If all of the checks have passed, then the arguments have produced a valid source path and compile command
183 | return true;
184 | }
185 |
186 | int main(int argc, const char** argv) {
187 | std::vector clangArgs(argv, argv + argc);
188 | addExtraClangArgs(&clangArgs);
189 |
190 | int clangArgsCount = (int)clangArgs.size();
191 | CommonOptionsParser optionsParser(clangArgsCount, clangArgs.data(), thuscOptionsCategory, cl::NumOccurrencesFlag::Required);
192 |
193 | if (!validateArguments(optionsParser)) {
194 | return EXIT_FAILURE;
195 | }
196 |
197 | if (clangArgsCount != clangArgs.size()) {
198 | // TODO I'm not sure of the implications if the argument count is changed, so report an error for now.
199 | llvm::errs() << "Error: CommonOptionsParser changed the argument count.\n";
200 | return EXIT_FAILURE;
201 | }
202 |
203 | std::error_code ec;
204 | llvm::ToolOutputFile hostOutputFile(hostOutputFilename, ec, llvm::sys::fs::OpenFlags::OF_None);
205 | if (ec) {
206 | llvm::errs() << "Error: Could not open output file '" << hostOutputFilename << "': " << ec.message() << "\n";
207 | return EXIT_FAILURE;
208 | }
209 |
210 | bool isDirectory = false;
211 | ec = llvm::sys::fs::is_directory(gpuOutputDirectory, isDirectory);
212 | if (ec) {
213 | llvm::errs() << "Error: Could not access GPU output directory '" << gpuOutputDirectory << "': " << ec.message() << "\n";
214 | return EXIT_FAILURE;
215 | }
216 | else if (!isDirectory) {
217 | llvm::errs() << "Error: Specified GPU output directory '" << gpuOutputDirectory << "' is not a directory\n";
218 | return EXIT_FAILURE;
219 | }
220 |
221 |
222 | // TODO Other backends?
223 | ThuscFrontendActionFactory factory(hostOutputFile.os(), gpuOutputDirectory, gpuOutputDirectoryVirtual);
224 | thusc::disableNameMangling = disableNameManglingOpt;
225 | thusc::outputAllGPUFuncs = outputAllGPUFuncsOpt;
226 |
227 | ClangTool tool(optionsParser.getCompilations(), optionsParser.getSourcePathList());
228 | int toolExitCode = tool.run(&factory);
229 |
230 | if (toolExitCode) {
231 | return toolExitCode;
232 | }
233 |
234 | hostOutputFile.keep();
235 |
236 | return toolExitCode;
237 | }
238 |
239 |
--------------------------------------------------------------------------------
/source/thusc/ThuscShaderIR.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #pragma once
30 |
31 | #include "ThuscCommon.h"
32 |
33 | #include
34 |
35 | DISABLE_WARNINGS_LLVM
36 | #include "clang/AST/Decl.h"
37 | #include "clang/AST/DeclCXX.h"
38 | #include "llvm/Support/Casting.h"
39 | ENABLE_WARNINGS_LLVM
40 |
41 | namespace thusc {
42 |
43 | // TODO Fix this hack. It's a quick-and-dirty way to get the corresponding command line option to this file
44 | extern bool disableNameMangling;
45 |
46 | // Constants
47 | extern const char* shaderImplClassPrefix;
48 |
49 | // Forward declaration
50 | class ImplClass;
51 | struct ShaderClass;
52 | struct ShaderIR;
53 |
54 |
55 | inline
56 | std::string generateMangledName(const clang::NamedDecl* decl) {
57 | std::string ret = decl->getName().str();
58 |
59 | if (disableNameMangling)
60 | return ret;
61 |
62 | const clang::DeclContext* context = decl->getDeclContext();
63 |
64 | while (const auto* namedDecl = llvm::dyn_cast(context)) {
65 | ret = (namedDecl->getName() + "_" + ret).str();
66 | context = namedDecl->getDeclContext();
67 | }
68 |
69 | ret = "thusc_" + ret;
70 |
71 | return ret;
72 | }
73 |
74 | struct UniformField {
75 | enum class Kind {
76 | Sampler,
77 | Texture,
78 | TextureSRV,
79 | TextureUAV,
80 | Primitive,
81 | Array,
82 | Struct,
83 | GlobalUniformBuffer,
84 | Unknown,
85 | };
86 |
87 | UniformField(const clang::FieldDecl* decl, llvm::StringRef name, llvm::StringRef type, Kind kind)
88 | : fieldDecl(decl)
89 | , name(name)
90 | , type(type)
91 | , kind(kind)
92 | {
93 | assert(kind != Kind::Unknown && "Creating a UniformField with Unknown kind");
94 | }
95 |
96 | Kind getKind() const { return kind; }
97 |
98 | const clang::FieldDecl* fieldDecl;
99 | const std::string name;
100 | const std::string type;
101 |
102 | private:
103 | Kind kind;
104 | };
105 |
106 | class PermutationShaderClass {
107 | public:
108 | PermutationShaderClass() = delete;
109 |
110 | PermutationShaderClass(const clang::FieldDecl* fieldDecl, llvm::StringRef name,
111 | const ShaderClass* shaderClassType, const ShaderIR* shaderIR);
112 |
113 | const llvm::StringRef getFieldName() const { return name; }
114 |
115 | const clang::FieldDecl* getFieldDecl() const { return fieldDecl; }
116 |
117 | const ShaderClass* getShaderClassType() const { return shaderClassType; }
118 |
119 | const std::vector& getValdShaderClasses() const { return validShaderClasses; }
120 |
121 | private:
122 | const clang::FieldDecl* const fieldDecl;
123 | const std::string name;
124 | const ShaderClass* shaderClassType;
125 | std::vector validShaderClasses;
126 | };
127 |
128 | struct PermutationField {
129 | enum class Kind {
130 | Enum,
131 | Bool,
132 | Int,
133 | SparseInt,
134 | Unknown,
135 | };
136 |
137 | PermutationField() = delete;
138 |
139 | PermutationField(const clang::FieldDecl* decl, llvm::StringRef name, llvm::StringRef type,
140 | llvm::ArrayRef valueOptions, Kind kind)
141 | : fieldDecl(decl)
142 | , name(name)
143 | , type(type)
144 | , valueOptions(valueOptions)
145 | , kind(kind)
146 | {
147 | assert(kind != Kind::Unknown && "Creating a PermutationField with Unknown kind");
148 | }
149 |
150 | Kind getKind() const { return kind; }
151 |
152 | const clang::FieldDecl* const fieldDecl = nullptr;
153 | const std::string name;
154 | const std::string type;
155 | const std::vector valueOptions;
156 | const Kind kind;
157 | };
158 |
159 | enum class ShaderParameterSemanticKind {
160 | // Compute shader semantics
161 | SV_DispatchThreadID,
162 | SV_GroupThreadID,
163 | SV_GroupID,
164 | SV_GroupIndex,
165 |
166 | None,
167 | Unknown,
168 | };
169 |
170 |
171 | class GPUFunctionBase {
172 | public:
173 | struct Parameter {
174 | Parameter(llvm::StringRef name, llvm::StringRef type, ShaderParameterSemanticKind kind, bool isInout)
175 | : name(name)
176 | , type(type)
177 | , semantic(kind)
178 | , isInout(isInout)
179 | {
180 | assert(kind != ShaderParameterSemanticKind::Unknown && "Creating a GPU function parameter with Unknown kind");
181 | }
182 |
183 | const std::string name;
184 | const std::string type;
185 | const ShaderParameterSemanticKind semantic;
186 | const bool isInout;
187 | };
188 |
189 | const clang::FunctionDecl* getFunctionDecl() const {
190 | return funcDecl;
191 | }
192 |
193 | llvm::StringRef getSourceName() const {
194 | return sourceName;
195 | }
196 |
197 | llvm::StringRef getMangledName() const {
198 | return mangledName;
199 | }
200 |
201 | llvm::StringRef getReturnType() const {
202 | return returnType;
203 | }
204 |
205 | const std::vector& getParameters() const {
206 | return parameters;
207 | }
208 |
209 | protected:
210 | GPUFunctionBase(const clang::FunctionDecl* funcDecl, const llvm::StringRef name, const llvm::StringRef returnType)
211 | : funcDecl(funcDecl)
212 | , sourceName(name)
213 | , mangledName(generateMangledName(funcDecl))
214 | , returnType(returnType)
215 | {}
216 |
217 | void addParameter(llvm::StringRef name, llvm::StringRef type, ShaderParameterSemanticKind semantic, bool isInout = false) {
218 | parameters.push_back(Parameter(name.str(), type.str(), semantic, isInout));
219 | }
220 |
221 | private:
222 | const clang::FunctionDecl* const funcDecl;
223 | const std::string sourceName;
224 | const std::string mangledName;
225 | const std::string returnType;
226 | std::vector parameters;
227 | };
228 |
229 |
230 | class GPUFunction : public GPUFunctionBase {
231 | public:
232 | GPUFunction(const clang::FunctionDecl* funcDecl, const llvm::StringRef name, const llvm::StringRef returnType,
233 | bool hostCallable)
234 | : GPUFunctionBase(funcDecl, name, returnType)
235 | , hostCallable(hostCallable)
236 | {}
237 |
238 | void addParameter(llvm::StringRef name, llvm::StringRef type, bool isInout) {
239 | GPUFunctionBase::addParameter(name, type, ShaderParameterSemanticKind::None, isInout);
240 | }
241 |
242 | bool isHostCallable() const { return hostCallable; }
243 |
244 | private:
245 | const bool hostCallable;
246 | };
247 |
248 |
249 | class EntryPoint : public GPUFunctionBase {
250 | public:
251 | enum class EntryPointKind {
252 | Compute,
253 | Unknown,
254 | };
255 |
256 | void addParameter(llvm::StringRef name, llvm::StringRef type, ShaderParameterSemanticKind semantic) {
257 | GPUFunctionBase::addParameter(name, type, semantic);
258 | }
259 |
260 | EntryPointKind getKind() const { return kind; }
261 |
262 | protected:
263 | EntryPoint(const clang::CXXMethodDecl* const methodDecl, const llvm::StringRef name,
264 | const llvm::StringRef returnType, const EntryPointKind kind)
265 | : GPUFunctionBase(methodDecl, name, returnType)
266 | , kind(kind)
267 | {
268 | assert(kind != EntryPointKind::Unknown && "Creating an EntryPoint with Unknown kind");
269 | }
270 |
271 | private:
272 | const EntryPointKind kind;
273 | };
274 |
275 | class ComputeEntryPoint : public EntryPoint {
276 | public:
277 | ComputeEntryPoint(const clang::CXXMethodDecl* const methodDecl,
278 | const llvm::StringRef name, llvm::ArrayRef threadgroupSize)
279 | : EntryPoint(methodDecl, name, "void", EntryPoint::EntryPointKind::Compute)
280 | , threadgroupSize{threadgroupSize[0].str(), threadgroupSize[1].str(), threadgroupSize[2].str()}
281 | {
282 | assert(threadgroupSize.size() == 3 && "threadgroupSize must contain exactly 3 elements");
283 | }
284 |
285 | static bool classof(const EntryPoint* entryPoint) {
286 | return entryPoint->getKind() == EntryPointKind::Compute;
287 | }
288 |
289 | const std::string threadgroupSize[3];
290 | };
291 |
292 | class OtherGPUDecl {
293 | public:
294 | OtherGPUDecl(const clang::Decl* decl, bool isHost, bool hasOutputOverride = false, const std::string outputOverride = "")
295 | : decl(decl)
296 | , isHostBool(isHost)
297 | , hasOutputOverrideBool(hasOutputOverride)
298 | , outputOverride(outputOverride)
299 | {}
300 |
301 | const clang::Decl* getDecl() const { return decl; }
302 | bool isHost() const { return isHostBool; }
303 | bool hasOutputOverride() const { return hasOutputOverrideBool; }
304 | llvm::StringRef getOutputOverride() const { return outputOverride; }
305 |
306 | private:
307 | const clang::Decl* decl;
308 | const bool isHostBool;
309 | const bool hasOutputOverrideBool;
310 | const std::string outputOverride;
311 | };
312 |
313 | class PermutationShaderClassSelection {
314 | public:
315 | PermutationShaderClassSelection(llvm::StringRef fieldName, const ShaderClass* shaderClass,
316 | unsigned int typeIDRelative, const ImplClass* implClass)
317 | : fieldName(fieldName)
318 | , shaderClass(shaderClass)
319 | , typeIDRelative(typeIDRelative)
320 | , implClass(implClass)
321 | {}
322 |
323 | const std::string fieldName;
324 | const ShaderClass* const shaderClass;
325 | const unsigned int typeIDRelative;
326 | const ImplClass* const implClass;
327 | };
328 |
329 | class ImplClass {
330 | // The code relies on stable pointers to ImplClass instances in various places,
331 | // so ImplClass objects can only be created as unique_ptrs.
332 | public:
333 | static std::unique_ptr create(const ShaderClass* parent, unsigned int id, std::vector& selections) {
334 | return std::unique_ptr(new ImplClass(parent, id, selections));
335 | }
336 |
337 | ImplClass(const ImplClass&) = delete;
338 |
339 | llvm::StringRef getName() const { return name; }
340 | unsigned int getID() const { return id; }
341 |
342 | const std::vector& getSelections() const { return selections; }
343 |
344 | private:
345 | ImplClass(const ShaderClass* parent, unsigned int id, const std::vector& selections)
346 | : parent(parent)
347 | , name(generateImplClassName(parent, selections))
348 | , id(id)
349 | , selections(selections)
350 | {}
351 |
352 | static std::string generateImplClassName(const ShaderClass* parent, const std::vector& selections);
353 |
354 | const ShaderClass* const parent;
355 | const std::string name;
356 | const unsigned int id;
357 | const std::vector selections;
358 | };
359 |
360 | struct ShaderClass {
361 | // The code relies on stable pointers to ShaderClass instances in various places,
362 | // so ShaderClass objects can only be created as unique_ptrs.
363 | public:
364 | ShaderClass(const ShaderClass&) = delete;
365 |
366 | static std::unique_ptr create() {
367 | return std::unique_ptr(new ShaderClass);
368 | }
369 |
370 | void addGPUMethod(std::unique_ptr gpuFunc);
371 |
372 | const std::vector>& getGPUMethods() const { return gpuMethods; }
373 |
374 | void setBaseShaderClass(const ShaderClass* base) {
375 | if (base == nullptr)
376 | return;
377 |
378 | baseShaderClass = base;
379 |
380 | const ShaderClass* nextBase = base;
381 | while (nextBase) {
382 | typeIDMap.insert(std::make_pair(nextBase, nextBase->getNextTypeID()));
383 | nextBase = nextBase->baseShaderClass;
384 | }
385 |
386 | // TODO This way of handling base ShaderClasses (i.e., manually pulling in its elements)
387 | // runs into issues if a subclass shadows a base class declaration or if the subclass
388 | // (or its user) needs to call a base class version of a virtual function that has been
389 | // overridden in the derived class.
390 |
391 | for (const auto& e : base->uniformFields) { uniformFields.push_back(e); }
392 | for (const auto& e : base->permutationShaderClasses) { permutationShaderClasses.push_back(e); }
393 | for (const auto& e : base->permutationFields) { permutationFields.push_back(e); }
394 | for (const auto& e : base->otherGPUDecls) { otherGPUDecls.push_back(e); }
395 | for (const auto& e : base->gpuMethods) { gpuMethods.push_back(std::make_unique(*e)); }
396 |
397 | // TODO Handle virtual functions appropriately
398 |
399 | // TODO Maybe pull in from base:
400 | // - entryPoints
401 | // - hlslPrecode / hlslPostcode
402 | }
403 |
404 | llvm::StringRef getName() const { return name; }
405 |
406 | const clang::CXXRecordDecl* classDecl = nullptr;
407 |
408 | std::string name;
409 | const ShaderClass* baseShaderClass = nullptr;
410 | bool hasShouldCompilePermutation = false;
411 |
412 | std::vector uniformFields;
413 | std::vector permutationShaderClasses;
414 | std::vector permutationFields;
415 | std::vector otherGPUDecls;
416 | std::vector> entryPoints;
417 |
418 | std::string hlslPrecode;
419 | std::string hlslPostcode;
420 |
421 | bool isIntPermutationField(llvm::StringRef fieldName) const {
422 | for (const auto& p : permutationFields) {
423 | if (fieldName == p.name && p.fieldDecl->getType()->isIntegralType(p.fieldDecl->getASTContext()))
424 | return true;
425 | }
426 |
427 | return false;
428 | }
429 |
430 | bool isUniformField(const clang::FieldDecl* fieldDecl, UniformField::Kind kind = UniformField::Kind::Unknown) const {
431 | for (const auto& uniform : uniformFields) {
432 | if (fieldDecl == uniform.fieldDecl && (kind == uniform.getKind() || kind == UniformField::Kind::Unknown)) {
433 | return true;
434 | }
435 | }
436 |
437 | return false;
438 | }
439 |
440 | bool isPermutationField(const clang::Decl* decl) const {
441 | for (const auto& permField : permutationFields) {
442 | if (permField.fieldDecl == decl)
443 | return true;
444 | }
445 |
446 | return false;
447 | }
448 |
449 | bool isPermutationShaderClassField(const clang::Decl* decl) const {
450 | for (const auto& permShaderClass : permutationShaderClasses) {
451 | if (permShaderClass.getFieldDecl() == decl) {
452 | return true;
453 | }
454 |
455 | if (permShaderClass.getShaderClassType()->isPermutationShaderClassField(decl)) {
456 | return true;
457 | }
458 | }
459 |
460 | return false;
461 | }
462 |
463 | bool isOtherGPUDecl(const clang::Decl* decl) const {
464 | for (const auto& gpuDecl : otherGPUDecls) {
465 | if (gpuDecl.getDecl() == decl)
466 | return true;
467 | }
468 |
469 | return false;
470 | }
471 |
472 | unsigned int getTypeIDRelativeTo(const ShaderClass* base) const {
473 | const auto mapEntry = typeIDMap.find(base);
474 | assert(mapEntry != typeIDMap.end() && "Cannot get TypeID relative to a non-base class");
475 |
476 | return mapEntry->second;
477 | }
478 |
479 | void generateImplClasses() {
480 | std::vector curSelections;
481 | generateImplClassesRecur(curSelections, 0);
482 | }
483 |
484 | const std::vector>& getImplClasses() const { return implClasses; }
485 |
486 | private:
487 | ShaderClass() {
488 | typeIDMap.insert(std::make_pair(this, getNextTypeID()));
489 | }
490 |
491 | unsigned int getNextTypeID() const { return nextTypeID++; }
492 |
493 | void generateImplClassesRecur(std::vector& curSelections, unsigned int fieldPos) {
494 | if (fieldPos >= permutationShaderClasses.size()) {
495 | implClasses.push_back(ImplClass::create(this, (unsigned int)implClasses.size(), curSelections));
496 | return;
497 | }
498 |
499 | const PermutationShaderClass& field = permutationShaderClasses[fieldPos];
500 |
501 | for (const auto* fieldShaderClass : field.getValdShaderClasses()) {
502 | for (const auto& fieldImplClass : fieldShaderClass->getImplClasses()) {
503 | curSelections.push_back(PermutationShaderClassSelection(field.getFieldName(), fieldShaderClass,
504 | fieldShaderClass->getTypeIDRelativeTo(field.getShaderClassType()), fieldImplClass.get()));
505 | generateImplClassesRecur(curSelections, fieldPos + 1);
506 | curSelections.pop_back();
507 | }
508 | }
509 | }
510 |
511 | std::vector> gpuMethods;
512 |
513 | mutable unsigned int nextTypeID = 0;
514 | std::vector> implClasses;
515 | llvm::DenseMap typeIDMap;
516 | };
517 |
518 | struct ShaderIR {
519 | std::vector otherGPUDecls;
520 | std::vector> gpuFunctions;
521 |
522 | inline
523 | void addShaderClass(std::unique_ptr shaderClass) {
524 | clangClassToShaderClass.insert(std::make_pair(shaderClass->classDecl, shaderClass.get()));
525 | shaderClass->generateImplClasses();
526 | shaderClasses.push_back(std::move(shaderClass));
527 | }
528 |
529 | inline
530 | const std::vector>& getShaderClasses() const {
531 | return shaderClasses;
532 | }
533 |
534 | inline
535 | const ShaderClass* getShaderClass(const clang::CXXRecordDecl* classDecl) const {
536 | if (classDecl == nullptr) return nullptr;
537 |
538 | const auto mapEntry = clangClassToShaderClass.find(classDecl);
539 | return (mapEntry == clangClassToShaderClass.end()) ? nullptr : mapEntry->second;
540 | }
541 |
542 | private:
543 | std::vector> shaderClasses;
544 | llvm::DenseMap clangClassToShaderClass;
545 | };
546 |
547 | }
548 |
--------------------------------------------------------------------------------
/source/thusc/ThuscBackendHLSL.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, The Regents of the University of California,
2 | // Davis campus. All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions
6 | // are met:
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither any name of The Regents of the University of California nor
13 | // the names of its contributors may be used to endorse or promote
14 | // products derived from this software without specific prior written
15 | // permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #include "ThuscBackendHLSL.h"
30 |
31 | #include "ClangHelperFunctions.h"
32 | #include "TypeHelpers.h"
33 |
34 | DISABLE_WARNINGS_LLVM
35 | #include "clang/AST/ASTContext.h"
36 | #include "clang/Basic/FileManager.h"
37 | #include "clang/Basic/SourceManager.h"
38 |
39 | #include "llvm/Support/FileSystem.h"
40 | #include "llvm/Support/ToolOutputFile.h"
41 | ENABLE_WARNINGS_LLVM
42 |
43 | #include