Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Interpreter/Interpreter.cpp
Line
Count
Source (jump to first uncovered line)
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"
45
using namespace clang;
46
47
// FIXME: Figure out how to unify with namespace init_convenience from
48
//        tools/clang-import-test/clang-import-test.cpp
49
namespace {
50
/// Retrieves the clang CC1 specific flags out of the compilation's jobs.
51
/// \returns NULL on error.
52
static llvm::Expected<const llvm::opt::ArgStringList *>
53
GetCC1Arguments(DiagnosticsEngine *Diagnostics,
54
50
                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
50
  const driver::JobList &Jobs = Compilation->getJobs();
58
50
  if (!Jobs.size() || !isa<driver::Command>(*Jobs.begin()))
59
0
    return llvm::createStringError(llvm::errc::not_supported,
60
0
                                   "Driver initialization failed. "
61
0
                                   "Unable to create a driver job");
62
63
  // The one job we find should be to invoke clang again.
64
50
  const driver::Command *Cmd = cast<driver::Command>(&(*Jobs.begin()));
65
50
  if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
66
0
    return llvm::createStringError(llvm::errc::not_supported,
67
0
                                   "Driver initialization failed");
68
69
50
  return &Cmd->getArguments();
70
50
}
71
72
static llvm::Expected<std::unique_ptr<CompilerInstance>>
73
50
CreateCI(const llvm::opt::ArgStringList &Argv) {
74
50
  std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
75
50
  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
50
  auto PCHOps = Clang->getPCHContainerOperations();
80
50
  PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
81
50
  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.
85
50
  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
86
50
  TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
87
50
  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
88
50
  bool Success = CompilerInvocation::CreateFromArgs(
89
50
      Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
90
91
  // Infer the builtin include path if unspecified.
92
50
  if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
93
50
      Clang->getHeaderSearchOpts().ResourceDir.empty())
94
0
    Clang->getHeaderSearchOpts().ResourceDir =
95
0
        CompilerInvocation::GetResourcesPath(Argv[0], nullptr);
96
97
  // Create the actual diagnostics engine.
98
50
  Clang->createDiagnostics();
99
50
  if (!Clang->hasDiagnostics())
100
0
    return llvm::createStringError(llvm::errc::not_supported,
101
0
                                   "Initialization failed. "
102
0
                                   "Unable to create diagnostics engine");
103
104
50
  DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
105
50
  if (!Success)
106
0
    return llvm::createStringError(llvm::errc::not_supported,
107
0
                                   "Initialization failed. "
108
0
                                   "Unable to flush diagnostics");
109
110
  // FIXME: Merge with CompilerInstance::ExecuteAction.
111
50
  llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release();
112
50
  Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);
113
114
50
  Clang->setTarget(TargetInfo::CreateTargetInfo(
115
50
      Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
116
50
  if (!Clang->hasTarget())
117
0
    return llvm::createStringError(llvm::errc::not_supported,
118
0
                                   "Initialization failed. "
119
0
                                   "Target is missing");
120
121
50
  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
50
  Clang->getCodeGenOpts().ClearASTBeforeBackend = false;
126
127
50
  Clang->getFrontendOpts().DisableFree = false;
128
50
  Clang->getCodeGenOpts().DisableFree = false;
129
50
  return std::move(Clang);
130
50
}
131
132
} // anonymous namespace
133
134
llvm::Expected<std::unique_ptr<CompilerInstance>>
135
50
IncrementalCompilerBuilder::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
50
  std::string MainExecutableName =
140
50
      llvm::sys::fs::getMainExecutable(nullptr, nullptr);
141
142
50
  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
50
  ClangArgv.insert(ClangArgv.end(), "-Xclang");
150
50
  ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions");
151
50
  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
50
  ClangArgv.push_back("<<< inputs >>>");
156
157
  // Buffer diagnostics from argument parsing so that we can output them using a
158
  // well formed diagnostic object.
159
50
  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
160
50
  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
161
50
      CreateAndPopulateDiagOpts(ClangArgv);
162
50
  TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
163
50
  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
164
165
50
  driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0],
