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