[RISCV] Fix mgather -> riscv.masked.strided.load combine not extending indices (...
[llvm-project.git] / llvm / lib / TextAPI / RecordsSlice.cpp
blob840fe1855da6a6c244a16a691b0711f47ed23cce
1 //===- RecordsSlice.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 //===----------------------------------------------------------------------===//
8 //
9 // Implements the Records Slice APIs.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/TextAPI/RecordsSlice.h"
14 #include "llvm/ADT/SetVector.h"
15 #include "llvm/TextAPI/Record.h"
16 #include "llvm/TextAPI/Symbol.h"
17 #include <utility>
19 using namespace llvm;
20 using namespace llvm::MachO;
22 Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
23 GlobalRecord::Kind GV, RecordLinkage Linkage) {
24 // Find a specific Record type to capture.
25 auto [APIName, SymKind] = parseSymbol(Name, Flags);
26 Name = APIName;
27 switch (SymKind) {
28 case SymbolKind::GlobalSymbol:
29 return addGlobal(Name, Linkage, GV, Flags);
30 case SymbolKind::ObjectiveCClass:
31 return addObjCInterface(Name, Linkage);
32 case SymbolKind::ObjectiveCClassEHType:
33 return addObjCInterface(Name, Linkage, /*HasEHType=*/true);
34 case SymbolKind::ObjectiveCInstanceVariable: {
35 auto [Super, IVar] = Name.split('.');
36 // Attempt to find super class.
37 ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super);
38 // If not found, create extension since there is no mapped class symbol.
39 if (Container == nullptr)
40 Container = addObjCCategory(Super, {});
41 return addObjCIVar(Container, IVar, Linkage);
45 llvm_unreachable("unexpected symbol kind when adding to Record Slice");
48 ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar,
49 StringRef Name) const {
50 StringRef Super = IsIVar ? Name.split('.').first : Name;
51 ObjCContainerRecord *Container = findObjCInterface(Super);
52 // Ivars can only exist with extensions, if they did not come from
53 // class.
54 if (Container == nullptr)
55 Container = findObjCCategory(Super, "");
56 return Container;
59 template <typename R, typename C = RecordMap<R>, typename K = StringRef>
60 R *findRecord(K Key, const C &Container) {
61 const auto *Record = Container.find(Key);
62 if (Record == Container.end())
63 return nullptr;
64 return Record->second.get();
67 GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
68 GlobalRecord::Kind GV) const {
69 auto *Record = findRecord<GlobalRecord>(Name, Globals);
70 if (!Record)
71 return nullptr;
73 switch (GV) {
74 case GlobalRecord::Kind::Variable: {
75 if (!Record->isVariable())
76 return nullptr;
77 break;
79 case GlobalRecord::Kind::Function: {
80 if (!Record->isFunction())
81 return nullptr;
82 break;
84 case GlobalRecord::Kind::Unknown:
85 return Record;
88 return Record;
91 ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
92 return findRecord<ObjCInterfaceRecord>(Name, Classes);
95 ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,
96 StringRef Category) const {
97 return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
98 Categories);
101 ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {
102 return findRecord<ObjCIVarRecord>(IVar, IVars);
105 ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,
106 StringRef Name) const {
107 // If scoped name, the name of the container is known.
108 if (IsScopedName) {
109 // IVar does not exist if there is not a container assigned to it.
110 auto *Container = findContainer(/*IsIVar=*/true, Name);
111 if (!Container)
112 return nullptr;
114 StringRef IVar = Name.substr(Name.find_first_of('.') + 1);
115 return Container->findObjCIVar(IVar);
118 // Otherwise traverse through containers and attempt to find IVar.
119 auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * {
120 for (const auto &[_, Container] : Records) {
121 if (auto *IVarR = Container->findObjCIVar(Name))
122 return IVarR;
124 return nullptr;
127 if (auto *IVarRecord = getIVar(Classes))
128 return IVarRecord;
130 return getIVar(Categories);
133 GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
134 GlobalRecord::Kind GV,
135 SymbolFlags Flags) {
136 if (GV == GlobalRecord::Kind::Function)
137 Flags |= SymbolFlags::Text;
138 else if (GV == GlobalRecord::Kind::Variable)
139 Flags |= SymbolFlags::Data;
141 Name = copyString(Name);
142 auto Result = Globals.insert({Name, nullptr});
143 if (Result.second)
144 Result.first->second =
145 std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV);
146 else {
147 updateLinkage(Result.first->second.get(), Linkage);
148 updateFlags(Result.first->second.get(), Flags);
150 return Result.first->second.get();
153 ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
154 RecordLinkage Linkage,
155 bool HasEHType) {
156 Name = copyString(Name);
157 auto Result = Classes.insert({Name, nullptr});
158 if (Result.second) {
159 Result.first->second =
160 std::make_unique<ObjCInterfaceRecord>(Name, Linkage, HasEHType);
161 } else {
162 // ObjC classes represent multiple symbols that could have competing
163 // linkages, in those cases assign the largest one.
164 if (Linkage >= RecordLinkage::Rexported)
165 updateLinkage(Result.first->second.get(), Linkage);
168 return Result.first->second.get();
170 SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
171 // Add Linkage properties into Flags.
172 switch (Linkage) {
173 case RecordLinkage::Rexported:
174 Flags |= SymbolFlags::Rexported;
175 return Flags;
176 case RecordLinkage::Undefined:
177 Flags |= SymbolFlags::Undefined;
178 return Flags;
179 default:
180 return Flags;
184 bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {
185 auto Result = Categories.insert({Name, Record});
186 return Result.second;
189 ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend,
190 StringRef Category) {
191 Category = copyString(Category);
193 // Add owning record first into record slice.
194 auto Result =
195 Categories.insert({std::make_pair(ClassToExtend, Category), nullptr});
196 if (Result.second)
197 Result.first->second =
198 std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category);
200 // Then add reference to it in in the class.
201 if (auto *ObjCClass = findObjCInterface(ClassToExtend))
202 ObjCClass->addObjCCategory(Result.first->second.get());
204 return Result.first->second.get();
207 std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const {
208 std::vector<ObjCIVarRecord *> Records;
209 llvm::for_each(IVars,
210 [&](auto &Record) { Records.push_back(Record.second.get()); });
211 return Records;
214 std::vector<ObjCCategoryRecord *>
215 ObjCInterfaceRecord::getObjCCategories() const {
216 std::vector<ObjCCategoryRecord *> Records;
217 llvm::for_each(Categories,
218 [&](auto &Record) { Records.push_back(Record.second); });
219 return Records;
222 ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar,
223 RecordLinkage Linkage) {
224 auto Result = IVars.insert({IVar, nullptr});
225 if (Result.second)
226 Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage);
227 return Result.first->second.get();
230 ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container,
231 StringRef Name,
232 RecordLinkage Linkage) {
233 Name = copyString(Name);
234 ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage);
235 updateLinkage(Record, Linkage);
236 return Record;
239 StringRef RecordsSlice::copyString(StringRef String) {
240 if (String.empty())
241 return {};
243 if (StringAllocator.identifyObject(String.data()))
244 return String;
246 void *Ptr = StringAllocator.Allocate(String.size(), 1);
247 memcpy(Ptr, String.data(), String.size());
248 return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
251 RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
252 if (!hasBinaryAttrs())
253 BA = std::make_unique<BinaryAttrs>();
254 return *BA;
257 void RecordsSlice::visit(RecordVisitor &V) const {
258 for (auto &G : Globals)
259 V.visitGlobal(*G.second);
260 for (auto &C : Classes)
261 V.visitObjCInterface(*C.second);
262 for (auto &Cat : Categories)
263 V.visitObjCCategory(*Cat.second);
266 static std::unique_ptr<InterfaceFile>
267 createInterfaceFile(const Records &Slices, StringRef InstallName) {
268 // Pickup symbols first.
269 auto Symbols = std::make_unique<SymbolSet>();
270 for (auto &S : Slices) {
271 if (S->empty())
272 continue;
273 auto &BA = S->getBinaryAttrs();
274 if (BA.InstallName != InstallName)
275 continue;
277 SymbolConverter Converter(Symbols.get(), S->getTarget(),
278 !BA.TwoLevelNamespace);
279 S->visit(Converter);
282 auto File = std::make_unique<InterfaceFile>(std::move(Symbols));
283 File->setInstallName(InstallName);
284 // Assign other attributes.
285 for (auto &S : Slices) {
286 if (S->empty())
287 continue;
288 auto &BA = S->getBinaryAttrs();
289 if (BA.InstallName != InstallName)
290 continue;
291 const Target &Targ = S->getTarget();
292 File->addTarget(Targ);
293 if (File->getFileType() == FileType::Invalid)
294 File->setFileType(BA.File);
295 if (BA.AppExtensionSafe && !File->isApplicationExtensionSafe())
296 File->setApplicationExtensionSafe();
297 if (BA.TwoLevelNamespace && !File->isTwoLevelNamespace())
298 File->setTwoLevelNamespace();
299 if (BA.OSLibNotForSharedCache && !File->isOSLibNotForSharedCache())
300 File->setOSLibNotForSharedCache();
301 if (File->getCurrentVersion().empty())
302 File->setCurrentVersion(BA.CurrentVersion);
303 if (File->getCompatibilityVersion().empty())
304 File->setCompatibilityVersion(BA.CompatVersion);
305 if (File->getSwiftABIVersion() == 0)
306 File->setSwiftABIVersion(BA.SwiftABI);
307 if (File->getPath().empty())
308 File->setPath(BA.Path);
309 if (!BA.ParentUmbrella.empty())
310 File->addParentUmbrella(Targ, BA.ParentUmbrella);
311 for (const auto &Client : BA.AllowableClients)
312 File->addAllowableClient(Client, Targ);
313 for (const auto &Lib : BA.RexportedLibraries)
314 File->addReexportedLibrary(Lib, Targ);
317 return File;
320 std::unique_ptr<InterfaceFile>
321 llvm::MachO::convertToInterfaceFile(const Records &Slices) {
322 std::unique_ptr<InterfaceFile> File;
323 if (Slices.empty())
324 return File;
326 SetVector<StringRef> InstallNames;
327 for (auto &S : Slices) {
328 auto Name = S->getBinaryAttrs().InstallName;
329 if (Name.empty())
330 continue;
331 InstallNames.insert(Name);
334 File = createInterfaceFile(Slices, *InstallNames.begin());
335 for (StringRef IN : llvm::drop_begin(InstallNames))
336 File->addDocument(createInterfaceFile(Slices, IN));
338 return File;