166
50
                        llvm::sys::getProcessTriple(), Diags);
167
50
  Driver.setCheckInputsExist(false); // the input comes from mem buffers
168
50
  llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
169
50
  std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
170
171
50
  if (Compilation->getArgs().hasArg(driver::options::OPT_v))
172
0
    Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
173
174
50
  auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
175
50
  if (auto Err = ErrOrCC1Args.takeError())
176
0
    return std::move(Err);
177
178
50
  return CreateCI(**ErrOrCC1Args);
179
50
}
180
181
llvm::Expected<std::unique_ptr<CompilerInstance>>
182
36
IncrementalCompilerBuilder::CreateCpp() {
183
36
  std::vector<const char *> Argv;
184
36
  Argv.reserve(5 + 1 + UserArgs.size());
185
36
  Argv.push_back("-xc++");
186
36
  Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
187
188
36
  return IncrementalCompilerBuilder::create(Argv);
189
36
}
190
191
llvm::Expected<std::unique_ptr<CompilerInstance>>
192
14
IncrementalCompilerBuilder::createCuda(bool device) {
193
14
  std::vector<const char *> Argv;
194
14
  Argv.reserve(5 + 4 + UserArgs.size());
195
196
14
  Argv.push_back("-xcuda");
197
14
  if (device)
198
7
    Argv.push_back("--cuda-device-only");
199
7
  else
200
7
    Argv.push_back("--cuda-host-only");
201
202
14
  std::string SDKPathArg = "--cuda-path=";
203
14
  if (!CudaSDKPath.empty()) {
204
0
    SDKPathArg += CudaSDKPath;
205
0
    Argv.push_back(SDKPathArg.c_str());
206
0
  }
207
208
14
  std::string ArchArg = "--offload-arch=";
209
14
  if (!OffloadArch.empty()) {
210
14
    ArchArg += OffloadArch;
211
14
    Argv.push_back(ArchArg.c_str());
212
14
  }
213
214
14
  Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
215
216
14
  return IncrementalCompilerBuilder::create(Argv);
217
14
}
218
219
llvm::Expected<std::unique_ptr<CompilerInstance>>
220
7
IncrementalCompilerBuilder::CreateCudaDevice() {
221
7
  return IncrementalCompilerBuilder::createCuda(true);
222
7
}
223
224
llvm::Expected<std::unique_ptr<CompilerInstance>>
225
7
IncrementalCompilerBuilder::CreateCudaHost() {
226
7
  return IncrementalCompilerBuilder::createCuda(false);
227
7
}
228
229
Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
230
43
                         llvm::Error &Err) {
231
43
  llvm::ErrorAsOutParameter EAO(&Err);
232
43
  auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
233
43
  TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
234
43
  IncrParser = std::make_unique<IncrementalParser>(*this, std::move(CI),
235
43
                                                   *TSCtx->getContext(), Err);
236
43
}
237
238
36
Interpreter::~Interpreter() {
239
36
  if (IncrExecutor) {
240
22
    if (llvm::Error Err = IncrExecutor->cleanUp())
241
0
      llvm::report_fatal_error(
242
0
          llvm::Twine("Failed to clean up IncrementalExecutor: ") +
243
0
          toString(std::move(Err)));
244
22
  }
245
36
}
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.
250
const 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
270
llvm::Expected<std::unique_ptr<Interpreter>>
271
43
Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
272
43
  llvm::Error Err = llvm::Error::success();
273
43
  auto Interp =
274
43
      std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err));
275
43
  if (Err)
276
0
    return std::move(Err);
277
278
43
  auto PTU = Interp->Parse(Runtimes);
279
43
  if (!PTU)
280
0
    return PTU.takeError();
281
282
43
  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
43
  Interp->InitPTUSize = Interp->IncrParser->getPTUs().size();
287
43
  return std::move(Interp);
