Skip to content

[HLSL][SPIR-V] Add Vulkan to target triple #76749

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -735,10 +735,10 @@ def err_drv_dxc_missing_target_profile : Error<
def err_drv_hlsl_unsupported_target : Error<
"HLSL code generation is unsupported for target '%0'">;
def err_drv_hlsl_bad_shader_required_in_target : Error<
"shader %select{model|stage}0 is required in target '%1' for HLSL code generation">;
"%select{shader model|Vulkan environment|shader stage}0 is required as %select{OS|environment}1 in target '%2' for HLSL code generation">;

def err_drv_hlsl_bad_shader_unsupported : Error<
"shader %select{model|stage}0 '%1' in target '%2' is invalid for HLSL code generation">;
"%select{shader model|Vulkan environment|shader stage}0 '%1' in target '%2' is invalid for HLSL code generation">;
def warn_drv_dxc_missing_dxv : Warning<"dxv not found. "
"Resulting DXIL will not be validated or signed for use in release environments.">,
InGroup<DXILValidation>;
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Basic/Targets/SPIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/TargetParser/Triple.h"
#include <optional>

Expand Down Expand Up @@ -301,8 +302,9 @@ class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo {
: BaseSPIRVTargetInfo(Triple, Opts) {
assert(Triple.getArch() == llvm::Triple::spirv &&
"Invalid architecture for Logical SPIR-V.");
assert(Triple.getOS() == llvm::Triple::ShaderModel &&
"Logical SPIR-V requires a valid ShaderModel.");
assert(Triple.getOS() == llvm::Triple::Vulkan &&
Triple.getVulkanVersion() != llvm::VersionTuple(0) &&
"Logical SPIR-V requires a valid Vulkan environment.");
assert(Triple.getEnvironment() >= llvm::Triple::Pixel &&
Triple.getEnvironment() <= llvm::Triple::Amplification &&
"Logical SPIR-V environment must be a valid shader stage.");
Expand Down
27 changes: 21 additions & 6 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4236,20 +4236,35 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
// TODO: Revisit restricting SPIR-V to logical once we've figured out how to
// handle PhysicalStorageBuffer64 memory model
if (T.isDXIL() || T.isSPIRVLogical()) {
enum { ShaderModel, ShaderStage };
enum { ShaderModel, VulkanEnv, ShaderStage };
enum { OS, Environment };

int ExpectedOS = T.isSPIRVLogical() ? VulkanEnv : ShaderModel;

if (T.getOSName().empty()) {
Diags.Report(diag::err_drv_hlsl_bad_shader_required_in_target)
<< ShaderModel << T.str();
} else if (!T.isShaderModelOS() || T.getOSVersion() == VersionTuple(0)) {
Diags.Report(diag::err_drv_hlsl_bad_shader_unsupported)
<< ShaderModel << T.getOSName() << T.str();
<< ExpectedOS << OS << T.str();
} else if (T.getEnvironmentName().empty()) {
Diags.Report(diag::err_drv_hlsl_bad_shader_required_in_target)
<< ShaderStage << T.str();
<< ShaderStage << Environment << T.str();
} else if (!T.isShaderStageEnvironment()) {
Diags.Report(diag::err_drv_hlsl_bad_shader_unsupported)
<< ShaderStage << T.getEnvironmentName() << T.str();
}

if (T.isDXIL()) {
if (!T.isShaderModelOS() || T.getOSVersion() == VersionTuple(0)) {
Diags.Report(diag::err_drv_hlsl_bad_shader_unsupported)
<< ShaderModel << T.getOSName() << T.str();
}
} else if (T.isSPIRVLogical()) {
if (!T.isVulkanOS() || T.getVulkanVersion() == VersionTuple(0)) {
Diags.Report(diag::err_drv_hlsl_bad_shader_unsupported)
<< VulkanEnv << T.getOSName() << T.str();
}
} else {
llvm_unreachable("expected DXIL or SPIR-V target");
}
} else
Diags.Report(diag::err_drv_hlsl_unsupported_target) << T.str();
}
Expand Down
28 changes: 19 additions & 9 deletions clang/test/Driver/hlsl-lang-targets-spirv.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,39 @@
// Supported targets
//
// RUN: %clang -target dxil-unknown-shadermodel6.2-compute %s -S -o /dev/null 2>&1 | FileCheck --allow-empty --check-prefix=CHECK-VALID %s
// RUN: %clang -target spirv-unknown-shadermodel6.2-compute %s -S -o /dev/null 2>&1 | FileCheck --allow-empty --check-prefix=CHECK-VALID %s
// RUN: %clang -target spirv-unknown-vulkan-compute %s -S -o /dev/null 2>&1 | FileCheck --allow-empty --check-prefix=CHECK-VALID %s
// RUN: %clang -target spirv-unknown-vulkan1.2-compute %s -S -o /dev/null 2>&1 | FileCheck --allow-empty --check-prefix=CHECK-VALID %s
// RUN: %clang -target spirv-unknown-vulkan1.3-compute %s -S -o /dev/null 2>&1 | FileCheck --allow-empty --check-prefix=CHECK-VALID %s
// RUN: %clang -target spirv1.5-unknown-vulkan1.2-compute %s -S -o /dev/null 2>&1 | FileCheck --allow-empty --check-prefix=CHECK-VALID %s
// RUN: %clang -target spirv1.6-unknown-vulkan1.3-compute %s -S -o /dev/null 2>&1 | FileCheck --allow-empty --check-prefix=CHECK-VALID %s

// Empty shader model
// Empty Vulkan environment
//
// RUN: not %clang -target spirv %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-NO-OS %s

// Invalid shader models
// Invalid Vulkan environment
//
// RUN: not %clang -target spirv--unknown %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-OS %s
// RUN: not %clang -target spirv--shadermodel %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-OS %s
// RUN: not %clang -target spirv-unknown-vulkan1.0-compute %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-OS %s
// RUN: not %clang -target spirv1.5-unknown-vulkan1.3-compute %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-OS %s

// Invalid SPIR-V version
// RUN: not %clang -target spirv1.0-unknown-vulkan-compute %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-TARGET %s

// Empty shader stage
//
// RUN: not %clang -target spirv--shadermodel6.2 %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-NO-ENV %s
// RUN: not %clang -target spirv--vulkan %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-NO-ENV %s

// Invalid shader stages
//
// RUN: not %clang -target spirv--shadermodel6.2-unknown %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-ENV %s
// RUN: not %clang -target spirv--vulkan-unknown %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-ENV %s

// CHECK-VALID-NOT: error:
// CHECK-NO-OS: error: shader model is required in target '{{.*}}' for HLSL code generation
// CHECK-BAD-OS: error: shader model '{{.*}}' in target '{{.*}}' is invalid for HLSL code generation
// CHECK-NO-ENV: error: shader stage is required in target '{{.*}}' for HLSL code generation
// CHECK-NO-OS: error: Vulkan environment is required as OS in target '{{.*}}' for HLSL code generation
// CHECK-BAD-OS: error: Vulkan environment '{{.*}}' in target '{{.*}}' is invalid for HLSL code generation
// CHECK-NO-ENV: error: shader stage is required as environment in target '{{.*}}' for HLSL code generation
// CHECK-BAD-ENV: error: shader stage '{{.*}}' in target '{{.*}}' is invalid for HLSL code generation
// CHECK-BAD-TARGET: error: HLSL code generation is unsupported for target '{{.*}}'

[shader("compute"), numthreads(1,1,1)]
void main() {}
6 changes: 3 additions & 3 deletions clang/test/Driver/hlsl-lang-targets.hlsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// REQUIRES: dxil-registered-target
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test wasn't being run for me before. I think this change is correct?

// REQUIRES: directx-registered-target

// Supported targets
//
Expand Down Expand Up @@ -43,9 +43,9 @@
// RUN: not %clang -target amdgcn %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-TARGET %s

// CHECK-VALID-NOT: error:
// CHECK-NO-OS: error: shader model is required in target '{{.*}}' for HLSL code generation
// CHECK-NO-OS: error: shader model is required as OS in target '{{.*}}' for HLSL code generation
// CHECK-BAD-OS: error: shader model '{{.*}}' in target '{{.*}}' is invalid for HLSL code generation
// CHECK-NO-ENV: error: shader stage is required in target '{{.*}}' for HLSL code generation
// CHECK-NO-ENV: error: shader stage is required as environment in target '{{.*}}' for HLSL code generation
// CHECK-BAD-ENV: error: shader stage '{{.*}}' in target '{{.*}}' is invalid for HLSL code generation
// CHECK-BAD-TARGET: error: HLSL code generation is unsupported for target '{{.*}}'

Expand Down
10 changes: 9 additions & 1 deletion llvm/include/llvm/TargetParser/Triple.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class Triple {
SPIRVSubArch_v13,
SPIRVSubArch_v14,
SPIRVSubArch_v15,
SPIRVSubArch_v16,
};
enum VendorType {
UnknownVendor,
Expand Down Expand Up @@ -224,7 +225,8 @@ class Triple {
ShaderModel, // DirectX ShaderModel
LiteOS,
Serenity,
LastOSType = Serenity
Vulkan, // Vulkan SPIR-V
LastOSType = Vulkan
};
enum EnvironmentType {
UnknownEnvironment,
Expand Down Expand Up @@ -410,6 +412,10 @@ class Triple {
/// Parse the version number as with getOSVersion.
VersionTuple getDriverKitVersion() const;

/// Parse the Vulkan version number from the OSVersion and SPIR-V version
/// (SubArch). This should only be called with Vulkan SPIR-V triples.
VersionTuple getVulkanVersion() const;

/// @}
/// @name Direct Component Access
/// @{
Expand Down Expand Up @@ -775,6 +781,8 @@ class Triple {
return getOS() == Triple::ShaderModel;
}

bool isVulkanOS() const { return getOS() == Triple::Vulkan; }

bool isShaderStageEnvironment() const {
EnvironmentType Env = getEnvironment();
return Env == Triple::Pixel || Env == Triple::Vertex ||
Expand Down
32 changes: 30 additions & 2 deletions llvm/lib/TargetParser/Triple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "llvm/TargetParser/Triple.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
Expand Down Expand Up @@ -274,6 +275,7 @@ StringRef Triple::getOSTypeName(OSType Kind) {
case ShaderModel: return "shadermodel";
case LiteOS: return "liteos";
case XROS: return "xros";
case Vulkan: return "vulkan";
}

llvm_unreachable("Invalid OSType");
Expand Down Expand Up @@ -551,8 +553,7 @@ static Triple::ArchType parseArch(StringRef ArchName) {
.Case("hsail64", Triple::hsail64)
.Case("spir", Triple::spir)
.Case("spir64", Triple::spir64)
.Cases("spirv", "spirv1.0", "spirv1.1", "spirv1.2",
"spirv1.3", "spirv1.4", "spirv1.5", Triple::spirv)
.Cases("spirv", "spirv1.5", "spirv1.6", Triple::spirv)
.Cases("spirv32", "spirv32v1.0", "spirv32v1.1", "spirv32v1.2",
"spirv32v1.3", "spirv32v1.4", "spirv32v1.5", Triple::spirv32)
.Cases("spirv64", "spirv64v1.0", "spirv64v1.1", "spirv64v1.2",
Expand Down Expand Up @@ -646,6 +647,7 @@ static Triple::OSType parseOS(StringRef OSName) {
.StartsWith("shadermodel", Triple::ShaderModel)
.StartsWith("liteos", Triple::LiteOS)
.StartsWith("serenity", Triple::Serenity)
.StartsWith("vulkan", Triple::Vulkan)
.Default(Triple::UnknownOS);
}

Expand Down Expand Up @@ -730,6 +732,7 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) {
.EndsWith("v1.3", Triple::SPIRVSubArch_v13)
.EndsWith("v1.4", Triple::SPIRVSubArch_v14)
.EndsWith("v1.5", Triple::SPIRVSubArch_v15)
.EndsWith("v1.6", Triple::SPIRVSubArch_v16)
.Default(Triple::NoSubArch);

StringRef ARMSubArch = ARM::getCanonicalArchName(SubArchName);
Expand Down Expand Up @@ -1345,6 +1348,31 @@ VersionTuple Triple::getDriverKitVersion() const {
}
}

VersionTuple Triple::getVulkanVersion() const {
if (getArch() != spirv || getOS() != Vulkan)
llvm_unreachable("invalid Vulkan SPIR-V triple");

VersionTuple VulkanVersion = getOSVersion();
SubArchType SpirvVersion = getSubArch();

llvm::DenseMap<VersionTuple, SubArchType> ValidVersionMap = {
// Vulkan 1.2 -> SPIR-V 1.5.
{VersionTuple(1, 2), SPIRVSubArch_v15},
// Vulkan 1.3 -> SPIR-V 1.6.
{VersionTuple(1, 3), SPIRVSubArch_v16}};

// If Vulkan version is unset, default to 1.2.
if (VulkanVersion == VersionTuple(0))
VulkanVersion = VersionTuple(1, 2);

if (ValidVersionMap.contains(VulkanVersion) &&
(ValidVersionMap.lookup(VulkanVersion) == SpirvVersion ||
SpirvVersion == NoSubArch))
return VulkanVersion;

return VersionTuple(0);
}

void Triple::setTriple(const Twine &Str) {
*this = Triple(Str);
}
Expand Down
Loading