Skip to content

Commit 7dcf2b4

Browse files
authored
Add SPIRV version macros to DXC (microsoft#6874)
With inline spir-v, it becomes important for users to know which version of SPIR-V is being targeted. They may need to generate different code depending on the version. This commit add these `__SPIRV_MAJOR_VERSION__` and `__SPIRV_MINOR_VERSION__` to the compiler.
1 parent 8a677d2 commit 7dcf2b4

File tree

7 files changed

+80
-3
lines changed

7 files changed

+80
-3
lines changed

docs/SPIR-V.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ interface variables:
397397
main([[vk::location(N)]] float4 input: A) : B
398398
{ ... }
399399
400-
Macro for SPIR-V
401-
----------------
400+
Macros for SPIR-V
401+
-----------------
402402

403403
If SPIR-V CodeGen is enabled and ``-spirv`` flag is used as one of the command
404404
line options (meaning that "generates SPIR-V code"), it defines an implicit
@@ -412,6 +412,12 @@ specific part of the HLSL code:
412412
#endif
413413
RWStructuredBuffer<S> mySBuffer;
414414
415+
When the ``-spirv`` flag is used, the ``-fspv-target-env`` option will
416+
implicitly define the macros ``__SPIRV_MAJOR_VERSION__`` and
417+
``__SPIRV_MINOR_VERSION__``, which will be integers representing the major and
418+
minor version of the SPIR-V being generated. This can be used to enable code that uses a feature
419+
only for environments where that feature is available.
420+
415421
SPIR-V version and extension
416422
----------------------------
417423

tools/clang/include/clang/Basic/LangOptions.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ class LangOptions : public LangOptionsBase {
171171
// HLSL Change Ends
172172

173173
bool SPIRV = false; // SPIRV Change
174-
174+
unsigned SpirvMajorVersion; // SPIRV Change
175+
unsigned SpirvMinorVersion; // SPIRV Change
176+
175177
bool isSignedOverflowDefined() const {
176178
return getSignedOverflowBehavior() == SOB_Defined;
177179
}

tools/clang/include/clang/SPIRV/FeatureManager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "dxc/Support/SPIRVOptions.h"
2121
#include "clang/Basic/Diagnostic.h"
2222
#include "clang/Basic/SourceLocation.h"
23+
#include "clang/Basic/VersionTuple.h"
2324
#include "llvm/ADT/Optional.h"
2425
#include "llvm/ADT/SmallBitVector.h"
2526
#include "llvm/ADT/StringRef.h"
@@ -138,6 +139,9 @@ class FeatureManager {
138139
static llvm::Optional<spv_target_env>
139140
stringToSpvEnvironment(const std::string &target_env);
140141

142+
// Returns the SPIR-V version used for the target environment.
143+
static clang::VersionTuple getSpirvVersion(spv_target_env env);
144+
141145
/// Returns the equivalent to spv_target_env in pretty, human readable form.
142146
/// (SPV_ENV_VULKAN_1_0 -> "Vulkan 1.0").
143147
/// Returns an empty Optional if the name cannot be matched.

tools/clang/lib/Frontend/InitPreprocessor.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,10 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
401401
#ifdef ENABLE_SPIRV_CODEGEN
402402
if (LangOpts.SPIRV) {
403403
Builder.defineMacro("__spirv__");
404+
Builder.defineMacro("__SPIRV_MAJOR_VERSION__",
405+
Twine(LangOpts.SpirvMajorVersion));
406+
Builder.defineMacro("__SPIRV_MINOR_VERSION__",
407+
Twine(LangOpts.SpirvMinorVersion));
404408
}
405409
#endif // ENABLE_SPIRV_CODEGEN
406410
// SPIRV Change Ends

tools/clang/lib/SPIRV/FeatureManager.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ constexpr std::array<std::pair<spv_target_env, const char *>, 6>
3535
{SPV_ENV_VULKAN_1_3, "Vulkan 1.3"},
3636
{SPV_ENV_UNIVERSAL_1_5, "SPIR-V 1.5"}}};
3737

38+
constexpr std::array<std::pair<spv_target_env, std::pair<uint32_t, uint32_t>>,
39+
6>
40+
kTargetEnvToSpirvVersion = {{{SPV_ENV_VULKAN_1_0, {1, 0}},
41+
{SPV_ENV_VULKAN_1_1, {1, 3}},
42+
{SPV_ENV_VULKAN_1_1_SPIRV_1_4, {1, 4}},
43+
{SPV_ENV_VULKAN_1_2, {1, 5}},
44+
{SPV_ENV_VULKAN_1_3, {1, 6}},
45+
{SPV_ENV_UNIVERSAL_1_5, {1, 5}}}};
46+
3847
static_assert(
3948
kKnownTargetEnv.size() == kHumanReadableTargetEnv.size(),
4049
"kKnownTargetEnv and kHumanReadableTargetEnv should remain in sync.");
@@ -52,6 +61,16 @@ FeatureManager::stringToSpvEnvironment(const std::string &target_env) {
5261
: llvm::Optional<spv_target_env>(it->second);
5362
}
5463

64+
clang::VersionTuple FeatureManager::getSpirvVersion(spv_target_env env) {
65+
auto it = std::find_if(kTargetEnvToSpirvVersion.cbegin(),
66+
kTargetEnvToSpirvVersion.cend(),
67+
[&](const auto &pair) { return pair.first == env; });
68+
69+
return it == kTargetEnvToSpirvVersion.end()
70+
? clang::VersionTuple()
71+
: clang::VersionTuple(it->second.first, it->second.second);
72+
}
73+
5574
llvm::Optional<std::string>
5675
FeatureManager::spvEnvironmentToPrettyName(spv_target_env target_env) {
5776
auto it = std::find_if(
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %dxc -T vs_6_5 -P -spirv -fspv-target-env=vulkan1.0 -Fi %t.vk_1_0.hlsl.pp %s
2+
// RUN: FileCheck --input-file=%t.vk_1_0.hlsl.pp %s --check-prefix=VK_1_0
3+
// VK_1_0: SPIR-V version 1 0
4+
5+
// RUN: %dxc -T vs_6_5 -P -spirv -fspv-target-env=vulkan1.1 -Fi %t.vk_1_1.hlsl.pp %s
6+
// RUN: FileCheck --input-file=%t.vk_1_1.hlsl.pp %s --check-prefix=VK_1_1
7+
// VK_1_1: SPIR-V version 1 3
8+
9+
// RUN: %dxc -T vs_6_5 -P -spirv -fspv-target-env=vulkan1.1spirv1.4 -Fi %t.vk_1_1.hlsl.pp %s
10+
// RUN: FileCheck --input-file=%t.vk_1_1.hlsl.pp %s --check-prefix=VK_1_1_SPV_1_4
11+
// VK_1_1_SPV_1_4: SPIR-V version 1 4
12+
13+
// RUN: %dxc -T vs_6_5 -P -spirv -fspv-target-env=vulkan1.2 -Fi %t.vk_1_2.hlsl.pp %s
14+
// RUN: FileCheck --input-file=%t.vk_1_2.hlsl.pp %s --check-prefix=VK_1_2
15+
// VK_1_2: SPIR-V version 1 5
16+
17+
// RUN: %dxc -T vs_6_5 -P -spirv -fspv-target-env=universal1.5 -Fi %t.universal_1_5.hlsl.pp %s
18+
// RUN: FileCheck --input-file=%t.universal_1_5.hlsl.pp %s --check-prefix=UNI_1_5
19+
// UNI_1_5: SPIR-V version 1 5
20+
21+
// RUN: %dxc -T vs_6_5 -P -spirv -fspv-target-env=vulkan1.3 -Fi %t.vk_1_3.hlsl.pp %s
22+
// RUN: FileCheck --input-file=%t.vk_1_3.hlsl.pp %s --check-prefix=VK_1_3
23+
// VK_1_3: SPIR-V version 1 6
24+
25+
SPIR-V version __SPIRV_MAJOR_VERSION__ __SPIRV_MINOR_VERSION__

tools/clang/tools/dxcompiler/dxcompilerobj.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
// SPIRV change starts
6464
#ifdef ENABLE_SPIRV_CODEGEN
6565
#include "clang/SPIRV/EmitSpirvAction.h"
66+
#include "clang/SPIRV/FeatureManager.h"
6667
#endif
6768
// SPIRV change ends
6869

@@ -1451,6 +1452,22 @@ class DxcCompiler : public IDxcCompiler3,
14511452
// SPIRV change starts
14521453
#ifdef ENABLE_SPIRV_CODEGEN
14531454
compiler.getLangOpts().SPIRV = Opts.GenSPIRV;
1455+
llvm::Optional<spv_target_env> spirvTargetEnv =
1456+
spirv::FeatureManager::stringToSpvEnvironment(
1457+
Opts.SpirvOptions.targetEnv);
1458+
1459+
// If we do not have a valid target environment, the error will be handled
1460+
// later.
1461+
if (spirvTargetEnv.hasValue()) {
1462+
VersionTuple spirvVersion =
1463+
spirv::FeatureManager::getSpirvVersion(spirvTargetEnv.getValue());
1464+
compiler.getLangOpts().SpirvMajorVersion = spirvVersion.getMajor();
1465+
assert(spirvVersion.getMinor().hasValue() &&
1466+
"There must always be a major and minor version number when "
1467+
"targeting SPIR-V.");
1468+
compiler.getLangOpts().SpirvMinorVersion =
1469+
spirvVersion.getMinor().getValue();
1470+
}
14541471
#endif
14551472
// SPIRV change ends
14561473

0 commit comments

Comments
 (0)