288
43
}
289
290
llvm::Expected<std::unique_ptr<Interpreter>>
291
Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
292
7
                            std::unique_ptr<CompilerInstance> DCI) {
293
  // avoid writing fat binary to disk using an in-memory virtual file system
294
7
  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> IMVFS =
295
7
      std::make_unique<llvm::vfs::InMemoryFileSystem>();
296
7
  llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayVFS =
297
7
      std::make_unique<llvm::vfs::OverlayFileSystem>(
298
7
          llvm::vfs::getRealFileSystem());
299
7
  OverlayVFS->pushOverlay(IMVFS);
300
7
  CI->createFileManager(OverlayVFS);
301
302
7
  auto Interp = Interpreter::create(std::move(CI));
303
7
  if (auto E = Interp.takeError())
304
0
    return std::move(E);
305
306
7
  llvm::Error Err = llvm::Error::success();
307
7
  auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
308
7
      **Interp, std::move(DCI), *(*Interp)->IncrParser.get(),
309
7
      *(*Interp)->TSCtx->getContext(), IMVFS, Err);
310
7
  if (Err)
311
0
    return std::move(Err);
312
313
7
  (*Interp)->DeviceParser = std::move(DeviceParser);
314
315
7
  return Interp;
316
7
}
317
318
448
const CompilerInstance *Interpreter::getCompilerInstance() const {
319
448
  return IncrParser->getCI();
320
448
}
321
322
7
llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {
323
7
  if (!IncrExecutor) {
324
7
    if (auto Err = CreateExecutor())
325
0
      return std::move(Err);
326
7
  }
327
328
7
  return IncrExecutor->GetExecutionEngine();
329
7
}
330
331
12
ASTContext &Interpreter::getASTContext() {
332
12
  return getCompilerInstance()->getASTContext();
333
12
}
334
335
0
const ASTContext &Interpreter::getASTContext() const {
336
0
  return getCompilerInstance()->getASTContext();
337
0
}
338
339
8
size_t Interpreter::getEffectivePTUSize() const {
340
8
  std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
341
8
  assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
342
8
  return PTUs.size() - InitPTUSize;
343
8
}
344
345
llvm::Expected<PartialTranslationUnit &>
346
366
Interpreter::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
366
  if (DeviceParser) {
350
0
    auto DevicePTU = DeviceParser->Parse(Code);
351
0
    if (auto E = DevicePTU.takeError())
352
0
      return std::move(E);
353
0
  }
354
355
  // Tell the interpreter sliently ignore unused expressions since value
356
  // printing could cause it.
357
366
  getCompilerInstance()->getDiagnostics().setSeverity(
358
366
      clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());
359
366
  return IncrParser->Parse(Code);
360
366
}
361
362
29
llvm::Error Interpreter::CreateExecutor() {
363
29
  const clang::TargetInfo &TI =
364
29
      getCompilerInstance()->getASTContext().getTargetInfo();
365
29
  llvm::Error Err = llvm::Error::success();
366
29
  auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
367
29
  if (!Err)
368
29
    IncrExecutor = std::move(Executor);
369
370
29
  return Err;
371
29
}
372
373
289
llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
374
289
  assert(T.TheModule);
375
289
  if (!IncrExecutor) {
376
22
    auto Err = CreateExecutor();
377
22
    if (Err)
378
0
      return Err;
379
22
  }
380
  // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
381
289
  if (auto Err = IncrExecutor->addModule(T))
382
0
    return Err;
383
384
289
  if (auto Err = IncrExecutor->runCtors())
385
0
    return Err;
386
387
289
  return llvm::Error::success();
388
289
}
389
390
303
llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
391
392
303
  auto PTU = Parse(Code);
393
303
  if (!PTU)
394
2
    return PTU.takeError();
395
301
  if (PTU->TheModule)
396
287
    if (llvm::Error Err = Execute(*PTU))
397
0
      return Err;
398
399
301
  if (LastValue.isValid()) {
400
9
    if (!V) {
401
0
      LastValue.dump();
402
0
      LastValue.clear();
403
0
    } else
404
9
      *V = std::move(LastValue);
405
9
  }
406
301
  return llvm::Error::success();
