Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / lib / InterfaceStub / IFSHandler.cpp
blobaa5817dceed54c804c037bb1317c1399d75b5f65
1 //===- IFSHandler.cpp -----------------------------------------------------===//
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 //===-----------------------------------------------------------------------===/
9 #include "llvm/InterfaceStub/IFSHandler.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/ADT/StringSwitch.h"
13 #include "llvm/BinaryFormat/ELF.h"
14 #include "llvm/InterfaceStub/IFSStub.h"
15 #include "llvm/Support/Error.h"
16 #include "llvm/Support/GlobPattern.h"
17 #include "llvm/Support/LineIterator.h"
18 #include "llvm/Support/YAMLTraits.h"
19 #include "llvm/TargetParser/Triple.h"
20 #include <functional>
21 #include <optional>
23 using namespace llvm;
24 using namespace llvm::ifs;
26 LLVM_YAML_IS_SEQUENCE_VECTOR(IFSSymbol)
28 namespace llvm {
29 namespace yaml {
31 /// YAML traits for ELFSymbolType.
32 template <> struct ScalarEnumerationTraits<IFSSymbolType> {
33 static void enumeration(IO &IO, IFSSymbolType &SymbolType) {
34 IO.enumCase(SymbolType, "NoType", IFSSymbolType::NoType);
35 IO.enumCase(SymbolType, "Func", IFSSymbolType::Func);
36 IO.enumCase(SymbolType, "Object", IFSSymbolType::Object);
37 IO.enumCase(SymbolType, "TLS", IFSSymbolType::TLS);
38 IO.enumCase(SymbolType, "Unknown", IFSSymbolType::Unknown);
39 // Treat other symbol types as noise, and map to Unknown.
40 if (!IO.outputting() && IO.matchEnumFallback())
41 SymbolType = IFSSymbolType::Unknown;
45 template <> struct ScalarTraits<IFSEndiannessType> {
46 static void output(const IFSEndiannessType &Value, void *,
47 llvm::raw_ostream &Out) {
48 switch (Value) {
49 case IFSEndiannessType::Big:
50 Out << "big";
51 break;
52 case IFSEndiannessType::Little:
53 Out << "little";
54 break;
55 default:
56 llvm_unreachable("Unsupported endianness");
60 static StringRef input(StringRef Scalar, void *, IFSEndiannessType &Value) {
61 Value = StringSwitch<IFSEndiannessType>(Scalar)
62 .Case("big", IFSEndiannessType::Big)
63 .Case("little", IFSEndiannessType::Little)
64 .Default(IFSEndiannessType::Unknown);
65 if (Value == IFSEndiannessType::Unknown) {
66 return "Unsupported endianness";
68 return StringRef();
71 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
74 template <> struct ScalarTraits<IFSBitWidthType> {
75 static void output(const IFSBitWidthType &Value, void *,
76 llvm::raw_ostream &Out) {
77 switch (Value) {
78 case IFSBitWidthType::IFS32:
79 Out << "32";
80 break;
81 case IFSBitWidthType::IFS64:
82 Out << "64";
83 break;
84 default:
85 llvm_unreachable("Unsupported bit width");
89 static StringRef input(StringRef Scalar, void *, IFSBitWidthType &Value) {
90 Value = StringSwitch<IFSBitWidthType>(Scalar)
91 .Case("32", IFSBitWidthType::IFS32)
92 .Case("64", IFSBitWidthType::IFS64)
93 .Default(IFSBitWidthType::Unknown);
94 if (Value == IFSBitWidthType::Unknown) {
95 return "Unsupported bit width";
97 return StringRef();
100 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
103 template <> struct MappingTraits<IFSTarget> {
104 static void mapping(IO &IO, IFSTarget &Target) {
105 IO.mapOptional("ObjectFormat", Target.ObjectFormat);
106 IO.mapOptional("Arch", Target.ArchString);
107 IO.mapOptional("Endianness", Target.Endianness);
108 IO.mapOptional("BitWidth", Target.BitWidth);
111 // Compacts symbol information into a single line.
112 static const bool flow = true; // NOLINT(readability-identifier-naming)
115 /// YAML traits for ELFSymbol.
116 template <> struct MappingTraits<IFSSymbol> {
117 static void mapping(IO &IO, IFSSymbol &Symbol) {
118 IO.mapRequired("Name", Symbol.Name);
119 IO.mapRequired("Type", Symbol.Type);
120 // The need for symbol size depends on the symbol type.
121 if (Symbol.Type == IFSSymbolType::NoType) {
122 // Size is None, so we are reading it in, or it is non 0 so we
123 // should emit it.
124 if (!Symbol.Size || *Symbol.Size)
125 IO.mapOptional("Size", Symbol.Size);
126 } else if (Symbol.Type != IFSSymbolType::Func) {
127 IO.mapOptional("Size", Symbol.Size);
129 IO.mapOptional("Undefined", Symbol.Undefined, false);
130 IO.mapOptional("Weak", Symbol.Weak, false);
131 IO.mapOptional("Warning", Symbol.Warning);
134 // Compacts symbol information into a single line.
135 static const bool flow = true; // NOLINT(readability-identifier-naming)
138 /// YAML traits for ELFStub objects.
139 template <> struct MappingTraits<IFSStub> {
140 static void mapping(IO &IO, IFSStub &Stub) {
141 if (!IO.mapTag("!ifs-v1", true))
142 IO.setError("Not a .tbe YAML file.");
143 IO.mapRequired("IfsVersion", Stub.IfsVersion);
144 IO.mapOptional("SoName", Stub.SoName);
145 IO.mapOptional("Target", Stub.Target);
146 IO.mapOptional("NeededLibs", Stub.NeededLibs);
147 IO.mapRequired("Symbols", Stub.Symbols);
151 /// YAML traits for ELFStubTriple objects.
152 template <> struct MappingTraits<IFSStubTriple> {
153 static void mapping(IO &IO, IFSStubTriple &Stub) {
154 if (!IO.mapTag("!ifs-v1", true))
155 IO.setError("Not a .tbe YAML file.");
156 IO.mapRequired("IfsVersion", Stub.IfsVersion);
157 IO.mapOptional("SoName", Stub.SoName);
158 IO.mapOptional("Target", Stub.Target.Triple);
159 IO.mapOptional("NeededLibs", Stub.NeededLibs);
160 IO.mapRequired("Symbols", Stub.Symbols);
163 } // end namespace yaml
164 } // end namespace llvm
166 /// Attempt to determine if a Text stub uses target triple.
167 bool usesTriple(StringRef Buf) {
168 for (line_iterator I(MemoryBufferRef(Buf, "ELFStub")); !I.is_at_eof(); ++I) {
169 StringRef Line = (*I).trim();
170 if (Line.startswith("Target:")) {
171 if (Line == "Target:" || Line.contains("{")) {
172 return false;
176 return true;
179 Expected<std::unique_ptr<IFSStub>> ifs::readIFSFromBuffer(StringRef Buf) {
180 yaml::Input YamlIn(Buf);
181 std::unique_ptr<IFSStubTriple> Stub(new IFSStubTriple());
182 if (usesTriple(Buf)) {
183 YamlIn >> *Stub;
184 } else {
185 YamlIn >> *static_cast<IFSStub *>(Stub.get());
187 if (std::error_code Err = YamlIn.error()) {
188 return createStringError(Err, "YAML failed reading as IFS");
191 if (Stub->IfsVersion > IFSVersionCurrent)
192 return make_error<StringError>(
193 "IFS version " + Stub->IfsVersion.getAsString() + " is unsupported.",
194 std::make_error_code(std::errc::invalid_argument));
195 if (Stub->Target.ArchString) {
196 uint16_t eMachine =
197 ELF::convertArchNameToEMachine(*Stub->Target.ArchString);
198 if (eMachine == ELF::EM_NONE)
199 return createStringError(
200 std::make_error_code(std::errc::invalid_argument),
201 "IFS arch '" + *Stub->Target.ArchString + "' is unsupported");
202 Stub->Target.Arch = eMachine;
204 return std::move(Stub);
207 Error ifs::writeIFSToOutputStream(raw_ostream &OS, const IFSStub &Stub) {
208 yaml::Output YamlOut(OS, nullptr, /*WrapColumn =*/0);
209 std::unique_ptr<IFSStubTriple> CopyStub(new IFSStubTriple(Stub));
210 if (Stub.Target.Arch) {
211 CopyStub->Target.ArchString =
212 std::string(ELF::convertEMachineToArchName(*Stub.Target.Arch));
214 IFSTarget Target = Stub.Target;
216 if (CopyStub->Target.Triple ||
217 (!CopyStub->Target.ArchString && !CopyStub->Target.Endianness &&
218 !CopyStub->Target.BitWidth))
219 YamlOut << *CopyStub;
220 else
221 YamlOut << *static_cast<IFSStub *>(CopyStub.get());
222 return Error::success();
225 Error ifs::overrideIFSTarget(
226 IFSStub &Stub, std::optional<IFSArch> OverrideArch,
227 std::optional<IFSEndiannessType> OverrideEndianness,
228 std::optional<IFSBitWidthType> OverrideBitWidth,
229 std::optional<std::string> OverrideTriple) {
230 std::error_code OverrideEC(1, std::generic_category());
231 if (OverrideArch) {
232 if (Stub.Target.Arch && *Stub.Target.Arch != *OverrideArch) {
233 return make_error<StringError>(
234 "Supplied Arch conflicts with the text stub", OverrideEC);
236 Stub.Target.Arch = *OverrideArch;
238 if (OverrideEndianness) {
239 if (Stub.Target.Endianness &&
240 *Stub.Target.Endianness != *OverrideEndianness) {
241 return make_error<StringError>(
242 "Supplied Endianness conflicts with the text stub", OverrideEC);
244 Stub.Target.Endianness = *OverrideEndianness;
246 if (OverrideBitWidth) {
247 if (Stub.Target.BitWidth && *Stub.Target.BitWidth != *OverrideBitWidth) {
248 return make_error<StringError>(
249 "Supplied BitWidth conflicts with the text stub", OverrideEC);
251 Stub.Target.BitWidth = *OverrideBitWidth;
253 if (OverrideTriple) {
254 if (Stub.Target.Triple && *Stub.Target.Triple != *OverrideTriple) {
255 return make_error<StringError>(
256 "Supplied Triple conflicts with the text stub", OverrideEC);
258 Stub.Target.Triple = *OverrideTriple;
260 return Error::success();
263 Error ifs::validateIFSTarget(IFSStub &Stub, bool ParseTriple) {
264 std::error_code ValidationEC(1, std::generic_category());
265 if (Stub.Target.Triple) {
266 if (Stub.Target.Arch || Stub.Target.BitWidth || Stub.Target.Endianness ||
267 Stub.Target.ObjectFormat) {
268 return make_error<StringError>(
269 "Target triple cannot be used simultaneously with ELF target format",
270 ValidationEC);
272 if (ParseTriple) {
273 IFSTarget TargetFromTriple = parseTriple(*Stub.Target.Triple);
274 Stub.Target.Arch = TargetFromTriple.Arch;
275 Stub.Target.BitWidth = TargetFromTriple.BitWidth;
276 Stub.Target.Endianness = TargetFromTriple.Endianness;
278 return Error::success();
280 if (!Stub.Target.Arch || !Stub.Target.BitWidth || !Stub.Target.Endianness) {
281 // TODO: unify the error message.
282 if (!Stub.Target.Arch) {
283 return make_error<StringError>("Arch is not defined in the text stub",
284 ValidationEC);
286 if (!Stub.Target.BitWidth) {
287 return make_error<StringError>("BitWidth is not defined in the text stub",
288 ValidationEC);
290 if (!Stub.Target.Endianness) {
291 return make_error<StringError>(
292 "Endianness is not defined in the text stub", ValidationEC);
295 return Error::success();
298 IFSTarget ifs::parseTriple(StringRef TripleStr) {
299 Triple IFSTriple(TripleStr);
300 IFSTarget RetTarget;
301 // TODO: Implement a Triple Arch enum to e_machine map.
302 switch (IFSTriple.getArch()) {
303 case Triple::ArchType::aarch64:
304 RetTarget.Arch = (IFSArch)ELF::EM_AARCH64;
305 break;
306 case Triple::ArchType::x86_64:
307 RetTarget.Arch = (IFSArch)ELF::EM_X86_64;
308 break;
309 case Triple::ArchType::riscv64:
310 RetTarget.Arch = (IFSArch)ELF::EM_RISCV;
311 break;
312 default:
313 RetTarget.Arch = (IFSArch)ELF::EM_NONE;
315 RetTarget.Endianness = IFSTriple.isLittleEndian() ? IFSEndiannessType::Little
316 : IFSEndiannessType::Big;
317 RetTarget.BitWidth =
318 IFSTriple.isArch64Bit() ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32;
319 return RetTarget;
322 void ifs::stripIFSTarget(IFSStub &Stub, bool StripTriple, bool StripArch,
323 bool StripEndianness, bool StripBitWidth) {
324 if (StripTriple || StripArch) {
325 Stub.Target.Arch.reset();
326 Stub.Target.ArchString.reset();
328 if (StripTriple || StripEndianness) {
329 Stub.Target.Endianness.reset();
331 if (StripTriple || StripBitWidth) {
332 Stub.Target.BitWidth.reset();
334 if (StripTriple) {
335 Stub.Target.Triple.reset();
337 if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) {
338 Stub.Target.ObjectFormat.reset();
342 Error ifs::filterIFSSyms(IFSStub &Stub, bool StripUndefined,
343 const std::vector<std::string> &Exclude) {
344 std::function<bool(const IFSSymbol &)> Filter = [](const IFSSymbol &) {
345 return false;
348 if (StripUndefined) {
349 Filter = [Filter](const IFSSymbol &Sym) {
350 return Sym.Undefined || Filter(Sym);
354 for (StringRef Glob : Exclude) {
355 Expected<llvm::GlobPattern> PatternOrErr = llvm::GlobPattern::create(Glob);
356 if (!PatternOrErr)
357 return PatternOrErr.takeError();
358 Filter = [Pattern = *PatternOrErr, Filter](const IFSSymbol &Sym) {
359 return Pattern.match(Sym.Name) || Filter(Sym);
363 llvm::erase_if(Stub.Symbols, Filter);
365 return Error::success();