1//===------ Interpreter.cpp - Incremental Compilation and Execution -------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the component which performs incremental code
10// compilation and execution.
11//
12//===----------------------------------------------------------------------===//
13
14#include "DeviceOffload.h"
15#include "IncrementalExecutor.h"
16#include "IncrementalParser.h"
17#include "InterpreterUtils.h"
18
19#include "clang/AST/ASTContext.h"
20#include "clang/AST/Mangle.h"
21#include "clang/AST/TypeVisitor.h"
22#include "clang/Basic/DiagnosticSema.h"
23#include "clang/Basic/TargetInfo.h"
24#include "clang/CodeGen/CodeGenAction.h"
25#include "clang/CodeGen/ModuleBuilder.h"
26#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
27#include "clang/Driver/Compilation.h"
28#include "clang/Driver/Driver.h"
29#include "clang/Driver/Job.h"
30#include "clang/Driver/Options.h"
31#include "clang/Driver/Tool.h"
32#include "clang/Frontend/CompilerInstance.h"
33#include "clang/Frontend/TextDiagnosticBuffer.h"
34#include "clang/Interpreter/Interpreter.h"
35#include "clang/Interpreter/Value.h"
36#include "clang/Lex/PreprocessorOptions.h"
37#include "clang/Sema/Lookup.h"
38#include "llvm/ExecutionEngine/JITSymbol.h"
39#include "llvm/ExecutionEngine/Orc/LLJIT.h"
40#include "llvm/IR/Module.h"
41#include "llvm/Support/Errc.h"
42#include "llvm/Support/ErrorHandling.h"
43#include "llvm/Support/raw_ostream.h"
44#include "llvm/TargetParser/Host.h"
45using namespace clang;
46
47// FIXME: Figure out how to unify with namespace init_convenience from
48// tools/clang-import-test/clang-import-test.cpp
49namespace {
50/// Retrieves the clang CC1 specific flags out of the compilation's jobs.
51/// \returns NULL on error.
52static llvm::Expected<const llvm::opt::ArgStringList *>
53GetCC1Arguments(DiagnosticsEngine *Diagnostics,
54 driver::Compilation *Compilation) {
55 // We expect to get back exactly one Command job, if we didn't something
56 // failed. Extract that job from the Compilation.
57 const driver::JobList &Jobs = Compilation->getJobs();
58 if (!Jobs.size() || !isa<driver::Command>(Val: *Jobs.begin()))
59 return llvm::createStringError(EC: llvm::errc::not_supported,
60 Msg: "Driver initialization failed. "
61 "Unable to create a driver job");
62
63 // The one job we find should be to invoke clang again.
64 const driver::Command *Cmd = cast<driver::Command>(Val: &(*Jobs.begin()));
65 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
66 return llvm::createStringError(EC: llvm::errc::not_supported,
67 Msg: "Driver initialization failed");
68
69 return &Cmd->getArguments();
70}
71
72static llvm::Expected<std::unique_ptr<CompilerInstance>>
73CreateCI(const llvm::opt::ArgStringList &Argv) {
74 std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
75 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
76
77 // Register the support for object-file-wrapped Clang modules.
78 // FIXME: Clang should register these container operations automatically.
79 auto PCHOps = Clang->getPCHContainerOperations();
80 PCHOps->registerWriter(Writer: std::make_unique<ObjectFilePCHContainerWriter>());
81 PCHOps->registerReader(Reader: std::make_unique<ObjectFilePCHContainerReader>());
82
83 // Buffer diagnostics from argument parsing so that we can output them using
84 // a well formed diagnostic object.
85 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
86 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
87 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
88 bool Success = CompilerInvocation::CreateFromArgs(
89 Res&: Clang->getInvocation(), CommandLineArgs: llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
90
91 // Infer the builtin include path if unspecified.
92 if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
93 Clang->getHeaderSearchOpts().ResourceDir.empty())
94 Clang->getHeaderSearchOpts().ResourceDir =
95 CompilerInvocation::GetResourcesPath(Argv0: Argv[0], MainAddr: nullptr);
96
97 // Create the actual diagnostics engine.
98 Clang->createDiagnostics();
99 if (!Clang->hasDiagnostics())
100 return llvm::createStringError(EC: llvm::errc::not_supported,
101 Msg: "Initialization failed. "
102 "Unable to create diagnostics engine");
103
104 DiagsBuffer->FlushDiagnostics(Diags&: Clang->getDiagnostics());
105 if (!Success)
106 return llvm::createStringError(EC: llvm::errc::not_supported,
107 Msg: "Initialization failed. "
108 "Unable to flush diagnostics");
109
110 // FIXME: Merge with CompilerInstance::ExecuteAction.
111 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer(InputData: "").release();
112 Clang->getPreprocessorOpts().addRemappedFile(From: "<<< inputs >>>", To: MB);
113
114 Clang->setTarget(TargetInfo::CreateTargetInfo(
115 Diags&: Clang->getDiagnostics(), Opts: Clang->getInvocation().TargetOpts));
116 if (!Clang->hasTarget())
117 return llvm::createStringError(EC: llvm::errc::not_supported,
118 Msg: "Initialization failed. "
119 "Target is missing");
120
121 Clang->getTarget().adjust(Diags&: Clang->getDiagnostics(), Opts&: Clang->getLangOpts());
122
123 // Don't clear the AST before backend codegen since we do codegen multiple
124 // times, reusing the same AST.
125 Clang->getCodeGenOpts().ClearASTBeforeBackend = false;
126
127 Clang->getFrontendOpts().DisableFree = false;
128 Clang->getCodeGenOpts().DisableFree = false;
129 return std::move(Clang);
130}
131
132} // anonymous namespace
133
134llvm::Expected<std::unique_ptr<CompilerInstance>>
135IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) {
136
137 // If we don't know ClangArgv0 or the address of main() at this point, try
138 // to guess it anyway (it's possible on some platforms).
139 std::string MainExecutableName =
140 llvm::sys::fs::getMainExecutable(argv0: nullptr, MainExecAddr: nullptr);
141
142 ClangArgv.insert(position: ClangArgv.begin(), x: MainExecutableName.c_str());
143
144 // Prepending -c to force the driver to do something if no action was
145 // specified. By prepending we allow users to override the default
146 // action and use other actions in incremental mode.
147 // FIXME: Print proper driver diagnostics if the driver flags are wrong.
148 // We do C++ by default; append right after argv[0] if no "-x" given
149 ClangArgv.insert(position: ClangArgv.end(), x: "-Xclang");
150 ClangArgv.insert(position: ClangArgv.end(), x: "-fincremental-extensions");
151 ClangArgv.insert(position: ClangArgv.end(), x: "-c");
152
153 // Put a dummy C++ file on to ensure there's at least one compile job for the
154 // driver to construct.
155 ClangArgv.push_back(x: "<<< inputs >>>");
156
157 // Buffer diagnostics from argument parsing so that we can output them using a
158 // well formed diagnostic object.
159 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
160 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
161 CreateAndPopulateDiagOpts(Argv: ClangArgv);
162 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
163 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
164
165 driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0],
166 llvm::sys::getProcessTriple(), Diags);
167 Driver.setCheckInputsExist(false); // the input comes from mem buffers
168 llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
169 std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(Args: RF));
170
171 if (Compilation->getArgs().hasArg(driver::options::OPT_v))
172 Compilation->getJobs().Print(OS&: llvm::errs(), Terminator: "\n", /*Quote=*/false);
173
174 auto ErrOrCC1Args = GetCC1Arguments(Diagnostics: &Diags, Compilation: Compilation.get());
175 if (auto Err = ErrOrCC1Args.takeError())
176 return std::move(Err);
177
178 return CreateCI(Argv: **ErrOrCC1Args);
179}
180
181llvm::Expected<std::unique_ptr<CompilerInstance>>
182IncrementalCompilerBuilder::CreateCpp() {
183 std::vector<const char *> Argv;
184 Argv.reserve(n: 5 + 1 + UserArgs.size());
185 Argv.push_back(x: "-xc++");
186 Argv.insert(position: Argv.end(), first: UserArgs.begin(), last: UserArgs.end());
187
188 return IncrementalCompilerBuilder::create(ClangArgv&: Argv);
189}
190
191llvm::Expected<std::unique_ptr<CompilerInstance>>
192IncrementalCompilerBuilder::createCuda(bool device) {
193 std::vector<const char *> Argv;
194 Argv.reserve(n: 5 + 4 + UserArgs.size());
195
196 Argv.push_back(x: "-xcuda");
197 if (device)
198 Argv.push_back(x: "--cuda-device-only");
199 else
200 Argv.push_back(x: "--cuda-host-only");
201
202 std::string SDKPathArg = "--cuda-path=";
203 if (!CudaSDKPath.empty()) {
204 SDKPathArg += CudaSDKPath;
205 Argv.push_back(x: SDKPathArg.c_str());
206 }
207
208 std::string ArchArg = "--offload-arch=";
209 if (!OffloadArch.empty()) {
210 ArchArg += OffloadArch;
211 Argv.push_back(x: ArchArg.c_str());
212 }
213
214 Argv.insert(position: Argv.end(), first: UserArgs.begin(), last: UserArgs.end());
215
216 return IncrementalCompilerBuilder::create(ClangArgv&: Argv);
217}
218
219llvm::Expected<std::unique_ptr<CompilerInstance>>
220IncrementalCompilerBuilder::CreateCudaDevice() {
221 return IncrementalCompilerBuilder::createCuda(device: true);
222}
223
224llvm::Expected<std::unique_ptr<CompilerInstance>>
225IncrementalCompilerBuilder::CreateCudaHost() {
226 return IncrementalCompilerBuilder::createCuda(device: false);
227}
228
229Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
230 llvm::Error &Err) {
231 llvm::ErrorAsOutParameter EAO(&Err);
232 auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
233 TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(args: std::move(LLVMCtx));
234 IncrParser = std::make_unique<IncrementalParser>(args&: *this, args: std::move(CI),
235 args&: *TSCtx->getContext(), args&: Err);
236}
237
238Interpreter::~Interpreter() {
239 if (IncrExecutor) {
240 if (llvm::Error Err = IncrExecutor->cleanUp())
241 llvm::report_fatal_error(
242 reason: llvm::Twine("Failed to clean up IncrementalExecutor: ") +
243 toString(E: std::move(Err)));
244 }
245}
246
247// These better to put in a runtime header but we can't. This is because we
248// can't find the precise resource directory in unittests so we have to hard
249// code them.
250const char *const Runtimes = R"(
251#ifdef __cplusplus
252 void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
253 void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*);
254 void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*);
255 void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, float);
256 void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double);
257 void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double);
258 void __clang_Interpreter_SetValueNoAlloc(void*,void*,void*,unsigned long long);
259 struct __clang_Interpreter_NewTag{} __ci_newtag;
260 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
261 template <class T, class = T (*)() /*disable for arrays*/>
262 void __clang_Interpreter_SetValueCopyArr(T* Src, void* Placement, unsigned long Size) {
263 for (auto Idx = 0; Idx < Size; ++Idx)
264 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
265 }
266 template <class T, unsigned long N>
267 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
268 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
269 }
270#endif // __cplusplus
271)";
272
273llvm::Expected<std::unique_ptr<Interpreter>>
274Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
275 llvm::Error Err = llvm::Error::success();
276 auto Interp =
277 std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err));
278 if (Err)
279 return std::move(Err);
280
281 auto PTU = Interp->Parse(Code: Runtimes);
282 if (!PTU)
283 return PTU.takeError();
284
285 Interp->ValuePrintingInfo.resize(N: 4);
286 // FIXME: This is a ugly hack. Undo command checks its availability by looking
287 // at the size of the PTU list. However we have parsed something in the
288 // beginning of the REPL so we have to mark them as 'Irrevocable'.
289 Interp->InitPTUSize = Interp->IncrParser->getPTUs().size();
290 return std::move(Interp);
291}
292
293llvm::Expected<std::unique_ptr<Interpreter>>
294Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
295 std::unique_ptr<CompilerInstance> DCI) {
296 // avoid writing fat binary to disk using an in-memory virtual file system
297 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> IMVFS =
298 std::make_unique<llvm::vfs::InMemoryFileSystem>();
299 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayVFS =
300 std::make_unique<llvm::vfs::OverlayFileSystem>(
301 args: llvm::vfs::getRealFileSystem());
302 OverlayVFS->pushOverlay(FS: IMVFS);
303 CI->createFileManager(VFS: OverlayVFS);
304
305 auto Interp = Interpreter::create(CI: std::move(CI));
306 if (auto E = Interp.takeError())
307 return std::move(E);
308
309 llvm::Error Err = llvm::Error::success();
310 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
311 args&: **Interp, args: std::move(DCI), args&: *(*Interp)->IncrParser.get(),
312 args&: *(*Interp)->TSCtx->getContext(), args&: IMVFS, args&: Err);
313 if (Err)
314 return std::move(Err);
315
316 (*Interp)->DeviceParser = std::move(DeviceParser);
317
318 return Interp;
319}
320
321const CompilerInstance *Interpreter::getCompilerInstance() const {
322 return IncrParser->getCI();
323}
324
325CompilerInstance *Interpreter::getCompilerInstance() {
326 return IncrParser->getCI();
327}
328
329llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {
330 if (!IncrExecutor) {
331 if (auto Err = CreateExecutor())
332 return std::move(Err);
333 }
334
335 return IncrExecutor->GetExecutionEngine();
336}
337
338ASTContext &Interpreter::getASTContext() {
339 return getCompilerInstance()->getASTContext();
340}
341
342const ASTContext &Interpreter::getASTContext() const {
343 return getCompilerInstance()->getASTContext();
344}
345
346size_t Interpreter::getEffectivePTUSize() const {
347 std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
348 assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
349 return PTUs.size() - InitPTUSize;
350}
351
352llvm::Expected<PartialTranslationUnit &>
353Interpreter::Parse(llvm::StringRef Code) {
354 // If we have a device parser, parse it first.
355 // The generated code will be included in the host compilation
356 if (DeviceParser) {
357 auto DevicePTU = DeviceParser->Parse(Input: Code);
358 if (auto E = DevicePTU.takeError())
359 return std::move(E);
360 }
361
362 // Tell the interpreter sliently ignore unused expressions since value
363 // printing could cause it.
364 getCompilerInstance()->getDiagnostics().setSeverity(
365 clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());
366 return IncrParser->Parse(Input: Code);
367}
368
369llvm::Error Interpreter::CreateExecutor() {
370 const clang::TargetInfo &TI =
371 getCompilerInstance()->getASTContext().getTargetInfo();
372 llvm::Error Err = llvm::Error::success();
373 auto Executor = std::make_unique<IncrementalExecutor>(args&: *TSCtx, args&: Err, args: TI);
374 if (!Err)
375 IncrExecutor = std::move(Executor);
376
377 return Err;
378}
379
380llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
381 assert(T.TheModule);
382 if (!IncrExecutor) {
383 auto Err = CreateExecutor();
384 if (Err)
385 return Err;
386 }
387 // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
388 if (auto Err = IncrExecutor->addModule(PTU&: T))
389 return Err;
390
391 if (auto Err = IncrExecutor->runCtors())
392 return Err;
393
394 return llvm::Error::success();
395}
396
397llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
398
399 auto PTU = Parse(Code);
400 if (!PTU)
401 return PTU.takeError();
402 if (PTU->TheModule)
403 if (llvm::Error Err = Execute(T&: *PTU))
404 return Err;
405
406 if (LastValue.isValid()) {
407 if (!V) {
408 LastValue.dump();
409 LastValue.clear();
410 } else
411 *V = std::move(LastValue);
412 }
413 return llvm::Error::success();
414}
415
416llvm::Expected<llvm::orc::ExecutorAddr>
417Interpreter::getSymbolAddress(GlobalDecl GD) const {
418 if (!IncrExecutor)
419 return llvm::make_error<llvm::StringError>(Args: "Operation failed. "
420 "No execution engine",
421 Args: std::error_code());
422 llvm::StringRef MangledName = IncrParser->GetMangledName(GD);
423 return getSymbolAddress(IRName: MangledName);
424}
425
426llvm::Expected<llvm::orc::ExecutorAddr>
427Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
428 if (!IncrExecutor)
429 return llvm::make_error<llvm::StringError>(Args: "Operation failed. "
430 "No execution engine",
431 Args: std::error_code());
432
433 return IncrExecutor->getSymbolAddress(Name: IRName, NameKind: IncrementalExecutor::IRName);
434}
435
436llvm::Expected<llvm::orc::ExecutorAddr>
437Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const {
438 if (!IncrExecutor)
439 return llvm::make_error<llvm::StringError>(Args: "Operation failed. "
440 "No execution engine",
441 Args: std::error_code());
442
443 return IncrExecutor->getSymbolAddress(Name, NameKind: IncrementalExecutor::LinkerName);
444}
445
446llvm::Error Interpreter::Undo(unsigned N) {
447
448 std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
449 if (N > getEffectivePTUSize())
450 return llvm::make_error<llvm::StringError>(Args: "Operation failed. "
451 "Too many undos",
452 Args: std::error_code());
453 for (unsigned I = 0; I < N; I++) {
454 if (IncrExecutor) {
455 if (llvm::Error Err = IncrExecutor->removeModule(PTU&: PTUs.back()))
456 return Err;
457 }
458
459 IncrParser->CleanUpPTU(PTU&: PTUs.back());
460 PTUs.pop_back();
461 }
462 return llvm::Error::success();
463}
464
465llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
466 auto EE = getExecutionEngine();
467 if (!EE)
468 return EE.takeError();
469
470 auto &DL = EE->getDataLayout();
471
472 if (auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::Load(
473 FileName: name, GlobalPrefix: DL.getGlobalPrefix()))
474 EE->getMainJITDylib().addGenerator(DefGenerator: std::move(*DLSG));
475 else
476 return DLSG.takeError();
477
478 return llvm::Error::success();
479}
480
481llvm::Expected<llvm::orc::ExecutorAddr>
482Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
483 assert(CXXRD && "Cannot compile a destructor for a nullptr");
484 if (auto Dtor = Dtors.find(Val: CXXRD); Dtor != Dtors.end())
485 return Dtor->getSecond();
486
487 if (CXXRD->hasIrrelevantDestructor())
488 return llvm::orc::ExecutorAddr{};
489
490 CXXDestructorDecl *DtorRD =
491 getCompilerInstance()->getSema().LookupDestructor(Class: CXXRD);
492
493 llvm::StringRef Name =
494 IncrParser->GetMangledName(GD: GlobalDecl(DtorRD, Dtor_Base));
495 auto AddrOrErr = getSymbolAddress(IRName: Name);
496 if (!AddrOrErr)
497 return AddrOrErr.takeError();
498
499 Dtors[CXXRD] = *AddrOrErr;
500 return AddrOrErr;
501}
502
503static constexpr llvm::StringRef MagicRuntimeInterface[] = {
504 "__clang_Interpreter_SetValueNoAlloc",
505 "__clang_Interpreter_SetValueWithAlloc",
506 "__clang_Interpreter_SetValueCopyArr", "__ci_newtag"};
507
508bool Interpreter::FindRuntimeInterface() {
509 if (llvm::all_of(Range&: ValuePrintingInfo, P: [](Expr *E) { return E != nullptr; }))
510 return true;
511
512 Sema &S = getCompilerInstance()->getSema();
513 ASTContext &Ctx = S.getASTContext();
514
515 auto LookupInterface = [&](Expr *&Interface, llvm::StringRef Name) {
516 LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(),
517 Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration);
518 S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl());
519 if (R.empty())
520 return false;
521
522 CXXScopeSpec CSS;
523 Interface = S.BuildDeclarationNameExpr(SS: CSS, R, /*ADL=*/NeedsADL: false).get();
524 return true;
525 };
526
527 if (!LookupInterface(ValuePrintingInfo[NoAlloc],
528 MagicRuntimeInterface[NoAlloc]))
529 return false;
530 if (!LookupInterface(ValuePrintingInfo[WithAlloc],
531 MagicRuntimeInterface[WithAlloc]))
532 return false;
533 if (!LookupInterface(ValuePrintingInfo[CopyArray],
534 MagicRuntimeInterface[CopyArray]))
535 return false;
536 if (!LookupInterface(ValuePrintingInfo[NewTag],
537 MagicRuntimeInterface[NewTag]))
538 return false;
539 return true;
540}
541
542namespace {
543
544class RuntimeInterfaceBuilder
545 : public TypeVisitor<RuntimeInterfaceBuilder, Interpreter::InterfaceKind> {
546 clang::Interpreter &Interp;
547 ASTContext &Ctx;
548 Sema &S;
549 Expr *E;
550 llvm::SmallVector<Expr *, 3> Args;
551
552public:
553 RuntimeInterfaceBuilder(clang::Interpreter &In, ASTContext &C, Sema &SemaRef,
554 Expr *VE, ArrayRef<Expr *> FixedArgs)
555 : Interp(In), Ctx(C), S(SemaRef), E(VE) {
556 // The Interpreter* parameter and the out parameter `OutVal`.
557 for (Expr *E : FixedArgs)
558 Args.push_back(Elt: E);
559
560 // Get rid of ExprWithCleanups.
561 if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(Val: E))
562 E = EWC->getSubExpr();
563 }
564
565 ExprResult getCall() {
566 QualType Ty = E->getType();
567 QualType DesugaredTy = Ty.getDesugaredType(Context: Ctx);
568
569 // For lvalue struct, we treat it as a reference.
570 if (DesugaredTy->isRecordType() && E->isLValue()) {
571 DesugaredTy = Ctx.getLValueReferenceType(T: DesugaredTy);
572 Ty = Ctx.getLValueReferenceType(T: Ty);
573 }
574
575 Expr *TypeArg =
576 CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)Ty.getAsOpaquePtr());
577 // The QualType parameter `OpaqueType`, represented as `void*`.
578 Args.push_back(Elt: TypeArg);
579
580 // We push the last parameter based on the type of the Expr. Note we need
581 // special care for rvalue struct.
582 Interpreter::InterfaceKind Kind = Visit(T: &*DesugaredTy);
583 switch (Kind) {
584 case Interpreter::InterfaceKind::WithAlloc:
585 case Interpreter::InterfaceKind::CopyArray: {
586 // __clang_Interpreter_SetValueWithAlloc.
587 ExprResult AllocCall = S.ActOnCallExpr(
588 /*Scope=*/S: nullptr,
589 Fn: Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::WithAlloc],
590 LParenLoc: E->getBeginLoc(), ArgExprs: Args, RParenLoc: E->getEndLoc());
591 assert(!AllocCall.isInvalid() && "Can't create runtime interface call!");
592
593 TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(T: Ty, Loc: SourceLocation());
594
595 // Force CodeGen to emit destructor.
596 if (auto *RD = Ty->getAsCXXRecordDecl()) {
597 auto *Dtor = S.LookupDestructor(Class: RD);
598 Dtor->addAttr(UsedAttr::CreateImplicit(Ctx));
599 Interp.getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
600 D: DeclGroupRef(Dtor));
601 }
602
603 // __clang_Interpreter_SetValueCopyArr.
604 if (Kind == Interpreter::InterfaceKind::CopyArray) {
605 const auto *ConstantArrTy =
606 cast<ConstantArrayType>(Val: DesugaredTy.getTypePtr());
607 size_t ArrSize = Ctx.getConstantArrayElementCount(CA: ConstantArrTy);
608 Expr *ArrSizeExpr = IntegerLiteralExpr(C&: Ctx, Val: ArrSize);
609 Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
610 return S.ActOnCallExpr(
611 /*Scope *=*/S: nullptr,
612 Fn: Interp
613 .getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
614 LParenLoc: SourceLocation(), ArgExprs: Args, RParenLoc: SourceLocation());
615 }
616 Expr *Args[] = {
617 AllocCall.get(),
618 Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NewTag]};
619 ExprResult CXXNewCall = S.BuildCXXNew(
620 Range: E->getSourceRange(),
621 /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), PlacementArgs: Args,
622 /*PlacementRParen=*/SourceLocation(),
623 /*TypeIdParens=*/SourceRange(), AllocType: TSI->getType(), AllocTypeInfo: TSI, ArraySize: std::nullopt,
624 DirectInitRange: E->getSourceRange(), Initializer: E);
625
626 assert(!CXXNewCall.isInvalid() &&
627 "Can't create runtime placement new call!");
628
629 return S.ActOnFinishFullExpr(Expr: CXXNewCall.get(),
630 /*DiscardedValue=*/false);
631 }
632 // __clang_Interpreter_SetValueNoAlloc.
633 case Interpreter::InterfaceKind::NoAlloc: {
634 return S.ActOnCallExpr(
635 /*Scope=*/S: nullptr,
636 Fn: Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
637 LParenLoc: E->getBeginLoc(), ArgExprs: Args, RParenLoc: E->getEndLoc());
638 }
639 default:
640 llvm_unreachable("Unhandled Interpreter::InterfaceKind");
641 }
642 }
643
644 Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
645 return Interpreter::InterfaceKind::WithAlloc;
646 }
647
648 Interpreter::InterfaceKind
649 VisitMemberPointerType(const MemberPointerType *Ty) {
650 return Interpreter::InterfaceKind::WithAlloc;
651 }
652
653 Interpreter::InterfaceKind
654 VisitConstantArrayType(const ConstantArrayType *Ty) {
655 return Interpreter::InterfaceKind::CopyArray;
656 }
657
658 Interpreter::InterfaceKind
659 VisitFunctionProtoType(const FunctionProtoType *Ty) {
660 HandlePtrType(Ty);
661 return Interpreter::InterfaceKind::NoAlloc;
662 }
663
664 Interpreter::InterfaceKind VisitPointerType(const PointerType *Ty) {
665 HandlePtrType(Ty);
666 return Interpreter::InterfaceKind::NoAlloc;
667 }
668
669 Interpreter::InterfaceKind VisitReferenceType(const ReferenceType *Ty) {
670 ExprResult AddrOfE = S.CreateBuiltinUnaryOp(OpLoc: SourceLocation(), Opc: UO_AddrOf, InputExpr: E);
671 assert(!AddrOfE.isInvalid() && "Can not create unary expression");
672 Args.push_back(Elt: AddrOfE.get());
673 return Interpreter::InterfaceKind::NoAlloc;
674 }
675
676 Interpreter::InterfaceKind VisitBuiltinType(const BuiltinType *Ty) {
677 if (Ty->isNullPtrType())
678 Args.push_back(Elt: E);
679 else if (Ty->isFloatingType())
680 Args.push_back(Elt: E);
681 else if (Ty->isIntegralOrEnumerationType())
682 HandleIntegralOrEnumType(Ty);
683 else if (Ty->isVoidType()) {
684 // Do we need to still run `E`?
685 }
686
687 return Interpreter::InterfaceKind::NoAlloc;
688 }
689
690 Interpreter::InterfaceKind VisitEnumType(const EnumType *Ty) {
691 HandleIntegralOrEnumType(Ty);
692 return Interpreter::InterfaceKind::NoAlloc;
693 }
694
695private:
696 // Force cast these types to uint64 to reduce the number of overloads of
697 // `__clang_Interpreter_SetValueNoAlloc`.
698 void HandleIntegralOrEnumType(const Type *Ty) {
699 TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(T: Ctx.UnsignedLongLongTy);
700 ExprResult CastedExpr =
701 S.BuildCStyleCastExpr(LParenLoc: SourceLocation(), Ty: TSI, RParenLoc: SourceLocation(), Op: E);
702 assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
703 Args.push_back(Elt: CastedExpr.get());
704 }
705
706 void HandlePtrType(const Type *Ty) {
707 TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(T: Ctx.VoidPtrTy);
708 ExprResult CastedExpr =
709 S.BuildCStyleCastExpr(LParenLoc: SourceLocation(), Ty: TSI, RParenLoc: SourceLocation(), Op: E);
710 assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");
711 Args.push_back(Elt: CastedExpr.get());
712 }
713};
714} // namespace
715
716// This synthesizes a call expression to a speciall
717// function that is responsible for generating the Value.
718// In general, we transform:
719// clang-repl> x
720// To:
721// // 1. If x is a built-in type like int, float.
722// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, x);
723// // 2. If x is a struct, and a lvalue.
724// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType,
725// &x);
726// // 3. If x is a struct, but a rvalue.
727// new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue,
728// xQualType)) (x);
729
730Expr *Interpreter::SynthesizeExpr(Expr *E) {
731 Sema &S = getCompilerInstance()->getSema();
732 ASTContext &Ctx = S.getASTContext();
733
734 if (!FindRuntimeInterface())
735 llvm_unreachable("We can't find the runtime iterface for pretty print!");
736
737 // Create parameter `ThisInterp`.
738 auto *ThisInterp = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this);
739
740 // Create parameter `OutVal`.
741 auto *OutValue = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue);
742
743 // Build `__clang_Interpreter_SetValue*` call.
744 RuntimeInterfaceBuilder Builder(*this, Ctx, S, E, {ThisInterp, OutValue});
745
746 ExprResult Result = Builder.getCall();
747 // It could fail, like printing an array type in C. (not supported)
748 if (Result.isInvalid())
749 return E;
750 return Result.get();
751}
752
753// Temporary rvalue struct that need special care.
754REPL_EXTERNAL_VISIBILITY void *
755__clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
756 void *OpaqueType) {
757 Value &VRef = *(Value *)OutVal;
758 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
759 return VRef.getPtr();
760}
761
762// Pointers, lvalue struct that can take as a reference.
763REPL_EXTERNAL_VISIBILITY void
764__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
765 void *Val) {
766 Value &VRef = *(Value *)OutVal;
767 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
768 VRef.setPtr(Val);
769}
770
771REPL_EXTERNAL_VISIBILITY void
772__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal,
773 void *OpaqueType) {
774 Value &VRef = *(Value *)OutVal;
775 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
776}
777
778static void SetValueDataBasedOnQualType(Value &V, unsigned long long Data) {
779 QualType QT = V.getType();
780 if (const auto *ET = QT->getAs<EnumType>())
781 QT = ET->getDecl()->getIntegerType();
782
783 switch (QT->castAs<BuiltinType>()->getKind()) {
784 default:
785 llvm_unreachable("unknown type kind!");
786#define X(type, name) \
787 case BuiltinType::name: \
788 V.set##name(Data); \
789 break;
790 REPL_BUILTIN_TYPES
791#undef X
792 }
793}
794
795REPL_EXTERNAL_VISIBILITY void
796__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
797 unsigned long long Val) {
798 Value &VRef = *(Value *)OutVal;
799 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
800 SetValueDataBasedOnQualType(V&: VRef, Data: Val);
801}
802
803REPL_EXTERNAL_VISIBILITY void
804__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
805 float Val) {
806 Value &VRef = *(Value *)OutVal;
807 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
808 VRef.setFloat(Val);
809}
810
811REPL_EXTERNAL_VISIBILITY void
812__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
813 double Val) {
814 Value &VRef = *(Value *)OutVal;
815 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
816 VRef.setDouble(Val);
817}
818
819REPL_EXTERNAL_VISIBILITY void
820__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
821 long double Val) {
822 Value &VRef = *(Value *)OutVal;
823 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
824 VRef.setLongDouble(Val);
825}
826
827// A trampoline to work around the fact that operator placement new cannot
828// really be forward declared due to libc++ and libstdc++ declaration mismatch.
829// FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same
830// definition in the interpreter runtime. We should move it in a runtime header
831// which gets included by the interpreter and here.
832struct __clang_Interpreter_NewTag {};
833REPL_EXTERNAL_VISIBILITY void *
834operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept {
835 // Just forward to the standard operator placement new.
836 return operator new(__sz, __p);
837}
838

source code of clang/lib/Interpreter/Interpreter.cpp