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 TEST(DxcModeTest, TargetProfileValidation) { 391 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 392 393 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 394 new llvm::vfs::InMemoryFileSystem); 395 396 InMemoryFileSystem->addFile("foo.hlsl", 0, 397 llvm::MemoryBuffer::getMemBuffer("\n")); 398 399 auto *DiagConsumer = new SimpleDiagnosticConsumer; 400 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 401 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer); 402 Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem); 403 std::unique_ptr<Compilation> C( 404 TheDriver.BuildCompilation({"clang", "--driver-mode=dxc", "foo.hlsl"})); 405 EXPECT_TRUE(C); 406 EXPECT_TRUE(!C->containsError()); 407 408 auto &TC = C->getDefaultToolChain(); 409 bool ContainsError = false; 410 auto Args = TheDriver.ParseArgStrings({"-Tvs_6_0"}, false, ContainsError); 411 EXPECT_FALSE(ContainsError); 412 auto Triple = TC.ComputeEffectiveClangTriple(Args); 413 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.0-vertex"); 414 EXPECT_EQ(Diags.getNumErrors(), 0u); 415 416 Args = TheDriver.ParseArgStrings({"-Ths_6_1"}, false, ContainsError); 417 EXPECT_FALSE(ContainsError); 418 Triple = TC.ComputeEffectiveClangTriple(Args); 419 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.1-hull"); 420 EXPECT_EQ(Diags.getNumErrors(), 0u); 421 422 Args = TheDriver.ParseArgStrings({"-Tds_6_2"}, false, ContainsError); 423 EXPECT_FALSE(ContainsError); 424 Triple = TC.ComputeEffectiveClangTriple(Args); 425 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.2-domain"); 426 EXPECT_EQ(Diags.getNumErrors(), 0u); 427 428 Args = TheDriver.ParseArgStrings({"-Tds_6_2"}, false, ContainsError); 429 EXPECT_FALSE(ContainsError); 430 Triple = TC.ComputeEffectiveClangTriple(Args); 431 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.2-domain"); 432 EXPECT_EQ(Diags.getNumErrors(), 0u); 433 434 Args = TheDriver.ParseArgStrings({"-Tgs_6_3"}, false, ContainsError); 435 EXPECT_FALSE(ContainsError); 436 Triple = TC.ComputeEffectiveClangTriple(Args); 437 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.3-geometry"); 438 EXPECT_EQ(Diags.getNumErrors(), 0u); 439 440 Args = TheDriver.ParseArgStrings({"-Tps_6_4"}, false, ContainsError); 441 EXPECT_FALSE(ContainsError); 442 Triple = TC.ComputeEffectiveClangTriple(Args); 443 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.4-pixel"); 444 EXPECT_EQ(Diags.getNumErrors(), 0u); 445 446 Args = TheDriver.ParseArgStrings({"-Tcs_6_5"}, false, ContainsError); 447 EXPECT_FALSE(ContainsError); 448 Triple = TC.ComputeEffectiveClangTriple(Args); 449 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.5-compute"); 450 EXPECT_EQ(Diags.getNumErrors(), 0u); 451 452 Args = TheDriver.ParseArgStrings({"-Tms_6_6"}, false, ContainsError); 453 EXPECT_FALSE(ContainsError); 454 Triple = TC.ComputeEffectiveClangTriple(Args); 455 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.6-mesh"); 456 EXPECT_EQ(Diags.getNumErrors(), 0u); 457 458 Args = TheDriver.ParseArgStrings({"-Tas_6_7"}, false, ContainsError); 459 EXPECT_FALSE(ContainsError); 460 Triple = TC.ComputeEffectiveClangTriple(Args); 461 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.7-amplification"); 462 EXPECT_EQ(Diags.getNumErrors(), 0u); 463 464 Args = TheDriver.ParseArgStrings({"-Tlib_6_x"}, false, ContainsError); 465 EXPECT_FALSE(ContainsError); 466 Triple = TC.ComputeEffectiveClangTriple(Args); 467 EXPECT_STREQ(Triple.c_str(), "dxil--shadermodel6.15-library"); 468 EXPECT_EQ(Diags.getNumErrors(), 0u); 469 470 // Invalid tests. 471 Args = TheDriver.ParseArgStrings({"-Tpss_6_1"}, false, ContainsError); 472 EXPECT_FALSE(ContainsError); 473 Triple = TC.ComputeEffectiveClangTriple(Args); 474 EXPECT_STREQ(Triple.c_str(), "unknown-unknown-shadermodel"); 475 EXPECT_EQ(Diags.getNumErrors(), 1u); 476 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), 477 "invalid profile : pss_6_1"); 478 Diags.Clear(); 479 DiagConsumer->clear(); 480 481 Args = TheDriver.ParseArgStrings({"-Tps_6_x"}, false, ContainsError); 482 EXPECT_FALSE(ContainsError); 483 Triple = TC.ComputeEffectiveClangTriple(Args); 484 EXPECT_STREQ(Triple.c_str(), "unknown-unknown-shadermodel"); 485 EXPECT_EQ(Diags.getNumErrors(), 2u); 486 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), "invalid profile : ps_6_x"); 487 Diags.Clear(); 488 DiagConsumer->clear(); 489 490 Args = TheDriver.ParseArgStrings({"-Tlib_6_1"}, false, ContainsError); 491 EXPECT_FALSE(ContainsError); 492 Triple = TC.ComputeEffectiveClangTriple(Args); 493 EXPECT_STREQ(Triple.c_str(), "unknown-unknown-shadermodel"); 494 EXPECT_EQ(Diags.getNumErrors(), 3u); 495 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), 496 "invalid profile : lib_6_1"); 497 Diags.Clear(); 498 DiagConsumer->clear(); 499 500 Args = TheDriver.ParseArgStrings({"-Tfoo"}, false, ContainsError); 501 EXPECT_FALSE(ContainsError); 502 Triple = TC.ComputeEffectiveClangTriple(Args); 503 EXPECT_STREQ(Triple.c_str(), "unknown-unknown-shadermodel"); 504 EXPECT_EQ(Diags.getNumErrors(), 4u); 505 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), "invalid profile : foo"); 506 Diags.Clear(); 507 DiagConsumer->clear(); 508 } 509 510 TEST(DxcModeTest, ValidatorVersionValidation) { 511 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 512 513 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 514 new llvm::vfs::InMemoryFileSystem); 515 516 InMemoryFileSystem->addFile("foo.hlsl", 0, 517 llvm::MemoryBuffer::getMemBuffer("\n")); 518 519 auto *DiagConsumer = new SimpleDiagnosticConsumer; 520 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 521 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer); 522 Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem); 523 std::unique_ptr<Compilation> C( 524 TheDriver.BuildCompilation({"clang", "--driver-mode=dxc", "foo.hlsl"})); 525 EXPECT_TRUE(C); 526 EXPECT_TRUE(!C->containsError()); 527 528 auto &TC = C->getDefaultToolChain(); 529 bool ContainsError = false; 530 auto Args = TheDriver.ParseArgStrings({"-validator-version", "1.1"}, false, 531 ContainsError); 532 EXPECT_FALSE(ContainsError); 533 auto DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 534 for (auto *A : Args) 535 DAL->append(A); 536 537 auto *TranslatedArgs = 538 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None); 539 EXPECT_NE(TranslatedArgs, nullptr); 540 if (TranslatedArgs) { 541 auto *A = TranslatedArgs->getLastArg( 542 clang::driver::options::OPT_dxil_validator_version); 543 EXPECT_NE(A, nullptr); 544 if (A) 545 EXPECT_STREQ(A->getValue(), "1.1"); 546 } 547 EXPECT_EQ(Diags.getNumErrors(), 0u); 548 549 // Invalid tests. 550 Args = TheDriver.ParseArgStrings({"-validator-version", "0.1"}, false, 551 ContainsError); 552 EXPECT_FALSE(ContainsError); 553 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 554 for (auto *A : Args) 555 DAL->append(A); 556 557 TranslatedArgs = TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None); 558 EXPECT_EQ(Diags.getNumErrors(), 1u); 559 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), 560 "invalid validator version : 0.1\nIf validator major version is " 561 "0, minor version must also be 0."); 562 Diags.Clear(); 563 DiagConsumer->clear(); 564 565 Args = TheDriver.ParseArgStrings({"-validator-version", "1"}, false, 566 ContainsError); 567 EXPECT_FALSE(ContainsError); 568 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 569 for (auto *A : Args) 570 DAL->append(A); 571 572 TranslatedArgs = TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None); 573 EXPECT_EQ(Diags.getNumErrors(), 2u); 574 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), 575 "invalid validator version : 1\nFormat of validator version is " 576 "\"<major>.<minor>\" (ex:\"1.4\")."); 577 Diags.Clear(); 578 DiagConsumer->clear(); 579 580 Args = TheDriver.ParseArgStrings({"-validator-version", "-Tlib_6_7"}, false, 581 ContainsError); 582 EXPECT_FALSE(ContainsError); 583 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 584 for (auto *A : Args) 585 DAL->append(A); 586 587 TranslatedArgs = TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None); 588 EXPECT_EQ(Diags.getNumErrors(), 3u); 589 EXPECT_STREQ( 590 DiagConsumer->Errors.back().c_str(), 591 "invalid validator version : -Tlib_6_7\nFormat of validator version is " 592 "\"<major>.<minor>\" (ex:\"1.4\")."); 593 Diags.Clear(); 594 DiagConsumer->clear(); 595 596 Args = TheDriver.ParseArgStrings({"-validator-version", "foo"}, false, 597 ContainsError); 598 EXPECT_FALSE(ContainsError); 599 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 600 for (auto *A : Args) 601 DAL->append(A); 602 603 TranslatedArgs = TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None); 604 EXPECT_EQ(Diags.getNumErrors(), 4u); 605 EXPECT_STREQ( 606 DiagConsumer->Errors.back().c_str(), 607 "invalid validator version : foo\nFormat of validator version is " 608 "\"<major>.<minor>\" (ex:\"1.4\")."); 609 Diags.Clear(); 610 DiagConsumer->clear(); 611 } 612 613 } // end anonymous namespace. 614