1 //===- unittests/Driver/MultilibTest.cpp --- Multilib tests ---------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Unit tests for Multilib and MultilibSet
11 //===----------------------------------------------------------------------===//
13 #include "clang/Driver/Multilib.h"
14 #include "../../lib/Driver/ToolChains/CommonArgs.h"
15 #include "SimpleDiagnosticConsumer.h"
16 #include "clang/Basic/LLVM.h"
17 #include "clang/Basic/Version.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"
24 using namespace clang::driver
;
25 using namespace clang
;
27 TEST(MultilibTest
, OpEqReflexivity1
) {
29 ASSERT_TRUE(M
== M
) << "Multilib::operator==() is not reflexive";
32 TEST(MultilibTest
, OpEqReflexivity2
) {
33 ASSERT_TRUE(Multilib() == Multilib())
34 << "Separately constructed default multilibs are not equal";
37 TEST(MultilibTest
, OpEqReflexivity3
) {
38 Multilib
M1({}, {}, {}, {"+foo"});
39 Multilib
M2({}, {}, {}, {"+foo"});
40 ASSERT_TRUE(M1
== M2
) << "Multilibs with the same flag should be the same";
43 TEST(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)";
51 TEST(MultilibTest
, OpEqInequivalence2
) {
53 Multilib
M2({}, {}, {}, {"+foo"});
54 ASSERT_FALSE(M1
== M2
) << "Flags make Multilibs different";
57 TEST(MultilibTest
, OpEqEquivalence2
) {
61 << "Constructor argument must match Multilib::gccSuffix()";
63 << "Constructor argument must match Multilib::gccSuffix() (commuted)";
66 TEST(MultilibTest
, OpEqEquivalence3
) {
67 Multilib
M1("", "/32");
68 Multilib
M2("", "/32");
70 << "Constructor argument must match Multilib::osSuffix()";
72 << "Constructor argument must match Multilib::osSuffix() (commuted)";
75 TEST(MultilibTest
, OpEqEquivalence4
) {
76 Multilib
M1("", "", "/16");
77 Multilib
M2("", "", "/16");
79 << "Constructor argument must match Multilib::includeSuffix()";
81 << "Constructor argument must match Multilib::includeSuffix() (commuted)";
84 TEST(MultilibTest
, OpEqInequivalence3
) {
87 ASSERT_FALSE(M1
== M2
) << "Differing gccSuffixes should be different";
88 ASSERT_FALSE(M2
== M1
)
89 << "Differing gccSuffixes should be different (commuted)";
92 TEST(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)";
100 TEST(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)";
108 TEST(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");
115 TEST(MultilibTest
, Construction2
) {
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)";
128 TEST(MultilibTest
, Construction3
) {
129 Multilib
M({}, {}, {}, {"+f1", "+f2", "-f3"});
130 for (Multilib::flags_list::const_iterator I
= M
.flags().begin(),
133 ASSERT_TRUE(llvm::StringSwitch
<bool>(*I
)
134 .Cases("+f1", "+f2", "-f3", true)
139 TEST(MultilibTest
, SetPushback
) {
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)
152 TEST(MultilibTest
, SetPriority
) {
154 Multilib("/foo", {}, {}, {"+foo"}),
155 Multilib("/bar", {}, {}, {"+bar"}),
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";
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";
173 TEST(MultilibTest
, SelectMultiple
) {
175 Multilib("/a", {}, {}, {"x"}),
176 Multilib("/b", {}, {}, {"y"}),
178 llvm::SmallVector
<Multilib
> Selection
;
179 Driver TheDriver
= diagnostic_test_driver();
181 ASSERT_TRUE(MS
.select(TheDriver
, {"x"}, Selection
));
182 ASSERT_EQ(1u, Selection
.size());
183 EXPECT_EQ("/a", Selection
[0].gccSuffix());
185 ASSERT_TRUE(MS
.select(TheDriver
, {"y"}, Selection
));
186 ASSERT_EQ(1u, Selection
.size());
187 EXPECT_EQ("/b", Selection
[0].gccSuffix());
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());
195 static void diagnosticCallback(const llvm::SMDiagnostic
&D
, void *Out
) {
196 *reinterpret_cast<std::string
*>(Out
) = D
.getMessage();
199 static bool parseYaml(MultilibSet
&MS
, std::string
&Diagnostic
,
201 auto ErrorOrMS
= MultilibSet::parseYaml(llvm::MemoryBufferRef(Data
, "TEST"),
202 diagnosticCallback
, &Diagnostic
);
203 if (ErrorOrMS
.getError())
205 MS
= std::move(ErrorOrMS
.get());
209 static bool parseYaml(MultilibSet
&MS
, const char *Data
) {
210 auto ErrorOrMS
= MultilibSet::parseYaml(llvm::MemoryBufferRef(Data
, "TEST"));
211 if (ErrorOrMS
.getError())
213 MS
= std::move(ErrorOrMS
.get());
217 // When updating this version also update MultilibVersionCurrent in Multilib.cpp
218 #define YAML_PREAMBLE "MultilibVersion: 1.0\n"
220 TEST(MultilibTest
, ParseInvalid
) {
221 std::string Diagnostic
;
225 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, R
"(
229 StringRef(Diagnostic
).contains("missing required key 'MultilibVersion'"))
232 // Reject files with a different major version
233 EXPECT_FALSE(parseYaml(MS
, Diagnostic
,
239 StringRef(Diagnostic
).contains("multilib version 2.0 is unsupported"))
241 EXPECT_FALSE(parseYaml(MS
, Diagnostic
,
247 StringRef(Diagnostic
).contains("multilib version 0.1 is unsupported"))
250 // Reject files with a later minor version
251 EXPECT_FALSE(parseYaml(MS
, Diagnostic
,
257 StringRef(Diagnostic
).contains("multilib version 1.9 is unsupported"))
260 // Accept files with the same major version and the same or earlier minor
262 EXPECT_TRUE(parseYaml(MS
, Diagnostic
, R
"(
267 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE
));
268 EXPECT_TRUE(StringRef(Diagnostic
).contains("missing required key 'Variants'"))
271 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
276 EXPECT_TRUE(StringRef(Diagnostic
).contains("paths must be relative"))
279 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
284 StringRef(Diagnostic
)
285 .contains("one of the 'Dir' and 'Error' keys must be specified"))
288 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
292 EXPECT_TRUE(StringRef(Diagnostic
).contains("missing required key 'Flags'"))
295 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
300 EXPECT_TRUE(StringRef(Diagnostic
).contains("value required for 'Flags'"))
303 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
310 EXPECT_TRUE(StringRef(Diagnostic
).contains("parentheses not balanced"))
314 TEST(MultilibTest
, Parse
) {
316 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
321 EXPECT_EQ(1U, MS
.size());
322 EXPECT_EQ("", MS
.begin()->gccSuffix());
324 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
329 EXPECT_EQ(1U, MS
.size());
330 EXPECT_EQ("/abc", MS
.begin()->gccSuffix());
332 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
335 Flags: [-mfloat-abi=soft]
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());
342 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
345 Flags: [-mfloat-abi=soft, -fno-exceptions]
347 EXPECT_EQ(1U, MS
.size());
348 EXPECT_EQ(std::vector
<std::string
>({"-mfloat-abi=soft", "-fno-exceptions"}),
349 MS
.begin()->flags());
351 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
358 EXPECT_EQ(2U, MS
.size());
361 TEST(MultilibTest
, SelectSoft
) {
363 llvm::SmallVector
<Multilib
> Selected
;
364 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
367 Flags: [-mfloat-abi=soft]
369 - Match: -mfloat-abi=softfp
370 Flags: [-mfloat-abi=soft]
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
));
378 TEST(MultilibTest
, SelectSoftFP
) {
380 llvm::SmallVector
<Multilib
> Selected
;
381 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
384 Flags: [-mfloat-abi=softfp]
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
));
392 TEST(MultilibTest
, SelectHard
) {
393 // If hard float is all that's available then select that only if compiling
396 llvm::SmallVector
<Multilib
> Selected
;
397 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
400 Flags: [-mfloat-abi=hard]
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
));
408 TEST(MultilibTest
, SelectFloatABI
) {
410 llvm::SmallVector
<Multilib
> Selected
;
411 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
414 Flags: [-mfloat-abi=soft]
416 Flags: [-mfloat-abi=softfp]
418 Flags: [-mfloat-abi=hard]
420 - Match: -mfloat-abi=softfp
421 Flags: [-mfloat-abi=soft]
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());
432 TEST(MultilibTest
, SelectFloatABIReversed
) {
433 // If soft is specified after softfp then softfp will never be
434 // selected because soft is compatible with softfp and last wins.
436 llvm::SmallVector
<Multilib
> Selected
;
437 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
440 Flags: [-mfloat-abi=hard]
442 Flags: [-mfloat-abi=softfp]
444 Flags: [-mfloat-abi=soft]
446 - Match: -mfloat-abi=softfp
447 Flags: [-mfloat-abi=soft]
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());
458 TEST(MultilibTest
, SelectMClass
) {
459 Driver TheDriver
= diagnostic_test_driver();
461 const char *MultilibSpec
= YAML_PREAMBLE R
"(
463 - Dir: thumb/v6-m/nofp
464 Flags: [--target=thumbv6m-none-unknown-eabi, -mfpu=none]
466 - Dir: thumb/v7-m/nofp
467 Flags: [--target=thumbv7m-none-unknown-eabi, -mfpu=none]
469 - Dir: thumb/v7e-m/nofp
470 Flags: [--target=thumbv7em-none-unknown-eabi, -mfpu=none]
472 - Dir: thumb/v8-m.main/nofp
473 Flags: [--target=thumbv8m.main-none-unknown-eabi, -mfpu=none]
475 - Dir: thumb/v8.1-m.main/nofp/nomve
476 Flags: [--target=thumbv8.1m.main-none-unknown-eabi, -mfpu=none]
478 - Dir: thumb/v7e-m/fpv4_sp_d16
479 Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv4-sp-d16]
481 - Dir: thumb/v7e-m/fpv5_d16
482 Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv5-d16]
484 - Dir: thumb/v8-m.main/fp
485 Flags: [--target=thumbv8m.main-none-unknown-eabihf]
487 - Dir: thumb/v8.1-m.main/fp
488 Flags: [--target=thumbv8.1m.main-none-unknown-eabihf]
490 - Dir: thumb/v8.1-m.main/nofp/mve
491 Flags: [--target=thumbv8.1m.main-none-unknown-eabihf, -march=thumbv8.1m.main+mve]
494 - Match: --target=thumbv8(\.[0-9]+)?m\.base-none-unknown-eabi
495 Flags: [--target=thumbv6m-none-unknown-eabi]
496 - Match: -target=thumbv8\.[1-9]m\.main-none-unknown-eabi
497 Flags: [--target=thumbv8.1m.main-none-unknown-eabi]
498 - Match: -target=thumbv8\.[1-9]m\.main-none-unknown-eabihf
499 Flags: [--target=thumbv8.1m.main-none-unknown-eabihf]
500 - Match: -march=thumbv8\.[1-9]m\.main.*\+mve($|\+).*
501 Flags: [-march=thumbv8.1m.main+mve]
505 llvm::SmallVector
<Multilib
> Selected
;
506 ASSERT_TRUE(parseYaml(MS
, MultilibSpec
));
508 ASSERT_TRUE(MS
.select(TheDriver
,
509 {"--target=thumbv6m-none-unknown-eabi", "-mfpu=none"},
511 EXPECT_EQ("/thumb/v6-m/nofp", Selected
.back().gccSuffix());
513 ASSERT_TRUE(MS
.select(TheDriver
,
514 {"--target=thumbv7m-none-unknown-eabi", "-mfpu=none"},
516 EXPECT_EQ("/thumb/v7-m/nofp", Selected
.back().gccSuffix());
518 ASSERT_TRUE(MS
.select(TheDriver
,
519 {"--target=thumbv7em-none-unknown-eabi", "-mfpu=none"},
521 EXPECT_EQ("/thumb/v7e-m/nofp", Selected
.back().gccSuffix());
523 ASSERT_TRUE(MS
.select(
524 TheDriver
, {"--target=thumbv8m.main-none-unknown-eabi", "-mfpu=none"},
526 EXPECT_EQ("/thumb/v8-m.main/nofp", Selected
.back().gccSuffix());
528 ASSERT_TRUE(MS
.select(
529 TheDriver
, {"--target=thumbv8.1m.main-none-unknown-eabi", "-mfpu=none"},
531 EXPECT_EQ("/thumb/v8.1-m.main/nofp/nomve", Selected
.back().gccSuffix());
535 {"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv4-sp-d16"},
537 EXPECT_EQ("/thumb/v7e-m/fpv4_sp_d16", Selected
.back().gccSuffix());
539 ASSERT_TRUE(MS
.select(
540 TheDriver
, {"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv5-d16"},
542 EXPECT_EQ("/thumb/v7e-m/fpv5_d16", Selected
.back().gccSuffix());
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());
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());
552 ASSERT_TRUE(MS
.select(TheDriver
,
553 {"--target=thumbv8.1m.main-none-unknown-eabihf",
554 "-mfpu=none", "-march=thumbv8.1m.main+dsp+mve"},
556 EXPECT_EQ("/thumb/v8.1-m.main/nofp/mve", Selected
.back().gccSuffix());