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

>From daa2ac12efa7b390c19962facb4ddeec66686e64 Mon Sep 17 00:00:00 2001
From: Aaron Jomy <[email protected]>
Date: Fri, 7 Aug 2026 19:05:11 +0200
Subject: [PATCH 1/2] [clang][CodeGen] Add a StartModule overload taking
 CodeGenOptions

---
 clang/include/clang/CodeGen/ModuleBuilder.h |  3 +++
 clang/lib/CodeGen/ModuleBuilder.cpp         | 15 ++++++++++++++-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h 
b/clang/include/clang/CodeGen/ModuleBuilder.h
index cd93ef7cc654a..8fe7b388197b7 100644
--- a/clang/include/clang/CodeGen/ModuleBuilder.h
+++ b/clang/include/clang/CodeGen/ModuleBuilder.h
@@ -116,6 +116,9 @@ class CodeGenerator : public ASTConsumer {
   /// Create a new \c llvm::Module after calling HandleTranslationUnit. This
   /// enable codegen in interactive processing environments.
   llvm::Module* StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C);
+
+  llvm::Module *StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C,
+                            const CodeGenOptions &CGO);
 };
 
 /// CreateLLVMCodeGen - Create a CodeGenerator instance.
diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp 
b/clang/lib/CodeGen/ModuleBuilder.cpp
index 0b00362487d2a..57d5ac3ebdbdf 100644
--- a/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -39,7 +39,7 @@ namespace {
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
     const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
     const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
-    const CodeGenOptions &CodeGenOpts;
+    CodeGenOptions CodeGenOpts; // copied in so caller can modify
 
     unsigned HandlingTopLevelDecls;
 
@@ -155,6 +155,12 @@ namespace {
       return M.get();
     }
 
+    llvm::Module *StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C,
+                              const CodeGenOptions &CGO) {
+      CodeGenOpts = CGO;
+      return StartModule(ModuleName, C);
+    }
+
     void Initialize(ASTContext &Context) override {
       Ctx = &Context;
 
@@ -394,6 +400,13 @@ llvm::Module *CodeGenerator::StartModule(llvm::StringRef 
ModuleName,
   return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C);
 }
 
+llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName,
+                                         llvm::LLVMContext &C,
+                                         const CodeGenOptions &CGO) {
+  return static_cast<CodeGeneratorImpl *>(this)->StartModule(ModuleName, C,
+                                                             CGO);
+}
+
 std::unique_ptr<CodeGenerator>
 clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
                          IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,

>From d9a2bafaa5b7f8cb05fe33da2e10da3b0a7b6893 Mon Sep 17 00:00:00 2001
From: Aaron Jomy <[email protected]>
Date: Fri, 7 Aug 2026 19:05:11 +0200
Subject: [PATCH 2/2] [clang-repl] Add setOptLevel and #pragma clang repl
 optimize(N)

---
 clang/include/clang/Interpreter/Interpreter.h |  7 ++
 clang/lib/Interpreter/Interpreter.cpp         | 74 +++++++++++++++++++
 .../pragma-optimize-diagnostics.cpp           |  9 +++
 clang/test/Interpreter/pragma-optimize.cpp    | 16 ++++
 .../unittests/Interpreter/InterpreterTest.cpp | 48 ++++++++++++
 5 files changed, 154 insertions(+)
 create mode 100644 clang/test/Interpreter/pragma-optimize-diagnostics.cpp
 create mode 100644 clang/test/Interpreter/pragma-optimize.cpp

diff --git a/clang/include/clang/Interpreter/Interpreter.h 
b/clang/include/clang/Interpreter/Interpreter.h
index c2622b23d5d9c..828f76eba0dfd 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -45,6 +45,7 @@ class CXXRecordDecl;
 class Decl;
 class IncrementalParser;
 class IncrementalCUDADeviceParser;
