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 "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"
23 using namespace clang::driver
;
24 using namespace clang
;
26 TEST(MultilibTest
, OpEqReflexivity1
) {
28 ASSERT_TRUE(M
== M
) << "Multilib::operator==() is not reflexive";
31 TEST(MultilibTest
, OpEqReflexivity2
) {
32 ASSERT_TRUE(Multilib() == Multilib())
33 << "Separately constructed default multilibs are not equal";
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";
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)";
50 TEST(MultilibTest
, OpEqInequivalence2
) {
52 Multilib
M2({}, {}, {}, {"+foo"});
53 ASSERT_FALSE(M1
== M2
) << "Flags make Multilibs different";
56 TEST(MultilibTest
, OpEqEquivalence2
) {
60 << "Constructor argument must match Multilib::gccSuffix()";
62 << "Constructor argument must match Multilib::gccSuffix() (commuted)";
65 TEST(MultilibTest
, OpEqEquivalence3
) {
66 Multilib
M1("", "/32");
67 Multilib
M2("", "/32");
69 << "Constructor argument must match Multilib::osSuffix()";
71 << "Constructor argument must match Multilib::osSuffix() (commuted)";
74 TEST(MultilibTest
, OpEqEquivalence4
) {
75 Multilib
M1("", "", "/16");
76 Multilib
M2("", "", "/16");
78 << "Constructor argument must match Multilib::includeSuffix()";
80 << "Constructor argument must match Multilib::includeSuffix() (commuted)";
83 TEST(MultilibTest
, OpEqInequivalence3
) {
86 ASSERT_FALSE(M1
== M2
) << "Differing gccSuffixes should be different";
87 ASSERT_FALSE(M2
== M1
)
88 << "Differing gccSuffixes should be different (commuted)";
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)";
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)";
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");
114 TEST(MultilibTest
, Construction2
) {
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)";
127 TEST(MultilibTest
, Construction3
) {
128 Multilib
M({}, {}, {}, {"+f1", "+f2", "-f3"});
129 for (Multilib::flags_list::const_iterator I
= M
.flags().begin(),
132 ASSERT_TRUE(llvm::StringSwitch
<bool>(*I
)
133 .Cases("+f1", "+f2", "-f3", true)
138 TEST(MultilibTest
, SetPushback
) {
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)
151 TEST(MultilibTest
, SetPriority
) {
153 Multilib("/foo", {}, {}, {"+foo"}),
154 Multilib("/bar", {}, {}, {"+bar"}),
156 Multilib::flags_list Flags1
= {"+foo", "-bar"};
157 llvm::SmallVector
<Multilib
> Selection1
;
158 ASSERT_TRUE(MS
.select(Flags1
, Selection1
))
159 << "Flag set was {\"+foo\"}, but selection not found";
160 ASSERT_TRUE(Selection1
.back().gccSuffix() == "/foo")
161 << "Selection picked " << Selection1
.back() << " which was not expected";
163 Multilib::flags_list Flags2
= {"+foo", "+bar"};
164 llvm::SmallVector
<Multilib
> Selection2
;
165 ASSERT_TRUE(MS
.select(Flags2
, Selection2
))
166 << "Flag set was {\"+bar\"}, but selection not found";
167 ASSERT_TRUE(Selection2
.back().gccSuffix() == "/bar")
168 << "Selection picked " << Selection2
.back() << " which was not expected";
171 TEST(MultilibTest
, SelectMultiple
) {
173 Multilib("/a", {}, {}, {"x"}),
174 Multilib("/b", {}, {}, {"y"}),
176 llvm::SmallVector
<Multilib
> Selection
;
178 ASSERT_TRUE(MS
.select({"x"}, Selection
));
179 ASSERT_EQ(1u, Selection
.size());
180 EXPECT_EQ("/a", Selection
[0].gccSuffix());
182 ASSERT_TRUE(MS
.select({"y"}, Selection
));
183 ASSERT_EQ(1u, Selection
.size());
184 EXPECT_EQ("/b", Selection
[0].gccSuffix());
186 ASSERT_TRUE(MS
.select({"y", "x"}, Selection
));
187 ASSERT_EQ(2u, Selection
.size());
188 EXPECT_EQ("/a", Selection
[0].gccSuffix());
189 EXPECT_EQ("/b", Selection
[1].gccSuffix());
192 static void diagnosticCallback(const llvm::SMDiagnostic
&D
, void *Out
) {
193 *reinterpret_cast<std::string
*>(Out
) = D
.getMessage();
196 static bool parseYaml(MultilibSet
&MS
, std::string
&Diagnostic
,
198 auto ErrorOrMS
= MultilibSet::parseYaml(llvm::MemoryBufferRef(Data
, "TEST"),
199 diagnosticCallback
, &Diagnostic
);
200 if (ErrorOrMS
.getError())
202 MS
= std::move(ErrorOrMS
.get());
206 static bool parseYaml(MultilibSet
&MS
, const char *Data
) {
207 auto ErrorOrMS
= MultilibSet::parseYaml(llvm::MemoryBufferRef(Data
, "TEST"));
208 if (ErrorOrMS
.getError())
210 MS
= std::move(ErrorOrMS
.get());
214 // When updating this version also update MultilibVersionCurrent in Multilib.cpp
215 #define YAML_PREAMBLE "MultilibVersion: 1.0\n"
217 TEST(MultilibTest
, ParseInvalid
) {
218 std::string Diagnostic
;
222 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, R
"(
226 StringRef(Diagnostic
).contains("missing required key 'MultilibVersion'"))
229 // Reject files with a different major version
230 EXPECT_FALSE(parseYaml(MS
, Diagnostic
,
236 StringRef(Diagnostic
).contains("multilib version 2.0 is unsupported"))
238 EXPECT_FALSE(parseYaml(MS
, Diagnostic
,
244 StringRef(Diagnostic
).contains("multilib version 0.1 is unsupported"))
247 // Reject files with a later minor version
248 EXPECT_FALSE(parseYaml(MS
, Diagnostic
,
254 StringRef(Diagnostic
).contains("multilib version 1.9 is unsupported"))
257 // Accept files with the same major version and the same or earlier minor
259 EXPECT_TRUE(parseYaml(MS
, Diagnostic
, R
"(
264 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE
));
265 EXPECT_TRUE(StringRef(Diagnostic
).contains("missing required key 'Variants'"))
268 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
273 EXPECT_TRUE(StringRef(Diagnostic
).contains("paths must be relative"))
276 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
280 EXPECT_TRUE(StringRef(Diagnostic
).contains("missing required key 'Dir'"))
283 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
287 EXPECT_TRUE(StringRef(Diagnostic
).contains("missing required key 'Flags'"))
290 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
295 EXPECT_TRUE(StringRef(Diagnostic
).contains("value required for 'Flags'"))
298 EXPECT_FALSE(parseYaml(MS
, Diagnostic
, YAML_PREAMBLE R
"(
305 EXPECT_TRUE(StringRef(Diagnostic
).contains("parentheses not balanced"))
309 TEST(MultilibTest
, Parse
) {
311 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
316 EXPECT_EQ(1U, MS
.size());
317 EXPECT_EQ("", MS
.begin()->gccSuffix());
319 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
324 EXPECT_EQ(1U, MS
.size());
325 EXPECT_EQ("/abc", MS
.begin()->gccSuffix());
327 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
330 Flags: [-mfloat-abi=soft]
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());
337 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
340 Flags: [-mfloat-abi=soft, -fno-exceptions]
342 EXPECT_EQ(1U, MS
.size());
343 EXPECT_EQ(std::vector
<std::string
>({"-mfloat-abi=soft", "-fno-exceptions"}),
344 MS
.begin()->flags());
346 EXPECT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
353 EXPECT_EQ(2U, MS
.size());
356 TEST(MultilibTest
, SelectSoft
) {
358 llvm::SmallVector
<Multilib
> Selected
;
359 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
362 Flags: [-mfloat-abi=soft]
364 - Match: -mfloat-abi=softfp
365 Flags: [-mfloat-abi=soft]
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
));
372 TEST(MultilibTest
, SelectSoftFP
) {
374 llvm::SmallVector
<Multilib
> Selected
;
375 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
378 Flags: [-mfloat-abi=softfp]
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
));
385 TEST(MultilibTest
, SelectHard
) {
386 // If hard float is all that's available then select that only if compiling
389 llvm::SmallVector
<Multilib
> Selected
;
390 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
393 Flags: [-mfloat-abi=hard]
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
));
400 TEST(MultilibTest
, SelectFloatABI
) {
402 llvm::SmallVector
<Multilib
> Selected
;
403 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
406 Flags: [-mfloat-abi=soft]
408 Flags: [-mfloat-abi=softfp]
410 Flags: [-mfloat-abi=hard]
412 - Match: -mfloat-abi=softfp
413 Flags: [-mfloat-abi=soft]
415 MS
.select({"-mfloat-abi=soft"}, Selected
);
416 EXPECT_EQ("/s", Selected
.back().gccSuffix());
417 MS
.select({"-mfloat-abi=softfp"}, Selected
);
418 EXPECT_EQ("/f", Selected
.back().gccSuffix());
419 MS
.select({"-mfloat-abi=hard"}, Selected
);
420 EXPECT_EQ("/h", Selected
.back().gccSuffix());
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.
427 llvm::SmallVector
<Multilib
> Selected
;
428 ASSERT_TRUE(parseYaml(MS
, YAML_PREAMBLE R
"(
431 Flags: [-mfloat-abi=hard]
433 Flags: [-mfloat-abi=softfp]
435 Flags: [-mfloat-abi=soft]
437 - Match: -mfloat-abi=softfp
438 Flags: [-mfloat-abi=soft]
440 MS
.select({"-mfloat-abi=soft"}, Selected
);
441 EXPECT_EQ("/s", Selected
.back().gccSuffix());
442 MS
.select({"-mfloat-abi=softfp"}, Selected
);
443 EXPECT_EQ("/s", Selected
.back().gccSuffix());
444 MS
.select({"-mfloat-abi=hard"}, Selected
);
445 EXPECT_EQ("/h", Selected
.back().gccSuffix());
448 TEST(MultilibTest
, SelectMClass
) {
449 const char *MultilibSpec
= YAML_PREAMBLE R
"(
451 - Dir: thumb/v6-m/nofp
452 Flags: [--target=thumbv6m-none-unknown-eabi, -mfpu=none]
454 - Dir: thumb/v7-m/nofp
455 Flags: [--target=thumbv7m-none-unknown-eabi, -mfpu=none]
457 - Dir: thumb/v7e-m/nofp
458 Flags: [--target=thumbv7em-none-unknown-eabi, -mfpu=none]
460 - Dir: thumb/v8-m.main/nofp
461 Flags: [--target=thumbv8m.main-none-unknown-eabi, -mfpu=none]
463 - Dir: thumb/v8.1-m.main/nofp/nomve
464 Flags: [--target=thumbv8.1m.main-none-unknown-eabi, -mfpu=none]
466 - Dir: thumb/v7e-m/fpv4_sp_d16
467 Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv4-sp-d16]
469 - Dir: thumb/v7e-m/fpv5_d16
470 Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv5-d16]
472 - Dir: thumb/v8-m.main/fp
473 Flags: [--target=thumbv8m.main-none-unknown-eabihf]
475 - Dir: thumb/v8.1-m.main/fp
476 Flags: [--target=thumbv8.1m.main-none-unknown-eabihf]
478 - Dir: thumb/v8.1-m.main/nofp/mve
479 Flags: [--target=thumbv8.1m.main-none-unknown-eabihf, -march=thumbv8.1m.main+mve]
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]
493 llvm::SmallVector
<Multilib
> Selected
;
494 ASSERT_TRUE(parseYaml(MS
, MultilibSpec
));
496 ASSERT_TRUE(MS
.select({"--target=thumbv6m-none-unknown-eabi", "-mfpu=none"},
498 EXPECT_EQ("/thumb/v6-m/nofp", Selected
.back().gccSuffix());
500 ASSERT_TRUE(MS
.select({"--target=thumbv7m-none-unknown-eabi", "-mfpu=none"},
502 EXPECT_EQ("/thumb/v7-m/nofp", Selected
.back().gccSuffix());
504 ASSERT_TRUE(MS
.select({"--target=thumbv7em-none-unknown-eabi", "-mfpu=none"},
506 EXPECT_EQ("/thumb/v7e-m/nofp", Selected
.back().gccSuffix());
508 ASSERT_TRUE(MS
.select(
509 {"--target=thumbv8m.main-none-unknown-eabi", "-mfpu=none"}, Selected
));
510 EXPECT_EQ("/thumb/v8-m.main/nofp", Selected
.back().gccSuffix());
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
.back().gccSuffix());
517 MS
.select({"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv4-sp-d16"},
519 EXPECT_EQ("/thumb/v7e-m/fpv4_sp_d16", Selected
.back().gccSuffix());
521 ASSERT_TRUE(MS
.select(
522 {"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv5-d16"}, Selected
));
523 EXPECT_EQ("/thumb/v7e-m/fpv5_d16", Selected
.back().gccSuffix());
526 MS
.select({"--target=thumbv8m.main-none-unknown-eabihf"}, Selected
));
527 EXPECT_EQ("/thumb/v8-m.main/fp", Selected
.back().gccSuffix());
530 MS
.select({"--target=thumbv8.1m.main-none-unknown-eabihf"}, Selected
));
531 EXPECT_EQ("/thumb/v8.1-m.main/fp", Selected
.back().gccSuffix());
533 ASSERT_TRUE(MS
.select({"--target=thumbv8.1m.main-none-unknown-eabihf",
534 "-mfpu=none", "-march=thumbv8.1m.main+dsp+mve"},
536 EXPECT_EQ("/thumb/v8.1-m.main/nofp/mve", Selected
.back().gccSuffix());