Skip to content

Commit 1d394d0

Browse files
committed
[Multilib] Custom flags processing for library selection
Select library variants in the multilib system using the flags passed in the '-fmultilib-flag=' format. Multilib flags that were not passed in the command-line have their default value fed into the library selection mechanism. A warning is shown if the flag's value is invalid. The closest valid value is suggested (string edit distance). Details about this change can be found in this thread: https://discourse.llvm.org/t/rfc-multilib-custom-flags/81058
1 parent 0020798 commit 1d394d0

File tree

4 files changed

+139
-1
lines changed

4 files changed

+139
-1
lines changed

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ def err_drv_no_such_file_with_suggestion : Error<
1414
def err_drv_unsupported_opt : Error<"unsupported option '%0'">;
1515
def err_drv_unsupported_opt_with_suggestion : Error<
1616
"unsupported option '%0'; did you mean '%1'?">;
17+
def warn_drv_unsupported_opt_with_suggestion : Warning<
18+
"unsupported option '%0'; did you mean '%1'?">,
19+
InGroup<UnusedCommandLineArgument>;
1720
def err_drv_unsupported_opt_for_target : Error<
1821
"unsupported option '%0' for target '%1'">;
1922
def err_drv_unsupported_opt_for_language_mode : Error<

clang/include/clang/Driver/Multilib.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ class MultilibSet {
150150
const_iterator begin() const { return Multilibs.begin(); }
151151
const_iterator end() const { return Multilibs.end(); }
152152

153+
Multilib::flags_list
154+
processCustomFlags(const Driver &D, const Multilib::flags_list &Flags) const;
155+
153156
/// Select compatible variants, \returns false if none are compatible
154157
bool select(const Driver &D, const Multilib::flags_list &Flags,
155158
llvm::SmallVectorImpl<Multilib> &) const;

clang/lib/Driver/Multilib.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "clang/Basic/Version.h"
1212
#include "clang/Driver/Driver.h"
1313
#include "llvm/ADT/DenseSet.h"
14+
#include "llvm/ADT/SmallSet.h"
1415
#include "llvm/ADT/SmallString.h"
1516
#include "llvm/ADT/StringRef.h"
1617
#include "llvm/Support/Compiler.h"
@@ -96,9 +97,83 @@ MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
9697

9798
void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
9899

100+
static void WarnUnclaimedMultilibCustomFlags(
101+
const Driver &D, const SmallVector<StringRef> &UnclaimedCustomFlagValues,
102+
const SmallVector<MultilibSet::CustomFlagDeclaration> &CustomFlagDecls,
103+
const StringRef MultilibFlagOptionStr) {
104+
struct EditDistanceInfo {
105+
StringRef FlagValue;
106+
unsigned EditDistance;
107+
};
108+
109+
for (StringRef Unclaimed : UnclaimedCustomFlagValues) {
110+
std::optional<EditDistanceInfo> BestCandidate;
111+
for (const auto &Decl : CustomFlagDecls) {
112+
for (StringRef FlagValue : Decl.Values) {
113+
unsigned EditDistance =
114+
Unclaimed.edit_distance(FlagValue, /*AllowReplacements=*/false);
115+
if (!BestCandidate || EditDistance < BestCandidate->EditDistance) {
116+
BestCandidate = {std::move(FlagValue), EditDistance};
117+
}
118+
}
119+
}
120+
if (!BestCandidate)
121+
continue;
122+
D.Diag(clang::diag::warn_drv_unsupported_opt_with_suggestion)
123+
<< (MultilibFlagOptionStr + Unclaimed).str()
124+
<< (MultilibFlagOptionStr + BestCandidate->FlagValue).str();
125+
}
126+
}
127+
128+
Multilib::flags_list
129+
MultilibSet::processCustomFlags(const Driver &D,
130+
const Multilib::flags_list &Flags) const {
131+
Multilib::flags_list Result;
132+
constexpr StringRef MultilibFlagOptionStr = "-fmultilib-flag=";
133+
SmallVector<StringRef> CustomFlags;
134+
135+
for (StringRef Flag : Flags) {
136+
if (Flag.starts_with(MultilibFlagOptionStr))
137+
CustomFlags.push_back(std::move(Flag));
138+
else
139+
Result.push_back(Flag.str());
140+
}
141+
142+
SmallVector<StringRef> UnclaimedCustomFlagValues;
143+
llvm::SmallSet<StringRef, 8> TriggeredCustomFlagDecls;
144+
145+
for (StringRef Flag : llvm::reverse(CustomFlags)) {
146+
StringRef CustomFlagValue = Flag.drop_front(MultilibFlagOptionStr.size());
147+
bool Claimed = false;
148+
for (const CustomFlagDeclaration &Decl : CustomFlagDecls) {
149+
if (llvm::is_contained(Decl.Values, CustomFlagValue)) {
150+
Result.push_back(Flag.str());
151+
TriggeredCustomFlagDecls.insert(Decl.Name);
152+
Claimed = true;
153+
break;
154+
}
155+
}
156+
if (!Claimed) {
157+
UnclaimedCustomFlagValues.push_back(std::move(CustomFlagValue));
158+
}
159+
}
160+
161+
for (const CustomFlagDeclaration &Decl : CustomFlagDecls) {
162+
if (TriggeredCustomFlagDecls.contains(Decl.Name))
163+
continue;
164+
Result.push_back(MultilibFlagOptionStr.str() + Decl.DefaultValue);
165+
}
166+
167+
WarnUnclaimedMultilibCustomFlags(D, UnclaimedCustomFlagValues,
168+
CustomFlagDecls, MultilibFlagOptionStr);
169+
170+
return Result;
171+
}
172+
99173
bool MultilibSet::select(const Driver &D, const Multilib::flags_list &Flags,
100174
llvm::SmallVectorImpl<Multilib> &Selected) const {
101-
llvm::StringSet<> FlagSet(expandFlags(Flags));
175+
Multilib::flags_list FlagsWithCustom = processCustomFlags(D, Flags);
176+
llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom));
102177
Selected.clear();
103178

