[clang] 4fb0805 - [clang-repl] Allow Interpreter::getSymbolAddress to take a mangled name.

Vassil Vassilev via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 10 04:59:20 PST 2021


Author: Vassil Vassilev
Date: 2021-11-10T12:52:05Z
New Revision: 4fb0805c6525b13e50067b9ddfe8677a0b7b2d7c

URL: https://github.com/llvm/llvm-project/commit/4fb0805c6525b13e50067b9ddfe8677a0b7b2d7c
DIFF: https://github.com/llvm/llvm-project/commit/4fb0805c6525b13e50067b9ddfe8677a0b7b2d7c.diff

LOG: [clang-repl] Allow Interpreter::getSymbolAddress to take a mangled name.

Added: 
    

Modified: 
    clang/include/clang/CodeGen/ModuleBuilder.h
    clang/include/clang/Interpreter/Interpreter.h
    clang/lib/CodeGen/ModuleBuilder.cpp
    clang/lib/Interpreter/IncrementalExecutor.cpp
    clang/lib/Interpreter/IncrementalExecutor.h
    clang/lib/Interpreter/IncrementalParser.cpp
    clang/lib/Interpreter/IncrementalParser.h
    clang/lib/Interpreter/Interpreter.cpp
    clang/unittests/Interpreter/CMakeLists.txt
    clang/unittests/Interpreter/InterpreterTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h
index f9d056ed8b1ea..26587e73bf6c7 100644
--- a/clang/include/clang/CodeGen/ModuleBuilder.h
+++ b/clang/include/clang/CodeGen/ModuleBuilder.h
@@ -74,6 +74,10 @@ class CodeGenerator : public ASTConsumer {
   /// This may return null if there was no matching declaration.
   const Decl *GetDeclForMangledName(llvm::StringRef MangledName);
 
+  /// Given a global declaration, return a mangled name for this declaration
+  /// which has been added to this code generator via a Handle method.
+  llvm::StringRef GetMangledName(GlobalDecl GD);
+
   /// Return the LLVM address of the given global entity.
   ///
   /// \param isForDefinition If true, the caller intends to define the

diff  --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 9f5b64ce21243..2dc0fd5963a2f 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -16,6 +16,8 @@
 
 #include "clang/Interpreter/PartialTranslationUnit.h"
 
+#include "clang/AST/GlobalDecl.h"
+
 #include "llvm/ExecutionEngine/JITSymbol.h"
 #include "llvm/Support/Error.h"
 
@@ -66,8 +68,20 @@ class Interpreter {
       return Execute(*PTU);
     return llvm::Error::success();
   }
+
+  /// \returns the \c JITTargetAddress of a \c GlobalDecl. This interface uses
+  /// the CodeGenModule's internal mangling cache to avoid recomputing the
+  /// mangled name.
+  llvm::Expected<llvm::JITTargetAddress> getSymbolAddress(GlobalDecl GD) const;
+
+  /// \returns the \c JITTargetAddress of a given name as written in the IR.
+  llvm::Expected<llvm::JITTargetAddress>
+  getSymbolAddress(llvm::StringRef IRName) const;
+
+  /// \returns the \c JITTargetAddress of a given name as written in the object
+  /// file.
   llvm::Expected<llvm::JITTargetAddress>
-  getSymbolAddress(llvm::StringRef UnmangledName) const;
+  getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
 };
 } // namespace clang
 

diff  --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp
index b63f756ca2884..f6642a79e1e48 100644
--- a/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -122,6 +122,10 @@ namespace {
       return D;
     }
 
+    llvm::StringRef GetMangledName(GlobalDecl GD) {
+      return Builder->getMangledName(GD);
+    }
+
     llvm::Constant *GetAddrOfGlobal(GlobalDecl global, bool isForDefinition) {
       return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition));
     }
@@ -325,6 +329,10 @@ const Decl *CodeGenerator::GetDeclForMangledName(llvm::StringRef name) {
   return static_cast<CodeGeneratorImpl*>(this)->GetDeclForMangledName(name);
 }
 