407
301
}
408
409
llvm::Expected<llvm::orc::ExecutorAddr>
410
1
Interpreter::getSymbolAddress(GlobalDecl GD) const {
411
1
  if (!IncrExecutor)
412
0
    return llvm::make_error<llvm::StringError>("Operation failed. "
413
0
                                               "No execution engine",
414
0
                                               std::error_code());
415
1
  llvm::StringRef MangledName = IncrParser->GetMangledName(GD);
416
1
  return getSymbolAddress(MangledName);
417
1
}
418
419
llvm::Expected<llvm::orc::ExecutorAddr>
420
6
Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
421
6
  if (!IncrExecutor)
422
0
    return llvm::make_error<llvm::StringError>("Operation failed. "
423
0
                                               "No execution engine",
424
0
                                               std::error_code());
425
426
6
  return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
427
6
}
428
429
llvm::Expected<llvm::orc::ExecutorAddr>
430
0
Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const {
431
0
  if (!IncrExecutor)
432
0
    return llvm::make_error<llvm::StringError>("Operation failed. "
433
0
                                               "No execution engine",
434
0
                                               std::error_code());
435
436
0
  return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
437
0
}
438
439
8
llvm::Error Interpreter::Undo(unsigned N) {
440
441
8
  std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
442
8
  if (N > getEffectivePTUSize())
443
2
    return llvm::make_error<llvm::StringError>("Operation failed. "
444
2
                                               "Too many undos",
445
2
                                               std::error_code());
446
12
  
for (unsigned I = 0; 6
I < N;
I++6
) {
447
6
    if (IncrExecutor) {
448
3
      if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
449
0
        return Err;
450
3
    }
451
452
6
    IncrParser->CleanUpPTU(PTUs.back());
453
6
    PTUs.pop_back();
454
6
  }
455
6
  return llvm::Error::success();
456
6
}
457
458
7
llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
459
7
  auto EE = getExecutionEngine();
460
7
  if (!EE)
461
0
    return EE.takeError();
462
463
7
  auto &DL = EE->getDataLayout();
464
465
7
  if (auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::Load(
466
7
          name, DL.getGlobalPrefix()))
467
0
    EE->getMainJITDylib().addGenerator(std::move(*DLSG));
468
7
  else
469
7
    return DLSG.takeError();
470
471
0
  return llvm::Error::success();
472
7
}
473
474
llvm::Expected<llvm::orc::ExecutorAddr>
475
1
Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
476
1
  assert(CXXRD && "Cannot compile a destructor for a nullptr");
477
1
  if (auto Dtor = Dtors.find(CXXRD); Dtor != Dtors.end())
478
0
    return Dtor->getSecond();
479
480
1
  if (CXXRD->hasIrrelevantDestructor())
481
0
    return llvm::orc::ExecutorAddr{};
482
483
1
  CXXDestructorDecl *DtorRD =
484
1
      getCompilerInstance()->getSema().LookupDestructor(CXXRD);
485
486
1
  llvm::StringRef Name =
487
1
      IncrParser->GetMangledName(GlobalDecl(DtorRD, Dtor_Base));
488
1
  auto AddrOrErr = getSymbolAddress(Name);
489
1
  if (!AddrOrErr)
490
0
    return AddrOrErr.takeError();
491
492
1
  Dtors[CXXRD] = *AddrOrErr;
493
1
  return AddrOrErr;
494
1
}
495
496
static constexpr llvm::StringRef MagicRuntimeInterface[] = {
497
    "__clang_Interpreter_SetValueNoAlloc",
498
    "__clang_Interpreter_SetValueWithAlloc",
499
    "__clang_Interpreter_SetValueCopyArr"};
500
501
9
bool Interpreter::FindRuntimeInterface() {
502
25
  if (
llvm::all_of(ValuePrintingInfo, [](Expr *E) 9
{ return E != nullptr; }))
503
8
    return true;
504
505
1
  Sema &S = getCompilerInstance()->getSema();
506
1
  ASTContext &Ctx = S.getASTContext();
507
508
3
  auto LookupInterface = [&](Expr *&Interface, llvm::StringRef Name) {
509
3
    LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(),
510
3
                   Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration);
511
3
    S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl());
