Skip to content

Commit 4fb0805

Browse files
committed
[clang-repl] Allow Interpreter::getSymbolAddress to take a mangled name.
1 parent 81c99c5 commit 4fb0805

File tree

10 files changed

+189
-6
lines changed

10 files changed

+189
-6
lines changed

clang/include/clang/CodeGen/ModuleBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ class CodeGenerator : public ASTConsumer {
7474
/// This may return null if there was no matching declaration.
7575
const Decl *GetDeclForMangledName(llvm::StringRef MangledName);
7676

77+
/// Given a global declaration, return a mangled name for this declaration
78+
/// which has been added to this code generator via a Handle method.
79+
llvm::StringRef GetMangledName(GlobalDecl GD);
80+
7781
/// Return the LLVM address of the given global entity.
7882
///
7983
/// \param isForDefinition If true, the caller intends to define the

clang/include/clang/Interpreter/Interpreter.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#include "clang/Interpreter/PartialTranslationUnit.h"
1818

19+
#include "clang/AST/GlobalDecl.h"
20+
1921
#include "llvm/ExecutionEngine/JITSymbol.h"
2022
#include "llvm/Support/Error.h"
2123

@@ -66,8 +68,20 @@ class Interpreter {
6668
return Execute(*PTU);
6769
return llvm::Error::success();
6870
}
71+
72+
/// \returns the \c JITTargetAddress of a \c GlobalDecl. This interface uses
73+
/// the CodeGenModule's internal mangling cache to avoid recomputing the
74+
/// mangled name.
75+
llvm::Expected<llvm::JITTargetAddress> getSymbolAddress(GlobalDecl GD) const;
76+
77+
/// \returns the \c JITTargetAddress of a given name as written in the IR.
78+
llvm::Expected<llvm::JITTargetAddress>
79+
getSymbolAddress(llvm::StringRef IRName) const;
80+
81+
/// \returns the \c JITTargetAddress of a given name as written in the object
82+
/// file.
6983
llvm::Expected<llvm::JITTargetAddress>
70-
getSymbolAddress(llvm::StringRef UnmangledName) const;
84+
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
7185
};
7286
} // namespace clang
7387

clang/lib/CodeGen/ModuleBuilder.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ namespace {
122122
return D;
123123
}
124124

125+
llvm::StringRef GetMangledName(GlobalDecl GD) {
126+
return Builder->getMangledName(GD);
127+
}
128+
125129
llvm::Constant *GetAddrOfGlobal(GlobalDecl global, bool isForDefinition) {
126130
return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition));
127131
}
@@ -325,6 +329,10 @@ const Decl *CodeGenerator::GetDeclForMangledName(llvm::StringRef name) {
325329
return static_cast<CodeGeneratorImpl*>(this)->GetDeclForMangledName(name);
326330
}
327331

332+
llvm::StringRef CodeGenerator::GetMangledName(GlobalDecl GD) {
333+
return static_cast<CodeGeneratorImpl *>(this)->GetMangledName(GD);
334+
}
335+
328336
llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global,
329337
bool isForDefinition) {
330338
return static_cast<CodeGeneratorImpl*>(this)

clang/lib/Interpreter/IncrementalExecutor.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,11 @@ llvm::Error IncrementalExecutor::runCtors() const {
6161
}
6262

6363
llvm::Expected<llvm::JITTargetAddress>
64-
IncrementalExecutor::getSymbolAddress(llvm::StringRef UnmangledName) const {
65-
auto Sym = Jit->lookup(UnmangledName);
64+
IncrementalExecutor::getSymbolAddress(llvm::StringRef Name,
65+
SymbolNameKind NameKind) const {
66+
auto Sym = (NameKind == LinkerName) ? Jit->lookupLinkerMangled(Name)
67+
: Jit->lookup(Name);
68+
6669
if (!Sym)
6770
return Sym.takeError();
6871
return Sym->getAddress();

clang/lib/Interpreter/IncrementalExecutor.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,16 @@ class IncrementalExecutor {
3535
llvm::orc::ThreadSafeContext &TSCtx;
3636

3737
public:
38+
enum SymbolNameKind { IRName, LinkerName };
39+
3840
IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err,
3941
const llvm::Triple &Triple);
4042
~IncrementalExecutor();
4143

4244
llvm::Error addModule(std::unique_ptr<llvm::Module> M);
4345
llvm::Error runCtors() const;
4446
llvm::Expected<llvm::JITTargetAddress>
45-
getSymbolAddress(llvm::StringRef UnmangledName) const;
47+
getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const;
4648
};
4749

4850
} // end namespace clang

clang/lib/Interpreter/IncrementalParser.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,4 +291,11 @@ IncrementalParser::Parse(llvm::StringRef input) {
291291

292292
return PTU;
293293
}
294+
295+
llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const {
296+
CodeGenerator *CG = getCodeGen(Act.get());
297+
assert(CG);
298+
return CG->GetMangledName(GD);
299+
}
300+
294301
} // end namespace clang

