Skip to content

Commit 065cd64

Browse files
jeayevgvassilevkylc
authored
[clang-repl] Teach clang-repl how to load PCHs (reprise) (#157359)
This is an updated version of @vgvassilev's PR from last year here: #94166 In short, it includes: 1. The fix for a blocking issue where `clang::Interpreter` (and thus `clang-repl`) cannot resolve symbols defined in a PCH 2. A test to prove this is working 3. A new hidden flag for `clang-repl` so that `llvm-lit` can match the host JIT triple between the PCH and `clang-repl`; previously, they may differ in some cases 4. Everything based on the latest LLVM main Shout out to @kylc for finding a logic issue which had us stumped for a while (and securing the [bounty](jank-lang/jank#446)). --------- Co-authored-by: Vassil Vassilev <[email protected]> Co-authored-by: Kyle Cesare <[email protected]>
1 parent 709a74d commit 065cd64

File tree

10 files changed

+65
-18
lines changed

10 files changed

+65
-18
lines changed

clang/include/clang/CodeGen/ModuleBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ namespace CodeGen {
5252
class CodeGenerator : public ASTConsumer {
5353
virtual void anchor();
5454

55+
protected:
56+
/// True if we've finished generating IR. This prevents us from generating
57+
/// additional LLVM IR after emitting output in HandleTranslationUnit. This
58+
/// can happen when Clang plugins trigger additional AST deserialization.
59+
bool IRGenFinished = false;
60+
5561
public:
5662
/// Return an opaque reference to the CodeGenModule object, which can
5763
/// be used in various secondary APIs. It is valid as long as the

clang/lib/CodeGen/BackendConsumer.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ class BackendConsumer : public ASTConsumer {
4040
llvm::Timer LLVMIRGeneration;
4141
unsigned LLVMIRGenerationRefCount = 0;
4242

43-
/// True if we've finished generating IR. This prevents us from generating
44-
/// additional LLVM IR after emitting output in HandleTranslationUnit. This
45-
/// can happen when Clang plugins trigger additional AST deserialization.
46-
bool IRGenFinished = false;
47-
4843
bool TimerIsEnabled = false;
4944

5045
BackendAction Action;

clang/lib/CodeGen/CodeGenAction.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,7 @@ void BackendConsumer::HandleInlineFunctionDefinition(FunctionDecl *D) {
190190
}
191191

192192
void BackendConsumer::HandleInterestingDecl(DeclGroupRef D) {
193-
// Ignore interesting decls from the AST reader after IRGen is finished.
194-
if (!IRGenFinished)
195-
HandleTopLevelDecl(D);
193+
HandleTopLevelDecl(D);
196194
}
197195

198196
// Links each entry in LinkModules into our module. Returns true on error.
@@ -243,8 +241,6 @@ void BackendConsumer::HandleTranslationUnit(ASTContext &C) {
243241

244242
if (TimerIsEnabled && !--LLVMIRGenerationRefCount)
245243
LLVMIRGeneration.yieldTo(CI.getFrontendTimer());
246-
247-
IRGenFinished = true;
248244
}
249245

250246
// Silently ignore if we weren't initialized for some reason.

clang/lib/CodeGen/ModuleBuilder.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ namespace {
138138
assert(!M && "Replacing existing Module?");
139139
M.reset(new llvm::Module(ExpandModuleName(ModuleName, CodeGenOpts), C));
140140

141+
IRGenFinished = false;
142+
141143
std::unique_ptr<CodeGenModule> OldBuilder = std::move(Builder);
142144

143145
Initialize(*Ctx);
@@ -179,6 +181,10 @@ namespace {
179181
}
180182

181183
bool HandleTopLevelDecl(DeclGroupRef DG) override {
184+
// Ignore interesting decls from the AST reader after IRGen is finished.
185+
if (IRGenFinished)
186+
return true; // We can't CodeGen more but pass to other consumers.
187+
182188
// FIXME: Why not return false and abort parsing?
183189
if (Diags.hasUnrecoverableErrorOccurred())
184190
return true;
@@ -292,8 +298,9 @@ namespace {
292298
if (Builder)
293299
Builder->clear();
294300
M.reset();
295-
return;
296301
}
302+
303+
IRGenFinished = true;
297304
}
298305

299306
void AssignInheritanceModel(CXXRecordDecl *RD) override {

clang/lib/Interpreter/IncrementalAction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ std::unique_ptr<llvm::Module> IncrementalAction::GenModule() {
106106
// around we created an empty module to make CodeGen happy. We should make
107107
// sure it always stays empty.
108108
assert(((!CachedInCodeGenModule ||
109-
!CI.getPreprocessorOpts().Includes.empty()) ||
109+
!CI.getPreprocessorOpts().Includes.empty() ||
110+
!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) ||
110111
(CachedInCodeGenModule->empty() &&
111112
CachedInCodeGenModule->global_empty() &&
112113
CachedInCodeGenModule->alias_empty() &&

clang/lib/Interpreter/IncrementalParser.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ IncrementalParser::IncrementalParser(CompilerInstance &Instance,
3737
llvm::ErrorAsOutParameter EAO(&Err);
3838
Consumer = &S.getASTConsumer();
3939
P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false));
40+
41+
if (ExternalASTSource *External = S.getASTContext().getExternalSource())
42+
External->StartTranslationUnit(Consumer);
43+
4044
P->Initialize();
4145
}
4246

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,10 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
278278

279279
if (Act->getCodeGen()) {
280280
Act->CacheCodeGenModule();
281-
// The initial PTU is filled by `-include` or by CUDA includes
282-
// automatically.
283-
if (!CI->getPreprocessorOpts().Includes.empty()) {
281+
// The initial PTU is filled by `-include`/`-include-pch` or by CUDA
282+
// includes automatically.
283+
if (!CI->getPreprocessorOpts().Includes.empty() ||
284+
!CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
284285
// We can't really directly pass the CachedInCodeGenModule to the Jit
285286
// because it will steal it, causing dangling references as explained in
286287
// Interpreter::Execute
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// REQUIRES: host-supports-jit
2+
// UNSUPPORTED: system-aix
3+
//
4+
// RUN: rm -rf %t
5+
// RUN: mkdir -p %t
6+
// RUN: split-file %s %t
7+
//
8+
// RUN: %clang -fmax-type-align=16 -Xclang -fdeprecated-macro -fno-stack-protector -Xclang -fwrapv -Xclang -fblocks -Xclang -fskip-odr-check-in-gmf -fexceptions -fcxx-exceptions -fgnuc-version=0 -target %host-jit-triple -Xclang -fblocks -Xclang -fmax-type-align=8 -Xclang -fincremental-extensions -Xclang -emit-pch -x c++-header -o %t/include.pch %t/include.hpp
9+
//
10+
// RUN: cat %t/main.cpp \
11+
// RUN: | clang-repl -Xcc -fgnuc-version=0 -Xcc -fno-stack-protector -Xcc -fwrapv -Xcc -fblocks -Xcc -fskip-odr-check-in-gmf -Xcc -fmax-type-align=8 -Xcc -include-pch -Xcc %t/include.pch \
12+
// RUN: | FileCheck %s
13+
14+
//--- include.hpp
15+
16+
int f_pch() { return 5; }
17+
18+
//--- main.cpp
19+
20+
extern "C" int printf(const char *, ...);
21+
printf("f_pch = %d\n", f_pch());
22+
23+
// CHECK: f_pch = 5

clang/test/lit.cfg.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,16 @@ def have_host_out_of_process_jit_feature_support():
140140

141141
return False
142142

143-
def have_host_jit_feature_support(feature_name):
143+
144+
def run_clang_repl(args):
144145
clang_repl_exe = lit.util.which("clang-repl", config.clang_tools_dir)
145146

146147
if not clang_repl_exe:
147148
return False
148149

149150
try:
150151
clang_repl_cmd = subprocess.Popen(
151-
[clang_repl_exe, "--host-supports-" + feature_name], stdout=subprocess.PIPE
152+
[clang_repl_exe, args], stdout=subprocess.PIPE
152153
)
153154
except OSError:
154155
print("could not exec clang-repl")
@@ -157,7 +158,11 @@ def have_host_jit_feature_support(feature_name):
157158
clang_repl_out = clang_repl_cmd.stdout.read().decode("ascii")
158159
clang_repl_cmd.wait()
159160

160-
return "true" in clang_repl_out
161+
return clang_repl_out
162+
163+
164+
def have_host_jit_feature_support(feature_name):
165+
return "true" in run_clang_repl("--host-supports-" + feature_name)
161166

162167
def have_host_clang_repl_cuda():
163168
clang_repl_exe = lit.util.which('clang-repl', config.clang_tools_dir)
@@ -191,6 +196,8 @@ def have_host_clang_repl_cuda():
191196

192197
if have_host_clang_repl_cuda():
193198
config.available_features.add('host-supports-cuda')
199+
hosttriple = run_clang_repl("--host-jit-triple")
200+
config.substitutions.append(("%host-jit-triple", hosttriple.strip()))
194201

195202
if have_host_out_of_process_jit_feature_support():
196203
config.available_features.add("host-supports-out-of-process-jit")

clang/tools/clang-repl/ClangRepl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ static llvm::cl::list<std::string>
8585
llvm::cl::CommaSeparated);
8686
static llvm::cl::opt<bool> OptHostSupportsJit("host-supports-jit",
8787
llvm::cl::Hidden);
88+
static llvm::cl::opt<bool> OptHostJitTriple("host-jit-triple",
89+
llvm::cl::Hidden);
8890
static llvm::cl::list<std::string> OptInputs(llvm::cl::Positional,
8991
llvm::cl::desc("[code to run]"));
9092

@@ -279,6 +281,11 @@ int main(int argc, const char **argv) {
279281
llvm::outs() << "false\n";
280282
}
281283
return 0;
284+
} else if (OptHostJitTriple) {
285+
auto J = ExitOnErr(llvm::orc::LLJITBuilder().create());
286+
auto T = J->getTargetTriple();
287+
llvm::outs() << T.normalize() << '\n';
288+
return 0;
282289
}
283290

284291
clang::IncrementalCompilerBuilder CB;

0 commit comments

Comments
 (0)