1 //===- unittests/Driver/DXCModeTest.cpp --- DXC Mode tests ----------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Unit tests for driver DXCMode.
11 //===----------------------------------------------------------------------===//
13 #include "clang/Basic/DiagnosticIDs.h"
14 #include "clang/Basic/DiagnosticOptions.h"
15 #include "clang/Basic/LLVM.h"
16 #include "clang/Basic/TargetOptions.h"
17 #include "clang/Driver/Compilation.h"
18 #include "clang/Driver/Driver.h"
19 #include "clang/Driver/ToolChain.h"
20 #include "clang/Frontend/CompilerInstance.h"
21 #include "llvm/Support/VirtualFileSystem.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "gtest/gtest.h"
26 #include "SimpleDiagnosticConsumer.h"
28 using namespace clang
;
29 using namespace clang::driver
;
31 static void validateTargetProfile(
32 StringRef TargetProfile
, StringRef ExpectTriple
,
33 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> &InMemoryFileSystem
,
34 DiagnosticsEngine
&Diags
) {
35 Driver
TheDriver("/bin/clang", "", Diags
, "", InMemoryFileSystem
);
36 std::unique_ptr
<Compilation
> C
{TheDriver
.BuildCompilation(
37 {"clang", "--driver-mode=dxc", TargetProfile
.data(), "foo.hlsl", "-Vd"})};
39 EXPECT_STREQ(TheDriver
.getTargetTriple().c_str(), ExpectTriple
.data());
40 EXPECT_EQ(Diags
.getNumErrors(), 0u);
43 static void validateTargetProfile(
44 StringRef TargetProfile
, StringRef ExpectError
,
45 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> &InMemoryFileSystem
,
46 DiagnosticsEngine
&Diags
, SimpleDiagnosticConsumer
*DiagConsumer
,
47 unsigned NumOfErrors
) {
48 Driver
TheDriver("/bin/clang", "", Diags
, "", InMemoryFileSystem
);
49 std::unique_ptr
<Compilation
> C
{TheDriver
.BuildCompilation(
50 {"clang", "--driver-mode=dxc", TargetProfile
.data(), "foo.hlsl", "-Vd"})};
52 EXPECT_EQ(Diags
.getNumErrors(), NumOfErrors
);
53 EXPECT_STREQ(DiagConsumer
->Errors
.back().c_str(), ExpectError
.data());
55 DiagConsumer
->clear();
58 TEST(DxcModeTest
, TargetProfileValidation
) {
59 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
61 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> InMemoryFileSystem(
62 new llvm::vfs::InMemoryFileSystem
);
64 InMemoryFileSystem
->addFile("foo.hlsl", 0,
65 llvm::MemoryBuffer::getMemBuffer("\n"));
67 auto *DiagConsumer
= new SimpleDiagnosticConsumer
;
68 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
69 DiagnosticsEngine
Diags(DiagID
, &*DiagOpts
, DiagConsumer
);
71 validateTargetProfile("-Tvs_6_0", "dxil--shadermodel6.0-vertex",
72 InMemoryFileSystem
, Diags
);
73 validateTargetProfile("-Ths_6_1", "dxil--shadermodel6.1-hull",
74 InMemoryFileSystem
, Diags
);
75 validateTargetProfile("-Tds_6_2", "dxil--shadermodel6.2-domain",
76 InMemoryFileSystem
, Diags
);
77 validateTargetProfile("-Tds_6_2", "dxil--shadermodel6.2-domain",
78 InMemoryFileSystem
, Diags
);
79 validateTargetProfile("-Tgs_6_3", "dxil--shadermodel6.3-geometry",
80 InMemoryFileSystem
, Diags
);
81 validateTargetProfile("-Tps_6_4", "dxil--shadermodel6.4-pixel",
82 InMemoryFileSystem
, Diags
);
83 validateTargetProfile("-Tcs_6_5", "dxil--shadermodel6.5-compute",
84 InMemoryFileSystem
, Diags
);
85 validateTargetProfile("-Tms_6_6", "dxil--shadermodel6.6-mesh",
86 InMemoryFileSystem
, Diags
);
87 validateTargetProfile("-Tas_6_7", "dxil--shadermodel6.7-amplification",
88 InMemoryFileSystem
, Diags
);
89 validateTargetProfile("-Tlib_6_x", "dxil--shadermodel6.15-library",
90 InMemoryFileSystem
, Diags
);
93 validateTargetProfile("-Tpss_6_1", "invalid profile : pss_6_1",
94 InMemoryFileSystem
, Diags
, DiagConsumer
, 1);
96 validateTargetProfile("-Tps_6_x", "invalid profile : ps_6_x",
97 InMemoryFileSystem
, Diags
, DiagConsumer
, 2);
98 validateTargetProfile("-Tlib_6_1", "invalid profile : lib_6_1",
99 InMemoryFileSystem
, Diags
, DiagConsumer
, 3);
100 validateTargetProfile("-Tfoo", "invalid profile : foo", InMemoryFileSystem
,
101 Diags
, DiagConsumer
, 4);
102 validateTargetProfile("", "target profile option (-T) is missing",
103 InMemoryFileSystem
, Diags
, DiagConsumer
, 5);
106 TEST(DxcModeTest
, ValidatorVersionValidation
) {
107 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
109 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> InMemoryFileSystem(
110 new llvm::vfs::InMemoryFileSystem
);
112 InMemoryFileSystem
->addFile("foo.hlsl", 0,
113 llvm::MemoryBuffer::getMemBuffer("\n"));
115 auto *DiagConsumer
= new SimpleDiagnosticConsumer
;
116 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
117 DiagnosticsEngine
Diags(DiagID
, &*DiagOpts
, DiagConsumer
);
118 Driver
TheDriver("/bin/clang", "", Diags
, "", InMemoryFileSystem
);
119 std::unique_ptr
<Compilation
> C(TheDriver
.BuildCompilation(
120 {"clang", "--driver-mode=dxc", "-Tlib_6_7", "foo.hlsl"}));
122 EXPECT_TRUE(!C
->containsError());
124 auto &TC
= C
->getDefaultToolChain();
125 bool ContainsError
= false;
126 auto Args
= TheDriver
.ParseArgStrings({"-validator-version", "1.1"}, false,
128 EXPECT_FALSE(ContainsError
);
129 auto DAL
= std::make_unique
<llvm::opt::DerivedArgList
>(Args
);
133 std::unique_ptr
<llvm::opt::DerivedArgList
> TranslatedArgs
{
134 TC
.TranslateArgs(*DAL
, "0", Action::OffloadKind::OFK_None
)};
135 EXPECT_NE(TranslatedArgs
, nullptr);
136 if (TranslatedArgs
) {
137 auto *A
= TranslatedArgs
->getLastArg(
138 clang::driver::options::OPT_dxil_validator_version
);
139 EXPECT_NE(A
, nullptr);
141 EXPECT_STREQ(A
->getValue(), "1.1");
144 EXPECT_EQ(Diags
.getNumErrors(), 0u);
147 Args
= TheDriver
.ParseArgStrings({"-validator-version", "0.1"}, false,
149 EXPECT_FALSE(ContainsError
);
150 DAL
= std::make_unique
<llvm::opt::DerivedArgList
>(Args
);
154 TranslatedArgs
.reset(
155 TC
.TranslateArgs(*DAL
, "0", Action::OffloadKind::OFK_None
));
156 EXPECT_EQ(Diags
.getNumErrors(), 1u);
157 EXPECT_STREQ(DiagConsumer
->Errors
.back().c_str(),
158 "invalid validator version : 0.1\nIf validator major version is "
159 "0, minor version must also be 0.");
161 DiagConsumer
->clear();
163 Args
= TheDriver
.ParseArgStrings({"-validator-version", "1"}, false,
165 EXPECT_FALSE(ContainsError
);
166 DAL
= std::make_unique
<llvm::opt::DerivedArgList
>(Args
);
170 TranslatedArgs
.reset(
171 TC
.TranslateArgs(*DAL
, "0", Action::OffloadKind::OFK_None
));
172 EXPECT_EQ(Diags
.getNumErrors(), 2u);
173 EXPECT_STREQ(DiagConsumer
->Errors
.back().c_str(),
174 "invalid validator version : 1\nFormat of validator version is "
175 "\"<major>.<minor>\" (ex:\"1.4\").");
177 DiagConsumer
->clear();
179 Args
= TheDriver
.ParseArgStrings({"-validator-version", "-Tlib_6_7"}, false,
181 EXPECT_FALSE(ContainsError
);
182 DAL
= std::make_unique
<llvm::opt::DerivedArgList
>(Args
);
186 TranslatedArgs
.reset(
187 TC
.TranslateArgs(*DAL
, "0", Action::OffloadKind::OFK_None
));
188 EXPECT_EQ(Diags
.getNumErrors(), 3u);
190 DiagConsumer
->Errors
.back().c_str(),
191 "invalid validator version : -Tlib_6_7\nFormat of validator version is "
192 "\"<major>.<minor>\" (ex:\"1.4\").");
194 DiagConsumer
->clear();
196 Args
= TheDriver
.ParseArgStrings({"-validator-version", "foo"}, false,
198 EXPECT_FALSE(ContainsError
);
199 DAL
= std::make_unique
<llvm::opt::DerivedArgList
>(Args
);
203 TranslatedArgs
.reset(
204 TC
.TranslateArgs(*DAL
, "0", Action::OffloadKind::OFK_None
));
205 EXPECT_EQ(Diags
.getNumErrors(), 4u);
207 DiagConsumer
->Errors
.back().c_str(),
208 "invalid validator version : foo\nFormat of validator version is "
209 "\"<major>.<minor>\" (ex:\"1.4\").");
211 DiagConsumer
->clear();
214 TEST(DxcModeTest
, DefaultEntry
) {
215 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> InMemoryFileSystem(
216 new llvm::vfs::InMemoryFileSystem
);
218 InMemoryFileSystem
->addFile("foo.hlsl", 0,
219 llvm::MemoryBuffer::getMemBuffer("\n"));
221 const char *Args
[] = {"clang", "--driver-mode=dxc", "-Tcs_6_7", "foo.hlsl"};
223 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags
=
224 CompilerInstance::createDiagnostics(new DiagnosticOptions());
226 CreateInvocationOptions CIOpts
;
227 CIOpts
.Diags
= Diags
;
228 std::unique_ptr
<CompilerInvocation
> CInvok
=
229 createInvocation(Args
, std::move(CIOpts
));
231 // Make sure default entry is "main".
232 EXPECT_STREQ(CInvok
->getTargetOpts().HLSLEntry
.c_str(), "main");
234 const char *EntryArgs
[] = {"clang", "--driver-mode=dxc", "-Ebar", "-Tcs_6_7",
236 CInvok
= createInvocation(EntryArgs
, std::move(CIOpts
));
238 // Make sure "-E" will set entry.
239 EXPECT_STREQ(CInvok
->getTargetOpts().HLSLEntry
.c_str(), "bar");