plotfi created this revision.
Herald added subscribers: cfe-commits, eraman, mgorny.
Herald added a project: clang.

This enables -emit-ifso to generate an interface library for each .o file. 
Currently it just writes a text file with the mangled names in it.


Repository:
  rC Clang

https://reviews.llvm.org/D60974

Files:
  clang/include/clang/Driver/Options.td
  clang/include/clang/Driver/Types.def
  clang/include/clang/Frontend/FrontendActions.h
  clang/include/clang/Frontend/FrontendOptions.h
  clang/lib/Driver/Driver.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CMakeLists.txt
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Frontend/FrontendActions.cpp
  clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
  clang/test/IFSO/foo-inline.h
  clang/test/IFSO/foo.cpp

Index: clang/test/IFSO/foo.cpp
===================================================================
--- /dev/null
+++ clang/test/IFSO/foo.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang -emit-ifso -fvisibility=hidden %s -o - | FileCheck --check-prefix=CHECK-HIDDEN %s
+// RUN: %clang -emit-ifso %s -o - | FileCheck %s
+
+// CHECK-HIDDEN-NOT: __Z4fbarff
+// CHECK: __Z4fbarff
+
+
+
+
+// CHECK-HIDDEN-NOT: __Z3fooii
+// CHECK-NOT:        __Z3fooii
+
+
+
+#include "foo-inline.h"
+
+__attribute__ ((visibility ("hidden"))) int foo(int a, int b) { return a + b; }
+__attribute__ ((visibility ("default"))) int foo_default_visi(int a, int b) { return a + b; }
+
+
+__attribute__ ((visibility ("default"))) int fvih_1(int a, int b) { return a + fvih(); }
+
+int dataA = 34;
+
+namespace baz {
+  template <typename T>
+  T add(T a, T b) {
+    return a + b;
+  }
+}
+
+namespace n {
+  template <typename T>
+  struct __attribute__((__visibility__("default"))) S {
+    S() = default;
+    ~S() = default;
+    int __attribute__((__visibility__(("default")))) func() const { return 32; }
+    int __attribute__((__visibility__(("hidden")))) operator()() const { return 53; }
+  };
+}
+
+template <typename T> T neverUsed(T t) { return t + 2; }
+
+template<> int neverUsed<int>(int t);
+
+void g() { n::S<int>()(); }
+
+namespace qux {
+int bar(int a, int b) { return baz::add<int>(a, b); }
+}
+
+float fbar(float a, float b) { return baz::add<float>(a, b); }
+
Index: clang/test/IFSO/foo-inline.h
===================================================================
--- /dev/null
+++ clang/test/IFSO/foo-inline.h
@@ -0,0 +1,6 @@
+
+inline int fvih() {
+static int fortytwo = 42;
+  return fortytwo;
+}
+
Index: clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
===================================================================
--- clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -64,6 +64,7 @@
   case GenerateHeaderModule:
     return llvm::make_unique<GenerateHeaderModuleAction>();
   case GeneratePCH:            return llvm::make_unique<GeneratePCHAction>();
+  case GenerateIFSO:           return llvm::make_unique<GenerateIFSOAction>();
   case InitOnly:               return llvm::make_unique<InitOnlyAction>();
   case ParseSyntaxOnly:        return llvm::make_unique<SyntaxOnlyAction>();
   case ModuleFileInfo:         return llvm::make_unique<DumpModuleInfoAction>();
Index: clang/lib/Frontend/FrontendActions.cpp
===================================================================
--- clang/lib/Frontend/FrontendActions.cpp
+++ clang/lib/Frontend/FrontendActions.cpp
@@ -25,6 +25,8 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/YAMLTraits.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Index/CodegenNameGenerator.h"
 #include <memory>
 #include <system_error>
 
@@ -158,6 +160,136 @@
   return true;
 }
 