clang/lib/Interpreter/IncrementalParser.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#include "clang/Interpreter/PartialTranslationUnit.h"
1717

18+
#include "clang/AST/GlobalDecl.h"
19+
1820
#include "llvm/ADT/ArrayRef.h"
1921
#include "llvm/ADT/StringRef.h"
2022
#include "llvm/Support/Error.h"
@@ -69,6 +71,10 @@ class IncrementalParser {
6971
/// \c TranslationUnitDecl and \c llvm::Module corresponding to the input.
7072
llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Input);
7173

74+
/// Uses the CodeGenModule mangled name cache and avoids recomputing.
75+
///\returns the mangled name of a \c GD.
76+
llvm::StringRef GetMangledName(GlobalDecl GD) const;
77+
7278
private:
7379
llvm::Expected<PartialTranslationUnit &> ParseOrWrapTopLevelDecl();
7480
};

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,31 @@ llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
223223
}
224224

225225
llvm::Expected<llvm::JITTargetAddress>
226-
Interpreter::getSymbolAddress(llvm::StringRef UnmangledName) const {
226+
Interpreter::getSymbolAddress(GlobalDecl GD) const {
227+
if (!IncrExecutor)
228+
return llvm::make_error<llvm::StringError>("Operation failed. "
229+
"No execution engine",
230+
std::error_code());
231+
llvm::StringRef MangledName = IncrParser->GetMangledName(GD);
232+
return getSymbolAddress(MangledName);
233+
}
234+
235+
llvm::Expected<llvm::JITTargetAddress>
236+
Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
237+
if (!IncrExecutor)
238+
return llvm::make_error<llvm::StringError>("Operation failed. "
239+
"No execution engine",
240+
std::error_code());
241+
242+
return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
243+
}
244+
245+
llvm::Expected<llvm::JITTargetAddress>
246+
Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const {
227247
if (!IncrExecutor)
228248
return llvm::make_error<llvm::StringError>("Operation failed. "
229249
"No execution engine",
230250
std::error_code());
231251

232-
return IncrExecutor->getSymbolAddress(UnmangledName);
252+
return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
233253
}

clang/unittests/Interpreter/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
set(LLVM_LINK_COMPONENTS
2+
${LLVM_TARGETS_TO_BUILD}
23
Core
34
)
45

@@ -11,6 +12,7 @@ target_link_libraries(ClangReplInterpreterTests PUBLIC
1112
clangBasic
1213
clangInterpreter
1314
clangFrontend
15+
clangSema
1416
)
1517

1618
# Exceptions on Windows are not yet supported.

clang/unittests/Interpreter/InterpreterTest.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@
1414

1515
#include "clang/AST/Decl.h"
1616
#include "clang/AST/DeclGroup.h"
17+
#include "clang/AST/Mangle.h"
1718
#include "clang/Frontend/CompilerInstance.h"
1819
#include "clang/Frontend/TextDiagnosticPrinter.h"
20+
#include "clang/Sema/Lookup.h"
21+
#include "clang/Sema/Sema.h"
22+
23+
#include "llvm/Support/TargetSelect.h"
1924

2025
#include "gmock/gmock.h"
2126
#include "gtest/gtest.h"
@@ -123,4 +128,116 @@ TEST(InterpreterTest, DeclsAndStatements) {
123128
EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err)));
124129
}
125130

