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