https://github.com/aaronj0 updated 
https://github.com/llvm/llvm-project/pull/217870

>From 9cda50552d8ba5b51c36cb7bbc967fdb13cdebbd Mon Sep 17 00:00:00 2001
From: Aaron Jomy <[email protected]>
Date: Wed, 19 Aug 2026 16:04:50 +0200
Subject: [PATCH 1/2] [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..9ed8013c22d03
--- /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
+
+extern "C" 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.
+extern "C" 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: ");
       }
 

>From 49d310a2221e7e51080146497faed2d4e62a16fd Mon Sep 17 00:00:00 2001
From: Aaron Jomy <[email protected]>
Date: Fri, 21 Aug 2026 16:55:09 +0200
Subject: [PATCH 2/2] [clang-repl] Move -emit-llvm printing into
 Interpreter::Parse

---
 clang/lib/Interpreter/Interpreter.cpp |  7 +++++++
 clang/test/Interpreter/emit-llvm.cpp  |  7 ++++---
 clang/tools/clang-repl/ClangRepl.cpp  | 21 ++-------------------
 3 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/clang/lib/Interpreter/Interpreter.cpp 
b/clang/lib/Interpreter/Interpreter.cpp
index 0536fdcd548a2..c9b127a360e5d 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -31,6 +31,7 @@
 #include "clang/Driver/Tool.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendOptions.h"
 #include "clang/Frontend/MultiplexConsumer.h"
 #include "clang/Frontend/TextDiagnosticBuffer.h"
 #include "clang/FrontendTool/Utils.h"
@@ -568,6 +569,12 @@ Interpreter::Parse(llvm::StringRef Code) {
 
   PartialTranslationUnit &LastPTU = IncrParser->RegisterPTU(*TuOrErr);
 
+  // Under -emit-llvm, print the module IR.
+  if (InitPTUSize && LastPTU.TheModule &&
+      getCompilerInstance()->getFrontendOpts().ProgramAction ==
+          frontend::EmitLLVM)
+    LastPTU.TheModule->print(llvm::outs(), /*AAW=*/nullptr);
+
   return LastPTU;
 }
 
diff --git a/clang/test/Interpreter/emit-llvm.cpp 
b/clang/test/Interpreter/emit-llvm.cpp
index 9ed8013c22d03..96f18a6d0d34d 100644
--- a/clang/test/Interpreter/emit-llvm.cpp
+++ b/clang/test/Interpreter/emit-llvm.cpp
@@ -1,6 +1,6 @@
 // REQUIRES: host-supports-jit
 //
-// -emit-llvm prints the IR of each input instead of running it.
+// -emit-llvm prints the IR of each input before running them.
 //
 // RUN: cat %s | clang-repl -Xcc -Xclang -Xcc -emit-llvm | FileCheck %s
 
@@ -14,7 +14,8 @@ extern "C" int answer = 42;
 extern "C" int neg(int a) { return -a; }
 // CHECK: define {{.*}}i32 @neg(
 
-// Not run, so the value is not printed.
 extern "C" int r = add(19, 23);
+// CHECK: @r = {{.*}}global i32
+// CHECK: call i32 @add(
 r
-// CHECK-NOT: (int) 42
+// CHECK: (int) 42
diff --git a/clang/tools/clang-repl/ClangRepl.cpp 
b/clang/tools/clang-repl/ClangRepl.cpp
index c8d705056e879..c9873540a5d66 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -15,7 +15,6 @@
 #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"
@@ -25,7 +24,6 @@
 #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"
@@ -344,10 +342,6 @@ 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) {
@@ -367,19 +361,8 @@ 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 = ProcessInput(input)) {
+    if (auto Err = Interp->ParseAndExecute(input)) {
       llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");
       HasError = true;
     }
@@ -430,7 +413,7 @@ int main(int argc, const char **argv) {
                 Input),
             std::error_code());
         llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");
-      } else if (auto Err = ProcessInput(Input)) {
+      } else if (auto Err = Interp->ParseAndExecute(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

Reply via email to