1276989f5SEric Christopher //===-- RecordStreamer.cpp - Record asm defined and used symbols ----------===//
213b69d63SRafael Espindola //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
613b69d63SRafael Espindola //
713b69d63SRafael Espindola //===----------------------------------------------------------------------===//
813b69d63SRafael Espindola 
9ba79dba8SRafael Espindola #include "RecordStreamer.h"
100d03881eSVitaly Buka #include "llvm/IR/Mangler.h"
110d03881eSVitaly Buka #include "llvm/IR/Module.h"
1247b4d6baSRafael Espindola #include "llvm/MC/MCContext.h"
1313b69d63SRafael Espindola #include "llvm/MC/MCSymbol.h"
141df42facSEugene Zelenko 
1513b69d63SRafael Espindola using namespace llvm;
1613b69d63SRafael Espindola 
markDefined(const MCSymbol & Symbol)1713b69d63SRafael Espindola void RecordStreamer::markDefined(const MCSymbol &Symbol) {
1813b69d63SRafael Espindola   State &S = Symbols[Symbol.getName()];
1913b69d63SRafael Espindola   switch (S) {
2013b69d63SRafael Espindola   case DefinedGlobal:
2113b69d63SRafael Espindola   case Global:
2213b69d63SRafael Espindola     S = DefinedGlobal;
2313b69d63SRafael Espindola     break;
2413b69d63SRafael Espindola   case NeverSeen:
2513b69d63SRafael Espindola   case Defined:
2613b69d63SRafael Espindola   case Used:
2713b69d63SRafael Espindola     S = Defined;
2813b69d63SRafael Espindola     break;
29f7518498SDavide Italiano   case DefinedWeak:
30ec7e29e9SDavide Italiano     break;
31f7518498SDavide Italiano   case UndefinedWeak:
32f7518498SDavide Italiano     S = DefinedWeak;
3313b69d63SRafael Espindola   }
3413b69d63SRafael Espindola }
3513b69d63SRafael Espindola 
markGlobal(const MCSymbol & Symbol,MCSymbolAttr Attribute)36ec7e29e9SDavide Italiano void RecordStreamer::markGlobal(const MCSymbol &Symbol,
37ec7e29e9SDavide Italiano                                 MCSymbolAttr Attribute) {
3813b69d63SRafael Espindola   State &S = Symbols[Symbol.getName()];
3913b69d63SRafael Espindola   switch (S) {
4013b69d63SRafael Espindola   case DefinedGlobal:
4113b69d63SRafael Espindola   case Defined:
42f7518498SDavide Italiano     S = (Attribute == MCSA_Weak) ? DefinedWeak : DefinedGlobal;
4313b69d63SRafael Espindola     break;
4413b69d63SRafael Espindola 
4513b69d63SRafael Espindola   case NeverSeen:
4613b69d63SRafael Espindola   case Global:
4713b69d63SRafael Espindola   case Used:
48f7518498SDavide Italiano     S = (Attribute == MCSA_Weak) ? UndefinedWeak : Global;
49ec7e29e9SDavide Italiano     break;
50f7518498SDavide Italiano   case UndefinedWeak:
51f7518498SDavide Italiano   case DefinedWeak:
5213b69d63SRafael Espindola     break;
5313b69d63SRafael Espindola   }
5413b69d63SRafael Espindola }
5513b69d63SRafael Espindola 
markUsed(const MCSymbol & Symbol)5613b69d63SRafael Espindola void RecordStreamer::markUsed(const MCSymbol &Symbol) {
5713b69d63SRafael Espindola   State &S = Symbols[Symbol.getName()];
5813b69d63SRafael Espindola   switch (S) {
5913b69d63SRafael Espindola   case DefinedGlobal:
6013b69d63SRafael Espindola   case Defined:
6113b69d63SRafael Espindola   case Global:
62f7518498SDavide Italiano   case DefinedWeak:
63f7518498SDavide Italiano   case UndefinedWeak:
6413b69d63SRafael Espindola     break;
6513b69d63SRafael Espindola 
6613b69d63SRafael Espindola   case NeverSeen:
6713b69d63SRafael Espindola   case Used:
6813b69d63SRafael Espindola     S = Used;
6913b69d63SRafael Espindola     break;
7013b69d63SRafael Espindola   }
7113b69d63SRafael Espindola }
7213b69d63SRafael Espindola 
visitUsedSymbol(const MCSymbol & Sym)7313b69d63SRafael Espindola void RecordStreamer::visitUsedSymbol(const MCSymbol &Sym) { markUsed(Sym); }
7413b69d63SRafael Espindola 
RecordStreamer(MCContext & Context,const Module & M)750d03881eSVitaly Buka RecordStreamer::RecordStreamer(MCContext &Context, const Module &M)
760d03881eSVitaly Buka     : MCStreamer(Context), M(M) {}
771df42facSEugene Zelenko 
begin()7813b69d63SRafael Espindola RecordStreamer::const_iterator RecordStreamer::begin() {
7913b69d63SRafael Espindola   return Symbols.begin();
8013b69d63SRafael Espindola }
8113b69d63SRafael Espindola 
end()8213b69d63SRafael Espindola RecordStreamer::const_iterator RecordStreamer::end() { return Symbols.end(); }
8313b69d63SRafael Espindola 
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)84bcd24b2dSFangrui Song void RecordStreamer::emitInstruction(const MCInst &Inst,
85edbf06a7SAndrea Di Biagio                                      const MCSubtargetInfo &STI) {
86bcd24b2dSFangrui Song   MCStreamer::emitInstruction(Inst, STI);
8713b69d63SRafael Espindola }
8813b69d63SRafael Espindola 
emitLabel(MCSymbol * Symbol,SMLoc Loc)896d2d589bSFangrui Song void RecordStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
906d2d589bSFangrui Song   MCStreamer::emitLabel(Symbol);
9113b69d63SRafael Espindola   markDefined(*Symbol);
9213b69d63SRafael Espindola }
9313b69d63SRafael Espindola 
emitAssignment(MCSymbol * Symbol,const MCExpr * Value)94a55daa14SFangrui Song void RecordStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
9513b69d63SRafael Espindola   markDefined(*Symbol);
96a55daa14SFangrui Song   MCStreamer::emitAssignment(Symbol, Value);
9713b69d63SRafael Espindola }
9813b69d63SRafael Espindola 
emitSymbolAttribute(MCSymbol * Symbol,MCSymbolAttr Attribute)99a55daa14SFangrui Song bool RecordStreamer::emitSymbolAttribute(MCSymbol *Symbol,
100395c8bedSFangrui Song                                          MCSymbolAttr Attribute) {
10116bfa13aSDavide Italiano   if (Attribute == MCSA_Global || Attribute == MCSA_Weak)
102ec7e29e9SDavide Italiano     markGlobal(*Symbol, Attribute);
103f9721ba5SMehdi Amini   if (Attribute == MCSA_LazyReference)
104f9721ba5SMehdi Amini     markUsed(*Symbol);
10513b69d63SRafael Espindola   return true;
10613b69d63SRafael Espindola }
10713b69d63SRafael Espindola 
emitZerofill(MCSection * Section,MCSymbol * Symbol,uint64_t Size,unsigned ByteAlignment,SMLoc Loc)108a55daa14SFangrui Song void RecordStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
1094d5b1073SFrancis Visoiu Mistrih                                   uint64_t Size, unsigned ByteAlignment,
1104d5b1073SFrancis Visoiu Mistrih                                   SMLoc Loc) {
11113b69d63SRafael Espindola   markDefined(*Symbol);
11213b69d63SRafael Espindola }
11313b69d63SRafael Espindola 
emitCommonSymbol(MCSymbol * Symbol,uint64_t Size,unsigned ByteAlignment)114a55daa14SFangrui Song void RecordStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
11513b69d63SRafael Espindola                                       unsigned ByteAlignment) {
11613b69d63SRafael Espindola   markDefined(*Symbol);
11713b69d63SRafael Espindola }
118d8204472STeresa Johnson 
getSymbolState(const MCSymbol * Sym)1190d03881eSVitaly Buka RecordStreamer::State RecordStreamer::getSymbolState(const MCSymbol *Sym) {
1200d03881eSVitaly Buka   auto SI = Symbols.find(Sym->getName());
1210d03881eSVitaly Buka   if (SI == Symbols.end())
1220d03881eSVitaly Buka     return NeverSeen;
1230d03881eSVitaly Buka   return SI->second;
1240d03881eSVitaly Buka }
1250d03881eSVitaly Buka 
emitELFSymverDirective(const MCSymbol * OriginalSym,StringRef Name,bool KeepOriginalSym)126*d96af2edSFangrui Song void RecordStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
127*d96af2edSFangrui Song                                             StringRef Name,
128*d96af2edSFangrui Song                                             bool KeepOriginalSym) {
129*d96af2edSFangrui Song   SymverAliasMap[OriginalSym].push_back(Name);
1300d03881eSVitaly Buka }
1310d03881eSVitaly Buka 
132230b2567SVlad Tsyrklevich iterator_range<RecordStreamer::const_symver_iterator>
symverAliases()133230b2567SVlad Tsyrklevich RecordStreamer::symverAliases() {
134230b2567SVlad Tsyrklevich   return {SymverAliasMap.begin(), SymverAliasMap.end()};
135230b2567SVlad Tsyrklevich }
136230b2567SVlad Tsyrklevich 
flushSymverDirectives()1370d03881eSVitaly Buka void RecordStreamer::flushSymverDirectives() {
1380d03881eSVitaly Buka   // Mapping from mangled name to GV.
1390d03881eSVitaly Buka   StringMap<const GlobalValue *> MangledNameMap;
1400d03881eSVitaly Buka   // The name in the assembler will be mangled, but the name in the IR
1410d03881eSVitaly Buka   // might not, so we first compute a mapping from mangled name to GV.
1420d03881eSVitaly Buka   Mangler Mang;
1430d03881eSVitaly Buka   SmallString<64> MangledName;
1440d03881eSVitaly Buka   for (const GlobalValue &GV : M.global_values()) {
1450d03881eSVitaly Buka     if (!GV.hasName())
1460d03881eSVitaly Buka       continue;
1470d03881eSVitaly Buka     MangledName.clear();
1480d03881eSVitaly Buka     MangledName.reserve(GV.getName().size() + 1);
1490d03881eSVitaly Buka     Mang.getNameWithPrefix(MangledName, &GV, /*CannotUsePrivateLabel=*/false);
1500d03881eSVitaly Buka     MangledNameMap[MangledName] = &GV;
1510d03881eSVitaly Buka   }
1520d03881eSVitaly Buka 
1530d03881eSVitaly Buka   // Walk all the recorded .symver aliases, and set up the binding
1540d03881eSVitaly Buka   // for each alias.
1550d03881eSVitaly Buka   for (auto &Symver : SymverAliasMap) {
1560d03881eSVitaly Buka     const MCSymbol *Aliasee = Symver.first;
1570d03881eSVitaly Buka     MCSymbolAttr Attr = MCSA_Invalid;
158849217abSVitaly Buka     bool IsDefined = false;
1590d03881eSVitaly Buka 
1600d03881eSVitaly Buka     // First check if the aliasee binding was recorded in the asm.
1610d03881eSVitaly Buka     RecordStreamer::State state = getSymbolState(Aliasee);
1620d03881eSVitaly Buka     switch (state) {
1630d03881eSVitaly Buka     case RecordStreamer::Global:
1640d03881eSVitaly Buka     case RecordStreamer::DefinedGlobal:
1650d03881eSVitaly Buka       Attr = MCSA_Global;
1660d03881eSVitaly Buka       break;
1670d03881eSVitaly Buka     case RecordStreamer::UndefinedWeak:
1680d03881eSVitaly Buka     case RecordStreamer::DefinedWeak:
1690d03881eSVitaly Buka       Attr = MCSA_Weak;
1700d03881eSVitaly Buka       break;
1710d03881eSVitaly Buka     default:
1720d03881eSVitaly Buka       break;
1730d03881eSVitaly Buka     }
1740d03881eSVitaly Buka 
175849217abSVitaly Buka     switch (state) {
176849217abSVitaly Buka     case RecordStreamer::Defined:
177849217abSVitaly Buka     case RecordStreamer::DefinedGlobal:
178849217abSVitaly Buka     case RecordStreamer::DefinedWeak:
179849217abSVitaly Buka       IsDefined = true;
180849217abSVitaly Buka       break;
181849217abSVitaly Buka     case RecordStreamer::NeverSeen:
182849217abSVitaly Buka     case RecordStreamer::Global:
183849217abSVitaly Buka     case RecordStreamer::Used:
184849217abSVitaly Buka     case RecordStreamer::UndefinedWeak:
185849217abSVitaly Buka       break;
186849217abSVitaly Buka     }
187849217abSVitaly Buka 
188849217abSVitaly Buka     if (Attr == MCSA_Invalid || !IsDefined) {
189849217abSVitaly Buka       const GlobalValue *GV = M.getNamedValue(Aliasee->getName());
1900d03881eSVitaly Buka       if (!GV) {
1910d03881eSVitaly Buka         auto MI = MangledNameMap.find(Aliasee->getName());
1920d03881eSVitaly Buka         if (MI != MangledNameMap.end())
1930d03881eSVitaly Buka           GV = MI->second;
1940d03881eSVitaly Buka       }
1950d03881eSVitaly Buka       if (GV) {
196849217abSVitaly Buka         // If we don't have a symbol attribute from assembly, then check if
197849217abSVitaly Buka         // the aliasee was defined in the IR.
198849217abSVitaly Buka         if (Attr == MCSA_Invalid) {
1990d03881eSVitaly Buka           if (GV->hasExternalLinkage())
2000d03881eSVitaly Buka             Attr = MCSA_Global;
2010d03881eSVitaly Buka           else if (GV->hasLocalLinkage())
2020d03881eSVitaly Buka             Attr = MCSA_Local;
2030d03881eSVitaly Buka           else if (GV->isWeakForLinker())
2040d03881eSVitaly Buka             Attr = MCSA_Weak;
2050d03881eSVitaly Buka         }
206849217abSVitaly Buka         IsDefined = IsDefined || !GV->isDeclarationForLinker();
2070d03881eSVitaly Buka       }
208849217abSVitaly Buka     }
209849217abSVitaly Buka 
2100d03881eSVitaly Buka     // Set the detected binding on each alias with this aliasee.
2110d03881eSVitaly Buka     for (auto AliasName : Symver.second) {
212849217abSVitaly Buka       std::pair<StringRef, StringRef> Split = AliasName.split("@@@");
213849217abSVitaly Buka       SmallString<128> NewName;
214849217abSVitaly Buka       if (!Split.second.empty() && !Split.second.startswith("@")) {
215849217abSVitaly Buka         // Special processing for "@@@" according
216849217abSVitaly Buka         // https://sourceware.org/binutils/docs/as/Symver.html
217849217abSVitaly Buka         const char *Separator = IsDefined ? "@@" : "@";
218849217abSVitaly Buka         AliasName =
219849217abSVitaly Buka             (Split.first + Separator + Split.second).toStringRef(NewName);
220849217abSVitaly Buka       }
22147b4d6baSRafael Espindola       MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
2220d03881eSVitaly Buka       // TODO: Handle "@@@". Depending on SymbolAttribute value it needs to be
2230d03881eSVitaly Buka       // converted into @ or @@.
22481e911cdSRafael Espindola       const MCExpr *Value = MCSymbolRefExpr::create(Aliasee, getContext());
2256c05a3bbSVitaly Buka       if (IsDefined)
2266c05a3bbSVitaly Buka         markDefined(*Alias);
2276c05a3bbSVitaly Buka       // Don't use EmitAssignment override as it always marks alias as defined.
228a55daa14SFangrui Song       MCStreamer::emitAssignment(Alias, Value);
2290d03881eSVitaly Buka       if (Attr != MCSA_Invalid)
230395c8bedSFangrui Song         emitSymbolAttribute(Alias, Attr);
2310d03881eSVitaly Buka     }
2320d03881eSVitaly Buka   }
233d8204472STeresa Johnson }
234