+llvm::StringRef CodeGenerator::GetMangledName(GlobalDecl GD) {
+  return static_cast<CodeGeneratorImpl *>(this)->GetMangledName(GD);
+}
+
 llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global,
                                                bool isForDefinition) {
   return static_cast<CodeGeneratorImpl*>(this)

diff  --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp
index 230b49167f347..705235aafa070 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.cpp
+++ b/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -61,8 +61,11 @@ llvm::Error IncrementalExecutor::runCtors() const {
 }
 
 llvm::Expected<llvm::JITTargetAddress>
-IncrementalExecutor::getSymbolAddress(llvm::StringRef UnmangledName) const {
-  auto Sym = Jit->lookup(UnmangledName);
+IncrementalExecutor::getSymbolAddress(llvm::StringRef Name,
+                                      SymbolNameKind NameKind) const {
+  auto Sym = (NameKind == LinkerName) ? Jit->lookupLinkerMangled(Name)
+                                      : Jit->lookup(Name);
+
   if (!Sym)
     return Sym.takeError();
   return Sym->getAddress();

diff  --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h
index b626ebedcdc30..24447994d5f1d 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.h
+++ b/clang/lib/Interpreter/IncrementalExecutor.h
@@ -35,6 +35,8 @@ class IncrementalExecutor {
   llvm::orc::ThreadSafeContext &TSCtx;
 
 public:
+  enum SymbolNameKind { IRName, LinkerName };
+
   IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err,
                       const llvm::Triple &Triple);
   ~IncrementalExecutor();
@@ -42,7 +44,7 @@ class IncrementalExecutor {
   llvm::Error addModule(std::unique_ptr<llvm::Module> M);
   llvm::Error runCtors() const;
   llvm::Expected<llvm::JITTargetAddress>
-  getSymbolAddress(llvm::StringRef UnmangledName) const;
+  getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const;
 };
 
 } // end namespace clang

diff  --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp
index 6c5a26e599033..84eabc3a210f7 100644
--- a/clang/lib/Interpreter/IncrementalParser.cpp
+++ b/clang/lib/Interpreter/IncrementalParser.cpp
@@ -291,4 +291,11 @@ IncrementalParser::Parse(llvm::StringRef input) {
 
   return PTU;
 }
+
+llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const {
+  CodeGenerator *CG = getCodeGen(Act.get());
+  assert(CG);
+  return CG->GetMangledName(GD);
+}
+
 } // end namespace clang

diff  --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h
index aa8142cbe4939..e5ce798025d9b 100644
--- a/clang/lib/Interpreter/IncrementalParser.h
+++ b/clang/lib/Interpreter/IncrementalParser.h
@@ -15,6 +15,8 @@
 
 #include "clang/Interpreter/PartialTranslationUnit.h"
 
+#include "clang/AST/GlobalDecl.h"
+
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
@@ -69,6 +71,10 @@ class IncrementalParser {
   /// \c TranslationUnitDecl and \c llvm::Module corresponding to the input.
   llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Input);
 
+  /// Uses the CodeGenModule mangled name cache and avoids recomputing.
+  ///\returns the mangled name of a \c GD.
+  llvm::StringRef GetMangledName(GlobalDecl GD) const;
+
 private:
   llvm::Expected<PartialTranslationUnit &> ParseOrWrapTopLevelDecl();
 };

diff  --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 9eed1122f97d7..b2e7727be39a0 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -223,11 +223,31 @@ llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
 }
 
 llvm::Expected<llvm::JITTargetAddress>
-Interpreter::getSymbolAddress(llvm::StringRef UnmangledName) const {
+Interpreter::getSymbolAddress(GlobalDecl GD) const {
+  if (!IncrExecutor)
+    return llvm::make_error<llvm::StringError>("Operation failed. "
+                                               "No execution engine",
+                                               std::error_code());
+  llvm::StringRef MangledName = IncrParser->GetMangledName(GD);
+  return getSymbolAddress(MangledName);
+}
+
+llvm::Expected<llvm::JITTargetAddress>
+Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
+  if (!IncrExecutor)
+    return llvm::make_error<llvm::StringError>("Operation failed. "
+                                               "No execution engine",
+                                               std::error_code());
+
+  return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
+}
+
+llvm::Expected<llvm::JITTargetAddress>
+Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const {
   if (!IncrExecutor)
     return llvm::make_error<llvm::StringError>("Operation failed. "
                                                "No execution engine",
                                                std::error_code());
 
-  return IncrExecutor->getSymbolAddress(UnmangledName);
+  return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
 }

diff  --git a/clang/unittests/Interpreter/CMakeLists.txt b/clang/unittests/Interpreter/CMakeLists.txt
index e79e6d4dbbee5..03a4ca4a048b4 100644
--- a/clang/unittests/Interpreter/CMakeLists.txt
+++ b/clang/unittests/Interpreter/CMakeLists.txt
@@ -1,4 +1,5 @@
 set(LLVM_LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
   Core
   )
 
@@ -11,6 +12,7 @@ target_link_libraries(ClangReplInterpreterTests PUBLIC
   clangBasic
   clangInterpreter
   clangFrontend
+  clangSema
   )
 
 # Exceptions on Windows are not yet supported.

diff  --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp
index dc045a40a699d..0f02935b533b4 100644
--- a/clang/unittests/Interpreter/InterpreterTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterTest.cpp
@@ -14,8 +14,13 @@
 
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclGroup.h"
+#include "clang/AST/Mangle.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
+
+#include "llvm/Support/TargetSelect.h"
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -123,4 +128,116 @@ TEST(InterpreterTest, DeclsAndStatements) {
   EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err)));
 }
 