+class PragmaHandler;
 
 /// Create a pre-configured \c CompilerInstance for incremental processing.
 class IncrementalCompilerBuilder {
@@ -105,6 +106,8 @@ class Interpreter {
   std::unique_ptr<IncrementalParser> IncrParser;
   std::unique_ptr<IncrementalExecutor> IncrExecutor;
 
+  std::unique_ptr<PragmaHandler> ReplPragma;
+
   // An optional parser for CUDA offloading
   std::unique_ptr<IncrementalCUDADeviceParser> DeviceParser;
 
@@ -160,6 +163,10 @@ class Interpreter {
   llvm::Error Execute(PartialTranslationUnit &T);
   llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr);
 
+  /// Set the optimization level for input parsed after this call. Affects
+  /// modules emitted subsequently; does not modify the shared 
CompilerInstance.
+  void setOptLevel(unsigned OptLevel);
+
   /// Undo N previous incremental inputs.
   llvm::Error Undo(unsigned N = 1);
 
diff --git a/clang/lib/Interpreter/Interpreter.cpp 
b/clang/lib/Interpreter/Interpreter.cpp
index 092f3ede771f6..f0b2a237b3362 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -20,6 +20,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Mangle.h"
 #include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/DiagnosticParse.h"
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/TargetInfo.h"
@@ -38,6 +39,8 @@
 #include "clang/Interpreter/IncrementalExecutor.h"
 #include "clang/Interpreter/Interpreter.h"
 #include "clang/Interpreter/Value.h"
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Options/OptionUtils.h"
 #include "clang/Options/Options.h"
@@ -216,6 +219,58 @@ static llvm::Error 
ExecuteIncrementalAction(CompilerInstance &CI,
   return llvm::Error::success();
 }
 
+// '#pragma clang repl optimize(N)' sets the optimization level (0-3) used to
+// emit modules for input parsed after the pragma.
+struct PragmaReplHandler : public PragmaHandler {
+  Interpreter &Interp;
+
+  PragmaReplHandler(Interpreter &Interp)
+      : PragmaHandler("repl"), Interp(Interp) {}
+
+  void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+                    Token &FirstToken) override {
+    Token Tok;
+    PP.LexUnexpandedToken(Tok);
+    if (Tok.isNot(tok::identifier) ||
+        !Tok.getIdentifierInfo()->isStr("optimize")) {
+      PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
+          << "clang repl";
+      return;
+    }
+
+    PP.LexUnexpandedToken(Tok);
+    if (Tok.isNot(tok::l_paren)) {
+      PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
+          << "clang repl optimize";
+      return;
+    }
+
+    PP.LexUnexpandedToken(Tok);
+    uint64_t OptLevel;
+    if (Tok.isNot(tok::numeric_constant) ||
+        !PP.parseSimpleIntegerLiteral(Tok, OptLevel) || OptLevel > 3) {
+      PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_integer)
+          << 0 << 3 << "clang repl optimize";
+      return;
+    }
+
+    if (Tok.isNot(tok::r_paren)) {
+      PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
+          << "clang repl optimize";
+      return;
+    }
+
+    PP.LexUnexpandedToken(Tok);
+    if (Tok.isNot(tok::eod)) {
+      PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+          << "clang repl optimize";
+      return;
+    }
+
+    Interp.setOptLevel(OptLevel);
+  }
+};
+
 } // anonymous namespace
 
 namespace clang {
@@ -370,6 +425,9 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> 
Instance,
   if (ErrOut)
     return;
 
+  ReplPragma = std::make_unique<PragmaReplHandler>(*this);
+  CI->getPreprocessor().AddPragmaHandler("clang", ReplPragma.get());
+
   if (Act->getCodeGen()) {
     Act->CacheCodeGenModule();
     // The initial PTU is filled by `-include`/`-include-pch` or by CUDA
@@ -402,6 +460,8 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> 
Instance,
 }
 
 Interpreter::~Interpreter() {
+  if (ReplPragma)
+    CI->getPreprocessor().RemovePragmaHandler("clang", ReplPragma.get());
   IncrParser.reset();
   Act->FinalizeAction();
   if (DeviceParser)
@@ -533,6 +593,20 @@ llvm::Expected<IncrementalExecutor &> 
Interpreter::getExecutionEngine() {
   return *IncrExecutor.get();
 }
 
+void Interpreter::setOptLevel(unsigned OptLevel) {
+  CodeGenerator *CG = Act->getCodeGen();
+  if (!CG)
+    return;
+
+  CodeGenOptions CGO = getCompilerInstance()->getCodeGenOpts();
+  CGO.OptimizationLevel = OptLevel;
+
+  // The next (empty) module was already staged with the old options; re-stage
+  // it so the new options apply to the next parsed input.
+  std::unique_ptr<llvm::Module> Empty(CG->ReleaseModule());
+  CG->StartModule("incr_module_opt", Empty->getContext(), CGO);
+}
+
 ASTContext &Interpreter::getASTContext() {
   return getCompilerInstance()->getASTContext();
 }
diff --git a/clang/test/Interpreter/pragma-optimize-diagnostics.cpp 
b/clang/test/Interpreter/pragma-optimize-diagnostics.cpp
new file mode 100644
index 0000000000000..ea6af462e54d0
--- /dev/null
+++ b/clang/test/Interpreter/pragma-optimize-diagnostics.cpp
@@ -0,0 +1,9 @@
+// REQUIRES: host-supports-jit
+//
+// RUN: cat %s | clang-repl -Xcc -Xclang -Xcc -verify
+
+#pragma clang repl optimise // expected-warning {{expected identifier in 
'#pragma clang repl' - ignored}}
+#pragma clang repl optimize // expected-warning {{missing '(' after '#pragma 
clang repl optimize' - ignoring}}
+#pragma clang repl optimize(9) // expected-warning {{expected integer between 
0 and 3 inclusive in '#pragma clang repl optimize' - ignored}}
+#pragma clang repl optimize(2 // expected-warning {{missing ')' after '#pragma 
clang repl optimize' - ignoring}}
+#pragma clang repl optimize(2) extra // expected-warning {{extra tokens at end 
of '#pragma clang repl optimize' - ignored}}
diff --git a/clang/test/Interpreter/pragma-optimize.cpp 
b/clang/test/Interpreter/pragma-optimize.cpp
new file mode 100644
index 0000000000000..ab262fc6db214
--- /dev/null
+++ b/clang/test/Interpreter/pragma-optimize.cpp
@@ -0,0 +1,16 @@
+// REQUIRES: host-supports-jit
+//
+// '#pragma clang repl optimize(N)' sets the optimization level used to emit
+// subsequent input: 'optnone' is present at -O0 and gone once the level is
+// raised.
+//
+// RUN: cat %s | clang-repl -Xcc -Xclang -Xcc -emit-llvm | FileCheck %s
+
+extern "C" int f_optnone() { return 0; }
+// CHECK: Function Attrs:{{.*}} optnone
+// CHECK-NEXT: define {{.*}} @f_optnone()
+
+#pragma clang repl optimize(2)
+extern "C" int f_optimized() { return 1; }
+// CHECK: define {{.*}} @f_optimized()
+// CHECK-NOT: optnone
diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp 
b/clang/unittests/Interpreter/InterpreterTest.cpp
index 450be2a25a12f..ff72baf7314a4 100644
--- a/clang/unittests/Interpreter/InterpreterTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterTest.cpp
@@ -22,6 +22,8 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Sema.h"
 
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
 #include "llvm/TargetParser/Host.h"
 
 #include "gmock/gmock.h"