512
3
    if (R.empty())
513
0
      return false;
514
515
3
    CXXScopeSpec CSS;
516
3
    Interface = S.BuildDeclarationNameExpr(CSS, R, /*ADL=*/false).get();
517
3
    return true;
518
3
  };
519
520
1
  if (!LookupInterface(ValuePrintingInfo[NoAlloc],
521
1
                       MagicRuntimeInterface[NoAlloc]))
522
0
    return false;
523
1
  if (!LookupInterface(ValuePrintingInfo[WithAlloc],
524
1
                       MagicRuntimeInterface[WithAlloc]))
525
0
    return false;
526
1
  if (!LookupInterface(ValuePrintingInfo[CopyArray],
527
1
                       MagicRuntimeInterface[CopyArray]))
528
0
    return false;
529
1
  return true;
530
1
}
531
532
namespace {
533
534
class RuntimeInterfaceBuilder
535
    : public TypeVisitor<RuntimeInterfaceBuilder, Interpreter::InterfaceKind> {
536
  clang::Interpreter &Interp;
537
  ASTContext &Ctx;
538
  Sema &S;
539
  Expr *E;
540
  llvm::SmallVector<Expr *, 3> Args;
541
542
public:
543
  RuntimeInterfaceBuilder(clang::Interpreter &In, ASTContext &C, Sema &SemaRef,
544
                          Expr *VE, ArrayRef<Expr *> FixedArgs)
545
9
      : Interp(In), Ctx(C), S(SemaRef), E(VE) {
546
    // The Interpreter* parameter and the out parameter `OutVal`.
547
9
    for (Expr *E : FixedArgs)
548
18
      Args.push_back(E);
549
550
    // Get rid of ExprWithCleanups.
551
9
    if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))
552
1
      E = EWC->getSubExpr();
553
9
  }
554
555
9
  ExprResult getCall() {
556
9
    QualType Ty = E->getType();
557
9
    QualType DesugaredTy = Ty.getDesugaredType(Ctx);
558
559
    // For lvalue struct, we treat it as a reference.
560
9
    if (DesugaredTy->isRecordType() && 
E->isLValue()1
) {
561
0
      DesugaredTy = Ctx.getLValueReferenceType(DesugaredTy);
562
0
      Ty = Ctx.getLValueReferenceType(Ty);
563
0
    }
564
565
9
    Expr *TypeArg =
566
9
        CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)Ty.getAsOpaquePtr());
567
    // The QualType parameter `OpaqueType`, represented as `void*`.
568
9
    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
9
    Interpreter::InterfaceKind Kind = Visit(&*DesugaredTy);
573
9
    switch (Kind) {
574
3
    case Interpreter::InterfaceKind::WithAlloc:
575
3
    case Interpreter::InterfaceKind::CopyArray: {
576
      // __clang_Interpreter_SetValueWithAlloc.
577
3
      ExprResult AllocCall = S.ActOnCallExpr(
578
3
          /*Scope=*/nullptr,
579
3
          Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::WithAlloc],
580
3
          E->getBeginLoc(), Args, E->getEndLoc());
581
3
      assert(!AllocCall.isInvalid() && "Can't create runtime interface call!");
582
583
3
      TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation());
584
585
      // Force CodeGen to emit destructor.
586
3
      if (auto *RD = Ty->getAsCXXRecordDecl()) {
587
1
        auto *Dtor = S.LookupDestructor(RD);
588
1
        Dtor->addAttr(UsedAttr::CreateImplicit(Ctx));
589
1
        Interp.getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
590
1
            DeclGroupRef(Dtor));
591
1
      }
592
593
      // __clang_Interpreter_SetValueCopyArr.
