forked from OSchip/llvm-project
[clang-repl] Allow Interpreter::getSymbolAddress to take a mangled name.
This commit is contained in:
parent
81c99c5404
commit
4fb0805c65
|
@ -74,6 +74,10 @@ public:
|
|||
/// 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
|
||||
|
|
|
@ -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 @@ public:
|
|||
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 UnmangledName) const;
|
||||
getSymbolAddress(llvm::StringRef IRName) const;
|
||||
|
||||
/// \returns the \c JITTargetAddress of a given name as written in the object
|
||||
/// file.
|
||||
llvm::Expected<llvm::JITTargetAddress>
|
||||
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
|
||||
};
|
||||
} // namespace clang
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 @@ public:
|
|||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 @@ public:
|
|||
/// \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();
|
||||
};
|
||||
|
|
|
@ -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(UnmangledName);
|
||||
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(Name, IncrementalExecutor::LinkerName);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue