1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
//===--- CodeGenModuleContainer.cpp - Emit .pcm files ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/CodeGenModuleContainer.h"
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/BackendUtil.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/TargetRegistry.h"
#include <memory>
using namespace clang;
namespace {
class ModuleContainerGenerator : public CodeGenerator {
DiagnosticsEngine &Diags;
std::unique_ptr<const llvm::DataLayout> TD;
ASTContext *Ctx;
const CodeGenOptions CodeGenOpts;
const TargetOptions TargetOpts;
const LangOptions LangOpts;
llvm::LLVMContext VMContext;
std::unique_ptr<llvm::Module> M;
std::unique_ptr<CodeGen::CodeGenModule> Builder;
raw_ostream *OS;
SmallVectorImpl<char> *SerializedASTBuffer;
public:
ModuleContainerGenerator(DiagnosticsEngine &diags,
const std::string &ModuleName,
const CodeGenOptions &CGO, const TargetOptions &TO,
const LangOptions &LO, raw_ostream *OS,
PCHGenerator *PCHGen)
: Diags(diags), CodeGenOpts(CGO), TargetOpts(TO), LangOpts(LO),
M(new llvm::Module(ModuleName, VMContext)), OS(OS) {
PCHGen->RegisterSerializationFinishedCallback(
[&](SmallVectorImpl<char> *Buf){
SerializedASTBuffer = Buf;
});
}
virtual ~ModuleContainerGenerator() {}
llvm::Module *GetModule() override { return M.get(); }
llvm::Module *ReleaseModule() override { return M.release(); }
/// Lifted from ModuleBuilder.
const Decl *GetDeclForMangledName(StringRef MangledName) override {
GlobalDecl Result;
if (!Builder->lookupRepresentativeDecl(MangledName, Result))
return nullptr;
const Decl *D = Result.getCanonicalDecl().getDecl();
if (auto FD = dyn_cast<FunctionDecl>(D)) {
if (FD->hasBody(FD))
return FD;
} else if (auto TD = dyn_cast<TagDecl>(D)) {
if (auto Def = TD->getDefinition())
return Def;
}
return D;
}
void Initialize(ASTContext &Context) override {
Ctx = &Context;
M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
M->setDataLayout(Ctx->getTargetInfo().getTargetDescription());
TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription()));
Builder.reset(
new CodeGen::CodeGenModule(Context, CodeGenOpts, *M, *TD, Diags));
}
/// Emit a container holding the serialized AST.
void HandleTranslationUnit(ASTContext &Ctx) override {
if (Diags.hasErrorOccurred()) {
if (Builder)
Builder->clear();
M.reset();
return;
}
// Finalize the Builder.
if (Builder)
Builder->Release();
// Initialize the backend if we haven't done so already.
LLVMInitializeAllTargetInfos();
LLVMInitializeAllTargets();
LLVMInitializeAllAsmPrinters();
LLVMInitializeAllTargetMCs();
// Ensure the target exists.
std::string Error;
auto Triple = Ctx.getTargetInfo().getTriple();
if (!llvm::TargetRegistry::lookupTarget(Triple.getTriple(), Error))
llvm::report_fatal_error(Error);
// Emit the serialized Clang AST into its own section.
auto Size = SerializedASTBuffer->size();
auto Int8Ty = llvm::Type::getInt8Ty(VMContext);
auto *Ty = llvm::ArrayType::get(Int8Ty, Size);
auto *Data = llvm::ConstantDataArray::getString(VMContext,
StringRef(SerializedASTBuffer->data(), Size), /*AddNull=*/false);
auto *ASTSym = new llvm::GlobalVariable(*M, Ty, /*constant*/ true,
llvm::GlobalVariable::InternalLinkage, Data, "__clang_ast");
ASTSym->setAlignment(8);
if (Triple.isOSBinFormatMachO())
// Include Mach-O segment name.
ASTSym->setSection("__CLANG,__clangast");
else if (Triple.isOSBinFormatCOFF())
// Adhere to COFF eight-character limit.
ASTSym->setSection("clangast");
else
ASTSym->setSection("__clangast");
// Use the LLVM backend to emit the pcm.
EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts,
Ctx.getTargetInfo().getTargetDescription(), M.get(),
BackendAction::Backend_EmitObj, OS);
// Make sure the module container hits disk now.
OS->flush();
// Free up some memory, in case the process is kept alive.
SerializedASTBuffer->clear();
}
};
}
CodeGenerator *clang::CreateModuleContainerGenerator(
DiagnosticsEngine &Diags, const std::string &ModuleName,
const CodeGenOptions &CGO, const TargetOptions &TO, const LangOptions &LO,
llvm::raw_ostream *OS, PCHGenerator *PCHGen) {
return
new ModuleContainerGenerator(Diags, ModuleName, CGO, TO, LO, OS, PCHGen);
}
|