clang 18.0.0git
Interpreter.cpp
Go to the documentation of this file.
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
20#include "clang/AST/Mangle.h"
28#include "clang/Driver/Driver.h"
29#include "clang/Driver/Job.h"
31#include "clang/Driver/Tool.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.
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>(*Jobs.begin()))
59 return llvm::createStringError(llvm::errc::not_supported,
60 "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>(&(*Jobs.begin()));
65 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
66 return llvm::createStringError(llvm::errc::not_supported,
67 "Driver initialization failed");
68
69 return &Cmd->getArguments();
70}
71
73CreateCI(const llvm::opt::ArgStringList &Argv) {
74 std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
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(std::make_unique<ObjectFilePCHContainerWriter>());
81 PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
82
83 // Buffer diagnostics from argument parsing so that we can output them using
84 // a well formed diagnostic object.
87 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
89 Clang->getInvocation(), 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 =
96
97 // Create the actual diagnostics engine.
98 Clang->createDiagnostics();
99 if (!Clang->hasDiagnostics())
100 return llvm::createStringError(llvm::errc::not_supported,
101 "Initialization failed. "
102 "Unable to create diagnostics engine");
103
104 DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
105 if (!Success)
106 return llvm::createStringError(llvm::errc::not_supported,
107 "Initialization failed. "
108 "Unable to flush diagnostics");
109
110 // FIXME: Merge with CompilerInstance::ExecuteAction.
111 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release();
112 Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);
113
114 Clang->setTarget(TargetInfo::CreateTargetInfo(
115 Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
116 if (!Clang->hasTarget())
117 return llvm::createStringError(llvm::errc::not_supported,
118 "Initialization failed. "
119 "Target is missing");
120
121 Clang->getTarget().adjust(Clang->getDiagnostics(), 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
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(nullptr, nullptr);
141
142 ClangArgv.insert(ClangArgv.begin(), 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(ClangArgv.end(), "-Xclang");
150 ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions");
151 ClangArgv.insert(ClangArgv.end(), "-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("<<< inputs >>>");
156
157 // Buffer diagnostics from argument parsing so that we can output them using a
158 // well formed diagnostic object.
161 CreateAndPopulateDiagOpts(ClangArgv);
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
169 std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
170
171 if (Compilation->getArgs().hasArg(driver::options::OPT_v))
172 Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
173
174 auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
175 if (auto Err = ErrOrCC1Args.takeError())
176 return std::move(Err);
177
178 return CreateCI(**ErrOrCC1Args);
179}
180
183 std::vector<const char *> Argv;
184 Argv.reserve(5 + 1 + UserArgs.size());
185 Argv.push_back("-xc++");
186 Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
187
188 return IncrementalCompilerBuilder::create(Argv);
189}
190
192IncrementalCompilerBuilder::createCuda(bool device) {
193 std::vector<const char *> Argv;
194 Argv.reserve(5 + 4 + UserArgs.size());
195
196 Argv.push_back("-xcuda");
197 if (device)
198 Argv.push_back("--cuda-device-only");
199 else
200 Argv.push_back("--cuda-host-only");
201
202 std::string SDKPathArg = "--cuda-path=";
203 if (!CudaSDKPath.empty()) {
204 SDKPathArg += CudaSDKPath;
205 Argv.push_back(SDKPathArg.c_str());
206 }
207
208 std::string ArchArg = "--offload-arch=";
209 if (!OffloadArch.empty()) {
210 ArchArg += OffloadArch;
211 Argv.push_back(ArchArg.c_str());
212 }
213
214 Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
215
216 return IncrementalCompilerBuilder::create(Argv);
217}
218
221 return IncrementalCompilerBuilder::createCuda(true);
222}
223
226 return IncrementalCompilerBuilder::createCuda(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>(std::move(LLVMCtx));
234 IncrParser = std::make_unique<IncrementalParser>(*this, std::move(CI),
235 *TSCtx->getContext(), Err);
236}
237
239 if (IncrExecutor) {
240 if (llvm::Error Err = IncrExecutor->cleanUp())
241 llvm::report_fatal_error(
242 llvm::Twine("Failed to clean up IncrementalExecutor: ") +
243 toString(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 void* operator new(__SIZE_TYPE__, void* __p) noexcept;
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 template <class T, class = T (*)() /*disable for arrays*/>
260 void __clang_Interpreter_SetValueCopyArr(T* Src, void* Placement, unsigned long Size) {
261 for (auto Idx = 0; Idx < Size; ++Idx)
262 new ((void*)(((T*)Placement) + Idx)) T(Src[Idx]);
263 }
264 template <class T, unsigned long N>
265 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
266 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
267 }
268)";
269
271Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
272 llvm::Error Err = llvm::Error::success();
273 auto Interp =
274 std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err));
275 if (Err)
276 return std::move(Err);
277
278 auto PTU = Interp->Parse(Runtimes);
279 if (!PTU)
280 return PTU.takeError();
281
282 Interp->ValuePrintingInfo.resize(3);
283 // FIXME: This is a ugly hack. Undo command checks its availability by looking
284 // at the size of the PTU list. However we have parsed something in the
285 // beginning of the REPL so we have to mark them as 'Irrevocable'.
286 Interp->InitPTUSize = Interp->IncrParser->getPTUs().size();
287 return std::move(Interp);
288}
289
291Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
292 std::unique_ptr<CompilerInstance> DCI) {
293 // avoid writing fat binary to disk using an in-memory virtual file system
295 std::make_unique<llvm::vfs::InMemoryFileSystem>();
297 std::make_unique<llvm::vfs::OverlayFileSystem>(
298 llvm::vfs::getRealFileSystem());
299 OverlayVFS->pushOverlay(IMVFS);
300 CI->createFileManager(OverlayVFS);
301
302 auto Interp = Interpreter::create(std::move(CI));
303 if (auto E = Interp.takeError())
304 return std::move(E);
305
306 llvm::Error Err = llvm::Error::success();
307 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
308 **Interp, std::move(DCI), *(*Interp)->IncrParser.get(),
309 *(*Interp)->TSCtx->getContext(), IMVFS, Err);
310 if (Err)
311 return std::move(Err);
312
313 (*Interp)->DeviceParser = std::move(DeviceParser);
314
315 return Interp;
316}
317
319 return IncrParser->getCI();
320}
321
323 if (!IncrExecutor) {
324 if (auto Err = CreateExecutor())
325 return std::move(Err);
326 }
327
328 return IncrExecutor->GetExecutionEngine();
329}
330
333}
334
337}
338
339size_t Interpreter::getEffectivePTUSize() const {
340 std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
341 assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
342 return PTUs.size() - InitPTUSize;
343}
344
346Interpreter::Parse(llvm::StringRef Code) {
347 // If we have a device parser, parse it first.
348 // The generated code will be included in the host compilation
349 if (DeviceParser) {
350 auto DevicePTU = DeviceParser->Parse(Code);
351 if (auto E = DevicePTU.takeError())
352 return std::move(E);
353 }
354
355 // Tell the interpreter sliently ignore unused expressions since value
356 // printing could cause it.
358 clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());
359 return IncrParser->Parse(Code);
360}
361
362llvm::Error Interpreter::CreateExecutor() {
363 const clang::TargetInfo &TI =
365 llvm::Error Err = llvm::Error::success();
366 auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
367 if (!Err)
368 IncrExecutor = std::move(Executor);
369
370 return Err;
371}
372
374 assert(T.TheModule);
375 if (!IncrExecutor) {
376 auto Err = CreateExecutor();
377 if (Err)
378 return Err;
379 }
380 // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
381 if (auto Err = IncrExecutor->addModule(T))
382 return Err;
383
384 if (auto Err = IncrExecutor->runCtors())
385 return Err;
386
387 return llvm::Error::success();
388}
389
390llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
391
392 auto PTU = Parse(Code);
393 if (!PTU)
394 return PTU.takeError();
395 if (PTU->TheModule)
396 if (llvm::Error Err = Execute(*PTU))
397 return Err;
398
399 if (LastValue.isValid()) {
400 if (!V) {
401 LastValue.dump();
402 LastValue.clear();
403 } else
404 *V = std::move(LastValue);
405 }
406 return llvm::Error::success();
407}
408
411 if (!IncrExecutor)
412 return llvm::make_error<llvm::StringError>("Operation failed. "
413 "No execution engine",
414 std::error_code());
415 llvm::StringRef MangledName = IncrParser->GetMangledName(GD);
416 return getSymbolAddress(MangledName);
417}
418
420Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
421 if (!IncrExecutor)
422 return llvm::make_error<llvm::StringError>("Operation failed. "
423 "No execution engine",
424 std::error_code());
425
426 return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
427}
428
431 if (!IncrExecutor)
432 return llvm::make_error<llvm::StringError>("Operation failed. "
433 "No execution engine",
434 std::error_code());
435
436 return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
437}
438
439llvm::Error Interpreter::Undo(unsigned N) {
440
441 std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
442 if (N > getEffectivePTUSize())
443 return llvm::make_error<llvm::StringError>("Operation failed. "
444 "Too many undos",
445 std::error_code());
446 for (unsigned I = 0; I < N; I++) {
447 if (IncrExecutor) {
448 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
449 return Err;
450 }
451
452 IncrParser->CleanUpPTU(PTUs.back());
453 PTUs.pop_back();
454 }
455 return llvm::Error::success();
456}
457
458llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
459 auto EE = getExecutionEngine();
460 if (!EE)
461 return EE.takeError();
462
463 auto &DL = EE->getDataLayout();
464
465 if (auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::Load(
466 name, DL.getGlobalPrefix()))
467 EE->getMainJITDylib().addGenerator(std::move(*DLSG));
468 else
469 return DLSG.takeError();
470
471 return llvm::Error::success();
472}
473
476 assert(CXXRD && "Cannot compile a destructor for a nullptr");
477 if (auto Dtor = Dtors.find(CXXRD); Dtor != Dtors.end())
478 return Dtor->getSecond();
479
480 if (CXXRD->hasIrrelevantDestructor())
481 return llvm::orc::ExecutorAddr{};
482
483 CXXDestructorDecl *DtorRD =
485
486 llvm::StringRef Name =
487 IncrParser->GetMangledName(GlobalDecl(DtorRD, Dtor_Base));
488 auto AddrOrErr = getSymbolAddress(Name);
489 if (!AddrOrErr)
490 return AddrOrErr.takeError();
491
492 Dtors[CXXRD] = *AddrOrErr;
493 return AddrOrErr;
494}
495
496static constexpr llvm::StringRef MagicRuntimeInterface[] = {
497 "__clang_Interpreter_SetValueNoAlloc",
498 "__clang_Interpreter_SetValueWithAlloc",
499 "__clang_Interpreter_SetValueCopyArr"};
500
501bool Interpreter::FindRuntimeInterface() {
502 if (llvm::all_of(ValuePrintingInfo, [](Expr *E) { return E != nullptr; }))
503 return true;
504
506 ASTContext &Ctx = S.getASTContext();
507
508 auto LookupInterface = [&](Expr *&Interface, llvm::StringRef Name) {
509 LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(),
512 if (R.empty())
513 return false;
514
515 CXXScopeSpec CSS;
516 Interface = S.BuildDeclarationNameExpr(CSS, R, /*ADL=*/false).get();
517 return true;
518 };
519
520 if (!LookupInterface(ValuePrintingInfo[NoAlloc],
522 return false;
523 if (!LookupInterface(ValuePrintingInfo[WithAlloc],
525 return false;
526 if (!LookupInterface(ValuePrintingInfo[CopyArray],
528 return false;
529 return true;
530}
531
532namespace {
533
534class RuntimeInterfaceBuilder
535 : public TypeVisitor<RuntimeInterfaceBuilder, Interpreter::InterfaceKind> {
536 clang::Interpreter &Interp;
537 ASTContext &Ctx;
538 Sema &S;
539 Expr *E;
541
542public:
543 RuntimeInterfaceBuilder(clang::Interpreter &In, ASTContext &C, Sema &SemaRef,
544 Expr *VE, ArrayRef<Expr *> FixedArgs)
545 : Interp(In), Ctx(C), S(SemaRef), E(VE) {
546 // The Interpreter* parameter and the out parameter `OutVal`.
547 for (Expr *E : FixedArgs)
548 Args.push_back(E);
549
550 // Get rid of ExprWithCleanups.
551 if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))
552 E = EWC->getSubExpr();
553 }
554
555 ExprResult getCall() {
556 QualType Ty = E->getType();
557 QualType DesugaredTy = Ty.getDesugaredType(Ctx);
558
559 // For lvalue struct, we treat it as a reference.
560 if (DesugaredTy->isRecordType() && E->isLValue()) {
561 DesugaredTy = Ctx.getLValueReferenceType(DesugaredTy);
562 Ty = Ctx.getLValueReferenceType(Ty);
563 }
564
565 Expr *TypeArg =
567 // The QualType parameter `OpaqueType`, represented as `void*`.
568 Args.push_back(TypeArg);
569
570 // We push the last parameter based on the type of the Expr. Note we need
571 // special care for rvalue struct.
572 Interpreter::InterfaceKind Kind = Visit(&*DesugaredTy);
573 switch (Kind) {
574 case Interpreter::InterfaceKind::WithAlloc:
575 case Interpreter::InterfaceKind::CopyArray: {
576 // __clang_Interpreter_SetValueWithAlloc.
577 ExprResult AllocCall = S.ActOnCallExpr(
578 /*Scope=*/nullptr,
579 Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::WithAlloc],
580 E->getBeginLoc(), Args, E->getEndLoc());
581 assert(!AllocCall.isInvalid() && "Can't create runtime interface call!");
582
584
585 // Force CodeGen to emit destructor.
586 if (auto *RD = Ty->getAsCXXRecordDecl()) {
587 auto *Dtor = S.LookupDestructor(RD);
588 Dtor->addAttr(UsedAttr::CreateImplicit(Ctx));
590 DeclGroupRef(Dtor));
591 }
592
593 // __clang_Interpreter_SetValueCopyArr.
594 if (Kind == Interpreter::InterfaceKind::CopyArray) {
595 const auto *ConstantArrTy =
596 cast<ConstantArrayType>(DesugaredTy.getTypePtr());
597 size_t ArrSize = Ctx.getConstantArrayElementCount(ConstantArrTy);
598 Expr *ArrSizeExpr = IntegerLiteralExpr(Ctx, ArrSize);
599 Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
600 return S.ActOnCallExpr(
601 /*Scope *=*/nullptr,
602 Interp
603 .getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
604 SourceLocation(), Args, SourceLocation());
605 }
606 Expr *Args[] = {AllocCall.get()};
607 ExprResult CXXNewCall = S.BuildCXXNew(
608 E->getSourceRange(),
609 /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
610 /*PlacementRParen=*/SourceLocation(),
611 /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
612 E->getSourceRange(), E);
613
614 assert(!CXXNewCall.isInvalid() &&
615 "Can't create runtime placement new call!");
616
617 return S.ActOnFinishFullExpr(CXXNewCall.get(),
618 /*DiscardedValue=*/false);
619 }
620 // __clang_Interpreter_SetValueNoAlloc.
621 case Interpreter::InterfaceKind::NoAlloc: {
622 return S.ActOnCallExpr(
623 /*Scope=*/nullptr,
624 Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
625 E->getBeginLoc(), Args, E->getEndLoc());
626 }
627 }
628 llvm_unreachable("Unhandled Interpreter::InterfaceKind");
629 }
630
631 Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
632 return Interpreter::InterfaceKind::WithAlloc;
633 }
634
636 VisitMemberPointerType(const MemberPointerType *Ty) {
637 return Interpreter::InterfaceKind::WithAlloc;
638 }
639
641 VisitConstantArrayType(const ConstantArrayType *Ty) {
642 return Interpreter::InterfaceKind::CopyArray;
643 }
644
646 VisitFunctionProtoType(const FunctionProtoType *Ty) {
647 HandlePtrType(Ty);
648 return Interpreter::InterfaceKind::NoAlloc;
649 }
650
651 Interpreter::InterfaceKind VisitPointerType(const PointerType *Ty) {
652 HandlePtrType(Ty);
653 return Interpreter::InterfaceKind::NoAlloc;
654 }
655
656 Interpreter::InterfaceKind VisitReferenceType(const ReferenceType *Ty) {
657 ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E);
658 assert(!AddrOfE.isInvalid() && "Can not create unary expression");
659 Args.push_back(AddrOfE.get());
660 return Interpreter::InterfaceKind::NoAlloc;
661 }
662
663 Interpreter::InterfaceKind VisitBuiltinType(const BuiltinType *Ty) {
664 if (Ty->isNullPtrType())
665 Args.push_back(E);
666 else if (Ty->isFloatingType())
667 Args.push_back(E);
668 else if (Ty->isIntegralOrEnumerationType())
669 HandleIntegralOrEnumType(Ty);
670 else if (Ty->isVoidType()) {
671 // Do we need to still run `E`?
672 }
673
674 return Interpreter::InterfaceKind::NoAlloc;
675 }
676
677 Interpreter::InterfaceKind VisitEnumType(const EnumType *Ty) {
678 HandleIntegralOrEnumType(Ty);
679 return Interpreter::InterfaceKind::NoAlloc;
680 }
681
682private:
683 // Force cast these types to uint64 to reduce the number of overloads of
684 // `__clang_Interpreter_SetValueNoAlloc`.
685 void HandleIntegralOrEnumType(const Type *Ty) {
687 ExprResult CastedExpr =
689 assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
690 Args.push_back(CastedExpr.get());
691 }
692
693 void HandlePtrType(const Type *Ty) {
695 ExprResult CastedExpr =
697 assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");
698 Args.push_back(CastedExpr.get());
699 }
700};
701} // namespace
702
703// This synthesizes a call expression to a speciall
704// function that is responsible for generating the Value.
705// In general, we transform:
706// clang-repl> x
707// To:
708// // 1. If x is a built-in type like int, float.
709// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, x);
710// // 2. If x is a struct, and a lvalue.
711// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType,
712// &x);
713// // 3. If x is a struct, but a rvalue.
714// new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue,
715// xQualType)) (x);
716
719 ASTContext &Ctx = S.getASTContext();
720
721 if (!FindRuntimeInterface())
722 llvm_unreachable("We can't find the runtime iterface for pretty print!");
723
724 // Create parameter `ThisInterp`.
725 auto *ThisInterp = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this);
726
727 // Create parameter `OutVal`.
728 auto *OutValue = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue);
729
730 // Build `__clang_Interpreter_SetValue*` call.
731 RuntimeInterfaceBuilder Builder(*this, Ctx, S, E, {ThisInterp, OutValue});
732
733 ExprResult Result = Builder.getCall();
734 // It could fail, like printing an array type in C. (not supported)
735 if (Result.isInvalid())
736 return E;
737 return Result.get();
738}
739
740// Temporary rvalue struct that need special care.
743 void *OpaqueType) {
744 Value &VRef = *(Value *)OutVal;
745 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
746 return VRef.getPtr();
747}
748
749// Pointers, lvalue struct that can take as a reference.
751__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
752 void *Val) {
753 Value &VRef = *(Value *)OutVal;
754 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
755 VRef.setPtr(Val);
756}
757
759__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal,
760 void *OpaqueType) {
761 Value &VRef = *(Value *)OutVal;
762 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
763}
764
765static void SetValueDataBasedOnQualType(Value &V, unsigned long long Data) {
766 QualType QT = V.getType();
767 if (const auto *ET = QT->getAs<EnumType>())
768 QT = ET->getDecl()->getIntegerType();
769
770 switch (QT->castAs<BuiltinType>()->getKind()) {
771 default:
772 llvm_unreachable("unknown type kind!");
773#define X(type, name) \
774 case BuiltinType::name: \
775 V.set##name(Data); \
776 break;
778#undef X
779 }
780}
781
783__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
784 unsigned long long Val) {
785 Value &VRef = *(Value *)OutVal;
786 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
788}
789
791__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
792 float Val) {
793 Value &VRef = *(Value *)OutVal;
794 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
795 VRef.setFloat(Val);
796}
797
799__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
800 double Val) {
801 Value &VRef = *(Value *)OutVal;
802 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
803 VRef.setDouble(Val);
804}
805
807__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
808 long double Val) {
809 Value &VRef = *(Value *)OutVal;
810 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
811 VRef.setLongDouble(Val);
812}
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3233
CompileCommand Cmd
#define REPL_EXTERNAL_VISIBILITY
Definition: Value.h:72
#define REPL_BUILTIN_TYPES
Definition: Value.h:75
static void SetValueDataBasedOnQualType(Value &V, unsigned long long Data)
const char *const Runtimes
REPL_EXTERNAL_VISIBILITY void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, void *Val)
REPL_EXTERNAL_VISIBILITY void * __clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal, void *OpaqueType)
static constexpr llvm::StringRef MagicRuntimeInterface[]
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
const char * Data
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
Definition: ASTConsumer.cpp:18
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1059
CanQualType VoidPtrTy
Definition: ASTContext.h:1104
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
IdentifierTable & Idents
Definition: ASTContext.h:630
TypeSourceInfo * getTrivialTypeSourceInfo(QualType T, SourceLocation Loc=SourceLocation()) const
Allocate a TypeSourceInfo where all locations have been initialized to a given location,...
CanQualType UnsignedLongLongTy
Definition: ASTContext.h:1088
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:743
uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const
Return number of constant array elements.
PtrTy get() const
Definition: Ownership.h:170
bool isInvalid() const
Definition: Ownership.h:166
This class is used for builtin types like 'int'.
Definition: Type.h:2682
Kind getKind() const
Definition: Type.h:2724
Represents a C++ destructor within a class.
Definition: DeclCXX.h:2755
Represents a C++ struct/union/class.
Definition: DeclCXX.h:254
bool hasIrrelevantDestructor() const
Determine whether this class has a destructor which has no semantic effect.
Definition: DeclCXX.h:1384
Represents a C++ nested-name-specifier or a global scope specifier.
Definition: DeclSpec.h:73
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
ASTContext & getASTContext() const
ASTConsumer & getASTConsumer() const
static std::string GetResourcesPath(const char *Argv0, void *MainAddr)
Get the directory where the compiler headers reside, relative to the compiler binary (found by the pa...
static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef< const char * > CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0=nullptr)
Create a compiler invocation from a list of input options.
Represents the canonical version of C arrays with a specified constant size.
Definition: Type.h:3131
void addAttr(Attr *A)
Definition: DeclBase.cpp:904
Used for handling and querying diagnostic IDs.
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:192
void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc)
This allows the client to specify that certain warnings are ignored.
Definition: Diagnostic.cpp:354
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of enums.
Definition: Type.h:4959
This represents one expression.
Definition: Expr.h:110
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Definition: Expr.h:271
QualType getType() const
Definition: Expr.h:142
Represents a prototype with parameter type info, e.g.
Definition: Type.h:4117
GlobalDecl - represents a global declaration.
Definition: GlobalDecl.h:56
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCudaHost()
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCpp()
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCudaDevice()
Provides top-level interfaces for incremental compilation and execution.
Definition: Interpreter.h:76
llvm::Expected< llvm::orc::ExecutorAddr > getSymbolAddress(GlobalDecl GD) const
llvm::Error Execute(PartialTranslationUnit &T)
llvm::Expected< llvm::orc::LLJIT & > getExecutionEngine()
llvm::Expected< llvm::orc::ExecutorAddr > getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const
static llvm::Expected< std::unique_ptr< Interpreter > > createWithCUDA(std::unique_ptr< CompilerInstance > CI, std::unique_ptr< CompilerInstance > DCI)
const CompilerInstance * getCompilerInstance() const
llvm::Expected< llvm::orc::ExecutorAddr > CompileDtorCall(CXXRecordDecl *CXXRD)
llvm::Error LoadDynamicLibrary(const char *name)
Link a dynamic library.
const llvm::SmallVectorImpl< Expr * > & getValuePrintingInfo() const
Definition: Interpreter.h:133
llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V=nullptr)
Expr * SynthesizeExpr(Expr *E)
static llvm::Expected< std::unique_ptr< Interpreter > > create(std::unique_ptr< CompilerInstance > CI)
llvm::Expected< PartialTranslationUnit & > Parse(llvm::StringRef Code)
llvm::Error Undo(unsigned N=1)
Undo N previous incremental inputs.
const ASTContext & getASTContext() const
Represents the results of name lookup.
Definition: Lookup.h:46
A pointer to member type per C++ 8.3.3 - Pointers to members.
Definition: Type.h:3031
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2840
A (possibly-)qualified type.
Definition: Type.h:736
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
Definition: Type.h:1084
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:6747
void * getAsOpaquePtr() const
Definition: Type.h:783
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4933
Base for LValueReferenceType and RValueReferenceType.
Definition: Type.h:2951
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:356
ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *InputExpr, bool IsAfterAmp=false)
Definition: SemaExpr.cpp:16245
@ LookupOrdinaryName
Ordinary name lookup, which finds ordinary names (functions, variables, typedefs, etc....
Definition: Sema.h:4360
ASTContext & getASTContext() const
Definition: Sema.h:1692
CXXDestructorDecl * LookupDestructor(CXXRecordDecl *Class)
Look for the destructor of the given class.
ExprResult BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, std::optional< Expr * > ArraySize, SourceRange DirectInitRange, Expr *Initializer)
ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, Expr *Op)
Definition: SemaCast.cpp:3331
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL, bool AcceptInvalidDecl=false)
Definition: SemaExpr.cpp:3410
@ ForVisibleRedeclaration
The lookup results will be used for redeclaration of a name, if an entity by that name already exists...
Definition: Sema.h:4416
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup=false)
Perform qualified name lookup into a given context.
ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig=nullptr)
ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
Definition: SemaExpr.cpp:7094
ExprResult ActOnFinishFullExpr(Expr *Expr, bool DiscardedValue)
Definition: Sema.h:6985
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceLocation getEndLoc() const LLVM_READONLY
Definition: Stmt.cpp:349
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:325
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.cpp:337
Exposes information about the current target.
Definition: TargetInfo.h:207
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:765
void FlushDiagnostics(DiagnosticsEngine &Diags) const
FlushDiagnostics - Flush the buffered diagnostics to an given diagnostic engine.
A container of type source information.
Definition: Type.h:6718
QualType getType() const
Return the type wrapped by this type source info.
Definition: Type.h:6729
An operation on a type.
Definition: TypeVisitor.h:64
The base class of the type hierarchy.
Definition: Type.h:1597
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1823
bool isVoidType() const
Definition: Type.h:7317
const T * castAs() const
Member-template castAs<specific type>.
Definition: Type.h:7590
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition: Type.h:7420
bool isFloatingType() const
Definition: Type.cpp:2190
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7523
bool isNullPtrType() const
Definition: Type.h:7342
bool isRecordType() const
Definition: Type.h:7089
void * getPtr() const
Definition: Value.cpp:229
void dump() const
Definition: Value.cpp:256
void clear()
Definition: Value.cpp:218
bool isValid() const
Definition: Value.h:131
void setPtr(void *Ptr)
Definition: Value.h:140
Command - An executable path/name and argument vector to execute.
Definition: Job.h:106
Compilation - A set of tasks to perform for a single driver invocation.
Definition: Compilation.h:45
const llvm::opt::DerivedArgList & getArgs() const
Definition: Compilation.h:201
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:77
JobList - A sequence of jobs to perform.
Definition: Job.h:262
size_type size() const
Definition: Job.h:285
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo=nullptr) const
Definition: Job.cpp:453
iterator begin()
Definition: Job.h:286
Defines the clang::TargetInfo interface.
@ Ignored
Do not present this diagnostic, ignore it.
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ C
Languages that the frontend can parse and compile.
@ Result
The result type of a method or function.
IntegerLiteral * IntegerLiteralExpr(ASTContext &C, uint64_t Val)
@ Dtor_Base
Base object dtor.
Definition: ABI.h:36
Expr * CStyleCastPtrExpr(Sema &S, QualType Ty, Expr *E)
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...
The class keeps track of various objects created as part of processing incremental inputs.
std::unique_ptr< llvm::Module > TheModule
The llvm IR produced for the input.