[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