aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp522
1 files changed, 325 insertions, 197 deletions
diff --git a/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp b/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp
index 9f97a3c6b0be..985d0b7c0ef3 100644
--- a/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp
+++ b/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp
@@ -15,6 +15,9 @@
#include "IncrementalExecutor.h"
#include "IncrementalParser.h"
#include "InterpreterUtils.h"
+#ifdef __EMSCRIPTEN__
+#include "Wasm.h"
+#endif // __EMSCRIPTEN__
#include "clang/AST/ASTContext.h"
#include "clang/AST/Mangle.h"
@@ -42,6 +45,9 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Host.h"
+
+#include <cstdarg>
+
using namespace clang;
// FIXME: Figure out how to unify with namespace init_convenience from
@@ -132,7 +138,8 @@ CreateCI(const llvm::opt::ArgStringList &Argv) {
} // anonymous namespace
llvm::Expected<std::unique_ptr<CompilerInstance>>
-IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) {
+IncrementalCompilerBuilder::create(std::string TT,
+ std::vector<const char *> &ClangArgv) {
// If we don't know ClangArgv0 or the address of main() at this point, try
// to guess it anyway (it's possible on some platforms).
@@ -162,8 +169,7 @@ IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) {
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
- driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0],
- llvm::sys::getProcessTriple(), Diags);
+ driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags);
Driver.setCheckInputsExist(false); // the input comes from mem buffers
llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
@@ -183,9 +189,16 @@ IncrementalCompilerBuilder::CreateCpp() {
std::vector<const char *> Argv;
Argv.reserve(5 + 1 + UserArgs.size());
Argv.push_back("-xc++");
+#ifdef __EMSCRIPTEN__
+ Argv.push_back("-target");
+ Argv.push_back("wasm32-unknown-emscripten");
+ Argv.push_back("-shared");
+ Argv.push_back("-fvisibility=default");
+#endif
Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
- return IncrementalCompilerBuilder::create(Argv);
+ std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
+ return IncrementalCompilerBuilder::create(TT, Argv);
}
llvm::Expected<std::unique_ptr<CompilerInstance>>
@@ -213,7 +226,8 @@ IncrementalCompilerBuilder::createCuda(bool device) {
Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
- return IncrementalCompilerBuilder::create(Argv);
+ std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
+ return IncrementalCompilerBuilder::create(TT, Argv);
}
llvm::Expected<std::unique_ptr<CompilerInstance>>
@@ -227,12 +241,32 @@ IncrementalCompilerBuilder::CreateCudaHost() {
}
Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
- llvm::Error &Err) {
- llvm::ErrorAsOutParameter EAO(&Err);
+ llvm::Error &ErrOut,
+ std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder)
+ : JITBuilder(std::move(JITBuilder)) {
+ llvm::ErrorAsOutParameter EAO(&ErrOut);
auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
- IncrParser = std::make_unique<IncrementalParser>(*this, std::move(CI),
- *TSCtx->getContext(), Err);
+ IncrParser = std::make_unique<IncrementalParser>(
+ *this, std::move(CI), *TSCtx->getContext(), ErrOut);
+ if (ErrOut)
+ return;
+
+ // Not all frontends support code-generation, e.g. ast-dump actions don't
+ if (IncrParser->getCodeGen()) {
+ if (llvm::Error Err = CreateExecutor()) {
+ ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
+ return;
+ }
+
+ // Process the PTUs that came from initialization. For example -include will
+ // give us a header that's processed at initialization of the preprocessor.
+ for (PartialTranslationUnit &PTU : IncrParser->getPTUs())
+ if (llvm::Error Err = Execute(PTU)) {
+ ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
+ return;
+ }
+ }
}
Interpreter::~Interpreter() {
@@ -248,14 +282,10 @@ Interpreter::~Interpreter() {
// can't find the precise resource directory in unittests so we have to hard
// code them.
const char *const Runtimes = R"(
+ #define __CLANG_REPL__ 1
#ifdef __cplusplus
+ #define EXTERN_C extern "C"
void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
- void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*);
- void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*);
- void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, float);
- void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double);
- void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double);
- void __clang_Interpreter_SetValueNoAlloc(void*,void*,void*,unsigned long long);
struct __clang_Interpreter_NewTag{} __ci_newtag;
void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
template <class T, class = T (*)() /*disable for arrays*/>
@@ -267,7 +297,11 @@ const char *const Runtimes = R"(
void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
__clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
}
+#else
+ #define EXTERN_C extern
#endif // __cplusplus
+
+ EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
)";
llvm::Expected<std::unique_ptr<Interpreter>>
@@ -278,15 +312,14 @@ Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
if (Err)
return std::move(Err);
+ // Add runtime code and set a marker to hide it from user code. Undo will not
+ // go through that.
auto PTU = Interp->Parse(Runtimes);
if (!PTU)
return PTU.takeError();
+ Interp->markUserCodeStart();
Interp->ValuePrintingInfo.resize(4);
- // FIXME: This is a ugly hack. Undo command checks its availability by looking
- // at the size of the PTU list. However we have parsed something in the
- // beginning of the REPL so we have to mark them as 'Irrevocable'.
- Interp->InitPTUSize = Interp->IncrParser->getPTUs().size();
return std::move(Interp);
}
@@ -343,6 +376,11 @@ const ASTContext &Interpreter::getASTContext() const {
return getCompilerInstance()->getASTContext();
}
+void Interpreter::markUserCodeStart() {
+ assert(!InitPTUSize && "We only do this once");
+ InitPTUSize = IncrParser->getPTUs().size();
+}
+
size_t Interpreter::getEffectivePTUSize() const {
std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
@@ -366,17 +404,51 @@ Interpreter::Parse(llvm::StringRef Code) {
return IncrParser->Parse(Code);
}
+static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
+createJITTargetMachineBuilder(const std::string &TT) {
+ if (TT == llvm::sys::getProcessTriple())
+ // This fails immediately if the target backend is not registered
+ return llvm::orc::JITTargetMachineBuilder::detectHost();
+
+ // If the target backend is not registered, LLJITBuilder::create() will fail
+ return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
+}
+
llvm::Error Interpreter::CreateExecutor() {
- const clang::TargetInfo &TI =
- getCompilerInstance()->getASTContext().getTargetInfo();
+ if (IncrExecutor)
+ return llvm::make_error<llvm::StringError>("Operation failed. "
+ "Execution engine exists",
+ std::error_code());
+ if (!IncrParser->getCodeGen())
+ return llvm::make_error<llvm::StringError>("Operation failed. "
+ "No code generator available",
+ std::error_code());
+ if (!JITBuilder) {
+ const std::string &TT = getCompilerInstance()->getTargetOpts().Triple;
+ auto JTMB = createJITTargetMachineBuilder(TT);
+ if (!JTMB)
+ return JTMB.takeError();
+ auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
+ if (!JB)
+ return JB.takeError();
+ JITBuilder = std::move(*JB);
+ }
+
llvm::Error Err = llvm::Error::success();
- auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
+#ifdef __EMSCRIPTEN__
+ auto Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
+#else
+ auto Executor =
+ std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Err);
+#endif
if (!Err)
IncrExecutor = std::move(Executor);
return Err;
}
+void Interpreter::ResetExecutor() { IncrExecutor.reset(); }
+
llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
assert(T.TheModule);
if (!IncrExecutor) {
@@ -505,16 +577,21 @@ static constexpr llvm::StringRef MagicRuntimeInterface[] = {
"__clang_Interpreter_SetValueWithAlloc",
"__clang_Interpreter_SetValueCopyArr", "__ci_newtag"};
-bool Interpreter::FindRuntimeInterface() {
+static std::unique_ptr<RuntimeInterfaceBuilder>
+createInProcessRuntimeInterfaceBuilder(Interpreter &Interp, ASTContext &Ctx,
+ Sema &S);
+
+std::unique_ptr<RuntimeInterfaceBuilder> Interpreter::FindRuntimeInterface() {
if (llvm::all_of(ValuePrintingInfo, [](Expr *E) { return E != nullptr; }))
- return true;
+ return nullptr;
Sema &S = getCompilerInstance()->getSema();
ASTContext &Ctx = S.getASTContext();
auto LookupInterface = [&](Expr *&Interface, llvm::StringRef Name) {
LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(),
- Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration);
+ Sema::LookupOrdinaryName,
+ RedeclarationKind::ForVisibleRedeclaration);
S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl());
if (R.empty())
return false;
@@ -526,120 +603,36 @@ bool Interpreter::FindRuntimeInterface() {
if (!LookupInterface(ValuePrintingInfo[NoAlloc],
MagicRuntimeInterface[NoAlloc]))
- return false;
- if (!LookupInterface(ValuePrintingInfo[WithAlloc],
- MagicRuntimeInterface[WithAlloc]))
- return false;
- if (!LookupInterface(ValuePrintingInfo[CopyArray],
- MagicRuntimeInterface[CopyArray]))
- return false;
- if (!LookupInterface(ValuePrintingInfo[NewTag],
- MagicRuntimeInterface[NewTag]))
- return false;
- return true;
+ return nullptr;
+ if (Ctx.getLangOpts().CPlusPlus) {
+ if (!LookupInterface(ValuePrintingInfo[WithAlloc],
+ MagicRuntimeInterface[WithAlloc]))
+ return nullptr;
+ if (!LookupInterface(ValuePrintingInfo[CopyArray],
+ MagicRuntimeInterface[CopyArray]))
+ return nullptr;
+ if (!LookupInterface(ValuePrintingInfo[NewTag],
+ MagicRuntimeInterface[NewTag]))
+ return nullptr;
+ }
+
+ return createInProcessRuntimeInterfaceBuilder(*this, Ctx, S);
}
namespace {
-class RuntimeInterfaceBuilder
- : public TypeVisitor<RuntimeInterfaceBuilder, Interpreter::InterfaceKind> {
- clang::Interpreter &Interp;
+class InterfaceKindVisitor
+ : public TypeVisitor<InterfaceKindVisitor, Interpreter::InterfaceKind> {
+ friend class InProcessRuntimeInterfaceBuilder;
+
ASTContext &Ctx;
Sema &S;
Expr *E;
llvm::SmallVector<Expr *, 3> Args;
public:
- RuntimeInterfaceBuilder(clang::Interpreter &In, ASTContext &C, Sema &SemaRef,
- Expr *VE, ArrayRef<Expr *> FixedArgs)
- : Interp(In), Ctx(C), S(SemaRef), E(VE) {
- // The Interpreter* parameter and the out parameter `OutVal`.
- for (Expr *E : FixedArgs)
- Args.push_back(E);
-
- // Get rid of ExprWithCleanups.
- if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))
- E = EWC->getSubExpr();
- }
-
- ExprResult getCall() {
- QualType Ty = E->getType();
- QualType DesugaredTy = Ty.getDesugaredType(Ctx);
-
- // For lvalue struct, we treat it as a reference.
- if (DesugaredTy->isRecordType() && E->isLValue()) {
- DesugaredTy = Ctx.getLValueReferenceType(DesugaredTy);
- Ty = Ctx.getLValueReferenceType(Ty);
- }
-
- Expr *TypeArg =
- CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)Ty.getAsOpaquePtr());
- // The QualType parameter `OpaqueType`, represented as `void*`.
- Args.push_back(TypeArg);
-
- // We push the last parameter based on the type of the Expr. Note we need
- // special care for rvalue struct.
- Interpreter::InterfaceKind Kind = Visit(&*DesugaredTy);
- switch (Kind) {
- case Interpreter::InterfaceKind::WithAlloc:
- case Interpreter::InterfaceKind::CopyArray: {
- // __clang_Interpreter_SetValueWithAlloc.
- ExprResult AllocCall = S.ActOnCallExpr(
- /*Scope=*/nullptr,
- Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::WithAlloc],
- E->getBeginLoc(), Args, E->getEndLoc());
- assert(!AllocCall.isInvalid() && "Can't create runtime interface call!");
-
- TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation());
-
- // Force CodeGen to emit destructor.
- if (auto *RD = Ty->getAsCXXRecordDecl()) {
- auto *Dtor = S.LookupDestructor(RD);
- Dtor->addAttr(UsedAttr::CreateImplicit(Ctx));
- Interp.getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
- DeclGroupRef(Dtor));
- }
-
- // __clang_Interpreter_SetValueCopyArr.
- if (Kind == Interpreter::InterfaceKind::CopyArray) {
- const auto *ConstantArrTy =
- cast<ConstantArrayType>(DesugaredTy.getTypePtr());
- size_t ArrSize = Ctx.getConstantArrayElementCount(ConstantArrTy);
- Expr *ArrSizeExpr = IntegerLiteralExpr(Ctx, ArrSize);
- Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
- return S.ActOnCallExpr(
- /*Scope *=*/nullptr,
- Interp
- .getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
- SourceLocation(), Args, SourceLocation());
- }
- Expr *Args[] = {
- AllocCall.get(),
- Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NewTag]};
- ExprResult CXXNewCall = S.BuildCXXNew(
- E->getSourceRange(),
- /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
- /*PlacementRParen=*/SourceLocation(),
- /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
- E->getSourceRange(), E);
-
- assert(!CXXNewCall.isInvalid() &&
- "Can't create runtime placement new call!");
-
- return S.ActOnFinishFullExpr(CXXNewCall.get(),
- /*DiscardedValue=*/false);
- }
- // __clang_Interpreter_SetValueNoAlloc.
- case Interpreter::InterfaceKind::NoAlloc: {
- return S.ActOnCallExpr(
- /*Scope=*/nullptr,
- Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
- E->getBeginLoc(), Args, E->getEndLoc());
- }
- default:
- llvm_unreachable("Unhandled Interpreter::InterfaceKind");
- }
- }
+ InterfaceKindVisitor(ASTContext &Ctx, Sema &S, Expr *E)
+ : Ctx(Ctx), S(S), E(E) {}
Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
return Interpreter::InterfaceKind::WithAlloc;
@@ -693,10 +686,12 @@ public:
}
private:
- // Force cast these types to uint64 to reduce the number of overloads of
- // `__clang_Interpreter_SetValueNoAlloc`.
+ // Force cast these types to the uint that fits the register size. That way we
+ // reduce the number of overloads of `__clang_Interpreter_SetValueNoAlloc`.
void HandleIntegralOrEnumType(const Type *Ty) {
- TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.UnsignedLongLongTy);
+ uint64_t PtrBits = Ctx.getTypeSize(Ctx.VoidPtrTy);
+ QualType UIntTy = Ctx.getBitIntType(/*Unsigned=*/true, PtrBits);
+ TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(UIntTy);
ExprResult CastedExpr =
S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
@@ -711,8 +706,124 @@ private:
Args.push_back(CastedExpr.get());
}
};
+
+class InProcessRuntimeInterfaceBuilder : public RuntimeInterfaceBuilder {
+ Interpreter &Interp;
+ ASTContext &Ctx;
+ Sema &S;
+
+public:
+ InProcessRuntimeInterfaceBuilder(Interpreter &Interp, ASTContext &C, Sema &S)
+ : Interp(Interp), Ctx(C), S(S) {}
+
+ TransformExprFunction *getPrintValueTransformer() override {
+ return &transformForValuePrinting;
+ }
+
+private:
+ static ExprResult transformForValuePrinting(RuntimeInterfaceBuilder *Builder,
+ Expr *E,
+ ArrayRef<Expr *> FixedArgs) {
+ auto *B = static_cast<InProcessRuntimeInterfaceBuilder *>(Builder);
+
+ // Get rid of ExprWithCleanups.
+ if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))
+ E = EWC->getSubExpr();
+
+ InterfaceKindVisitor Visitor(B->Ctx, B->S, E);
+
+ // The Interpreter* parameter and the out parameter `OutVal`.
+ for (Expr *E : FixedArgs)
+ Visitor.Args.push_back(E);
+
+ QualType Ty = E->getType();
+ QualType DesugaredTy = Ty.getDesugaredType(B->Ctx);
+
+ // For lvalue struct, we treat it as a reference.
+ if (DesugaredTy->isRecordType() && E->isLValue()) {
+ DesugaredTy = B->Ctx.getLValueReferenceType(DesugaredTy);
+ Ty = B->Ctx.getLValueReferenceType(Ty);
+ }
+
+ Expr *TypeArg = CStyleCastPtrExpr(B->S, B->Ctx.VoidPtrTy,
+ (uintptr_t)Ty.getAsOpaquePtr());
+ // The QualType parameter `OpaqueType`, represented as `void*`.
+ Visitor.Args.push_back(TypeArg);
+
+ // We push the last parameter based on the type of the Expr. Note we need
+ // special care for rvalue struct.
+ Interpreter::InterfaceKind Kind = Visitor.Visit(&*DesugaredTy);
+ switch (Kind) {
+ case Interpreter::InterfaceKind::WithAlloc:
+ case Interpreter::InterfaceKind::CopyArray: {
+ // __clang_Interpreter_SetValueWithAlloc.
+ ExprResult AllocCall = B->S.ActOnCallExpr(
+ /*Scope=*/nullptr,
+ B->Interp
+ .getValuePrintingInfo()[Interpreter::InterfaceKind::WithAlloc],
+ E->getBeginLoc(), Visitor.Args, E->getEndLoc());
+ assert(!AllocCall.isInvalid() && "Can't create runtime interface call!");
+
+ TypeSourceInfo *TSI =
+ B->Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation());
+
+ // Force CodeGen to emit destructor.
+ if (auto *RD = Ty->getAsCXXRecordDecl()) {
+ auto *Dtor = B->S.LookupDestructor(RD);
+ Dtor->addAttr(UsedAttr::CreateImplicit(B->Ctx));
+ B->Interp.getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
+ DeclGroupRef(Dtor));
+ }
+
+ // __clang_Interpreter_SetValueCopyArr.
+ if (Kind == Interpreter::InterfaceKind::CopyArray) {
+ const auto *ConstantArrTy =
+ cast<ConstantArrayType>(DesugaredTy.getTypePtr());
+ size_t ArrSize = B->Ctx.getConstantArrayElementCount(ConstantArrTy);
+ Expr *ArrSizeExpr = IntegerLiteralExpr(B->Ctx, ArrSize);
+ Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
+ return B->S.ActOnCallExpr(
+ /*Scope *=*/nullptr,
+ B->Interp
+ .getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
+ SourceLocation(), Args, SourceLocation());
+ }
+ Expr *Args[] = {
+ AllocCall.get(),
+ B->Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NewTag]};
+ ExprResult CXXNewCall = B->S.BuildCXXNew(
+ E->getSourceRange(),
+ /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
+ /*PlacementRParen=*/SourceLocation(),
+ /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
+ E->getSourceRange(), E);
+
+ assert(!CXXNewCall.isInvalid() &&
+ "Can't create runtime placement new call!");
+
+ return B->S.ActOnFinishFullExpr(CXXNewCall.get(),
+ /*DiscardedValue=*/false);
+ }
+ // __clang_Interpreter_SetValueNoAlloc.
+ case Interpreter::InterfaceKind::NoAlloc: {
+ return B->S.ActOnCallExpr(
+ /*Scope=*/nullptr,
+ B->Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
+ E->getBeginLoc(), Visitor.Args, E->getEndLoc());
+ }
+ default:
+ llvm_unreachable("Unhandled Interpreter::InterfaceKind");
+ }
+ }
+};
} // namespace
+static std::unique_ptr<RuntimeInterfaceBuilder>
+createInProcessRuntimeInterfaceBuilder(Interpreter &Interp, ASTContext &Ctx,
+ Sema &S) {
+ return std::make_unique<InProcessRuntimeInterfaceBuilder>(Interp, Ctx, S);
+}
+
// This synthesizes a call expression to a speciall
// function that is responsible for generating the Value.
// In general, we transform:
@@ -731,8 +842,13 @@ Expr *Interpreter::SynthesizeExpr(Expr *E) {
Sema &S = getCompilerInstance()->getSema();
ASTContext &Ctx = S.getASTContext();
- if (!FindRuntimeInterface())
- llvm_unreachable("We can't find the runtime iterface for pretty print!");
+ if (!RuntimeIB) {
+ RuntimeIB = FindRuntimeInterface();
+ AddPrintValueCall = RuntimeIB->getPrintValueTransformer();
+ }
+
+ assert(AddPrintValueCall &&
+ "We don't have a runtime interface for pretty print!");
// Create parameter `ThisInterp`.
auto *ThisInterp = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this);
@@ -741,9 +857,9 @@ Expr *Interpreter::SynthesizeExpr(Expr *E) {
auto *OutValue = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue);
// Build `__clang_Interpreter_SetValue*` call.
- RuntimeInterfaceBuilder Builder(*this, Ctx, S, E, {ThisInterp, OutValue});
+ ExprResult Result =
+ AddPrintValueCall(RuntimeIB.get(), E, {ThisInterp, OutValue});
- ExprResult Result = Builder.getCall();
// It could fail, like printing an array type in C. (not supported)
if (Result.isInvalid())
return E;
@@ -759,69 +875,81 @@ __clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
return VRef.getPtr();
}
-// Pointers, lvalue struct that can take as a reference.
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- void *Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- VRef.setPtr(Val);
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal,
- void *OpaqueType) {
+extern "C" void REPL_EXTERNAL_VISIBILITY __clang_Interpreter_SetValueNoAlloc(
+ void *This, void *OutVal, void *OpaqueType, ...) {
Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
-}
-
-static void SetValueDataBasedOnQualType(Value &V, unsigned long long Data) {
- QualType QT = V.getType();
- if (const auto *ET = QT->getAs<EnumType>())
- QT = ET->getDecl()->getIntegerType();
-
- switch (QT->castAs<BuiltinType>()->getKind()) {
- default:
- llvm_unreachable("unknown type kind!");
-#define X(type, name) \
- case BuiltinType::name: \
- V.set##name(Data); \
- break;
- REPL_BUILTIN_TYPES
-#undef X
+ Interpreter *I = static_cast<Interpreter *>(This);
+ VRef = Value(I, OpaqueType);
+ if (VRef.isVoid())
+ return;
+
+ va_list args;
+ va_start(args, /*last named param*/ OpaqueType);
+
+ QualType QT = VRef.getType();
+ if (VRef.getKind() == Value::K_PtrOrObj) {
+ VRef.setPtr(va_arg(args, void *));
+ } else {
+ if (const auto *ET = QT->getAs<EnumType>())
+ QT = ET->getDecl()->getIntegerType();
+ switch (QT->castAs<BuiltinType>()->getKind()) {
+ default:
+ llvm_unreachable("unknown type kind!");
+ break;
+ // Types shorter than int are resolved as int, else va_arg has UB.
+ case BuiltinType::Bool:
+ VRef.setBool(va_arg(args, int));
+ break;
+ case BuiltinType::Char_S:
+ VRef.setChar_S(va_arg(args, int));
+ break;
+ case BuiltinType::SChar:
+ VRef.setSChar(va_arg(args, int));
+ break;
+ case BuiltinType::Char_U:
+ VRef.setChar_U(va_arg(args, unsigned));
+ break;
+ case BuiltinType::UChar:
+ VRef.setUChar(va_arg(args, unsigned));
+ break;
+ case BuiltinType::Short:
+ VRef.setShort(va_arg(args, int));
+ break;
+ case BuiltinType::UShort:
+ VRef.setUShort(va_arg(args, unsigned));
+ break;
+ case BuiltinType::Int:
+ VRef.setInt(va_arg(args, int));
+ break;
+ case BuiltinType::UInt:
+ VRef.setUInt(va_arg(args, unsigned));
+ break;
+ case BuiltinType::Long:
+ VRef.setLong(va_arg(args, long));
+ break;
+ case BuiltinType::ULong:
+ VRef.setULong(va_arg(args, unsigned long));
+ break;
+ case BuiltinType::LongLong:
+ VRef.setLongLong(va_arg(args, long long));
+ break;
+ case BuiltinType::ULongLong:
+ VRef.setULongLong(va_arg(args, unsigned long long));
+ break;
+ // Types shorter than double are resolved as double, else va_arg has UB.
+ case BuiltinType::Float:
+ VRef.setFloat(va_arg(args, double));
+ break;
+ case BuiltinType::Double:
+ VRef.setDouble(va_arg(args, double));
+ break;
+ case BuiltinType::LongDouble:
+ VRef.setLongDouble(va_arg(args, long double));
+ break;
+ // See REPL_BUILTIN_TYPES.
+ }
}
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- unsigned long long Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- SetValueDataBasedOnQualType(VRef, Val);
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- float Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- VRef.setFloat(Val);
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- double Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- VRef.setDouble(Val);
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- long double Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- VRef.setLongDouble(Val);
+ va_end(args);
}
// A trampoline to work around the fact that operator placement new cannot