1 //===- unittests/Driver/MultilibTest.cpp --- Multilib 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 Multilib and MultilibSet 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Driver/Multilib.h" 14 #include "../../lib/Driver/ToolChains/CommonArgs.h" 15 #include "clang/Basic/LLVM.h" 16 #include "clang/Basic/Version.h" 17 #include "llvm/ADT/ArrayRef.h" 18 #include "llvm/ADT/StringRef.h" 19 #include "llvm/ADT/StringSwitch.h" 20 #include "llvm/Support/SourceMgr.h" 21 #include "gtest/gtest.h" 22 23 using namespace clang::driver; 24 using namespace clang; 25 26 TEST(MultilibTest, OpEqReflexivity1) { 27 Multilib M; 28 ASSERT_TRUE(M == M) << "Multilib::operator==() is not reflexive"; 29 } 30 31 TEST(MultilibTest, OpEqReflexivity2) { 32 ASSERT_TRUE(Multilib() == Multilib()) 33 << "Separately constructed default multilibs are not equal"; 34 } 35 36 TEST(MultilibTest, OpEqReflexivity3) { 37 Multilib M1({}, {}, {}, {"+foo"}); 38 Multilib M2({}, {}, {}, {"+foo"}); 39 ASSERT_TRUE(M1 == M2) << "Multilibs with the same flag should be the same"; 40 } 41 42 TEST(MultilibTest, OpEqInequivalence1) { 43 Multilib M1({}, {}, {}, {"+foo"}); 44 Multilib M2({}, {}, {}, {"-foo"}); 45 ASSERT_FALSE(M1 == M2) << "Multilibs with conflicting flags are not the same"; 46 ASSERT_FALSE(M2 == M1) 47 << "Multilibs with conflicting flags are not the same (commuted)"; 48 } 49 50 TEST(MultilibTest, OpEqInequivalence2) { 51 Multilib M1; 52 Multilib M2({}, {}, {}, {"+foo"}); 53 ASSERT_FALSE(M1 == M2) << "Flags make Multilibs different"; 54 } 55 56 TEST(MultilibTest, OpEqEquivalence2) { 57 Multilib M1("/64"); 58 Multilib M2("/64"); 59 ASSERT_TRUE(M1 == M2) 60 << "Constructor argument must match Multilib::gccSuffix()"; 61 ASSERT_TRUE(M2 == M1) 62 << "Constructor argument must match Multilib::gccSuffix() (commuted)"; 63 } 64 65 TEST(MultilibTest, OpEqEquivalence3) { 66 Multilib M1("", "/32"); 67 Multilib M2("", "/32"); 68 ASSERT_TRUE(M1 == M2) 69 << "Constructor argument must match Multilib::osSuffix()"; 70 ASSERT_TRUE(M2 == M1) 71 << "Constructor argument must match Multilib::osSuffix() (commuted)"; 72 } 73 74 TEST(MultilibTest, OpEqEquivalence4) { 75 Multilib M1("", "", "/16"); 76 Multilib M2("", "", "/16"); 77 ASSERT_TRUE(M1 == M2) 78 << "Constructor argument must match Multilib::includeSuffix()"; 79 ASSERT_TRUE(M2 == M1) 80 << "Constructor argument must match Multilib::includeSuffix() (commuted)"; 81 } 82 83 TEST(MultilibTest, OpEqInequivalence3) { 84 Multilib M1("/foo"); 85 Multilib M2("/bar"); 86 ASSERT_FALSE(M1 == M2) << "Differing gccSuffixes should be different"; 87 ASSERT_FALSE(M2 == M1) 88 << "Differing gccSuffixes should be different (commuted)"; 89 } 90 91 TEST(MultilibTest, OpEqInequivalence4) { 92 Multilib M1("", "/foo"); 93 Multilib M2("", "/bar"); 94 ASSERT_FALSE(M1 == M2) << "Differing osSuffixes should be different"; 95 ASSERT_FALSE(M2 == M1) 96 << "Differing osSuffixes should be different (commuted)"; 97 } 98 99 TEST(MultilibTest, OpEqInequivalence5) { 100 Multilib M1("", "", "/foo"); 101 Multilib M2("", "", "/bar"); 102 ASSERT_FALSE(M1 == M2) << "Differing includeSuffixes should be different"; 103 ASSERT_FALSE(M2 == M1) 104 << "Differing includeSuffixes should be different (commuted)"; 105 } 106 107 TEST(MultilibTest, Construction1) { 108 Multilib M("/gcc64", "/os64", "/inc64"); 109 ASSERT_TRUE(M.gccSuffix() == "/gcc64"); 110 ASSERT_TRUE(M.osSuffix() == "/os64"); 111 ASSERT_TRUE(M.includeSuffix() == "/inc64"); 112 } 113 114 TEST(MultilibTest, Construction2) { 115 Multilib M1; 116 Multilib M2(""); 117 Multilib M3("", ""); 118 Multilib M4("", "", ""); 119 ASSERT_TRUE(M1 == M2) 120 << "Default arguments to Multilib constructor broken (first argument)"; 121 ASSERT_TRUE(M1 == M3) 122 << "Default arguments to Multilib constructor broken (second argument)"; 123 ASSERT_TRUE(M1 == M4) 124 << "Default arguments to Multilib constructor broken (third argument)"; 125 } 126 127 TEST(MultilibTest, Construction3) { 128 Multilib M({}, {}, {}, {"+f1", "+f2", "-f3"}); 129 for (Multilib::flags_list::const_iterator I = M.flags().begin(), 130 E = M.flags().end(); 131 I != E; ++I) { 132 ASSERT_TRUE(llvm::StringSwitch<bool>(*I) 133 .Cases("+f1", "+f2", "-f3", true) 134 .Default(false)); 135 } 136 } 137 138 TEST(MultilibTest, SetPushback) { 139 MultilibSet MS({ 140 Multilib("/one"), 141 Multilib("/two"), 142 }); 143 ASSERT_TRUE(MS.size() == 2); 144 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { 145 ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) 146 .Cases("/one", "/two", true) 147 .Default(false)); 148 } 149 } 150 151 TEST(MultilibTest, SetPriority) { 152 MultilibSet MS({ 153 Multilib("/foo", {}, {}, {"+foo"}), 154 Multilib("/bar", {}, {}, {"+bar"}), 155 }); 156 Multilib::flags_list Flags1 = {"+foo", "-bar"}; 157 Multilib Selection1; 158 ASSERT_TRUE(MS.select(Flags1, Selection1)) 159 << "Flag set was {\"+foo\"}, but selection not found"; 160 ASSERT_TRUE(Selection1.gccSuffix() == "/foo") 161 << "Selection picked " << Selection1 << " which was not expected"; 162 163 Multilib::flags_list Flags2 = {"+foo", "+bar"}; 164 Multilib Selection2; 165 ASSERT_TRUE(MS.select(Flags2, Selection2)) 166 << "Flag set was {\"+bar\"}, but selection not found"; 167 ASSERT_TRUE(Selection2.gccSuffix() == "/bar") 168 << "Selection picked " << Selection2 << " which was not expected"; 169 } 170 171 TEST(MultilibTest, SelectMultiple) { 172 MultilibSet MS({ 173 Multilib("/a", {}, {}, {"x"}), 174 Multilib("/b", {}, {}, {"y"}), 175 }); 176 std::vector<Multilib> Selection; 177 178 Selection = MS.select({"x"}); 179 ASSERT_EQ(1u, Selection.size()); 180 EXPECT_EQ("/a", Selection[0].gccSuffix()); 181 182 Selection = MS.select({"y"}); 183 ASSERT_EQ(1u, Selection.size()); 184 EXPECT_EQ("/b", Selection[0].gccSuffix()); 185 186 Selection = MS.select({"y", "x"}); 187 ASSERT_EQ(2u, Selection.size()); 188 EXPECT_EQ("/a", Selection[0].gccSuffix()); 189 EXPECT_EQ("/b", Selection[1].gccSuffix()); 190 } 191 192 static void diagnosticCallback(const llvm::SMDiagnostic &D, void *Out) { 193 *reinterpret_cast<std::string *>(Out) = D.getMessage(); 194 } 195 196 static bool parseYaml(MultilibSet &MS, std::string &Diagnostic, 197 const char *Data) { 198 auto ErrorOrMS = MultilibSet::parseYaml(llvm::MemoryBufferRef(Data, "TEST"), 199 diagnosticCallback, &Diagnostic); 200 if (ErrorOrMS.getError()) 201 return false; 202 MS = std::move(ErrorOrMS.get()); 203 return true; 204 } 205 206 static bool parseYaml(MultilibSet &MS, const char *Data) { 207 auto ErrorOrMS = MultilibSet::parseYaml(llvm::MemoryBufferRef(Data, "TEST")); 208 if (ErrorOrMS.getError()) 209 return false; 210 MS = std::move(ErrorOrMS.get()); 211 return true; 212 } 213 214 // When updating this version also update MultilibVersionCurrent in Multilib.cpp 215 #define YAML_PREAMBLE "MultilibVersion: 1.0\n" 216 217 TEST(MultilibTest, ParseInvalid) { 218 std::string Diagnostic; 219 220 MultilibSet MS; 221 222 EXPECT_FALSE(parseYaml(MS, Diagnostic, R"( 223 Variants: [] 224 )")); 225 EXPECT_TRUE( 226 StringRef(Diagnostic).contains("missing required key 'MultilibVersion'")) 227 << Diagnostic; 228 229 // Reject files with a different major version 230 EXPECT_FALSE(parseYaml(MS, Diagnostic, 231 R"( 232 MultilibVersion: 2.0 233 Variants: [] 234 )")); 235 EXPECT_TRUE( 236 StringRef(Diagnostic).contains("multilib version 2.0 is unsupported")) 237 << Diagnostic; 238 EXPECT_FALSE(parseYaml(MS, Diagnostic, 239 R"( 240 MultilibVersion: 0.1 241 Variants: [] 242 )")); 243 EXPECT_TRUE( 244 StringRef(Diagnostic).contains("multilib version 0.1 is unsupported")) 245 << Diagnostic; 246 247 // Reject files with a later minor version 248 EXPECT_FALSE(parseYaml(MS, Diagnostic, 249 R"( 250 MultilibVersion: 1.9 251 Variants: [] 252 )")); 253 EXPECT_TRUE( 254 StringRef(Diagnostic).contains("multilib version 1.9 is unsupported")) 255 << Diagnostic; 256 257 // Accept files with the same major version and the same or earlier minor 258 // version 259 EXPECT_TRUE(parseYaml(MS, Diagnostic, R"( 260 MultilibVersion: 1.0 261 Variants: [] 262 )")) << Diagnostic; 263 264 EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE)); 265 EXPECT_TRUE(StringRef(Diagnostic).contains("missing required key 'Variants'")) 266 << Diagnostic; 267 268 EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"( 269 Variants: 270 - Dir: /abc 271 Flags: [] 272 )")); 273 EXPECT_TRUE(StringRef(Diagnostic).contains("paths must be relative")) 274 << Diagnostic; 275 276 EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"( 277 Variants: 278 - Flags: [] 279 )")); 280 EXPECT_TRUE(StringRef(Diagnostic).contains("missing required key 'Dir'")) 281 << Diagnostic; 282 283 EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"( 284 Variants: 285 - Dir: . 286 )")); 287 EXPECT_TRUE(StringRef(Diagnostic).contains("missing required key 'Flags'")) 288 << Diagnostic; 289 290 EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"( 291 Variants: [] 292 Mappings: 293 - Match: abc 294 )")); 295 EXPECT_TRUE(StringRef(Diagnostic).contains("value required for 'Flags'")) 296 << Diagnostic; 297 298 EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"( 299 Variants: [] 300 Mappings: 301 - Dir: . 302 Match: '(' 303 Flags: [] 304 )")); 305 EXPECT_TRUE(StringRef(Diagnostic).contains("parentheses not balanced")) 306 << Diagnostic; 307 } 308 309 TEST(MultilibTest, Parse) { 310 MultilibSet MS; 311 EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 312 Variants: 313 - Dir: . 314 Flags: [] 315 )")); 316 EXPECT_EQ(1U, MS.size()); 317 EXPECT_EQ("", MS.begin()->gccSuffix()); 318 319 EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 320 Variants: 321 - Dir: abc 322 Flags: [] 323 )")); 324 EXPECT_EQ(1U, MS.size()); 325 EXPECT_EQ("/abc", MS.begin()->gccSuffix()); 326 327 EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 328 Variants: 329 - Dir: pqr 330 Flags: [-mfloat-abi=soft] 331 )")); 332 EXPECT_EQ(1U, MS.size()); 333 EXPECT_EQ("/pqr", MS.begin()->gccSuffix()); 334 EXPECT_EQ(std::vector<std::string>({"-mfloat-abi=soft"}), 335 MS.begin()->flags()); 336 337 EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 338 Variants: 339 - Dir: pqr 340 Flags: [-mfloat-abi=soft, -fno-exceptions] 341 )")); 342 EXPECT_EQ(1U, MS.size()); 343 EXPECT_EQ(std::vector<std::string>({"-mfloat-abi=soft", "-fno-exceptions"}), 344 MS.begin()->flags()); 345 346 EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 347 Variants: 348 - Dir: a 349 Flags: [] 350 - Dir: b 351 Flags: [] 352 )")); 353 EXPECT_EQ(2U, MS.size()); 354 } 355 356 TEST(MultilibTest, SelectSoft) { 357 MultilibSet MS; 358 Multilib Selected; 359 ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 360 Variants: 361 - Dir: s 362 Flags: [-mfloat-abi=soft] 363 Mappings: 364 - Match: -mfloat-abi=softfp 365 Flags: [-mfloat-abi=soft] 366 )")); 367 EXPECT_TRUE(MS.select({"-mfloat-abi=soft"}, Selected)); 368 EXPECT_TRUE(MS.select({"-mfloat-abi=softfp"}, Selected)); 369 EXPECT_FALSE(MS.select({"-mfloat-abi=hard"}, Selected)); 370 } 371 372 TEST(MultilibTest, SelectSoftFP) { 373 MultilibSet MS; 374 Multilib Selected; 375 ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 376 Variants: 377 - Dir: f 378 Flags: [-mfloat-abi=softfp] 379 )")); 380 EXPECT_FALSE(MS.select({"-mfloat-abi=soft"}, Selected)); 381 EXPECT_TRUE(MS.select({"-mfloat-abi=softfp"}, Selected)); 382 EXPECT_FALSE(MS.select({"-mfloat-abi=hard"}, Selected)); 383 } 384 385 TEST(MultilibTest, SelectHard) { 386 // If hard float is all that's available then select that only if compiling 387 // with hard float. 388 MultilibSet MS; 389 Multilib Selected; 390 ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 391 Variants: 392 - Dir: h 393 Flags: [-mfloat-abi=hard] 394 )")); 395 EXPECT_FALSE(MS.select({"-mfloat-abi=soft"}, Selected)); 396 EXPECT_FALSE(MS.select({"-mfloat-abi=softfp"}, Selected)); 397 EXPECT_TRUE(MS.select({"-mfloat-abi=hard"}, Selected)); 398 } 399 400 TEST(MultilibTest, SelectFloatABI) { 401 MultilibSet MS; 402 Multilib Selected; 403 ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 404 Variants: 405 - Dir: s 406 Flags: [-mfloat-abi=soft] 407 - Dir: f 408 Flags: [-mfloat-abi=softfp] 409 - Dir: h 410 Flags: [-mfloat-abi=hard] 411 Mappings: 412 - Match: -mfloat-abi=softfp 413 Flags: [-mfloat-abi=soft] 414 )")); 415 MS.select({"-mfloat-abi=soft"}, Selected); 416 EXPECT_EQ("/s", Selected.gccSuffix()); 417 MS.select({"-mfloat-abi=softfp"}, Selected); 418 EXPECT_EQ("/f", Selected.gccSuffix()); 419 MS.select({"-mfloat-abi=hard"}, Selected); 420 EXPECT_EQ("/h", Selected.gccSuffix()); 421 } 422 423 TEST(MultilibTest, SelectFloatABIReversed) { 424 // If soft is specified after softfp then softfp will never be 425 // selected because soft is compatible with softfp and last wins. 426 MultilibSet MS; 427 Multilib Selected; 428 ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"( 429 Variants: 430 - Dir: h 431 Flags: [-mfloat-abi=hard] 432 - Dir: f 433 Flags: [-mfloat-abi=softfp] 434 - Dir: s 435 Flags: [-mfloat-abi=soft] 436 Mappings: 437 - Match: -mfloat-abi=softfp 438 Flags: [-mfloat-abi=soft] 439 )")); 440 MS.select({"-mfloat-abi=soft"}, Selected); 441 EXPECT_EQ("/s", Selected.gccSuffix()); 442 MS.select({"-mfloat-abi=softfp"}, Selected); 443 EXPECT_EQ("/s", Selected.gccSuffix()); 444 MS.select({"-mfloat-abi=hard"}, Selected); 445 EXPECT_EQ("/h", Selected.gccSuffix()); 446 } 447 448 TEST(MultilibTest, SelectMClass) { 449 const char *MultilibSpec = YAML_PREAMBLE R"( 450 Variants: 451 - Dir: thumb/v6-m/nofp 452 Flags: [--target=thumbv6m-none-unknown-eabi, -mfpu=none] 453 454 - Dir: thumb/v7-m/nofp 455 Flags: [--target=thumbv7m-none-unknown-eabi, -mfpu=none] 456 457 - Dir: thumb/v7e-m/nofp 458 Flags: [--target=thumbv7em-none-unknown-eabi, -mfpu=none] 459 460 - Dir: thumb/v8-m.main/nofp 461 Flags: [--target=thumbv8m.main-none-unknown-eabi, -mfpu=none] 462 463 - Dir: thumb/v8.1-m.main/nofp/nomve 464 Flags: [--target=thumbv8.1m.main-none-unknown-eabi, -mfpu=none] 465 466 - Dir: thumb/v7e-m/fpv4_sp_d16 467 Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv4-sp-d16] 468 469 - Dir: thumb/v7e-m/fpv5_d16 470 Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv5-d16] 471 472 - Dir: thumb/v8-m.main/fp 473 Flags: [--target=thumbv8m.main-none-unknown-eabihf] 474 475 - Dir: thumb/v8.1-m.main/fp 476 Flags: [--target=thumbv8.1m.main-none-unknown-eabihf] 477 478 - Dir: thumb/v8.1-m.main/nofp/mve 479 Flags: [--target=thumbv8.1m.main-none-unknown-eabihf, -march=thumbv8.1m.main+mve] 480 481 Mappings: 482 - Match: --target=thumbv8(\.[0-9]+)?m\.base-none-unknown-eabi 483 Flags: [--target=thumbv6m-none-unknown-eabi] 484 - Match: -target=thumbv8\.[1-9]m\.main-none-unknown-eabi 485 Flags: [--target=thumbv8.1m.main-none-unknown-eabi] 486 - Match: -target=thumbv8\.[1-9]m\.main-none-unknown-eabihf 487 Flags: [--target=thumbv8.1m.main-none-unknown-eabihf] 488 - Match: -march=thumbv8\.[1-9]m\.main.*\+mve($|\+).* 489 Flags: [-march=thumbv8.1m.main+mve] 490 )"; 491 492 MultilibSet MS; 493 Multilib Selected; 494 ASSERT_TRUE(parseYaml(MS, MultilibSpec)); 495 496 ASSERT_TRUE(MS.select({"--target=thumbv6m-none-unknown-eabi", "-mfpu=none"}, 497 Selected)); 498 EXPECT_EQ("/thumb/v6-m/nofp", Selected.gccSuffix()); 499 500 ASSERT_TRUE(MS.select({"--target=thumbv7m-none-unknown-eabi", "-mfpu=none"}, 501 Selected)); 502 EXPECT_EQ("/thumb/v7-m/nofp", Selected.gccSuffix()); 503 504 ASSERT_TRUE(MS.select({"--target=thumbv7em-none-unknown-eabi", "-mfpu=none"}, 505 Selected)); 506 EXPECT_EQ("/thumb/v7e-m/nofp", Selected.gccSuffix()); 507 508 ASSERT_TRUE(MS.select( 509 {"--target=thumbv8m.main-none-unknown-eabi", "-mfpu=none"}, Selected)); 510 EXPECT_EQ("/thumb/v8-m.main/nofp", Selected.gccSuffix()); 511 512 ASSERT_TRUE(MS.select( 513 {"--target=thumbv8.1m.main-none-unknown-eabi", "-mfpu=none"}, Selected)); 514 EXPECT_EQ("/thumb/v8.1-m.main/nofp/nomve", Selected.gccSuffix()); 515 516 ASSERT_TRUE( 517 MS.select({"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv4-sp-d16"}, 518 Selected)); 519 EXPECT_EQ("/thumb/v7e-m/fpv4_sp_d16", Selected.gccSuffix()); 520 521 ASSERT_TRUE(MS.select( 522 {"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv5-d16"}, Selected)); 523 EXPECT_EQ("/thumb/v7e-m/fpv5_d16", Selected.gccSuffix()); 524 525 ASSERT_TRUE( 526 MS.select({"--target=thumbv8m.main-none-unknown-eabihf"}, Selected)); 527 EXPECT_EQ("/thumb/v8-m.main/fp", Selected.gccSuffix()); 528 529 ASSERT_TRUE( 530 MS.select({"--target=thumbv8.1m.main-none-unknown-eabihf"}, Selected)); 531 EXPECT_EQ("/thumb/v8.1-m.main/fp", Selected.gccSuffix()); 532 533 ASSERT_TRUE(MS.select({"--target=thumbv8.1m.main-none-unknown-eabihf", 534 "-mfpu=none", "-march=thumbv8.1m.main+dsp+mve"}, 535 Selected)); 536 EXPECT_EQ("/thumb/v8.1-m.main/nofp/mve", Selected.gccSuffix()); 537 } 538