xref: /llvm-project/clang/unittests/Driver/MultilibTest.cpp (revision 4794bdab7aed92e699db29e031bfe71f4005326f)
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