================
@@ -187,13 +161,174 @@ void ModuleSymbolTable::CollectAsmSymbols(
   }
 }
 
+static void
+addSymbols(RecordStreamer &Streamer,
+           function_ref<void(StringRef, BasicSymbolRef::Flags)> AsmSymbol) {
+  Streamer.flushSymverDirectives();
+
+  for (const auto &[Name, State] : Streamer) {
+    // FIXME: For now we just assume that all asm symbols are executable.
+    uint32_t Res = BasicSymbolRef::SF_Executable;
+    switch (State) {
+    case RecordStreamer::NeverSeen:
+      llvm_unreachable("NeverSeen should have been replaced earlier");
+    case RecordStreamer::DefinedGlobal:
+      Res |= BasicSymbolRef::SF_Global;
+      break;
+    case RecordStreamer::Defined:
+      break;
+    case RecordStreamer::Global:
+    case RecordStreamer::Used:
+      Res |= BasicSymbolRef::SF_Undefined;
+      Res |= BasicSymbolRef::SF_Global;
+      break;
+    case RecordStreamer::DefinedWeak:
+      Res |= BasicSymbolRef::SF_Weak;
+      Res |= BasicSymbolRef::SF_Global;
+      break;
+    case RecordStreamer::UndefinedWeak:
+      Res |= BasicSymbolRef::SF_Weak;
+      Res |= BasicSymbolRef::SF_Undefined;
+    }
+    AsmSymbol(Name, BasicSymbolRef::Flags(Res));
+  }
+}
+
+void ModuleSymbolTable::CollectAsmSymbols(
+    const Module &M,
+    function_ref<void(StringRef, BasicSymbolRef::Flags)> AsmSymbol) {
+
+  MDTuple *SymbolsMD =
+      dyn_cast_if_present<MDTuple>(M.getModuleFlag("global-asm-symbols"));
+
+  if (SymbolsMD) {
+    for (const Metadata *MD : SymbolsMD->operands()) {
+      const MDTuple *SymMD = cast<MDTuple>(MD);
+      const MDString *Name = cast<MDString>(SymMD->getOperand(0));
+      const ConstantInt *Flags =
+          mdconst::extract<ConstantInt>(SymMD->getOperand(1));
+      AsmSymbol(Name->getString(),
+                static_cast<BasicSymbolRef::Flags>(Flags->getZExtValue()));
+    }
+    addSpecialSymbols(M, AsmSymbol);
+    return;
+  }
+
+  initializeRecordStreamer(
+      M, /*CPU=*/"", /*Features=*/"",
+      [&](RecordStreamer &Streamer) { addSymbols(Streamer, AsmSymbol); },
+      /*DiagHandler=*/nullptr);
+
+  addSpecialSymbols(M, AsmSymbol);
+}
+
+static void addSymvers(RecordStreamer &Streamer,
+                       function_ref<void(StringRef, StringRef)> AsmSymver) {
+  for (const auto &[Name, Aliases] : Streamer.symverAliases())
+    for (StringRef Alias : Aliases)
+      AsmSymver(Name->getName(), Alias);
+}
+
 void ModuleSymbolTable::CollectAsmSymvers(
     const Module &M, function_ref<void(StringRef, StringRef)> AsmSymver) {
-  initializeRecordStreamer(M, [&](RecordStreamer &Streamer) {
-    for (auto &KV : Streamer.symverAliases())
-      for (auto &Alias : KV.second)
-        AsmSymver(KV.first->getName(), Alias);
-  });
+
+  MDTuple *SymversMD =
+      dyn_cast_if_present<MDTuple>(M.getModuleFlag("global-asm-symvers"));
+
+  if (SymversMD) {
+    for (const Metadata *MD : SymversMD->operands()) {
+      const MDTuple *SymverMD = cast<MDTuple>(MD);
+      StringRef Name = cast<MDString>(SymverMD->getOperand(0))->getString();
+      for (size_t i = 1, End = SymverMD->getNumOperands(); i < End; ++i) {
+        AsmSymver(Name, cast<MDString>(SymverMD->getOperand(i))->getString());
+      }
+    }
+    return;
+  }
+
+  initializeRecordStreamer(
+      M, /*CPU=*/"", /*Features=*/"",
+      [&](RecordStreamer &Streamer) { addSymvers(Streamer, AsmSymver); },
+      /*DiagHandler=*/nullptr);
+}
+
+bool ModuleSymbolTable::EmitModuleFlags(Module &M, StringRef CPU,
+                                        StringRef Features) {
+  bool Changed = false;
+  llvm::LLVMContext &Ctx = M.getContext();
+
+  bool HaveErrors = false;
+  auto DiagHandler = [&](const llvm::DiagnosticInfo &DI) {
+    // Ignore diagnostics from the assembly parser.
+    //
+    // Errors in assembly mean that we cannot build a symbol table
+    // from it. However, we do not diagnose them here, because we
+    // don't know if the Module is ever going to actually reach
+    // CodeGen where this would matter.
+    if (DI.getSeverity() == llvm::DS_Error)
+      HaveErrors = true;
+  };
+
+  // Build global-asm-symbols as a list of pairs (name, flags bitmask).
+  SmallVector<llvm::Metadata *, 16> Symbols;
+
+  auto AsmSymbol = [&](StringRef Name,
+                       llvm::object::BasicSymbolRef::Flags Flags) {
+    Symbols.push_back(llvm::MDNode::get(
+        Ctx, {llvm::MDString::get(Ctx, Name),
+              llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+                  llvm::Type::getInt32Ty(Ctx), Flags))}));
+  };
+
+  // Build global-asm-symvers as a list of lists (name, followed by all
+  // aliases).
+  llvm::MapVector<StringRef, SmallVector<llvm::Metadata *, 2>> SymversMap;
+
+  auto AsmSymver = [&](StringRef Name, StringRef Alias) {
+    auto ItNew = SymversMap.try_emplace(Name);
+    SmallVector<llvm::Metadata *, 2> &Aliases = ItNew.first->second;
+
+    // If it is a new list, insert the primary name at the front.
+    if (ItNew.second)
+      Aliases.push_back(llvm::MDString::get(Ctx, Name));
+
+    Aliases.push_back(llvm::MDString::get(Ctx, Alias));
+  };
+
+  // Parse global inline assembly and collect all symbols and symvers.
+  initializeRecordStreamer(
+      M, CPU, Features,
+      [&](RecordStreamer &Streamer) {
+        addSymvers(Streamer, AsmSymver);
+        addSymbols(Streamer, AsmSymbol);
+      },
+      DiagHandler);
+
+  if (HaveErrors)
+    return false;
+
+  // Emit a symbol table as module flags, so they can be traversed
+  // later with CollectAsmSymbols and CollectAsmSymvers.
+
+  if (!Symbols.empty()) {
+    M.addModuleFlag(llvm::Module::Append, "global-asm-symbols",
+                    llvm::MDNode::get(Ctx, Symbols));
+    Changed = true;
+  }
+
+  if (!SymversMap.empty()) {
+    SmallVector<llvm::Metadata *, 16> Symvers;
+    Symvers.reserve(SymversMap.size());
+    for (const auto &KV : SymversMap) {
----------------
mysterymath wrote:

nit: no braces on single line block

https://github.com/llvm/llvm-project/pull/174995
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to