xref: /llvm-project/clang/unittests/Driver/MultilibTest.cpp (revision e0df221dcf5696c6e99952ee62a3b3b689433f3b)
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 "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"
23 
24 using namespace clang::driver;
25 using namespace clang;
26 
27 TEST(MultilibTest, OpEqReflexivity1) {
28   Multilib M;
29   ASSERT_TRUE(M == M) << "Multilib::operator==() is not reflexive";
30 }
31 
32 TEST(MultilibTest, OpEqReflexivity2) {
33   ASSERT_TRUE(Multilib() == Multilib())
34       << "Separately constructed default multilibs are not equal";
35 }
36 
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";
41 }
42 
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)";
49 }
50 
51 TEST(MultilibTest, OpEqInequivalence2) {
52   Multilib M1;
53   Multilib M2({}, {}, {}, {"+foo"});
54   ASSERT_FALSE(M1 == M2) << "Flags make Multilibs different";
55 }
56 
57 TEST(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 
66 TEST(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 
75 TEST(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 
84 TEST(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 
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)";
98 }
99 
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)";
106 }
107 
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");
113 }
114 
115 TEST(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 
128 TEST(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 
139 TEST(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 
152 TEST(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 
173 TEST(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 
195 static void diagnosticCallback(const llvm::SMDiagnostic &D, void *Out) {
196   *reinterpret_cast<std::string *>(Out) = D.getMessage();
197 }
198 
199 static 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 
209 static 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.cpp
218 #define YAML_PREAMBLE "MultilibVersion: 1.0\n"
219 
220 TEST(MultilibTest, ParseInvalid) {
221   std::string Diagnostic;
222 
223   MultilibSet MS;
224 
225   EXPECT_FALSE(parseYaml(MS, Diagnostic, R"(
226 Variants: []
227 )"));
228   EXPECT_TRUE(
229       StringRef(Diagnostic).contains("missing required key 'MultilibVersion'"))
230       << Diagnostic;
231 
232   // Reject files with a different major version
233   EXPECT_FALSE(parseYaml(MS, Diagnostic,
234                          R"(
235 MultilibVersion: 2.0
236 Variants: []
237 )"));
238   EXPECT_TRUE(
239       StringRef(Diagnostic).contains("multilib version 2.0 is unsupported"))
240       << Diagnostic;
241   EXPECT_FALSE(parseYaml(MS, Diagnostic,
242                          R"(
243 MultilibVersion: 0.1
244 Variants: []
245 )"));
246   EXPECT_TRUE(
247       StringRef(Diagnostic).contains("multilib version 0.1 is unsupported"))
248       << Diagnostic;
249 
250   // Reject files with a later minor version
251   EXPECT_FALSE(parseYaml(MS, Diagnostic,
252                          R"(
253 MultilibVersion: 1.9
254 Variants: []
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 minor
261   // version
262   EXPECT_TRUE(parseYaml(MS, Diagnostic, R"(
263 MultilibVersion: 1.0
264 Variants: []
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"(
272 Variants:
273 - Dir: /abc
274   Flags: []
275 )"));
276   EXPECT_TRUE(StringRef(Diagnostic).contains("paths must be relative"))
277       << Diagnostic;
278 
279   EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"(
280 Variants:
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"(
289 Variants:
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"(
296 Variants: []
297 Mappings:
298 - Match: abc
299 )"));
300   EXPECT_TRUE(StringRef(Diagnostic).contains("value required for 'Flags'"))
301       << Diagnostic;
302 
303   EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"(
304 Variants: []
305 Mappings:
306 - Dir: .
307   Match: '('
308   Flags: []
309 )"));
310   EXPECT_TRUE(StringRef(Diagnostic).contains("parentheses not balanced"))
311       << Diagnostic;
312 }
313 
314 TEST(MultilibTest, Parse) {
315   MultilibSet MS;
316   EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
317 Variants:
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"(
325 Variants:
326 - Dir: abc
327   Flags: []
328 )"));
329   EXPECT_EQ(1U, MS.size());
330   EXPECT_EQ("/abc", MS.begin()->gccSuffix());
331 
332   EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
333 Variants:
334 - Dir: pqr
335   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"(
343 Variants:
344 - Dir: pqr
345   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"(
352 Variants:
353 - Dir: a
354   Flags: []
355 - Dir: b
356   Flags: []
357 )"));
358   EXPECT_EQ(2U, MS.size());
359 }
360 
361 TEST(MultilibTest, SelectSoft) {
362   MultilibSet MS;
363   llvm::SmallVector<Multilib> Selected;
364   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
365 Variants:
366 - Dir: s
367   Flags: [-mfloat-abi=soft]
368 Mappings:
369 - Match: -mfloat-abi=softfp
370   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 
378 TEST(MultilibTest, SelectSoftFP) {
379   MultilibSet MS;
380   llvm::SmallVector<Multilib> Selected;
381   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
382 Variants:
383 - Dir: f
384   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 
392 TEST(MultilibTest, SelectHard) {
393   // If hard float is all that's available then select that only if compiling
394   // with hard float.
395   MultilibSet MS;
396   llvm::SmallVector<Multilib> Selected;
397   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
398 Variants:
399 - Dir: h
400   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 
408 TEST(MultilibTest, SelectFloatABI) {
409   MultilibSet MS;
410   llvm::SmallVector<Multilib> Selected;
411   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
412 Variants:
413 - Dir: s
414   Flags: [-mfloat-abi=soft]
415 - Dir: f
416   Flags: [-mfloat-abi=softfp]
417 - Dir: h
418   Flags: [-mfloat-abi=hard]
419 Mappings:
420 - Match: -mfloat-abi=softfp
421   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 
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.
435   MultilibSet MS;
436   llvm::SmallVector<Multilib> Selected;
437   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
438 Variants:
439 - Dir: h
440   Flags: [-mfloat-abi=hard]
441 - Dir: f
442   Flags: [-mfloat-abi=softfp]
443 - Dir: s
444   Flags: [-mfloat-abi=soft]
445 Mappings:
446 - Match: -mfloat-abi=softfp
447   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 
458 TEST(MultilibTest, SelectMClass) {
459   Driver TheDriver = diagnostic_test_driver();
460 
461   const char *MultilibSpec = YAML_PREAMBLE R"(
462 Variants:
463 - Dir: thumb/v6-m/nofp
464   Flags: [--target=thumbv6m-none-unknown-eabi, -mfpu=none]
465 
466 - Dir: thumb/v7-m/nofp
467   Flags: [--target=thumbv7m-none-unknown-eabi, -mfpu=none]
468 
469 - Dir: thumb/v7e-m/nofp
470   Flags: [--target=thumbv7em-none-unknown-eabi, -mfpu=none]
471 
472 - Dir: thumb/v8-m.main/nofp
473   Flags: [--target=thumbv8m.main-none-unknown-eabi, -mfpu=none]
474 
475 - Dir: thumb/v8.1-m.main/nofp/nomve
476   Flags: [--target=thumbv8.1m.main-none-unknown-eabi, -mfpu=none]
477 
478 - Dir: thumb/v7e-m/fpv4_sp_d16
479   Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv4-sp-d16]
480 
481 - Dir: thumb/v7e-m/fpv5_d16
482   Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv5-d16]
483 
484 - Dir: thumb/v8-m.main/fp
485   Flags: [--target=thumbv8m.main-none-unknown-eabihf]
486 
487 - Dir: thumb/v8.1-m.main/fp
488   Flags: [--target=thumbv8.1m.main-none-unknown-eabihf]
489 
490 - Dir: thumb/v8.1-m.main/nofp/mve
491   Flags: [--target=thumbv8.1m.main-none-unknown-eabihf, -march=thumbv8.1m.main+mve]
492 
493 Mappings:
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]
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