131+
static std::string MangleName(NamedDecl *ND) {
132+
ASTContext &C = ND->getASTContext();
133+
std::unique_ptr<MangleContext> MangleC(C.createMangleContext());
134+
std::string mangledName;
135+
llvm::raw_string_ostream RawStr(mangledName);
136+
MangleC->mangleName(ND, RawStr);
137+
return RawStr.str();
138+
}
139+
140+
struct LLVMInitRAII {
141+
LLVMInitRAII() {
142+
llvm::InitializeNativeTarget();
143+
llvm::InitializeNativeTargetAsmPrinter();
144+
}
145+
~LLVMInitRAII() { llvm::llvm_shutdown(); }
146+
} LLVMInit;
147+
148+
TEST(IncrementalProcessing, FindMangledNameSymbol) {
149+
150+
std::unique_ptr<Interpreter> Interp = createInterpreter();
151+
152+
auto &PTU(cantFail(Interp->Parse("int f(const char*) {return 0;}")));
153+
EXPECT_EQ(1U, DeclsSize(PTU.TUPart));
154+
auto R1DeclRange = PTU.TUPart->decls();
155+
156+
NamedDecl *FD = cast<FunctionDecl>(*R1DeclRange.begin());
157+
// Lower the PTU
158+
if (llvm::Error Err = Interp->Execute(PTU)) {
159+
// We cannot execute on the platform.
160+
consumeError(std::move(Err));
161+
return;
162+
}
163+
164+
std::string MangledName = MangleName(FD);
165+
auto Addr = cantFail(Interp->getSymbolAddress(MangledName));
166+
EXPECT_NE(0U, Addr);
167+
GlobalDecl GD(FD);
168+
EXPECT_EQ(Addr, cantFail(Interp->getSymbolAddress(GD)));
169+
}
170+
171+
static void *AllocateObject(TypeDecl *TD, Interpreter &Interp) {
172+
std::string Name = TD->getQualifiedNameAsString();
173+
const clang::Type *RDTy = TD->getTypeForDecl();
174+
clang::ASTContext &C = Interp.getCompilerInstance()->getASTContext();
175+
size_t Size = C.getTypeSize(RDTy);
176+
void *Addr = malloc(Size);
177+
178+
// Tell the interpreter to call the default ctor with this memory. Synthesize:
179+
// new (loc) ClassName;
180+
static unsigned Counter = 0;
181+
std::stringstream SS;
182+
SS << "auto _v" << Counter++ << " = "
183+
<< "new ((void*)"
184+
// Windows needs us to prefix the hexadecimal value of a pointer with '0x'.
185+
<< std::hex << std::showbase << (size_t)Addr << ")" << Name << "();";
186+
187+
auto R = Interp.ParseAndExecute(SS.str());
188+
if (!R)
189+
return nullptr;
190+
191+
return Addr;
192+
}
193+
194+
static NamedDecl *LookupSingleName(Interpreter &Interp, const char *Name) {
195+
Sema &SemaRef = Interp.getCompilerInstance()->getSema();
196+
ASTContext &C = SemaRef.getASTContext();
197+
DeclarationName DeclName = &C.Idents.get(Name);
198+
LookupResult R(SemaRef, DeclName, SourceLocation(), Sema::LookupOrdinaryName);
199+
SemaRef.LookupName(R, SemaRef.TUScope);
200+
assert(!R.empty());
201+
return R.getFoundDecl();
202+
}
203+
204+
TEST(IncrementalProcessing, InstantiateTemplate) {
205+
// FIXME: We cannot yet handle delayed template parsing. If we run with
206+
// -fdelayed-template-parsing we try adding the newly created decl to the
207+
// active PTU which causes an assert.
208+
std::vector<const char *> Args = {"-fno-delayed-template-parsing"};
209+
std::unique_ptr<Interpreter> Interp = createInterpreter(Args);
210+
211+
llvm::cantFail(Interp->Parse("void* operator new(__SIZE_TYPE__, void* __p);"
212+
"extern \"C\" int printf(const char*,...);"
213+
"class A {};"
214+
"struct B {"
215+
" template<typename T>"
216+
" int callme(T) { return 42; }"
217+
"};"));
218+
auto &PTU = llvm::cantFail(Interp->Parse("auto _t = &B::callme<A*>;"));
219+
auto PTUDeclRange = PTU.TUPart->decls();
220+
EXPECT_EQ(1, std::distance(PTUDeclRange.begin(), PTUDeclRange.end()));
221+
222+
// Lower the PTU
223+
if (llvm::Error Err = Interp->Execute(PTU)) {
224+
// We cannot execute on the platform.
225+
consumeError(std::move(Err));
226+
return;
227+
}
228+
229+
TypeDecl *TD = cast<TypeDecl>(LookupSingleName(*Interp, "A"));
230+
void *NewA = AllocateObject(TD, *Interp);
231+
232+
// Find back the template specialization
233+
VarDecl *VD = static_cast<VarDecl *>(*PTUDeclRange.begin());
234+
UnaryOperator *UO = llvm::cast<UnaryOperator>(VD->getInit());
235+
NamedDecl *TmpltSpec = llvm::cast<DeclRefExpr>(UO->getSubExpr())->getDecl();
236+
237+
std::string MangledName = MangleName(TmpltSpec);
238+
typedef int (*TemplateSpecFn)(void *);
239+
auto fn = (TemplateSpecFn)cantFail(Interp->getSymbolAddress(MangledName));
240+
EXPECT_EQ(42, fn(NewA));
241+
}
242+
126243
} // end anonymous namespace

0 commit comments

Comments
 (0)