[HLSL][clang][Driver] Parse target profile early to update Driver::TargetTriple.

This is to avoid err_target_unknown_abi which is caused by use default TargetTriple instead of shader model target triple.

Reviewed By: beanz

Differential Revision: https://reviews.llvm.org/D125585
This commit is contained in:
Xiang Li 2022-05-13 14:36:27 -07:00
parent ce5ebf0b91
commit fde240c9c3
6 changed files with 82 additions and 132 deletions

View File

@ -666,6 +666,8 @@ def err_drv_target_variant_invalid : Error<
def err_drv_invalid_directx_shader_module : Error<
"invalid profile : %0">;
def err_drv_dxc_missing_target_profile : Error<
"target profile option (-T) is missing">;
def err_drv_invalid_range_dxil_validator_version : Error<
"invalid validator version : %0\n"

View File

@ -1236,11 +1236,19 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
T.setObjectFormat(llvm::Triple::COFF);
TargetTriple = T.str();
} else if (IsDXCMode()) {
// clang-dxc target is build from target_profile option.
// Just set OS to shader model to select HLSLToolChain.
llvm::Triple T(TargetTriple);
T.setOS(llvm::Triple::ShaderModel);
TargetTriple = T.str();
// Build TargetTriple from target_profile option for clang-dxc.
if (const Arg *A = Args.getLastArg(options::OPT_target_profile)) {
StringRef TargetProfile = A->getValue();
if (auto Triple =
toolchains::HLSLToolChain::parseTargetProfile(TargetProfile))
TargetTriple = Triple.getValue();
else
Diag(diag::err_drv_invalid_directx_shader_module) << TargetProfile;
A->claim();
} else {
Diag(diag::err_drv_dxc_missing_target_profile);
}
}
if (const Arg *A = Args.getLastArg(options::OPT_target))

View File

@ -64,12 +64,12 @@ bool isLegalShaderModel(Triple &T) {
return false;
}
std::string tryParseProfile(StringRef Profile) {
llvm::Optional<std::string> tryParseProfile(StringRef Profile) {
// [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor]
SmallVector<StringRef, 3> Parts;
Profile.split(Parts, "_");
if (Parts.size() != 3)
return "";
return NoneType();
Triple::EnvironmentType Kind =
StringSwitch<Triple::EnvironmentType>(Parts[0])
@ -84,17 +84,17 @@ std::string tryParseProfile(StringRef Profile) {
.Case("as", Triple::EnvironmentType::Amplification)
.Default(Triple::EnvironmentType::UnknownEnvironment);
if (Kind == Triple::EnvironmentType::UnknownEnvironment)
return "";
return NoneType();
unsigned long long Major = 0;
if (llvm::getAsUnsignedInteger(Parts[1], 0, Major))
return "";
return NoneType();
unsigned long long Minor = 0;
if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library)
Minor = OfflineLibMinor;
else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor))
return "";
return NoneType();
// dxil-unknown-shadermodel-hull
llvm::Triple T;
@ -105,7 +105,7 @@ std::string tryParseProfile(StringRef Profile) {
if (isLegalShaderModel(T))
return T.getTriple();
else
return "";
return NoneType();
}
bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) {
@ -138,21 +138,10 @@ HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args) {}
std::string
HLSLToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const {
if (Arg *A = Args.getLastArg(options::OPT_target_profile)) {
StringRef Profile = A->getValue();
std::string Triple = tryParseProfile(Profile);
if (Triple == "") {
getDriver().Diag(diag::err_drv_invalid_directx_shader_module) << Profile;
Triple = ToolChain::ComputeEffectiveClangTriple(Args, InputType);
}
A->claim();
return Triple;
} else {
return ToolChain::ComputeEffectiveClangTriple(Args, InputType);
}
llvm::Optional<std::string>
clang::driver::toolchains::HLSLToolChain::parseTargetProfile(
StringRef TargetProfile) {
return tryParseProfile(TargetProfile);
}
DerivedArgList *

View File

@ -29,8 +29,8 @@ public:
llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
Action::OffloadKind DeviceOffloadKind) const override;
std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
types::ID InputType) const override;
static llvm::Optional<std::string>
parseTargetProfile(StringRef TargetProfile);
};
} // end namespace toolchains

