Index: clang/include/clang/CodeGen/ModuleBuilder.h =================================================================== --- clang/include/clang/CodeGen/ModuleBuilder.h +++ clang/include/clang/CodeGen/ModuleBuilder.h @@ -74,6 +74,10 @@ /// 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 Index: clang/include/clang/Interpreter/Interpreter.h =================================================================== --- clang/include/clang/Interpreter/Interpreter.h +++ 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 @@ 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 getSymbolAddress(GlobalDecl GD) const; + + /// \returns the \c JITTargetAddress of a given name as written in the IR. + llvm::Expected + getSymbolAddress(llvm::StringRef IRName) const; + + /// \returns the \c JITTargetAddress of a given name as written in the object + /// file. llvm::Expected - getSymbolAddress(llvm::StringRef UnmangledName) const; + getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const; }; } // namespace clang Index: clang/lib/CodeGen/ModuleBuilder.cpp =================================================================== --- clang/lib/CodeGen/ModuleBuilder.cpp +++ clang/lib/CodeGen/ModuleBuilder.cpp @@ -122,6 +122,10 @@ 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 @@ return static_cast(this)->GetDeclForMangledName(name); } +llvm::StringRef CodeGenerator::GetMangledName(GlobalDecl GD) { + return static_cast(this)->GetMangledName(GD); +} + llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global, bool isForDefinition) { return static_cast(this) Index: clang/lib/Interpreter/IncrementalExecutor.h =================================================================== --- clang/lib/Interpreter/IncrementalExecutor.h +++ clang/lib/Interpreter/IncrementalExecutor.h @@ -35,6 +35,8 @@ 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 @@ llvm::Error addModule(std::unique_ptr M); llvm::Error runCtors() const; llvm::Expected - getSymbolAddress(llvm::StringRef UnmangledName) const; + getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const; }; } // end namespace clang Index: clang/lib/Interpreter/IncrementalExecutor.cpp =================================================================== --- clang/lib/Interpreter/IncrementalExecutor.cpp +++ clang/lib/Interpreter/IncrementalExecutor.cpp @@ -61,8 +61,11 @@ } llvm::Expected -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(); Index: clang/lib/Interpreter/IncrementalParser.h =================================================================== --- clang/lib/Interpreter/IncrementalParser.h +++ 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 @@ /// \c TranslationUnitDecl and \c llvm::Module corresponding to the input. llvm::Expected 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 ParseOrWrapTopLevelDecl(); }; Index: clang/lib/Interpreter/IncrementalParser.cpp =================================================================== --- clang/lib/Interpreter/IncrementalParser.cpp +++ clang/lib/Interpreter/IncrementalParser.cpp @@ -291,4 +291,11 @@ return PTU; } + +llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const { + CodeGenerator *CG = getCodeGen(Act.get()); + assert(CG); + return CG->GetMangledName(GD); +} + } // end namespace clang Index: clang/lib/Interpreter/Interpreter.cpp =================================================================== --- clang/lib/Interpreter/Interpreter.cpp +++ clang/lib/Interpreter/Interpreter.cpp @@ -223,11 +223,31 @@ } llvm::Expected -Interpreter::getSymbolAddress(llvm::StringRef UnmangledName) const { +Interpreter::getSymbolAddress(GlobalDecl GD) const { + if (!IncrExecutor) + return llvm::make_error("Operation failed. " + "No execution engine", + std::error_code()); + llvm::StringRef MangledName = IncrParser->GetMangledName(GD); + return getSymbolAddress(MangledName); +} + +llvm::Expected +Interpreter::getSymbolAddress(llvm::StringRef IRName) const { + if (!IncrExecutor) + return llvm::make_error("Operation failed. " + "No execution engine", + std::error_code()); + + return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName); +} + +llvm::Expected +Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const { if (!IncrExecutor) return llvm::make_error("Operation failed. " "No execution engine", std::error_code()); - return IncrExecutor->getSymbolAddress(UnmangledName); + return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName); } Index: clang/unittests/Interpreter/CMakeLists.txt =================================================================== --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} Core ) @@ -11,6 +12,7 @@ clangBasic clangInterpreter clangFrontend + clangSema ) # Exceptions on Windows are not yet supported. Index: clang/unittests/Interpreter/InterpreterTest.cpp =================================================================== --- clang/unittests/Interpreter/InterpreterTest.cpp +++ 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 @@ EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err))); } +static std::string MangleName(NamedDecl *ND) { + ASTContext &C = ND->getASTContext(); + std::unique_ptr 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 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(*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 Args = {"-fno-delayed-template-parsing"}; + std::unique_ptr 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" + " int callme(T) { return 42; }" + "};")); + auto &PTU = llvm::cantFail(Interp->Parse("auto _t = &B::callme;")); + 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(LookupSingleName(*Interp, "A")); + void *NewA = AllocateObject(TD, *Interp); + + // Find back the template specialization + VarDecl *VD = static_cast(*PTUDeclRange.begin()); + UnaryOperator *UO = llvm::cast(VD->getInit()); + NamedDecl *TmpltSpec = llvm::cast(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