1875ed548SDimitry Andric //===--- ObjectFilePCHContainerOperations.cpp -----------------------------===// 2875ed548SDimitry Andric // 3875ed548SDimitry Andric // The LLVM Compiler Infrastructure 4875ed548SDimitry Andric // 5875ed548SDimitry Andric // This file is distributed under the University of Illinois Open Source 6875ed548SDimitry Andric // License. See LICENSE.TXT for details. 7875ed548SDimitry Andric // 8875ed548SDimitry Andric //===----------------------------------------------------------------------===// 9875ed548SDimitry Andric 10875ed548SDimitry Andric #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" 11875ed548SDimitry Andric #include "CGDebugInfo.h" 12875ed548SDimitry Andric #include "CodeGenModule.h" 13875ed548SDimitry Andric #include "clang/AST/ASTContext.h" 14875ed548SDimitry Andric #include "clang/AST/DeclObjC.h" 15875ed548SDimitry Andric #include "clang/AST/Expr.h" 16875ed548SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 17875ed548SDimitry Andric #include "clang/Basic/Diagnostic.h" 18875ed548SDimitry Andric #include "clang/Basic/TargetInfo.h" 19875ed548SDimitry Andric #include "clang/CodeGen/BackendUtil.h" 20875ed548SDimitry Andric #include "clang/Frontend/CodeGenOptions.h" 21875ed548SDimitry Andric #include "clang/Serialization/ASTWriter.h" 22875ed548SDimitry Andric #include "llvm/ADT/StringRef.h" 23875ed548SDimitry Andric #include "llvm/Bitcode/BitstreamReader.h" 24875ed548SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 25875ed548SDimitry Andric #include "llvm/IR/Constants.h" 26875ed548SDimitry Andric #include "llvm/IR/DataLayout.h" 27875ed548SDimitry Andric #include "llvm/IR/LLVMContext.h" 28875ed548SDimitry Andric #include "llvm/IR/Module.h" 29875ed548SDimitry Andric #include "llvm/Object/COFF.h" 30875ed548SDimitry Andric #include "llvm/Object/ObjectFile.h" 31875ed548SDimitry Andric #include "llvm/Support/TargetRegistry.h" 32875ed548SDimitry Andric #include <memory> 33875ed548SDimitry Andric using namespace clang; 34875ed548SDimitry Andric 35875ed548SDimitry Andric #define DEBUG_TYPE "pchcontainer" 36875ed548SDimitry Andric 37875ed548SDimitry Andric namespace { 38875ed548SDimitry Andric class PCHContainerGenerator : public ASTConsumer { 39875ed548SDimitry Andric DiagnosticsEngine &Diags; 40875ed548SDimitry Andric const std::string MainFileName; 41875ed548SDimitry Andric ASTContext *Ctx; 42875ed548SDimitry Andric const HeaderSearchOptions &HeaderSearchOpts; 43875ed548SDimitry Andric const PreprocessorOptions &PreprocessorOpts; 44875ed548SDimitry Andric CodeGenOptions CodeGenOpts; 45875ed548SDimitry Andric const TargetOptions TargetOpts; 46875ed548SDimitry Andric const LangOptions LangOpts; 47875ed548SDimitry Andric std::unique_ptr<llvm::LLVMContext> VMContext; 48875ed548SDimitry Andric std::unique_ptr<llvm::Module> M; 49875ed548SDimitry Andric std::unique_ptr<CodeGen::CodeGenModule> Builder; 50875ed548SDimitry Andric raw_pwrite_stream *OS; 51875ed548SDimitry Andric std::shared_ptr<PCHBuffer> Buffer; 52875ed548SDimitry Andric 53875ed548SDimitry Andric public: 54875ed548SDimitry Andric PCHContainerGenerator(DiagnosticsEngine &diags, 55875ed548SDimitry Andric const HeaderSearchOptions &HSO, 56875ed548SDimitry Andric const PreprocessorOptions &PPO, const TargetOptions &TO, 57875ed548SDimitry Andric const LangOptions &LO, const std::string &MainFileName, 58875ed548SDimitry Andric const std::string &OutputFileName, 59875ed548SDimitry Andric raw_pwrite_stream *OS, 60875ed548SDimitry Andric std::shared_ptr<PCHBuffer> Buffer) 61875ed548SDimitry Andric : Diags(diags), HeaderSearchOpts(HSO), PreprocessorOpts(PPO), 62875ed548SDimitry Andric TargetOpts(TO), LangOpts(LO), OS(OS), Buffer(Buffer) { 63875ed548SDimitry Andric // The debug info output isn't affected by CodeModel and 64875ed548SDimitry Andric // ThreadModel, but the backend expects them to be nonempty. 65875ed548SDimitry Andric CodeGenOpts.CodeModel = "default"; 66875ed548SDimitry Andric CodeGenOpts.ThreadModel = "single"; 67875ed548SDimitry Andric CodeGenOpts.setDebugInfo(CodeGenOptions::FullDebugInfo); 68875ed548SDimitry Andric CodeGenOpts.SplitDwarfFile = OutputFileName; 69875ed548SDimitry Andric } 70875ed548SDimitry Andric 71875ed548SDimitry Andric virtual ~PCHContainerGenerator() {} 72875ed548SDimitry Andric 73875ed548SDimitry Andric void Initialize(ASTContext &Context) override { 74875ed548SDimitry Andric Ctx = &Context; 75875ed548SDimitry Andric VMContext.reset(new llvm::LLVMContext()); 76875ed548SDimitry Andric M.reset(new llvm::Module(MainFileName, *VMContext)); 77875ed548SDimitry Andric M->setDataLayout(Ctx->getTargetInfo().getTargetDescription()); 78875ed548SDimitry Andric Builder.reset(new CodeGen::CodeGenModule(*Ctx, HeaderSearchOpts, 79875ed548SDimitry Andric PreprocessorOpts, CodeGenOpts, *M, 80875ed548SDimitry Andric M->getDataLayout(), Diags)); 81875ed548SDimitry Andric } 82875ed548SDimitry Andric 83875ed548SDimitry Andric /// Emit a container holding the serialized AST. 84875ed548SDimitry Andric void HandleTranslationUnit(ASTContext &Ctx) override { 85875ed548SDimitry Andric assert(M && VMContext && Builder); 86875ed548SDimitry Andric // Delete these on function exit. 87875ed548SDimitry Andric std::unique_ptr<llvm::LLVMContext> VMContext = std::move(this->VMContext); 88875ed548SDimitry Andric std::unique_ptr<llvm::Module> M = std::move(this->M); 89875ed548SDimitry Andric std::unique_ptr<CodeGen::CodeGenModule> Builder = std::move(this->Builder); 90875ed548SDimitry Andric 91875ed548SDimitry Andric if (Diags.hasErrorOccurred()) 92875ed548SDimitry Andric return; 93875ed548SDimitry Andric 94875ed548SDimitry Andric M->setTargetTriple(Ctx.getTargetInfo().getTriple().getTriple()); 95875ed548SDimitry Andric M->setDataLayout(Ctx.getTargetInfo().getTargetDescription()); 96875ed548SDimitry Andric 97875ed548SDimitry Andric // Finalize the Builder. 98875ed548SDimitry Andric if (Builder) 99875ed548SDimitry Andric Builder->Release(); 100875ed548SDimitry Andric 101875ed548SDimitry Andric // Ensure the target exists. 102875ed548SDimitry Andric std::string Error; 103875ed548SDimitry Andric auto Triple = Ctx.getTargetInfo().getTriple(); 104875ed548SDimitry Andric if (!llvm::TargetRegistry::lookupTarget(Triple.getTriple(), Error)) 105875ed548SDimitry Andric llvm::report_fatal_error(Error); 106875ed548SDimitry Andric 107875ed548SDimitry Andric // Emit the serialized Clang AST into its own section. 108875ed548SDimitry Andric assert(Buffer->IsComplete && "serialization did not complete"); 109875ed548SDimitry Andric auto &SerializedAST = Buffer->Data; 110875ed548SDimitry Andric auto Size = SerializedAST.size(); 111875ed548SDimitry Andric auto Int8Ty = llvm::Type::getInt8Ty(*VMContext); 112875ed548SDimitry Andric auto *Ty = llvm::ArrayType::get(Int8Ty, Size); 113875ed548SDimitry Andric auto *Data = llvm::ConstantDataArray::getString( 114875ed548SDimitry Andric *VMContext, StringRef(SerializedAST.data(), Size), 115875ed548SDimitry Andric /*AddNull=*/false); 116875ed548SDimitry Andric auto *ASTSym = new llvm::GlobalVariable( 117875ed548SDimitry Andric *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage, Data, 118875ed548SDimitry Andric "__clang_ast"); 119875ed548SDimitry Andric // The on-disk hashtable needs to be aligned. 120875ed548SDimitry Andric ASTSym->setAlignment(8); 121875ed548SDimitry Andric 122875ed548SDimitry Andric // Mach-O also needs a segment name. 123875ed548SDimitry Andric if (Triple.isOSBinFormatMachO()) 124875ed548SDimitry Andric ASTSym->setSection("__CLANG,__clangast"); 125875ed548SDimitry Andric // COFF has an eight character length limit. 126875ed548SDimitry Andric else if (Triple.isOSBinFormatCOFF()) 127875ed548SDimitry Andric ASTSym->setSection("clangast"); 128875ed548SDimitry Andric else 129875ed548SDimitry Andric ASTSym->setSection("__clangast"); 130875ed548SDimitry Andric 131875ed548SDimitry Andric DEBUG({ 132875ed548SDimitry Andric // Print the IR for the PCH container to the debug output. 133875ed548SDimitry Andric llvm::SmallString<0> Buffer; 134875ed548SDimitry Andric llvm::raw_svector_ostream OS(Buffer); 135875ed548SDimitry Andric clang::EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts, 136875ed548SDimitry Andric Ctx.getTargetInfo().getTargetDescription(), 137875ed548SDimitry Andric M.get(), BackendAction::Backend_EmitLL, &OS); 138875ed548SDimitry Andric OS.flush(); 139875ed548SDimitry Andric llvm::dbgs() << Buffer; 140875ed548SDimitry Andric }); 141875ed548SDimitry Andric 142875ed548SDimitry Andric // Use the LLVM backend to emit the pch container. 143875ed548SDimitry Andric clang::EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts, 144875ed548SDimitry Andric Ctx.getTargetInfo().getTargetDescription(), 145875ed548SDimitry Andric M.get(), BackendAction::Backend_EmitObj, OS); 146875ed548SDimitry Andric 147875ed548SDimitry Andric // Make sure the pch container hits disk. 148875ed548SDimitry Andric OS->flush(); 149875ed548SDimitry Andric 150875ed548SDimitry Andric // Free the memory for the temporary buffer. 151875ed548SDimitry Andric llvm::SmallVector<char, 0> Empty; 152875ed548SDimitry Andric SerializedAST = std::move(Empty); 153875ed548SDimitry Andric } 154875ed548SDimitry Andric }; 155875ed548SDimitry Andric 156875ed548SDimitry Andric } // namespace 157875ed548SDimitry Andric 158875ed548SDimitry Andric std::unique_ptr<ASTConsumer> 159875ed548SDimitry Andric ObjectFilePCHContainerOperations::CreatePCHContainerGenerator( 160875ed548SDimitry Andric DiagnosticsEngine &Diags, const HeaderSearchOptions &HSO, 161875ed548SDimitry Andric const PreprocessorOptions &PPO, const TargetOptions &TO, 162875ed548SDimitry Andric const LangOptions &LO, const std::string &MainFileName, 163875ed548SDimitry Andric const std::string &OutputFileName, llvm::raw_pwrite_stream *OS, 164875ed548SDimitry Andric std::shared_ptr<PCHBuffer> Buffer) const { 165875ed548SDimitry Andric return llvm::make_unique<PCHContainerGenerator>( 166875ed548SDimitry Andric Diags, HSO, PPO, TO, LO, MainFileName, OutputFileName, OS, Buffer); 167875ed548SDimitry Andric } 168875ed548SDimitry Andric 169875ed548SDimitry Andric void ObjectFilePCHContainerOperations::ExtractPCH( 170875ed548SDimitry Andric llvm::MemoryBufferRef Buffer, llvm::BitstreamReader &StreamFile) const { 171875ed548SDimitry Andric if (auto OF = llvm::object::ObjectFile::createObjectFile(Buffer)) { 172875ed548SDimitry Andric auto *Obj = OF.get().get(); 173875ed548SDimitry Andric bool IsCOFF = isa<llvm::object::COFFObjectFile>(Obj); 174875ed548SDimitry Andric // Find the clang AST section in the container. 175875ed548SDimitry Andric for (auto &Section : OF->get()->sections()) { 176875ed548SDimitry Andric StringRef Name; 177875ed548SDimitry Andric Section.getName(Name); 178875ed548SDimitry Andric if ((!IsCOFF && Name == "__clangast") || 179875ed548SDimitry Andric ( IsCOFF && Name == "clangast")) { 180875ed548SDimitry Andric StringRef Buf; 181875ed548SDimitry Andric Section.getContents(Buf); 182875ed548SDimitry Andric StreamFile.init((const unsigned char *)Buf.begin(), 183875ed548SDimitry Andric (const unsigned char *)Buf.end()); 184875ed548SDimitry Andric return; 185875ed548SDimitry Andric } 186875ed548SDimitry Andric } 187875ed548SDimitry Andric } 188875ed548SDimitry Andric 189875ed548SDimitry Andric // As a fallback, treat the buffer as a raw AST. 190875ed548SDimitry Andric StreamFile.init((const unsigned char *)Buffer.getBufferStart(), 191875ed548SDimitry Andric (const unsigned char *)Buffer.getBufferEnd()); 192875ed548SDimitry Andric return; 193875ed548SDimitry Andric } 194