summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-target.cpp
diff options
context:
space:
mode:
authorTheresa Foley <10618364+tangent-vector@users.noreply.github.com>2025-07-24 12:59:58 -0700
committerGitHub <noreply@github.com>2025-07-24 19:59:58 +0000
commit8ccd495d5eaa82cb831378c28dd190e657b6c999 (patch)
treec39dc364d95f78984fd4ba2776d259ff944d2596 /source/slang/slang-target.cpp
parent2d23a962766a97cbb11bcee5483a66aec923da49 (diff)
Organize code better by splitting some big files (#7890)
* Organize code better by splitting some big files The basic change here is that the majority of the declarations in `slang-compiler.h` have been split out into a set of smaller and more focused files. As a result, the implement of those declarations have been moved from `slang-compiler.cpp` and `slang.cpp` over to those new files when the proper home for code is obvious. I have tried as much as possible to *not* make any edits to the code along the way, and just copy-paste declarations from one place to another as-is. The exceptions I am aware of are: * In some cases a function that used to be file-scope `static` was used by code that landed in two or more different `.cpp` files. In these cases, I changed the function to be non-`static` (removing the `_` prefix from its name, if it had one, per our naming conventions), and put a declaration for the function into the most appropriate header I could identify. * I added a few comments in places where I saw ugly or unfortunate things in the code I was moving, and wanted to tag them with `TODO`s so we can hopefully get to them in the fullness of time. * I added top-level comments to each of the new `.h` files that was introduced to try to explain the logic for what goes into that file. * In cases where one of the new header files mostly existed to declare a single type, I sometimes added more detail to the doc comment on that type, to better explain the type and its role in the compiler (this is text that otherwise might have gone into the comment at the top leve lof the file, but I figured that the doc comment would have higher discoverability). I expect that the most contentious choice here is that the `Session` class lands in `slang-global-session.h` while `slang-session.h` holds the `Linkage` class. The names used in this change are consistent with how the relevant concepts in the public Slang API are named, and are consistent with how we *intend* to rename the classes themselves in time. * format code * fixup --------- Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'source/slang/slang-target.cpp')
-rw-r--r--source/slang/slang-target.cpp248
1 files changed, 248 insertions, 0 deletions
diff --git a/source/slang/slang-target.cpp b/source/slang/slang-target.cpp
new file mode 100644
index 000000000..29430abde
--- /dev/null
+++ b/source/slang/slang-target.cpp
@@ -0,0 +1,248 @@
+// slang-target.cpp
+#include "slang-target.h"
+
+#include "../core/slang-type-text-util.h"
+#include "compiler-core/slang-artifact-desc-util.h"
+#include "slang-compiler.h"
+#include "slang-type-layout.h"
+
+namespace Slang
+{
+
+bool isHeterogeneousTarget(CodeGenTarget target)
+{
+ return ArtifactDescUtil::makeDescForCompileTarget(asExternal(target)).style ==
+ ArtifactStyle::Host;
+}
+
+void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val)
+{
+ UnownedStringSlice name = TypeTextUtil::getCompileTargetName(asExternal(val));
+ name = name.getLength() ? name : toSlice("<unknown>");
+ sb << name;
+}
+
+//
+// TargetRequest
+//
+
+TargetRequest::TargetRequest(Linkage* linkage, CodeGenTarget format)
+ : linkage(linkage)
+{
+ optionSet = linkage->m_optionSet;
+ optionSet.add(CompilerOptionName::Target, format);
+}
+
+TargetRequest::TargetRequest(const TargetRequest& other)
+ : RefObject(), linkage(other.linkage), optionSet(other.optionSet)
+{
+}
+
+
+Session* TargetRequest::getSession()
+{
+ return linkage->getSessionImpl();
+}
+
+HLSLToVulkanLayoutOptions* TargetRequest::getHLSLToVulkanLayoutOptions()
+{
+ if (!hlslToVulkanOptions)
+ {
+ hlslToVulkanOptions = new HLSLToVulkanLayoutOptions();
+ hlslToVulkanOptions->loadFromOptionSet(optionSet);
+ }
+ return hlslToVulkanOptions.get();
+}
+
+void TargetRequest::setTargetCaps(CapabilitySet capSet)
+{
+ cookedCapabilities = capSet;
+}
+
+CapabilitySet TargetRequest::getTargetCaps()
+{
+ if (!cookedCapabilities.isEmpty())
+ return cookedCapabilities;
+
+ // The full `CapabilitySet` for the target will be computed
+ // from the combination of the code generation format, and
+ // the profile.
+ //
+ // Note: the preofile might have been set in a way that is
+ // inconsistent with the output code format of SPIR-V, but
+ // a profile of Direct3D Shader Model 5.1. In those cases,
+ // the format should always override the implications in
+ // the profile.
+ //
+ // TODO: This logic isn't currently taking int account
+ // the information in the profile, because the current
+ // `CapabilityAtom`s that we support don't include any
+ // of the details there (e.g., the shader model versions).
+ //
+ // Eventually, we'd want to have a rich set of capability
+ // atoms, so that most of the information about what operations
+ // are available where can be directly encoded on the declarations.
+
+ List<CapabilityName> atoms;
+
+ // If the user specified a explicit profile, we should pull
+ // a corresponding atom representing the target version from the profile.
+ CapabilitySet profileCaps = optionSet.getProfile().getCapabilityName();
+
+ bool isGLSLTarget = false;
+ switch (getTarget())
+ {
+ case CodeGenTarget::GLSL:
+ isGLSLTarget = true;
+ atoms.add(CapabilityName::glsl);
+ break;
+ case CodeGenTarget::SPIRV:
+ case CodeGenTarget::SPIRVAssembly:
+ if (getOptionSet().shouldEmitSPIRVDirectly())
+ {
+ // Default to SPIRV 1.5 if the user has not specified a target version.
+ bool hasTargetVersionAtom = false;
+ if (!profileCaps.isEmpty())
+ {
+ profileCaps.join(CapabilitySet(CapabilityName::spirv_1_0));
+ for (auto profileCapAtomSet : profileCaps.getAtomSets())
+ {
+ for (auto atom : profileCapAtomSet)
+ {
+ if (isTargetVersionAtom(asAtom(atom)))
+ {
+ atoms.add((CapabilityName)atom);
+ hasTargetVersionAtom = true;
+ }
+ }
+ }
+ }
+ if (!hasTargetVersionAtom)
+ {
+ atoms.add(CapabilityName::spirv_1_5);
+ }
+ // If the user specified any SPIR-V extensions in the profile,
+ // pull them in.
+ for (auto profileCapAtomSet : profileCaps.getAtomSets())
+ {
+ for (auto atom : profileCapAtomSet)
+ {
+ if (isSpirvExtensionAtom(asAtom(atom)))
+ {
+ atoms.add((CapabilityName)atom);
+ hasTargetVersionAtom = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ isGLSLTarget = true;
+ atoms.add(CapabilityName::glsl);
+ profileCaps.addSpirvVersionFromOtherAsGlslSpirvVersion(profileCaps);
+ }
+ break;
+
+ case CodeGenTarget::HLSL:
+ case CodeGenTarget::DXBytecode:
+ case CodeGenTarget::DXBytecodeAssembly:
+ case CodeGenTarget::DXIL:
+ case CodeGenTarget::DXILAssembly:
+ atoms.add(CapabilityName::hlsl);
+ break;
+
+ case CodeGenTarget::CSource:
+ atoms.add(CapabilityName::c);
+ break;
+
+ case CodeGenTarget::CPPSource:
+ case CodeGenTarget::PyTorchCppBinding:
+ case CodeGenTarget::HostExecutable:
+ case CodeGenTarget::ShaderSharedLibrary:
+ case CodeGenTarget::HostSharedLibrary:
+ case CodeGenTarget::HostHostCallable:
+ case CodeGenTarget::ShaderHostCallable:
+ atoms.add(CapabilityName::cpp);
+ break;
+
+ case CodeGenTarget::CUDASource:
+ case CodeGenTarget::PTX:
+ atoms.add(CapabilityName::cuda);
+ break;
+
+ case CodeGenTarget::Metal:
+ case CodeGenTarget::MetalLib:
+ case CodeGenTarget::MetalLibAssembly:
+ atoms.add(CapabilityName::metal);
+ break;
+
+ case CodeGenTarget::WGSLSPIRV:
+ case CodeGenTarget::WGSLSPIRVAssembly:
+ case CodeGenTarget::WGSL:
+ atoms.add(CapabilityName::wgsl);
+ break;
+
+ default:
+ break;
+ }
+
+ CapabilitySet targetCap = CapabilitySet(atoms);
+
+ if (profileCaps.atLeastOneSetImpliedInOther(targetCap) ==
+ CapabilitySet::ImpliesReturnFlags::Implied)
+ targetCap.join(profileCaps);
+
+ for (auto atomVal : optionSet.getArray(CompilerOptionName::Capability))
+ {
+ CapabilitySet toAdd;
+ switch (atomVal.kind)
+ {
+ case CompilerOptionValueKind::Int:
+ toAdd = CapabilitySet(CapabilityName(atomVal.intValue));
+ break;
+ case CompilerOptionValueKind::String:
+ toAdd = CapabilitySet(findCapabilityName(atomVal.stringValue.getUnownedSlice()));
+ break;
+ }
+
+ if (isGLSLTarget)
+ targetCap.addSpirvVersionFromOtherAsGlslSpirvVersion(toAdd);
+
+ if (!targetCap.isIncompatibleWith(toAdd))
+ targetCap.join(toAdd);
+ }
+
+ cookedCapabilities = targetCap;
+
+ SLANG_ASSERT(!cookedCapabilities.isInvalid());
+
+ return cookedCapabilities;
+}
+
+
+TypeLayout* TargetRequest::getTypeLayout(Type* type, slang::LayoutRules rules)
+{
+ SLANG_AST_BUILDER_RAII(getLinkage()->getASTBuilder());
+
+ // TODO: We are not passing in a `ProgramLayout` here, although one
+ // is nominally required to establish the global ordering of
+ // generic type parameters, which might be referenced from field types.
+ //
+ // The solution here is to make sure that the reflection data for
+ // uses of global generic/existential types does *not* include any
+ // kind of index in that global ordering, and just refers to the
+ // parameter instead (leaving the user to figure out how that
+ // maps to the ordering via some API on the program layout).
+ //
+ auto layoutContext = getInitialLayoutContextForTarget(this, nullptr, rules);
+
+ RefPtr<TypeLayout> result;
+ auto key = TypeLayoutKey{type, rules};
+ if (getTypeLayouts().tryGetValue(key, result))
+ return result.Ptr();
+ result = createTypeLayout(layoutContext, type);
+ getTypeLayouts()[key] = result;
+ return result.Ptr();
+}
+
+} // namespace Slang