+class IFSOFunctionsConsumer : public ASTConsumer {
+  CompilerInstance &Instance;
+  StringRef InFile = "";
+  std::set<std::string> ParsedTemplates;
+
+  enum RootDeclOrigin { TopLevel = 0, FromTU = 1, IsLate = 2 };
+
+  template <typename T>
+  bool WriteNamedDecl(const NamedDecl *ND, raw_pwrite_stream &OS, int RDO) {
+    if (!isa<T>(ND))
+      return false;
+    if (ND->getVisibility() != DefaultVisibility)
+      return true;
+    // If this is a FunctionDecl that is dependent on a template parameter, then
+    // don't get the symbol because we can only export specializations.
+    bool IsRDOLate = (RDO & IsLate);
+    if (const auto *FD = dyn_cast<FunctionDecl>(ND))
+      if (FD->isDependentContext() && !IsRDOLate)
+        return true;
+    index::CodegenNameGenerator CGNameGen(ND->getASTContext());
+    std::string MangledName = CGNameGen.getName(ND);
+    OS << (IsRDOLate ? "late-parsed-decl: " : "")
+       << (IsRDOLate ? ND->getNameAsString() : MangledName) << "\n";
+    // For now, lets just dump the -fdelayed-template-parsing decls until we
+    // decide how to handle them.
+    if (IsRDOLate)
+      ND->dump();
+    return true;
+  }
+
+  template <typename T>
+  bool HandleSomeDecl(const NamedDecl *ND, raw_pwrite_stream &OS,
+                      int RDO) {
+    if (!isa<T>(ND))
+      return false;
+    for (auto *I : cast<T>(ND)->decls())
+      HandleNamedDecl(dyn_cast<NamedDecl>(I), OS, RDO);
+    return true;
+  }
+
+  template <typename T>
+  bool HandleSomeDeclSpec(const NamedDecl *ND, raw_pwrite_stream &OS,
+                          int RDO) {
+    if (!isa<T>(ND))
+      return false;
+    for (auto *I : cast<T>(ND)->specializations())
+      HandleNamedDecl(dyn_cast<NamedDecl>(I), OS, RDO);
+    return true;
+  }
+
+  bool HandleNamedDecl(const NamedDecl *ND, raw_pwrite_stream &OS,
+                       int RDO) {
+    if (!ND)
+      return false;
+    // Handle NamespaceDecls first so that we fully recurse to every decl.
+    if (HandleSomeDecl<NamespaceDecl>(ND, OS, RDO) ||
+        HandleSomeDecl<CXXRecordDecl>(ND, OS, RDO) ||
+        HandleSomeDeclSpec<ClassTemplateDecl>(ND, OS, RDO) ||
+        HandleSomeDeclSpec<FunctionTemplateDecl>(ND, OS, RDO))
+      return true;
+    if (!(RDO & FromTU))
+      return true;
+    if (const auto *TTPD = dyn_cast<TemplateTypeParmDecl>(ND))
+      return true;
+    if (WriteNamedDecl<VarDecl>(ND, OS, RDO) ||
+        WriteNamedDecl<CXXMethodDecl>(ND, OS, RDO) ||
+        WriteNamedDecl<FunctionDecl>(ND, OS, RDO))
+      return true;
+    // While IFSOs are in the development stage, it's probably best to catch
+    // anything that's not a VarDecl or Template/FunctionDecl.
+    ND->dump();
+    llvm_unreachable("ifso: Expected a function or function template decl.");
+    return false;
+  }
+
+public:
+  IFSOFunctionsConsumer(CompilerInstance &Instance, StringRef InFile)
+      : Instance(Instance), InFile(InFile) {}
+
+  void HandleTranslationUnit(ASTContext &context) override {
+    struct Visitor : public RecursiveASTVisitor<Visitor> {
+      bool VisitNamedDecl(NamedDecl *ND) {
+        if (auto *FD = dyn_cast<FunctionDecl>(ND))
+          (FD->isLateTemplateParsed() ? LateParsedDecls : NamedDecls)
+              .insert(FD);
+        else if (auto *VD = dyn_cast<ValueDecl>(ND))
+          ValueDecls.insert(VD);
+        else
+          NamedDecls.insert(ND);
+        return true;
+      }
+
+      std::set<NamedDecl *> LateParsedDecls;
+      std::set<NamedDecl *> NamedDecls;
+      std::set<ValueDecl *> ValueDecls;
+    } v;
+
+    v.TraverseDecl(context.getTranslationUnitDecl());
+
+    auto OS =
+        Instance.createDefaultOutputFile(/*Binary=*/false, InFile, "ifso");
+    if (!OS)
+      return;
+
+    if (Instance.getLangOpts().DelayedTemplateParsing) {
+      llvm::errs() << "\nLate Decls:\n";
+      clang::Sema &sema = Instance.getSema();
+      for (const auto *FD : v.LateParsedDecls) {
+        clang::LateParsedTemplate &LPT =
+            *sema.LateParsedTemplateMap.find(cast<FunctionDecl>(FD))->second;
+        sema.LateTemplateParser(sema.OpaqueParser, LPT);
+        HandleNamedDecl(FD, *OS, (FromTU | IsLate));
+      }
+    }
+
+    (*OS) << "\nValueDecls:\n";
+    for (const ValueDecl *VD : v.ValueDecls)
+      HandleNamedDecl(VD, *OS, FromTU);
+
+    (*OS) << "\nNamedDecls:\n";
+    for (const NamedDecl *ND : v.NamedDecls)
+      HandleNamedDecl(ND, *OS, FromTU);
+  }
+};
+
+std::unique_ptr<ASTConsumer>
+GenerateIFSOAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+  return llvm::make_unique<IFSOFunctionsConsumer>(CI, InFile);
+}
+
 std::unique_ptr<ASTConsumer>
 GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
                                         StringRef InFile) {
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -1644,6 +1644,8 @@
       Opts.ProgramAction = frontend::GenerateHeaderModule; break;
     case OPT_emit_pch:
       Opts.ProgramAction = frontend::GeneratePCH; break;
+    case OPT_emit_ifso:
+      Opts.ProgramAction = frontend::GenerateIFSO; break;
     case OPT_init_only:
       Opts.ProgramAction = frontend::InitOnly; break;
     case OPT_fsyntax_only:
@@ -3065,6 +3067,7 @@
   case frontend::GenerateModuleInterface:
   case frontend::GenerateHeaderModule:
   case frontend::GeneratePCH:
+  case frontend::GenerateIFSO:
   case frontend::ParseSyntaxOnly:
   case frontend::ModuleFileInfo:
   case frontend::VerifyPCH:
Index: clang/lib/Frontend/CMakeLists.txt
===================================================================
--- clang/lib/Frontend/CMakeLists.txt
+++ clang/lib/Frontend/CMakeLists.txt
@@ -54,6 +54,7 @@
   clangAST
   clangBasic
   clangDriver
+  clangIndex
   clangEdit
   clangLex
   clangParse
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -3582,6 +3582,8 @@
     } else if (JA.getType() == types::TY_LLVM_BC ||
                JA.getType() == types::TY_LTO_BC) {
       CmdArgs.push_back("-emit-llvm-bc");
+    } else if (JA.getType() == types::TY_IFSO) {
+      CmdArgs.push_back("-emit-ifso");
     } else if (JA.getType() == types::TY_PP_Asm) {
       CmdArgs.push_back("-S");
     } else if (JA.getType() == types::TY_AST) {
Index: clang/lib/Driver/Driver.cpp
===================================================================
--- clang/lib/Driver/Driver.cpp
+++ clang/lib/Driver/Driver.cpp
@@ -284,6 +284,7 @@
              (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) ||
              (PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
+             (PhaseArg = DAL.getLastArg(options::OPT_emit_ifso)) ||
              (PhaseArg = DAL.getLastArg(options::OPT__analyze,
                                         options::OPT__analyze_auto)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) {
@@ -3444,6 +3445,8 @@
       return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile);
     if (Args.hasArg(options::OPT_verify_pch))
       return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
+    if (Args.hasArg(options::OPT_emit_ifso))
+      return C.MakeAction<CompileJobAction>(Input, types::TY_IFSO);
     return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
   }
   case phases::Backend: {
Index: clang/include/clang/Frontend/FrontendOptions.h
===================================================================
--- clang/include/clang/Frontend/FrontendOptions.h
+++ clang/include/clang/Frontend/FrontendOptions.h
@@ -87,6 +87,9 @@
   /// Generate pre-compiled header.
   GeneratePCH,
 
+  /// Generate Interface Library.
+  GenerateIFSO,
+
   /// Only execute frontend initialization.
   InitOnly,
 
Index: clang/include/clang/Frontend/FrontendActions.h
===================================================================
--- clang/include/clang/Frontend/FrontendActions.h
+++ clang/include/clang/Frontend/FrontendActions.h
@@ -119,6 +119,18 @@
   bool hasASTFileSupport() const override { return false; }
 };
 
+class GenerateIFSOAction : public ASTFrontendAction {
+protected:
+  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+                                                 StringRef InFile) override;
+
+  TranslationUnitKind getTranslationUnitKind() override {
+    return TU_Module;
+  }
+
+  bool hasASTFileSupport() const override { return false; }
+};
+
 class GenerateModuleFromModuleMapAction : public GenerateModuleAction {
 private:
   bool BeginSourceFileAction(CompilerInstance &CI) override;
Index: clang/include/clang/Driver/Types.def
===================================================================
--- clang/include/clang/Driver/Types.def
+++ clang/include/clang/Driver/Types.def
@@ -88,6 +88,7 @@
 
 // Misc.
 TYPE("ast",                      AST,          INVALID,         "ast",   "u")
+TYPE("ifso",                     IFSO,         INVALID,         "ifso",  "u")
 TYPE("pcm",                      ModuleFile,   INVALID,         "pcm",   "u")
 TYPE("plist",                    Plist,        INVALID,         "plist", "")
 TYPE("rewritten-objc",           RewrittenObjC,INVALID,         "cpp",   "")
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -623,6 +623,8 @@
   HelpText<"Emit Clang AST files for source inputs">;
 def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group<Action_Group>,
   HelpText<"Use the LLVM representation for assembler and object files">;
+def emit_ifso : Flag<["-"], "emit-ifso">, Flags<[CC1Option]>, Group<Action_Group>,
+  HelpText<"Generate Inteface Library File.">;
 def exported__symbols__list : Separate<["-"], "exported_symbols_list">;
 def e : JoinedOrSeparate<["-"], "e">, Group<Link_Group>;
 def fPIC : Flag<["-"], "fPIC">, Group<f_Group>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to