Skip to content

Commit d95a5ff

Browse files
authored
[CIR][link-builtin-code] This PR adds support to link in bytecodes on CC1. (#2010)
@bcardosolopes I need some advice here. Is this a valid direction, do I respect sufficiently the original driver? If not, any pointers?
1 parent 0255897 commit d95a5ff

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

clang/lib/CIR/FrontendAction/CIRGenAction.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "llvm/IR/DebugInfo.h"
4141
#include "llvm/IR/DiagnosticInfo.h"
4242
#include "llvm/IR/DiagnosticPrinter.h"
43+
#include "llvm/IR/Function.h"
4344
#include "llvm/IR/GlobalValue.h"
4445
#include "llvm/IR/LLVMContext.h"
4546
#include "llvm/IR/LLVMRemarkStreamer.h"
@@ -48,6 +49,7 @@
4849
#include "llvm/LTO/LTOBackend.h"
4950
#include "llvm/Linker/Linker.h"
5051
#include "llvm/Pass.h"
52+
#include "llvm/Support/Error.h"
5153
#include "llvm/Support/MemoryBuffer.h"
5254
#include "llvm/Support/Path.h"
5355
#include "llvm/Support/Signals.h"
@@ -127,6 +129,27 @@ class CIRGenConsumer : public clang::ASTConsumer {
127129
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
128130
std::unique_ptr<CIRGenerator> Gen;
129131

132+
/// NOTE: LinkModule is taken from clang/include/clang/CodeGen/CodeGenAction.h
133+
/// This is clearly suboptimal and we should reuse their functionality.
134+
/// Info about module to link into a module we're generating.
135+
struct LinkModule {
136+
/// The module to link in.
137+
std::unique_ptr<llvm::Module> Module;
138+
139+
/// If true, we set attributes on Module's functions according to our
140+
/// CodeGenOptions and LangOptions, as though we were generating the
141+
/// function ourselves.
142+
bool PropagateAttrs;
143+
144+
/// If true, we use LLVM module internalizer.
145+
bool Internalize;
146+
147+
/// Bitwise combination of llvm::LinkerFlags used when we link the module.
148+
unsigned LinkFlags;
149+
};
150+
/// Bitcode modules to link in to our module.
151+
SmallVector<LinkModule, 4> LinkModules;
152+
130153
public:
131154
CIRGenConsumer(CIRGenAction::OutputType Action, class CompilerInstance &CI,
132155
class DiagnosticsEngine &Diags,
@@ -344,14 +367,27 @@ class CIRGenConsumer : public clang::ASTConsumer {
344367
case CIRGenAction::OutputType::EmitBC:
345368
case CIRGenAction::OutputType::EmitObj:
346369
case CIRGenAction::OutputType::EmitAssembly: {
370+
auto &CGOpts = CI.getCodeGenOpts();
371+
347372
llvm::LLVMContext LlvmCtx;
373+
LlvmCtx.setDefaultTargetCPU(TargetOpts.CPU);
374+
LlvmCtx.setDefaultTargetFeatures(llvm::join(TargetOpts.Features, ","));
375+
348376
bool DisableDebugInfo =
349377
CodeGenOpts.getDebugInfo() == llvm::codegenoptions::NoDebugInfo;
378+
379+
LoadLinkModules(LlvmCtx);
380+
350381
auto LlvmModule = lowerFromCIRToLLVMIR(
351382
FeOptions, MlirMod, std::move(MlirCtx), LlvmCtx,
352383
FeOptions.ClangIRDisableCIRVerifier,
353384
!FeOptions.ClangIRCallConvLowering, DisableDebugInfo);
354385

386+
LlvmModule->setTargetTriple(llvm::Triple(CI.getTargetOpts().Triple));
387+
LlvmModule->setDataLayout(C.getTargetInfo().getDataLayoutString());
388+
389+
LinkInModules(*LlvmModule);
390+
355391
BackendAction BackendAction = getBackendActionFromOutputType(Action);
356392

357393
emitBackendOutput(
@@ -364,6 +400,47 @@ class CIRGenConsumer : public clang::ASTConsumer {
364400
}
365401
}
366402

403+
void LoadLinkModules(llvm::LLVMContext &LlvmCtx) {
404+
for (const CodeGenOptions::BitcodeFileToLink &F :
405+
CI.getCodeGenOpts().LinkBitcodeFiles) {
406+
auto BCBuf = CI.getFileManager().getBufferForFile(F.Filename);
407+
if (!BCBuf) {
408+
CI.getDiagnostics().Report(diag::err_cannot_open_file)
409+
<< F.Filename << BCBuf.getError().message();
410+
LinkModules.clear();
411+
return;
412+
}
413+
414+
Expected<std::unique_ptr<llvm::Module>> ModuleOrErr =
415+
getOwningLazyBitcodeModule(std::move(*BCBuf), LlvmCtx);
416+
if (!ModuleOrErr) {
417+
handleAllErrors(ModuleOrErr.takeError(), [&](llvm::ErrorInfoBase &EIB) {
418+
CI.getDiagnostics().Report(diag::err_cannot_open_file)
419+
<< F.Filename << EIB.message();
420+
});
421+
LinkModules.clear();
422+
return;
423+
}
424+
LinkModules.push_back({std::move(ModuleOrErr.get()), F.PropagateAttrs,
425+
F.Internalize, F.LinkFlags});
426+
}
427+
return;
428+
}
429+
430+
// Links each entry in LinkModules into our module. Returns true on error.
431+
void LinkInModules(llvm::Module &M) {
432+
llvm::Linker L(M);
433+
434+
for (auto &LM : LinkModules) {
435+
// Link the module using LLVM's linker
436+
if (llvm::Linker::linkModules(M, std::move(LM.Module), LM.LinkFlags)) {
437+
CI.getDiagnostics().Report(diag::err_fe_linking_module)
438+
<< M.getModuleIdentifier() << LM.Module->getModuleIdentifier();
439+
return;
440+
}
441+
}
442+
}
443+
367444
void HandleTagDeclDefinition(TagDecl *D) override {
368445
PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
369446
AstContext->getSourceManager(),
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gpu -fclangir -DBITCODE -emit-llvm-bc -o %t.bc %s
2+
// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gpu -fclangir -DBITCODE2 -emit-llvm-bc -o %t-2.bc %s
3+
// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gpu -fclangir -mlink-bitcode-file %t.bc \
4+
// RUN: -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NO-BC %s
5+
// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gpu -fclangir -emit-llvm -o - \
6+
// RUN: -mlink-bitcode-file %t.bc -mlink-bitcode-file %t-2.bc %s \
7+
// RUN: | FileCheck -check-prefix=CHECK-NO-BC -check-prefix=CHECK-NO-BC2 %s
8+
// RUN: not %clang_cc1 -O1 -triple x86_64-unknown-linux-gpu -fclangir -DBITCODE -O3 -emit-llvm -o - \
9+
// RUN: -mlink-bitcode-file %t.bc %s 2>&1 | FileCheck -check-prefix=CHECK-BC %s
10+
// Make sure we deal with failure to load the file.
11+
// RUN: not %clang_cc1 -O1 -triple x86_64-unknown-linux-gpu -fclangir -mlink-bitcode-file no-such-file.bc \
12+
// RUN: -emit-llvm -o - %s 2>&1 | FileCheck -check-prefix=CHECK-NO-FILE %s
13+
14+
15+
int f(void);
16+
17+
#ifdef BITCODE
18+
19+
extern int f2(void);
20+
// CHECK-BC: error: Linking globals named {{.*}}'f': symbol multiply defined
21+
int f(void) {
22+
f2();
23+
return 42;
24+
}
25+
26+
#elif BITCODE2
27+
int f2(void) { return 43; }
28+
#else
29+
30+
// CHECK-NO-BC-LABEL: define{{.*}} i32 @g
31+
// CHECK-NO-BC: ret i32 42
32+
int g(void) {
33+
return f();
34+
}
35+
36+
// CHECK-NO-BC-LABEL: define{{.*}} i32 @f
37+
// CHECK-NO-BC2-LABEL: define{{.*}} i32 @f2
38+
39+
#endif
40+
41+
// CHECK-NO-FILE: fatal error: cannot open file 'no-such-file.bc'

0 commit comments

Comments
 (0)