+static std::string MangleName(NamedDecl *ND) {
+  ASTContext &C = ND->getASTContext();
+  std::unique_ptr<MangleContext> MangleC(C.createMangleContext());
+  std::string mangledName;
+  llvm::raw_string_ostream RawStr(mangledName);
+  MangleC->mangleName(ND, RawStr);
+  return RawStr.str();
+}
+
+struct LLVMInitRAII {
+  LLVMInitRAII() {
+    llvm::InitializeNativeTarget();
+    llvm::InitializeNativeTargetAsmPrinter();
+  }
+  ~LLVMInitRAII() { llvm::llvm_shutdown(); }
+} LLVMInit;
+
+TEST(IncrementalProcessing, FindMangledNameSymbol) {
+
+  std::unique_ptr<Interpreter> Interp = createInterpreter();
+
+  auto &PTU(cantFail(Interp->Parse("int f(const char*) {return 0;}")));
+  EXPECT_EQ(1U, DeclsSize(PTU.TUPart));
+  auto R1DeclRange = PTU.TUPart->decls();
+
+  NamedDecl *FD = cast<FunctionDecl>(*R1DeclRange.begin());
+  // Lower the PTU
+  if (llvm::Error Err = Interp->Execute(PTU)) {
+    // We cannot execute on the platform.
+    consumeError(std::move(Err));
+    return;
+  }
+
+  std::string MangledName = MangleName(FD);
+  auto Addr = cantFail(Interp->getSymbolAddress(MangledName));
+  EXPECT_NE(0U, Addr);
+  GlobalDecl GD(FD);
+  EXPECT_EQ(Addr, cantFail(Interp->getSymbolAddress(GD)));
+}
+
+static void *AllocateObject(TypeDecl *TD, Interpreter &Interp) {
+  std::string Name = TD->getQualifiedNameAsString();
+  const clang::Type *RDTy = TD->getTypeForDecl();
+  clang::ASTContext &C = Interp.getCompilerInstance()->getASTContext();
+  size_t Size = C.getTypeSize(RDTy);
+  void *Addr = malloc(Size);
+
+  // Tell the interpreter to call the default ctor with this memory. Synthesize:
+  // new (loc) ClassName;
+  static unsigned Counter = 0;
+  std::stringstream SS;
+  SS << "auto _v" << Counter++ << " = "
+     << "new ((void*)"
+     // Windows needs us to prefix the hexadecimal value of a pointer with '0x'.
+     << std::hex << std::showbase << (size_t)Addr << ")" << Name << "();";
+
+  auto R = Interp.ParseAndExecute(SS.str());
+  if (!R)
+    return nullptr;
+
+  return Addr;
+}
+
+static NamedDecl *LookupSingleName(Interpreter &Interp, const char *Name) {
+  Sema &SemaRef = Interp.getCompilerInstance()->getSema();
+  ASTContext &C = SemaRef.getASTContext();
+  DeclarationName DeclName = &C.Idents.get(Name);
+  LookupResult R(SemaRef, DeclName, SourceLocation(), Sema::LookupOrdinaryName);
+  SemaRef.LookupName(R, SemaRef.TUScope);
+  assert(!R.empty());
+  return R.getFoundDecl();
+}
+
+TEST(IncrementalProcessing, InstantiateTemplate) {
+  // FIXME: We cannot yet handle delayed template parsing. If we run with
+  // -fdelayed-template-parsing we try adding the newly created decl to the
+  // active PTU which causes an assert.
+  std::vector<const char *> Args = {"-fno-delayed-template-parsing"};
+  std::unique_ptr<Interpreter> Interp = createInterpreter(Args);
+
+  llvm::cantFail(Interp->Parse("void* operator new(__SIZE_TYPE__, void* __p);"
+                               "extern \"C\" int printf(const char*,...);"
+                               "class A {};"
+                               "struct B {"
+                               "  template<typename T>"
+                               "  int callme(T) { return 42; }"
+                               "};"));
+  auto &PTU = llvm::cantFail(Interp->Parse("auto _t = &B::callme<A*>;"));
+  auto PTUDeclRange = PTU.TUPart->decls();
+  EXPECT_EQ(1, std::distance(PTUDeclRange.begin(), PTUDeclRange.end()));
+
+  // Lower the PTU
+  if (llvm::Error Err = Interp->Execute(PTU)) {
+    // We cannot execute on the platform.
+    consumeError(std::move(Err));
+    return;
+  }
+
+  TypeDecl *TD = cast<TypeDecl>(LookupSingleName(*Interp, "A"));
+  void *NewA = AllocateObject(TD, *Interp);
+
+  // Find back the template specialization
+  VarDecl *VD = static_cast<VarDecl *>(*PTUDeclRange.begin());
+  UnaryOperator *UO = llvm::cast<UnaryOperator>(VD->getInit());
+  NamedDecl *TmpltSpec = llvm::cast<DeclRefExpr>(UO->getSubExpr())->getDecl();
+
+  std::string MangledName = MangleName(TmpltSpec);
+  typedef int (*TemplateSpecFn)(void *);
+  auto fn = (TemplateSpecFn)cantFail(Interp->getSymbolAddress(MangledName));
+  EXPECT_EQ(42, fn(NewA));
+}
+
 } // end anonymous namespace


        


More information about the cfe-commits mailing list