594
3
      if (Kind == Interpreter::InterfaceKind::CopyArray) {
595
0
        const auto *ConstantArrTy =
596
0
            cast<ConstantArrayType>(DesugaredTy.getTypePtr());
597
0
        size_t ArrSize = Ctx.getConstantArrayElementCount(ConstantArrTy);
598
0
        Expr *ArrSizeExpr = IntegerLiteralExpr(Ctx, ArrSize);
599
0
        Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
600
0
        return S.ActOnCallExpr(
601
0
            /*Scope *=*/nullptr,
602
0
            Interp
603
0
                .getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
604
0
            SourceLocation(), Args, SourceLocation());
605
0
      }
606
3
      Expr *Args[] = {AllocCall.get()};
607
3
      ExprResult CXXNewCall = S.BuildCXXNew(
608
3
          E->getSourceRange(),
609
3
          /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
610
3
          /*PlacementRParen=*/SourceLocation(),
611
3
          /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
612
3
          E->getSourceRange(), E);
613
614
3
      assert(!CXXNewCall.isInvalid() &&
615
3
             "Can't create runtime placement new call!");
616
617
3
      return S.ActOnFinishFullExpr(CXXNewCall.get(),
618
3
                                   /*DiscardedValue=*/false);
619
3
    }
620
      // __clang_Interpreter_SetValueNoAlloc.
621
6
    case Interpreter::InterfaceKind::NoAlloc: {
622
6
      return S.ActOnCallExpr(
623
6
          /*Scope=*/nullptr,
624
6
          Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
625
6
          E->getBeginLoc(), Args, E->getEndLoc());
626
3
    }
627
9
    }
628
0
    llvm_unreachable("Unhandled Interpreter::InterfaceKind");
629
0
  }
630
631
1
  Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
632
1
    return Interpreter::InterfaceKind::WithAlloc;
633
1
  }
634
635
  Interpreter::InterfaceKind
636
2
  VisitMemberPointerType(const MemberPointerType *Ty) {
637
2
    return Interpreter::InterfaceKind::WithAlloc;
638
2
  }
639
640
  Interpreter::InterfaceKind
641
0
  VisitConstantArrayType(const ConstantArrayType *Ty) {
642
0
    return Interpreter::InterfaceKind::CopyArray;
643
0
  }
644
645
  Interpreter::InterfaceKind
646
1
  VisitFunctionProtoType(const FunctionProtoType *Ty) {
647
1
    HandlePtrType(Ty);
648
1
    return Interpreter::InterfaceKind::NoAlloc;
649
1
  }
650
651
0
  Interpreter::InterfaceKind VisitPointerType(const PointerType *Ty) {
652
0
    HandlePtrType(Ty);
653
0
    return Interpreter::InterfaceKind::NoAlloc;
654
0
  }
655
656
0
  Interpreter::InterfaceKind VisitReferenceType(const ReferenceType *Ty) {
657
0
    ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E);
658
0
    assert(!AddrOfE.isInvalid() && "Can not create unary expression");
659
0
    Args.push_back(AddrOfE.get());
660
0
    return Interpreter::InterfaceKind::NoAlloc;
661
0
  }
662
663
5
  Interpreter::InterfaceKind VisitBuiltinType(const BuiltinType *Ty) {
664
5
    if (Ty->isNullPtrType())
665
0
      Args.push_back(E);
666
5
    else if (Ty->isFloatingType())
667
1
      Args.push_back(E);
668
4
    else if (Ty->isIntegralOrEnumerationType())
669
3
      HandleIntegralOrEnumType(Ty);
670
1
    else if (Ty->isVoidType()) {
671
      // Do we need to still run `E`?
672
1
    }
673
674
5
    return Interpreter::InterfaceKind::NoAlloc;
675
5
  }
676
677
0
  Interpreter::InterfaceKind VisitEnumType(const EnumType *Ty) {
678
0
    HandleIntegralOrEnumType(Ty);
679
0
    return Interpreter::InterfaceKind::NoAlloc;
680
0
  }
681
682
private:
683
  // Force cast these types to uint64 to reduce the number of overloads of
684
  // `__clang_Interpreter_SetValueNoAlloc`.
685
3
  void HandleIntegralOrEnumType(const Type *Ty) {
686
3
    TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.UnsignedLongLongTy);