104179
// Decide which multilibs we're going to select at all.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# REQUIRES: shell
2+
# UNSUPPORTED: system-windows
3+
4+
# RUN: rm -rf %T/baremetal_multilib
5+
# RUN: mkdir -p %T/baremetal_multilib/bin
6+
# RUN: mkdir -p %T/baremetal_multilib/lib/clang-runtimes
7+
# RUN: ln -s %clang %T/baremetal_multilib/bin/clang
8+
# RUN: ln -s %s %T/baremetal_multilib/lib/clang-runtimes/multilib.yaml
9+
10+
# RUN: %T/baremetal_multilib/bin/clang -no-canonical-prefixes -x c %s -### -o %t.out 2>&1 \
11+
# RUN: --target=thumbv8m.main-none-eabi -mfpu=none --sysroot= \
12+
# RUN: | FileCheck -DSYSROOT=%T/baremetal_multilib --check-prefix=CHECK-DEFAULT %s
13+
14+
# CHECK-DEFAULT: "-cc1" "-triple" "thumbv8m.main-unknown-none-eabi"
15+
# CHECK-DEFAULT-SAME: "-internal-isystem" "[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/include"
16+
# CHECK-DEFAULT-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/lib"
17+
18+
# RUN: %T/baremetal_multilib/bin/clang -no-canonical-prefixes -x c %s -### -o %t.out 2>&1 \
19+
# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -fmultilib-flag=no-multithreaded --sysroot= \
20+
# RUN: | FileCheck -DSYSROOT=%T/baremetal_multilib --check-prefix=CHECK-NOMULTI %s
21+
22+
# CHECK-NOMULTI: "-cc1" "-triple" "thumbv8m.main-unknown-none-eabi"
23+
# CHECK-NOMULTI-SAME: "-internal-isystem" "[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/include"
24+
# CHECK-NOMULTI-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/lib"
25+
26+
# RUN: %T/baremetal_multilib/bin/clang -no-canonical-prefixes -x c %s -### -o %t.out 2>&1 \
27+
# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -fmultilib-flag=multithreaded --sysroot= \
28+
# RUN: | FileCheck -DSYSROOT=%T/baremetal_multilib --check-prefix=CHECK-MULTI %s
29+
30+
# CHECK-MULTI: "-cc1" "-triple" "thumbv8m.main-unknown-none-eabi"
31+
# CHECK-MULTI-SAME: "-internal-isystem" "[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/multithreaded/thumb/v8-m.main/nofp/include"
32+
# CHECK-MULTI-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/multithreaded/thumb/v8-m.main/nofp/lib"
33+
34+
# RUN: %T/baremetal_multilib/bin/clang -no-canonical-prefixes -x c %s -### -o %t.out 2>&1 \
35+
# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -fmultilib-flag=multi-threaded --sysroot= \
36+
# RUN: | FileCheck -DSYSROOT=%T/baremetal_multilib --check-prefix=CHECK-WARNING %s
37+
# CHECK-WARNING: warning: unsupported option '-fmultilib-flag=multi-threaded'; did you mean '-fmultilib-flag=multithreaded'?
38+
39+
---
40+
MultilibVersion: 1.0
41+
42+
Groups:
43+
- Name: stdlib
44+
Type: Exclusive
45+
46+
Variants:
47+
- Dir: arm-none-eabi/thumb/v8-m.main/nofp
48+
Flags: [--target=thumbv8m.main-unknown-none-eabi, -mfpu=none, -fmultilib-flag=no-multithreaded]
49+
Group: stdlib
50+
- Dir: arm-none-eabi/multithreaded/thumb/v8-m.main/nofp
51+
Flags: [--target=thumbv8m.main-unknown-none-eabi, -mfpu=none, -fmultilib-flag=multithreaded]
52+
Group: stdlib
53+
54+
Flags:
55+
- Name: multithreading
56+
Values: [no-multithreaded, multithreaded]
57+
Default: no-multithreaded

0 commit comments

Comments
 (0)