@@ -551,6 +553,52 @@ TEST_F(InterpreterTest, ValueMoveSemantics) {
   Interp.reset();
 }
 
+TEST_F(InterpreterTest, SetOptLevel) {
+  std::unique_ptr<Interpreter> Interp = createInterpreter();
+
+  // -O0 emits functions with the 'optnone' attribute.
+  auto &PTU0 = cantFail(Interp->Parse("extern \"C\" int f0() { return 0; }"));
+  llvm::Function *F0 = PTU0.TheModule->getFunction("f0");
+  ASSERT_NE(F0, nullptr);
+  EXPECT_TRUE(F0->hasFnAttribute(llvm::Attribute::OptimizeNone));
+
+  // -O2 does not; the change must reach the next emitted module.
+  Interp->setOptLevel(2);
+
+  auto &PTU1 = cantFail(Interp->Parse("extern \"C\" int f1() { return 1; }"));
+  llvm::Function *F1 = PTU1.TheModule->getFunction("f1");
+  ASSERT_NE(F1, nullptr);
+  EXPECT_FALSE(F1->hasFnAttribute(llvm::Attribute::OptimizeNone));
+}
+
+TEST_F(InterpreterTest, PragmaOptimizeLevel) {
+  std::unique_ptr<Interpreter> Interp = createInterpreter();
+
+  auto HasOptNone = [](PartialTranslationUnit &PTU, const char *Name) {
+    llvm::Function *F = PTU.TheModule->getFunction(Name);
+    EXPECT_NE(F, nullptr);
+    return F && F->hasFnAttribute(llvm::Attribute::OptimizeNone);
+  };
+
+  // Default -O0: 'optnone' present.
+  auto &PTU0 = cantFail(Interp->Parse("extern \"C\" int f0() { return 0; }"));
+  EXPECT_TRUE(HasOptNone(PTU0, "f0"));
+
+  // The pragma governs the whole input it appears in; f1 is emitted at -O2.
+  auto &PTU1 = cantFail(Interp->Parse("#pragma clang repl optimize(2)\n"
+                                      "extern \"C\" int f1() { return 1; }"));
+  EXPECT_FALSE(HasOptNone(PTU1, "f1"));
+
+  // The level is sticky across inputs.
+  auto &PTU2 = cantFail(Interp->Parse("extern \"C\" int f2() { return 2; }"));
+  EXPECT_FALSE(HasOptNone(PTU2, "f2"));
+
+  // optimize(0) restores 'optnone'.
+  auto &PTU3 = cantFail(Interp->Parse("#pragma clang repl optimize(0)\n"
+                                      "extern \"C\" int f3() { return 3; }"));
+  EXPECT_TRUE(HasOptNone(PTU3, "f3"));
+}
+
 TEST_F(InterpreterTest, TranslationUnit_CanonicalDecl) {
   std::vector<const char *> Args;
   std::unique_ptr<Interpreter> Interp = createInterpreter(Args);

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to