https://github.com/aaronj0 created https://github.com/llvm/llvm-project/pull/217870
clang-repl cannot currently emit the LLVM IR it generates. The command-line emit actions are accepted but folded into `EmitLLVMOnlyAction` (producing no output), and `frontend::EmitLLVM` is rejected by the incremental frontend action when `-emit-llvm` is passed. This prevents users from inspecting IR produced per-input PTU. This patch teaches clang-repl to honor `-emit-llvm` by allowing the IncrementalAction to accept `frontend::EmitLLVM` , making the driver print each input's `llvm::Modul` to stdout instead of executing it, similar to `clang -emit-llvm`. This enables a lit-level test to FileCheck the IR produced by clang-repl and the effect of a statement on it. Exposing this functionality beyond the driver level to allow library consumers of `clang::Interpreter` to use it is a planned follow-up. >From 7c2499af26c1d1269ea5fbc9e180419f416ef94b Mon Sep 17 00:00:00 2001 From: Aaron Jomy <[email protected]> Date: Wed, 19 Aug 2026 16:04:50 +0200 Subject: [PATCH] [clang-repl] Honor -emit-llvm to print incremental IR clang-repl cannot currently emit the LLVM IR it generates. The command-line emit actions are accepted but folded into `EmitLLVMOnlyAction` (producing no output), and `frontend::EmitLLVM` is rejected by the incremental frontend action when `-emit-llvm` is passed. This prevents users from inspecting IR produced per-input PTU. This patch teaches clang-repl to honor `-emit-llvm` by allowing the IncrementalAction to accept `frontend::EmitLLVM` , making the driver print each input's `llvm::Modul` to stdout instead of executing it, similar to `clang -emit-llvm`. This enables a lit-level test to FileCheck the IR produced by clang-repl and the effect of a statement on it. Exposing this functionality beyond the driver level to allow library consumers of `clang::Interpreter` to use it is a planned follow-up. --- clang/lib/Interpreter/IncrementalAction.cpp | 1 + clang/test/Interpreter/emit-llvm.cpp | 20 ++++++++++++++++++++ clang/tools/clang-repl/ClangRepl.cpp | 21 +++++++++++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 clang/test/Interpreter/emit-llvm.cpp diff --git a/clang/lib/Interpreter/IncrementalAction.cpp b/clang/lib/Interpreter/IncrementalAction.cpp index d22031c8fa893..85f00c36dd5aa 100644 --- a/clang/lib/Interpreter/IncrementalAction.cpp +++ b/clang/lib/Interpreter/IncrementalAction.cpp @@ -47,6 +47,7 @@ IncrementalAction::IncrementalAction(CompilerInstance &Instance, case frontend::EmitBC: case frontend::EmitObj: case frontend::PrintPreprocessedInput: + case frontend::EmitLLVM: case frontend::EmitLLVMOnly: Act.reset(new EmitLLVMOnlyAction(&LLVMCtx)); break; diff --git a/clang/test/Interpreter/emit-llvm.cpp b/clang/test/Interpreter/emit-llvm.cpp new file mode 100644 index 0000000000000..9b2bad1dc9208 --- /dev/null +++ b/clang/test/Interpreter/emit-llvm.cpp @@ -0,0 +1,20 @@ +// REQUIRES: host-supports-jit +// +// -emit-llvm prints the IR of each input instead of running it. +// +// RUN: cat %s | clang-repl -Xcc -Xclang -Xcc -emit-llvm | FileCheck %s + +extern "C" int add(int a, int b) { return a + b; } +// CHECK: define {{.*}}i32 @add( +// CHECK: ret i32 + +int answer = 42; +// CHECK: @answer = {{.*}}i32 42 + +extern "C" int neg(int a) { return -a; } +// CHECK: define {{.*}}i32 @neg( + +// Not run, so the value is not printed. +int r = add(19, 23); +r +// CHECK-NOT: (int) 42 diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp index c9873540a5d66..c8d705056e879 100644 --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/clang/tools/clang-repl/ClangRepl.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendOptions.h" #include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/IncrementalExecutor.h" #include "clang/Interpreter/Interpreter.h" @@ -24,6 +25,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/IR/Module.h" #include "llvm/LineEditor/LineEditor.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -342,6 +344,10 @@ int main(int argc, const char **argv) { if (CudaEnabled) DeviceCI->LoadRequestedPlugins(); + // '-emit-llvm' prints the IR of each input instead of executing it. + const bool EmitLLVMIR = + CI->getFrontendOpts().ProgramAction == clang::frontend::EmitLLVM; + std::unique_ptr<clang::Interpreter> Interp; if (CudaEnabled) { @@ -361,8 +367,19 @@ int main(int argc, const char **argv) { bool HasError = false; + auto ProcessInput = [&](llvm::StringRef Input) -> llvm::Error { + if (!EmitLLVMIR) + return Interp->ParseAndExecute(Input); + auto PTU = Interp->Parse(Input); + if (!PTU) + return PTU.takeError(); + if (PTU->TheModule) + PTU->TheModule->print(llvm::outs(), /*AAW=*/nullptr); + return llvm::Error::success(); + }; + for (const std::string &input : OptInputs) { - if (auto Err = Interp->ParseAndExecute(input)) { + if (auto Err = ProcessInput(input)) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); HasError = true; } @@ -413,7 +430,7 @@ int main(int argc, const char **argv) { Input), std::error_code()); llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); - } else if (auto Err = Interp->ParseAndExecute(Input)) { + } else if (auto Err = ProcessInput(Input)) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