687
3
    ExprResult CastedExpr =
688
3
        S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
689
3
    assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
690
3
    Args.push_back(CastedExpr.get());
691
3
  }
692
693
1
  void HandlePtrType(const Type *Ty) {
694
1
    TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.VoidPtrTy);
695
1
    ExprResult CastedExpr =
696
1
        S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
697
1
    assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");
698
1
    Args.push_back(CastedExpr.get());
699
1
  }
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
717
9
Expr *Interpreter::SynthesizeExpr(Expr *E) {
718
9
  Sema &S = getCompilerInstance()->getSema();
719
9
  ASTContext &Ctx = S.getASTContext();
720
721
9
  if (!FindRuntimeInterface())
722
0
    llvm_unreachable("We can't find the runtime iterface for pretty print!");
723
724
  // Create parameter `ThisInterp`.
725
9
  auto *ThisInterp = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this);
726
727
  // Create parameter `OutVal`.
728
9
  auto *OutValue = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue);
729
730
  // Build `__clang_Interpreter_SetValue*` call.
731
9
  RuntimeInterfaceBuilder Builder(*this, Ctx, S, E, {ThisInterp, OutValue});
732
733
9
  ExprResult Result = Builder.getCall();
734
  // It could fail, like printing an array type in C. (not supported)
735
9
  if (Result.isInvalid())
736
0
    return E;
737
9
  return Result.get();
738
9
}
739
740
// Temporary rvalue struct that need special care.
741
REPL_EXTERNAL_VISIBILITY void *
742
__clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
743
3
                                      void *OpaqueType) {
744
3
  Value &VRef = *(Value *)OutVal;
745
3
  VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
746
3
  return VRef.getPtr();
747
3
}
748
749
// Pointers, lvalue struct that can take as a reference.
750
REPL_EXTERNAL_VISIBILITY void
751
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
752
1
                                    void *Val) {
753
1
  Value &VRef = *(Value *)OutVal;
754
1
  VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
755
1
  VRef.setPtr(Val);
756
1
}
757
758
REPL_EXTERNAL_VISIBILITY void
759
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal,
760
1
                                    void *OpaqueType) {
761
1
  Value &VRef = *(Value *)OutVal;
762
1
  VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
763
1
}
764
765
3
static void SetValueDataBasedOnQualType(Value &V, unsigned long long Data) {
766
3
  QualType QT = V.getType();
767
3
  if (const auto *ET = QT->getAs<EnumType>())
768
0
    QT = ET->getDecl()->getIntegerType();
769
770
3
  switch (QT->castAs<BuiltinType>()->getKind()) {
771
0
  default:
772
0
    llvm_unreachable("unknown type kind!");
773
0
#define X(type, name)                                                          \
774
3
  case BuiltinType::name:                                                      \
775
3
    V.set##name(Data);                                                         \
776
3
    break;
777
3
    
REPL_BUILTIN_TYPES0
778
3
#undef X
779
3
  }
780
3
}
781
782
REPL_EXTERNAL_VISIBILITY void
783
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
784
3
                                    unsigned long long Val) {
785
3
  Value &VRef = *(Value *)OutVal;
786
3
  VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
787
3
  SetValueDataBasedOnQualType(VRef, Val);
788
3
}
789
790
REPL_EXTERNAL_VISIBILITY void
791
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
792
0
                                    float Val) {
793
0
  Value &VRef = *(Value *)OutVal;
794
0
  VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
795
0
  VRef.setFloat(Val);
796
0
}
797
798
REPL_EXTERNAL_VISIBILITY void
799
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
800
1
                                    double Val) {
801
1
  Value &VRef = *(Value *)OutVal;
802
1
  VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
803
1
  VRef.setDouble(Val);
804
1
}
805
806
REPL_EXTERNAL_VISIBILITY void
807
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
808
0
                                    long double Val) {
809
0
  Value &VRef = *(Value *)OutVal;
810
0
  VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
811
0
  VRef.setLongDouble(Val);
812
0
}