View File

@ -1,4 +1,4 @@
// RUN: %clang_dxc -fcgl foo.hlsl -### %s 2>&1 | FileCheck %s
// RUN: %clang_dxc -fcgl -T lib_6_7 foo.hlsl -### %s 2>&1 | FileCheck %s
// Make sure fcgl option flag which translated into "-S" "-emit-llvm" "-disable-llvm-passes".
// CHECK:"-S" "-emit-llvm" "-disable-llvm-passes"

View File

@ -387,6 +387,28 @@ struct SimpleDiagnosticConsumer : public DiagnosticConsumer {
std::vector<SmallString<32>> Errors;
};
static void validateTargetProfile(StringRef TargetProfile,
StringRef ExpectTriple, Driver &TheDriver,
DiagnosticsEngine &Diags) {
EXPECT_TRUE(TheDriver.BuildCompilation(
{"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl"}));
EXPECT_STREQ(TheDriver.getTargetTriple().c_str(), ExpectTriple.data());
EXPECT_EQ(Diags.getNumErrors(), 0u);
}
static void validateTargetProfile(StringRef TargetProfile,
StringRef ExpectError, Driver &TheDriver,
DiagnosticsEngine &Diags,
SimpleDiagnosticConsumer *DiagConsumer,
unsigned NumOfErrors) {
EXPECT_TRUE(TheDriver.BuildCompilation(
{"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl"}));
EXPECT_EQ(Diags.getNumErrors(), NumOfErrors);
EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), ExpectError.data());
Diags.Clear();
DiagConsumer->clear();
}
TEST(DxcModeTest, TargetProfileValidation) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
@ -400,111 +422,40 @@ TEST(DxcModeTest, TargetProfileValidation) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
std::unique_ptr<Compilation> C(
TheDriver.BuildCompilation({"clang", "--driver-mode=dxc", "foo.hlsl"}));
EXPECT_TRUE(C);
EXPECT_TRUE(!C->containsError());
auto &TC = C->getDefaultToolChain();
bool ContainsError = false;
auto Args = TheDriver.ParseArgStrings({"-Tvs_6_0"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
auto Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.0-vertex");
EXPECT_EQ(Diags.getNumErrors(), 0u);
Args = TheDriver.ParseArgStrings({"-Ths_6_1"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.1-hull");
EXPECT_EQ(Diags.getNumErrors(), 0u);
Args = TheDriver.ParseArgStrings({"-Tds_6_2"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.2-domain");
EXPECT_EQ(Diags.getNumErrors(), 0u);
Args = TheDriver.ParseArgStrings({"-Tds_6_2"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.2-domain");
EXPECT_EQ(Diags.getNumErrors(), 0u);
Args = TheDriver.ParseArgStrings({"-Tgs_6_3"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.3-geometry");
EXPECT_EQ(Diags.getNumErrors(), 0u);
Args = TheDriver.ParseArgStrings({"-Tps_6_4"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.4-pixel");
EXPECT_EQ(Diags.getNumErrors(), 0u);
Args = TheDriver.ParseArgStrings({"-Tcs_6_5"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.5-compute");
EXPECT_EQ(Diags.getNumErrors(), 0u);
Args = TheDriver.ParseArgStrings({"-Tms_6_6"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.6-mesh");
EXPECT_EQ(Diags.getNumErrors(), 0u);
Args = TheDriver.ParseArgStrings({"-Tas_6_7"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.7-amplification");
EXPECT_EQ(Diags.getNumErrors(), 0u);
Args = TheDriver.ParseArgStrings({"-Tlib_6_x"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.15-library");
EXPECT_EQ(Diags.getNumErrors(), 0u);
validateTargetProfile("-Tvs_6_0", "dxil--shadermodel6.0-vertex", TheDriver,
Diags);
validateTargetProfile("-Ths_6_1", "dxil--shadermodel6.1-hull", TheDriver,
Diags);
validateTargetProfile("-Tds_6_2", "dxil--shadermodel6.2-domain", TheDriver,
Diags);
validateTargetProfile("-Tds_6_2", "dxil--shadermodel6.2-domain", TheDriver,
Diags);
validateTargetProfile("-Tgs_6_3", "dxil--shadermodel6.3-geometry", TheDriver,
Diags);
validateTargetProfile("-Tps_6_4", "dxil--shadermodel6.4-pixel", TheDriver,
Diags);
validateTargetProfile("-Tcs_6_5", "dxil--shadermodel6.5-compute", TheDriver,
Diags);
validateTargetProfile("-Tms_6_6", "dxil--shadermodel6.6-mesh", TheDriver,
Diags);
validateTargetProfile("-Tas_6_7", "dxil--shadermodel6.7-amplification",
TheDriver, Diags);
validateTargetProfile("-Tlib_6_x", "dxil--shadermodel6.15-library", TheDriver,
Diags);
// Invalid tests.
Args = TheDriver.ParseArgStrings({"-Tpss_6_1"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "unknown-unknown-shadermodel");
EXPECT_EQ(Diags.getNumErrors(), 1u);
EXPECT_STREQ(DiagConsumer->Errors.back().c_str(),
"invalid profile : pss_6_1");
Diags.Clear();
DiagConsumer->clear();
validateTargetProfile("-Tpss_6_1", "invalid profile : pss_6_1", TheDriver,
Diags, DiagConsumer, 1);
Args = TheDriver.ParseArgStrings({"-Tps_6_x"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "unknown-unknown-shadermodel");
EXPECT_EQ(Diags.getNumErrors(), 2u);
EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), "invalid profile : ps_6_x");
Diags.Clear();
DiagConsumer->clear();
Args = TheDriver.ParseArgStrings({"-Tlib_6_1"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "unknown-unknown-shadermodel");
EXPECT_EQ(Diags.getNumErrors(), 3u);
EXPECT_STREQ(DiagConsumer->Errors.back().c_str(),
"invalid profile : lib_6_1");
Diags.Clear();
DiagConsumer->clear();
Args = TheDriver.ParseArgStrings({"-Tfoo"}, false, ContainsError);
EXPECT_FALSE(ContainsError);
Triple = TC.ComputeEffectiveClangTriple(Args);
EXPECT_STREQ(Triple.c_str(), "unknown-unknown-shadermodel");
EXPECT_EQ(Diags.getNumErrors(), 4u);
EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), "invalid profile : foo");
Diags.Clear();
DiagConsumer->clear();
validateTargetProfile("-Tps_6_x", "invalid profile : ps_6_x", TheDriver,
Diags, DiagConsumer, 2);
validateTargetProfile("-Tlib_6_1", "invalid profile : lib_6_1", TheDriver,
Diags, DiagConsumer, 3);
validateTargetProfile("-Tfoo", "invalid profile : foo", TheDriver, Diags,
DiagConsumer, 4);
validateTargetProfile("", "target profile option (-T) is missing", TheDriver,
Diags, DiagConsumer, 5);
}
TEST(DxcModeTest, ValidatorVersionValidation) {
@ -520,8 +471,8 @@ TEST(DxcModeTest, ValidatorVersionValidation) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
std::unique_ptr<Compilation> C(
TheDriver.BuildCompilation({"clang", "--driver-mode=dxc", "foo.hlsl"}));
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
{"clang", "--driver-mode=dxc", "-Tlib_6_7", "foo.hlsl"}));
EXPECT_TRUE(C);
EXPECT_TRUE(!C->containsError());