1 //===- unittests/Driver/ToolChainTest.cpp --- ToolChain tests -------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Unit tests for ToolChains.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "clang/Driver/ToolChain.h"
14 #include "clang/Basic/DiagnosticIDs.h"
15 #include "clang/Basic/DiagnosticOptions.h"
16 #include "clang/Basic/LLVM.h"
17 #include "clang/Driver/Compilation.h"
18 #include "clang/Driver/Driver.h"
19 #include "llvm/ADT/ArrayRef.h"
20 #include "llvm/MC/TargetRegistry.h"
21 #include "llvm/Support/TargetSelect.h"
22 #include "llvm/Support/VirtualFileSystem.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include "gtest/gtest.h"
25 #include <memory>
26 using namespace clang;
27 using namespace clang::driver;
28
29 namespace {
30
TEST(ToolChainTest,VFSGCCInstallation)31 TEST(ToolChainTest, VFSGCCInstallation) {
32 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
33
34 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
35 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
36 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
37 new llvm::vfs::InMemoryFileSystem);
38
39 const char *EmptyFiles[] = {
40 "foo.cpp",
41 "/bin/clang",
42 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
43 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o",
44 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o",
45 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o",
46 "/usr/lib/arm-linux-gnueabi/crt1.o",
47 "/usr/lib/arm-linux-gnueabi/crti.o",
48 "/usr/lib/arm-linux-gnueabi/crtn.o",
49 "/usr/lib/arm-linux-gnueabihf/crt1.o",
50 "/usr/lib/arm-linux-gnueabihf/crti.o",
51 "/usr/lib/arm-linux-gnueabihf/crtn.o",
52 "/usr/include/arm-linux-gnueabi/.keep",
53 "/usr/include/arm-linux-gnueabihf/.keep",
54 "/lib/arm-linux-gnueabi/.keep",
55 "/lib/arm-linux-gnueabihf/.keep",
56
57 "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtbegin.o",
58 "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtend.o",
59 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtbegin.o",
60 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtend.o",
61 "/sysroot/usr/lib/arm-linux-gnueabi/crt1.o",
62 "/sysroot/usr/lib/arm-linux-gnueabi/crti.o",
63 "/sysroot/usr/lib/arm-linux-gnueabi/crtn.o",
64 "/sysroot/usr/lib/arm-linux-gnueabihf/crt1.o",
65 "/sysroot/usr/lib/arm-linux-gnueabihf/crti.o",
66 "/sysroot/usr/lib/arm-linux-gnueabihf/crtn.o",
67 "/sysroot/usr/include/arm-linux-gnueabi/.keep",
68 "/sysroot/usr/include/arm-linux-gnueabihf/.keep",
69 "/sysroot/lib/arm-linux-gnueabi/.keep",
70 "/sysroot/lib/arm-linux-gnueabihf/.keep",
71 };
72
73 for (const char *Path : EmptyFiles)
74 InMemoryFileSystem->addFile(Path, 0,
75 llvm::MemoryBuffer::getMemBuffer("\n"));
76
77 {
78 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
79 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
80 "clang LLVM compiler", InMemoryFileSystem);
81 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
82 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=", "foo.cpp"}));
83 ASSERT_TRUE(C);
84 std::string S;
85 {
86 llvm::raw_string_ostream OS(S);
87 C->getDefaultToolChain().printVerboseInfo(OS);
88 }
89 if (is_style_windows(llvm::sys::path::Style::native))
90 std::replace(S.begin(), S.end(), '\\', '/');
91 EXPECT_EQ(
92 "Found candidate GCC installation: "
93 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
94 "Selected GCC installation: /usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
95 "Candidate multilib: .;@m32\n"
96 "Selected multilib: .;@m32\n",
97 S);
98 }
99
100 {
101 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
102 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
103 "clang LLVM compiler", InMemoryFileSystem);
104 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
105 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=/sysroot",
106 "foo.cpp"}));
107 ASSERT_TRUE(C);
108 std::string S;
109 {
110 llvm::raw_string_ostream OS(S);
111 C->getDefaultToolChain().printVerboseInfo(OS);
112 }
113 if (is_style_windows(llvm::sys::path::Style::native))
114 std::replace(S.begin(), S.end(), '\\', '/');
115 // Test that 4.5.3 from --sysroot is not overridden by 4.6.3 (larger
116 // version) from /usr.
117 EXPECT_EQ("Found candidate GCC installation: "
118 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n"
119 "Selected GCC installation: "
120 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n"
121 "Candidate multilib: .;@m32\n"
122 "Selected multilib: .;@m32\n",
123 S);
124 }
125 }
126
TEST(ToolChainTest,VFSGCCInstallationRelativeDir)127 TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
128 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
129
130 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
131 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
132 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
133 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
134 new llvm::vfs::InMemoryFileSystem);
135 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
136 "clang LLVM compiler", InMemoryFileSystem);
137
138 const char *EmptyFiles[] = {
139 "foo.cpp", "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
140 "/home/test/include/arm-linux-gnueabi/.keep"};
141
142 for (const char *Path : EmptyFiles)
143 InMemoryFileSystem->addFile(Path, 0,
144 llvm::MemoryBuffer::getMemBuffer("\n"));
145
146 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
147 {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
148 EXPECT_TRUE(C);
149
150 std::string S;
151 {
152 llvm::raw_string_ostream OS(S);
153 C->getDefaultToolChain().printVerboseInfo(OS);
154 }
155 if (is_style_windows(llvm::sys::path::Style::native))
156 std::replace(S.begin(), S.end(), '\\', '/');
157 EXPECT_EQ("Found candidate GCC installation: "
158 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
159 "Selected GCC installation: "
160 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
161 "Candidate multilib: .;@m32\n"
162 "Selected multilib: .;@m32\n",
163 S);
164 }
165
TEST(ToolChainTest,DefaultDriverMode)166 TEST(ToolChainTest, DefaultDriverMode) {
167 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
168
169 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
170 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
171 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
172 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
173 new llvm::vfs::InMemoryFileSystem);
174
175 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
176 "clang LLVM compiler", InMemoryFileSystem);
177 CCDriver.setCheckInputsExist(false);
178 Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags,
179 "clang LLVM compiler", InMemoryFileSystem);
180 CXXDriver.setCheckInputsExist(false);
181 Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags,
182 "clang LLVM compiler", InMemoryFileSystem);
183 CLDriver.setCheckInputsExist(false);
184
185 std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation(
186 { "/home/test/bin/clang", "foo.cpp"}));
187 std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation(
188 { "/home/test/bin/clang++", "foo.cpp"}));
189 std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation(
190 { "/home/test/bin/clang-cl", "foo.cpp"}));
191
192 EXPECT_TRUE(CC);
193 EXPECT_TRUE(CXX);
194 EXPECT_TRUE(CL);
195 EXPECT_TRUE(CCDriver.CCCIsCC());
196 EXPECT_TRUE(CXXDriver.CCCIsCXX());
197 EXPECT_TRUE(CLDriver.IsCLMode());
198 }
TEST(ToolChainTest,InvalidArgument)199 TEST(ToolChainTest, InvalidArgument) {
200 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
201 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
202 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
203 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
204 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
205 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
206 {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
207 EXPECT_TRUE(C);
208 EXPECT_TRUE(C->containsError());
209 }
210
TEST(ToolChainTest,ParsedClangName)211 TEST(ToolChainTest, ParsedClangName) {
212 ParsedClangName Empty;
213 EXPECT_TRUE(Empty.TargetPrefix.empty());
214 EXPECT_TRUE(Empty.ModeSuffix.empty());
215 EXPECT_TRUE(Empty.DriverMode == nullptr);
216 EXPECT_FALSE(Empty.TargetIsValid);
217
218 ParsedClangName DriverOnly("clang", nullptr);
219 EXPECT_TRUE(DriverOnly.TargetPrefix.empty());
220 EXPECT_TRUE(DriverOnly.ModeSuffix == "clang");
221 EXPECT_TRUE(DriverOnly.DriverMode == nullptr);
222 EXPECT_FALSE(DriverOnly.TargetIsValid);
223
224 ParsedClangName DriverOnly2("clang++", "--driver-mode=g++");
225 EXPECT_TRUE(DriverOnly2.TargetPrefix.empty());
226 EXPECT_TRUE(DriverOnly2.ModeSuffix == "clang++");
227 EXPECT_STREQ(DriverOnly2.DriverMode, "--driver-mode=g++");
228 EXPECT_FALSE(DriverOnly2.TargetIsValid);
229
230 ParsedClangName TargetAndMode("i386", "clang-g++", "--driver-mode=g++", true);
231 EXPECT_TRUE(TargetAndMode.TargetPrefix == "i386");
232 EXPECT_TRUE(TargetAndMode.ModeSuffix == "clang-g++");
233 EXPECT_STREQ(TargetAndMode.DriverMode, "--driver-mode=g++");
234 EXPECT_TRUE(TargetAndMode.TargetIsValid);
235 }
236
TEST(ToolChainTest,GetTargetAndMode)237 TEST(ToolChainTest, GetTargetAndMode) {
238 llvm::InitializeAllTargets();
239 std::string IgnoredError;
240 if (!llvm::TargetRegistry::lookupTarget("x86_64", IgnoredError))
241 return;
242
243 ParsedClangName Res = ToolChain::getTargetAndModeFromProgramName("clang");
244 EXPECT_TRUE(Res.TargetPrefix.empty());
245 EXPECT_TRUE(Res.ModeSuffix == "clang");
246 EXPECT_TRUE(Res.DriverMode == nullptr);
247 EXPECT_FALSE(Res.TargetIsValid);
248
249 Res = ToolChain::getTargetAndModeFromProgramName("clang++");
250 EXPECT_TRUE(Res.TargetPrefix.empty());
251 EXPECT_TRUE(Res.ModeSuffix == "clang++");
252 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
253 EXPECT_FALSE(Res.TargetIsValid);
254
255 Res = ToolChain::getTargetAndModeFromProgramName("clang++6.0");
256 EXPECT_TRUE(Res.TargetPrefix.empty());
257 EXPECT_TRUE(Res.ModeSuffix == "clang++");
258 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
259 EXPECT_FALSE(Res.TargetIsValid);
260
261 Res = ToolChain::getTargetAndModeFromProgramName("clang++-release");
262 EXPECT_TRUE(Res.TargetPrefix.empty());
263 EXPECT_TRUE(Res.ModeSuffix == "clang++");
264 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
265 EXPECT_FALSE(Res.TargetIsValid);
266
267 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-clang++");
268 EXPECT_TRUE(Res.TargetPrefix == "x86_64");
269 EXPECT_TRUE(Res.ModeSuffix == "clang++");
270 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
271 EXPECT_TRUE(Res.TargetIsValid);
272
273 Res = ToolChain::getTargetAndModeFromProgramName(
274 "x86_64-linux-gnu-clang-c++");
275 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
276 EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
277 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
278 EXPECT_TRUE(Res.TargetIsValid);
279
280 Res = ToolChain::getTargetAndModeFromProgramName(
281 "x86_64-linux-gnu-clang-c++-tot");
282 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
283 EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
284 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
285 EXPECT_TRUE(Res.TargetIsValid);
286
287 Res = ToolChain::getTargetAndModeFromProgramName("qqq");
288 EXPECT_TRUE(Res.TargetPrefix.empty());
289 EXPECT_TRUE(Res.ModeSuffix.empty());
290 EXPECT_TRUE(Res.DriverMode == nullptr);
291 EXPECT_FALSE(Res.TargetIsValid);
292
293 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-qqq");
294 EXPECT_TRUE(Res.TargetPrefix.empty());
295 EXPECT_TRUE(Res.ModeSuffix.empty());
296 EXPECT_TRUE(Res.DriverMode == nullptr);
297 EXPECT_FALSE(Res.TargetIsValid);
298
299 Res = ToolChain::getTargetAndModeFromProgramName("qqq-clang-cl");
300 EXPECT_TRUE(Res.TargetPrefix == "qqq");
301 EXPECT_TRUE(Res.ModeSuffix == "clang-cl");
302 EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl");
303 EXPECT_FALSE(Res.TargetIsValid);
304
305 Res = ToolChain::getTargetAndModeFromProgramName("clang-dxc");
306 EXPECT_TRUE(Res.TargetPrefix.empty());
307 EXPECT_TRUE(Res.ModeSuffix == "clang-dxc");
308 EXPECT_STREQ(Res.DriverMode, "--driver-mode=dxc");
309 EXPECT_FALSE(Res.TargetIsValid);
310 }
311
TEST(ToolChainTest,CommandOutput)312 TEST(ToolChainTest, CommandOutput) {
313 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
314
315 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
316 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
317 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
318 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
319 new llvm::vfs::InMemoryFileSystem);
320
321 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
322 "clang LLVM compiler", InMemoryFileSystem);
323 CCDriver.setCheckInputsExist(false);
324 std::unique_ptr<Compilation> CC(
325 CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"}));
326 const JobList &Jobs = CC->getJobs();
327
328 const auto &CmdCompile = Jobs.getJobs().front();
329 const auto &InFile = CmdCompile->getInputInfos().front().getFilename();
330 EXPECT_STREQ(InFile, "foo.cpp");
331 auto ObjFile = CmdCompile->getOutputFilenames().front();
332 EXPECT_TRUE(StringRef(ObjFile).endswith(".o"));
333
334 const auto &CmdLink = Jobs.getJobs().back();
335 const auto LinkInFile = CmdLink->getInputInfos().front().getFilename();
336 EXPECT_EQ(ObjFile, LinkInFile);
337 auto ExeFile = CmdLink->getOutputFilenames().front();
338 EXPECT_EQ("a.out", ExeFile);
339 }
340
TEST(ToolChainTest,PostCallback)341 TEST(ToolChainTest, PostCallback) {
342 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
343 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
344 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
345 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
346 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
347 new llvm::vfs::InMemoryFileSystem);
348
349 // The executable path must not exist.
350 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
351 "clang LLVM compiler", InMemoryFileSystem);
352 CCDriver.setCheckInputsExist(false);
353 std::unique_ptr<Compilation> CC(
354 CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"}));
355 bool CallbackHasCalled = false;
356 CC->setPostCallback(
357 [&](const Command &C, int Ret) { CallbackHasCalled = true; });
358 const JobList &Jobs = CC->getJobs();
359 auto &CmdCompile = Jobs.getJobs().front();
360 const Command *FailingCmd = nullptr;
361 CC->ExecuteCommand(*CmdCompile, FailingCmd);
362 EXPECT_TRUE(CallbackHasCalled);
363 }
364
TEST(GetDriverMode,PrefersLastDriverMode)365 TEST(GetDriverMode, PrefersLastDriverMode) {
366 static constexpr const char *Args[] = {"clang-cl", "--driver-mode=foo",
367 "--driver-mode=bar", "foo.cpp"};
368 EXPECT_EQ(getDriverMode(Args[0], llvm::makeArrayRef(Args).slice(1)), "bar");
369 }
370
371 struct SimpleDiagnosticConsumer : public DiagnosticConsumer {
HandleDiagnostic__anonb0d3f4420111::SimpleDiagnosticConsumer372 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
373 const Diagnostic &Info) override {
374 if (DiagLevel == DiagnosticsEngine::Level::Error) {
375 Errors.emplace_back();
376 Info.FormatDiagnostic(Errors.back());
377 } else {
378 Msgs.emplace_back();
379 Info.FormatDiagnostic(Msgs.back());
380 }
381 }
clear__anonb0d3f4420111::SimpleDiagnosticConsumer382 void clear() override {
383 Msgs.clear();
384 Errors.clear();
385 DiagnosticConsumer::clear();
386 }
387 std::vector<SmallString<32>> Msgs;
388 std::vector<SmallString<32>> Errors;
389 };
390
validateTargetProfile(StringRef TargetProfile,StringRef ExpectTriple,IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> & InMemoryFileSystem,DiagnosticsEngine & Diags)391 static void validateTargetProfile(
392 StringRef TargetProfile, StringRef ExpectTriple,
393 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> &InMemoryFileSystem,
394 DiagnosticsEngine &Diags) {
395 Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
396 std::unique_ptr<Compilation> C{TheDriver.BuildCompilation(
397 {"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl"})};
398 EXPECT_TRUE(C);
399 EXPECT_STREQ(TheDriver.getTargetTriple().c_str(), ExpectTriple.data());
400 EXPECT_EQ(Diags.getNumErrors(), 0u);
401 }
402
validateTargetProfile(StringRef TargetProfile,StringRef ExpectError,IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> & InMemoryFileSystem,DiagnosticsEngine & Diags,SimpleDiagnosticConsumer * DiagConsumer,unsigned NumOfErrors)403 static void validateTargetProfile(
404 StringRef TargetProfile, StringRef ExpectError,
405 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> &InMemoryFileSystem,
406 DiagnosticsEngine &Diags, SimpleDiagnosticConsumer *DiagConsumer,
407 unsigned NumOfErrors) {
408 Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
409 std::unique_ptr<Compilation> C{TheDriver.BuildCompilation(
410 {"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl"})};
411 EXPECT_TRUE(C);
412 EXPECT_EQ(Diags.getNumErrors(), NumOfErrors);
413 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), ExpectError.data());
414 Diags.Clear();
415 DiagConsumer->clear();
416 }
417
TEST(DxcModeTest,TargetProfileValidation)418 TEST(DxcModeTest, TargetProfileValidation) {
419 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
420
421 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
422 new llvm::vfs::InMemoryFileSystem);
423
424 InMemoryFileSystem->addFile("foo.hlsl", 0,
425 llvm::MemoryBuffer::getMemBuffer("\n"));
426
427 auto *DiagConsumer = new SimpleDiagnosticConsumer;
428 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
429 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
430
431 validateTargetProfile("-Tvs_6_0", "dxil--shadermodel6.0-vertex",
432 InMemoryFileSystem, Diags);
433 validateTargetProfile("-Ths_6_1", "dxil--shadermodel6.1-hull",
434 InMemoryFileSystem, Diags);
435 validateTargetProfile("-Tds_6_2", "dxil--shadermodel6.2-domain",
436 InMemoryFileSystem, Diags);
437 validateTargetProfile("-Tds_6_2", "dxil--shadermodel6.2-domain",
438 InMemoryFileSystem, Diags);
439 validateTargetProfile("-Tgs_6_3", "dxil--shadermodel6.3-geometry",
440 InMemoryFileSystem, Diags);
441 validateTargetProfile("-Tps_6_4", "dxil--shadermodel6.4-pixel",
442 InMemoryFileSystem, Diags);
443 validateTargetProfile("-Tcs_6_5", "dxil--shadermodel6.5-compute",
444 InMemoryFileSystem, Diags);
445 validateTargetProfile("-Tms_6_6", "dxil--shadermodel6.6-mesh",
446 InMemoryFileSystem, Diags);
447 validateTargetProfile("-Tas_6_7", "dxil--shadermodel6.7-amplification",
448 InMemoryFileSystem, Diags);
449 validateTargetProfile("-Tlib_6_x", "dxil--shadermodel6.15-library",
450 InMemoryFileSystem, Diags);
451
452 // Invalid tests.
453 validateTargetProfile("-Tpss_6_1", "invalid profile : pss_6_1",
454 InMemoryFileSystem, Diags, DiagConsumer, 1);
455
456 validateTargetProfile("-Tps_6_x", "invalid profile : ps_6_x",
457 InMemoryFileSystem, Diags, DiagConsumer, 2);
458 validateTargetProfile("-Tlib_6_1", "invalid profile : lib_6_1",
459 InMemoryFileSystem, Diags, DiagConsumer, 3);
460 validateTargetProfile("-Tfoo", "invalid profile : foo", InMemoryFileSystem,
461 Diags, DiagConsumer, 4);
462 validateTargetProfile("", "target profile option (-T) is missing",
463 InMemoryFileSystem, Diags, DiagConsumer, 5);
464 }
465
TEST(DxcModeTest,ValidatorVersionValidation)466 TEST(DxcModeTest, ValidatorVersionValidation) {
467 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
468
469 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
470 new llvm::vfs::InMemoryFileSystem);
471
472 InMemoryFileSystem->addFile("foo.hlsl", 0,
473 llvm::MemoryBuffer::getMemBuffer("\n"));
474
475 auto *DiagConsumer = new SimpleDiagnosticConsumer;
476 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
477 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
478 Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
479 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
480 {"clang", "--driver-mode=dxc", "-Tlib_6_7", "foo.hlsl"}));
481 EXPECT_TRUE(C);
482 EXPECT_TRUE(!C->containsError());
483
484 auto &TC = C->getDefaultToolChain();
485 bool ContainsError = false;
486 auto Args = TheDriver.ParseArgStrings({"-validator-version", "1.1"}, false,
487 ContainsError);
488 EXPECT_FALSE(ContainsError);
489 auto DAL = std::make_unique<llvm::opt::DerivedArgList>(Args);
490 for (auto *A : Args)
491 DAL->append(A);
492
493 std::unique_ptr<llvm::opt::DerivedArgList> TranslatedArgs{
494 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None)};
495 EXPECT_NE(TranslatedArgs, nullptr);
496 if (TranslatedArgs) {
497 auto *A = TranslatedArgs->getLastArg(
498 clang::driver::options::OPT_dxil_validator_version);
499 EXPECT_NE(A, nullptr);
500 if (A)
501 EXPECT_STREQ(A->getValue(), "1.1");
502 }
503 EXPECT_EQ(Diags.getNumErrors(), 0u);
504
505 // Invalid tests.
506 Args = TheDriver.ParseArgStrings({"-validator-version", "0.1"}, false,
507 ContainsError);
508 EXPECT_FALSE(ContainsError);
509 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args);
510 for (auto *A : Args)
511 DAL->append(A);
512
513 TranslatedArgs.reset(
514 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None));
515 EXPECT_EQ(Diags.getNumErrors(), 1u);
516 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(),
517 "invalid validator version : 0.1\nIf validator major version is "
518 "0, minor version must also be 0.");
519 Diags.Clear();
520 DiagConsumer->clear();
521
522 Args = TheDriver.ParseArgStrings({"-validator-version", "1"}, false,
523 ContainsError);
524 EXPECT_FALSE(ContainsError);
525 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args);
526 for (auto *A : Args)
527 DAL->append(A);
528
529 TranslatedArgs.reset(
530 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None));
531 EXPECT_EQ(Diags.getNumErrors(), 2u);
532 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(),
533 "invalid validator version : 1\nFormat of validator version is "
534 "\"<major>.<minor>\" (ex:\"1.4\").");
535 Diags.Clear();
536 DiagConsumer->clear();
537
538 Args = TheDriver.ParseArgStrings({"-validator-version", "-Tlib_6_7"}, false,
539 ContainsError);
540 EXPECT_FALSE(ContainsError);
541 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args);
542 for (auto *A : Args)
543 DAL->append(A);
544
545 TranslatedArgs.reset(
546 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None));
547 EXPECT_EQ(Diags.getNumErrors(), 3u);
548 EXPECT_STREQ(
549 DiagConsumer->Errors.back().c_str(),
550 "invalid validator version : -Tlib_6_7\nFormat of validator version is "
551 "\"<major>.<minor>\" (ex:\"1.4\").");
552 Diags.Clear();
553 DiagConsumer->clear();
554
555 Args = TheDriver.ParseArgStrings({"-validator-version", "foo"}, false,
556 ContainsError);
557 EXPECT_FALSE(ContainsError);
558 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args);
559 for (auto *A : Args)
560 DAL->append(A);
561
562 TranslatedArgs.reset(
563 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None));
564 EXPECT_EQ(Diags.getNumErrors(), 4u);
565 EXPECT_STREQ(
566 DiagConsumer->Errors.back().c_str(),
567 "invalid validator version : foo\nFormat of validator version is "
568 "\"<major>.<minor>\" (ex:\"1.4\").");
569 Diags.Clear();
570 DiagConsumer->clear();
571 }
572 } // end anonymous namespace.
573